@jingyi0605/codingns4dsh 0.2.1-beta.7 → 0.2.1-beta.8

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 (159) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +5 -3
  3. package/data/build/dist/client/avatar/desktop-bridge.js +1 -1
  4. package/data/build/dist/client/avatar/desktop-bridge.js.map +1 -1
  5. package/data/build/dist/client/avatar/desktop-view.d.ts +4 -2
  6. package/data/build/dist/client/avatar/desktop-view.d.ts.map +1 -1
  7. package/data/build/dist/client/avatar/desktop-view.js +25 -9
  8. package/data/build/dist/client/avatar/desktop-view.js.map +1 -1
  9. package/data/build/dist/client/avatar/floating.d.ts +5 -2
  10. package/data/build/dist/client/avatar/floating.d.ts.map +1 -1
  11. package/data/build/dist/client/avatar/floating.js +16 -5
  12. package/data/build/dist/client/avatar/floating.js.map +1 -1
  13. package/data/build/dist/client/avatar/notification-bubble.d.ts +18 -5
  14. package/data/build/dist/client/avatar/notification-bubble.d.ts.map +1 -1
  15. package/data/build/dist/client/avatar/notification-bubble.js +208 -56
  16. package/data/build/dist/client/avatar/notification-bubble.js.map +1 -1
  17. package/data/build/dist/client/avatar/notification-surface.d.ts +16 -0
  18. package/data/build/dist/client/avatar/notification-surface.d.ts.map +1 -0
  19. package/data/build/dist/client/avatar/notification-surface.js +54 -0
  20. package/data/build/dist/client/avatar/notification-surface.js.map +1 -0
  21. package/data/build/dist/client/avatar/reaction-badge.d.ts.map +1 -1
  22. package/data/build/dist/client/avatar/reaction-badge.js +11 -2
  23. package/data/build/dist/client/avatar/reaction-badge.js.map +1 -1
  24. package/data/build/dist/client/bundle.js +1131 -392
  25. package/data/build/dist/client/bundle.js.map +1 -1
  26. package/data/build/dist/client/client.assistant-notifications.js.map +1 -1
  27. package/data/build/dist/client/client.assistant-workbench.js +235 -109
  28. package/data/build/dist/client/client.assistant-workbench.js.map +1 -1
  29. package/data/build/dist/client/client.manager.js +46 -9
  30. package/data/build/dist/client/client.manager.js.map +1 -1
  31. package/data/build/dist/client/client.native-workspace-store.js +1 -1
  32. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  33. package/data/build/dist/client/client.theme.js +2 -0
  34. package/data/build/dist/client/client.theme.js.map +1 -1
  35. package/data/build/dist/client/client.transport.js +37 -9
  36. package/data/build/dist/client/client.transport.js.map +1 -1
  37. package/data/build/dist/client/desktop-assistant.js +57743 -359
  38. package/data/build/dist/client/features/assistant-conversation-message.d.ts +2 -1
  39. package/data/build/dist/client/features/assistant-conversation-message.d.ts.map +1 -1
  40. package/data/build/dist/client/features/assistant-conversation-message.js +59 -24
  41. package/data/build/dist/client/features/assistant-conversation-message.js.map +1 -1
  42. package/data/build/dist/client/features/assistant-notification-store.d.ts +7 -1
  43. package/data/build/dist/client/features/assistant-notification-store.d.ts.map +1 -1
  44. package/data/build/dist/client/features/assistant-notification-store.js +44 -0
  45. package/data/build/dist/client/features/assistant-notification-store.js.map +1 -1
  46. package/data/build/dist/client/features/assistant-record-style.js +11 -4
  47. package/data/build/dist/client/features/assistant-record-style.js.map +1 -1
  48. package/data/build/dist/client/features/assistant-workbench.d.ts +4 -0
  49. package/data/build/dist/client/features/assistant-workbench.d.ts.map +1 -1
  50. package/data/build/dist/client/features/assistant-workbench.js +27 -1
  51. package/data/build/dist/client/features/assistant-workbench.js.map +1 -1
  52. package/data/build/dist/client/features/global-voice-assistant.d.ts.map +1 -1
  53. package/data/build/dist/client/features/global-voice-assistant.js +36 -4
  54. package/data/build/dist/client/features/global-voice-assistant.js.map +1 -1
  55. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  56. package/data/build/dist/client/features/peer-host.js +33 -2
  57. package/data/build/dist/client/features/peer-host.js.map +1 -1
  58. package/data/build/dist/client/locales/assistantWorkbench.d.ts +17 -3
  59. package/data/build/dist/client/locales/assistantWorkbench.d.ts.map +1 -1
  60. package/data/build/dist/client/locales/assistantWorkbench.js +15 -11
  61. package/data/build/dist/client/locales/assistantWorkbench.js.map +1 -1
  62. package/data/build/dist/client/peer-host-native-projection.d.ts +4 -0
  63. package/data/build/dist/client/peer-host-native-projection.d.ts.map +1 -1
  64. package/data/build/dist/client/peer-host-native-projection.js +40 -1
  65. package/data/build/dist/client/peer-host-native-projection.js.map +1 -1
  66. package/data/build/dist/client/peer-host-remote-events.d.ts +14 -0
  67. package/data/build/dist/client/peer-host-remote-events.d.ts.map +1 -1
  68. package/data/build/dist/client/peer-host-remote-events.js +92 -3
  69. package/data/build/dist/client/peer-host-remote-events.js.map +1 -1
  70. package/data/build/dist/client/style.css +2561 -0
  71. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  72. package/data/build/dist/client/subscription-slot.js +5 -1
  73. package/data/build/dist/client/subscription-slot.js.map +1 -1
  74. package/data/build/dist/client/theme.d.ts +2 -0
  75. package/data/build/dist/client/theme.d.ts.map +1 -1
  76. package/data/build/dist/client/theme.js +3 -0
  77. package/data/build/dist/client/theme.js.map +1 -1
  78. package/data/build/dist/client/workspace-session-visibility-dom.d.ts.map +1 -1
  79. package/data/build/dist/client/workspace-session-visibility-dom.js +22 -10
  80. package/data/build/dist/client/workspace-session-visibility-dom.js.map +1 -1
  81. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.d.ts +9 -1
  82. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.d.ts.map +1 -1
  83. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.js +39 -0
  84. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.js.map +1 -1
  85. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +1 -0
  86. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  87. package/data/build/dist/host/cli-adapters/codex-driver.js +7 -0
  88. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  89. package/data/build/dist/host/cli-adapters/codex-file-citations.d.ts +13 -0
  90. package/data/build/dist/host/cli-adapters/codex-file-citations.d.ts.map +1 -0
  91. package/data/build/dist/host/cli-adapters/codex-file-citations.js +271 -0
  92. package/data/build/dist/host/cli-adapters/codex-file-citations.js.map +1 -0
  93. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +2 -1
  94. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  95. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +16 -5
  96. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  97. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  98. package/data/build/dist/host/cli-adapters/feature.js +1 -0
  99. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  100. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.d.ts.map +1 -1
  101. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js +20 -3
  102. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js.map +1 -1
  103. package/data/build/dist/host/desktop-assistant/controller.d.ts +2 -0
  104. package/data/build/dist/host/desktop-assistant/controller.d.ts.map +1 -1
  105. package/data/build/dist/host/desktop-assistant/controller.js +28 -1
  106. package/data/build/dist/host/desktop-assistant/controller.js.map +1 -1
  107. package/data/build/dist/host/features/assistant-management-tools.d.ts +2 -1
  108. package/data/build/dist/host/features/assistant-management-tools.d.ts.map +1 -1
  109. package/data/build/dist/host/features/assistant-management-tools.js +10 -3
  110. package/data/build/dist/host/features/assistant-management-tools.js.map +1 -1
  111. package/data/build/dist/host/features/assistant-notification-events.js +1 -1
  112. package/data/build/dist/host/features/assistant-notification-events.js.map +1 -1
  113. package/data/build/dist/host/features/assistant-notifications.d.ts +8 -1
  114. package/data/build/dist/host/features/assistant-notifications.d.ts.map +1 -1
  115. package/data/build/dist/host/features/assistant-notifications.js +105 -11
  116. package/data/build/dist/host/features/assistant-notifications.js.map +1 -1
  117. package/data/build/dist/host/features/global-voice-rpc.d.ts +2 -2
  118. package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
  119. package/data/build/dist/host/features/global-voice-rpc.js +89 -2
  120. package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
  121. package/data/build/dist/host/features/peer-host.d.ts.map +1 -1
  122. package/data/build/dist/host/features/peer-host.js +34 -5
  123. package/data/build/dist/host/features/peer-host.js.map +1 -1
  124. package/data/build/dist/host/features/types.d.ts +3 -1
  125. package/data/build/dist/host/features/types.d.ts.map +1 -1
  126. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts +7 -1
  127. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts.map +1 -1
  128. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js +23 -4
  129. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js.map +1 -1
  130. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  131. package/data/build/dist/host/native-session-bridge.js +22 -9
  132. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  133. package/data/build/dist/host/rpc.js +1 -1
  134. package/data/build/dist/host/rpc.js.map +1 -1
  135. package/data/build/dist/shared/assistant-message-timeline.d.ts +11 -0
  136. package/data/build/dist/shared/assistant-message-timeline.d.ts.map +1 -1
  137. package/data/build/dist/shared/assistant-message-timeline.js +19 -0
  138. package/data/build/dist/shared/assistant-message-timeline.js.map +1 -1
  139. package/data/build/dist/shared/assistant-notifications.d.ts +34 -0
  140. package/data/build/dist/shared/assistant-notifications.d.ts.map +1 -1
  141. package/data/build/dist/shared/assistant-notifications.js +8 -0
  142. package/data/build/dist/shared/assistant-notifications.js.map +1 -1
  143. package/data/build/dist/shared/assistant-session-messages.d.ts +13 -0
  144. package/data/build/dist/shared/assistant-session-messages.d.ts.map +1 -0
  145. package/data/build/dist/shared/assistant-session-messages.js +155 -0
  146. package/data/build/dist/shared/assistant-session-messages.js.map +1 -0
  147. package/data/build/dist/shared/contracts/assistant.d.ts +13 -0
  148. package/data/build/dist/shared/contracts/assistant.d.ts.map +1 -1
  149. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  150. package/data/build/dist/shared/contracts/version.js +1 -1
  151. package/data/build/dist/shared/desktop-assistant.d.ts +2 -1
  152. package/data/build/dist/shared/desktop-assistant.d.ts.map +1 -1
  153. package/data/build/dist/shared/desktop-assistant.js +21 -9
  154. package/data/build/dist/shared/desktop-assistant.js.map +1 -1
  155. package/package.json +16 -14
  156. package/profile/README.md +2 -2
  157. package/profile/package.json +2 -2
  158. package/profile/version.json +1 -1
  159. package/version.json +1 -1
@@ -1569,6 +1569,28 @@ window.__ModuleLoader__.load({
1569
1569
  });
1570
1570
  return parts;
1571
1571
  }
1572
+ /** 将同一正文位置连续发生的工具归入一个 DSH 风格 step;正文仍保持原有穿插位置。 */
1573
+ function assistantMessageStepTimeline(text, calls = []) {
1574
+ const parts = assistantMessageTimeline(text, calls);
1575
+ const grouped = [];
1576
+ for (const part of parts) {
1577
+ if (part.kind === "text") {
1578
+ grouped.push(part);
1579
+ continue;
1580
+ }
1581
+ const previous = grouped.at(-1);
1582
+ if (previous?.kind === "tool-step") grouped[grouped.length - 1] = {
1583
+ ...previous,
1584
+ calls: [...previous.calls, part.call]
1585
+ };
1586
+ else grouped.push({
1587
+ kind: "tool-step",
1588
+ key: `tool-step-${part.call.id}`,
1589
+ calls: [part.call]
1590
+ });
1591
+ }
1592
+ return grouped;
1593
+ }
1572
1594
  //#endregion
1573
1595
  //#region src/client/features/assistant-record-style.ts
1574
1596
  /** 工具记录和通话记录共享交互反馈,选择器只作用于这两类组件。 */
@@ -1594,14 +1616,21 @@ window.__ModuleLoader__.load({
1594
1616
  }, (0, react.createElement)("path", { d: "m9 5 7 7-7 7" }));
1595
1617
  }
1596
1618
  const recordCss = `
1597
- .codingns-assistant-tool-summary{list-style:none;cursor:pointer;border-radius:9px}
1619
+ .codingns-assistant-tool-summary{list-style:none;cursor:pointer}
1598
1620
  .codingns-assistant-tool-summary::-webkit-details-marker{display:none}
1599
- .codingns-assistant-tool-summary:hover,.codingns-assistant-record-button:hover{background:${require_theme.dshThemeColor.hoverBackground}!important}
1600
- .codingns-assistant-tool-summary:active,.codingns-assistant-record-button:active{background:${require_theme.dshThemeColor.activeBackground}!important}
1621
+ .codingns-assistant-tool-summary:hover,.codingns-assistant-record-button:hover{color:${require_theme.dshThemeColor.labelPrimary}!important}
1622
+ .codingns-assistant-tool-summary:active,.codingns-assistant-record-button:active{color:${require_theme.dshThemeColor.labelPrimary}!important}
1601
1623
  .codingns-assistant-tool-summary:focus-visible,.codingns-assistant-record-button:focus-visible{outline:2px solid ${require_theme.dshThemeColor.accent};outline-offset:2px}
1602
- .codingns-assistant-tool-details[open]>.codingns-assistant-tool-summary{border-radius:9px 9px 0 0}
1603
1624
  .codingns-assistant-tool-details[open] .codingns-assistant-tool-name{white-space:normal!important;overflow-wrap:anywhere}
1604
1625
  .codingns-assistant-tool-details[open]>.codingns-assistant-tool-summary .codingns-assistant-record-chevron{transform:rotate(90deg)}
1626
+ .codingns-assistant-tool-step-summary{list-style:none;cursor:pointer}
1627
+ .codingns-assistant-tool-step-summary::-webkit-details-marker{display:none}
1628
+ .codingns-assistant-tool-step-summary:hover{color:${require_theme.dshThemeColor.labelPrimary}!important}
1629
+ .codingns-assistant-tool-step-summary:active{color:${require_theme.dshThemeColor.labelPrimary}!important}
1630
+ .codingns-assistant-tool-step-summary:focus-visible{outline:2px solid ${require_theme.dshThemeColor.accent};outline-offset:2px}
1631
+ .codingns-assistant-tool-step-details[open]>.codingns-assistant-tool-step-summary .codingns-assistant-step-chevron{transform:rotate(180deg)}
1632
+ .codingns-assistant-tool-step-details[open] .codingns-assistant-tool-step-body{padding-inline:4px}
1633
+ .codingns-assistant-tool-step-details[open] .codingns-assistant-tool-step-preview{white-space:normal;overflow-wrap:anywhere}
1605
1634
  .codingns-assistant-voice-dialog[open]{display:flex;flex-direction:column}
1606
1635
  .codingns-assistant-voice-dialog::backdrop{background:${require_theme.dshThemeColor.overlay}}
1607
1636
  `;
@@ -1660,9 +1689,9 @@ window.__ModuleLoader__.load({
1660
1689
  }
1661
1690
  /** 文字聊天、实时字幕与通话历史共用同一时间线,不额外生成工具汇总区。 */
1662
1691
  function AssistantMessageContentView({ text, calls, t }) {
1663
- return (0, react.createElement)(react.Fragment, null, ...assistantMessageTimeline(text, calls).map((part) => part.kind === "tool" ? (0, react.createElement)(AssistantToolCallsView, {
1692
+ return (0, react.createElement)(react.Fragment, null, ...assistantMessageStepTimeline(text, calls).map((part) => part.kind === "tool-step" ? (0, react.createElement)(AssistantToolStepView, {
1664
1693
  key: part.key,
1665
- calls: [part.call],
1694
+ calls: part.calls,
1666
1695
  t
1667
1696
  }) : (0, react.createElement)("div", {
1668
1697
  key: part.key,
@@ -1674,14 +1703,15 @@ window.__ModuleLoader__.load({
1674
1703
  }, part.text)));
1675
1704
  }
1676
1705
  /** 工具信息单独展示,不拼入消息正文,字幕与语音合成都只使用原始 text。 */
1677
- function AssistantToolCallsView({ calls, t }) {
1706
+ function AssistantToolCallsView({ calls, t, compact = false }) {
1678
1707
  if (!calls?.length) return null;
1679
1708
  return (0, react.createElement)("div", {
1680
1709
  "data-codingns-assistant-tools": true,
1710
+ "data-codingns-assistant-tools-compact": compact,
1681
1711
  style: {
1682
1712
  display: "grid",
1683
- gap: 6,
1684
- marginBlock: 6,
1713
+ gap: 2,
1714
+ marginBlock: compact ? 0 : 6,
1685
1715
  textAlign: "left",
1686
1716
  whiteSpace: "normal",
1687
1717
  minWidth: 0
@@ -1689,26 +1719,113 @@ window.__ModuleLoader__.load({
1689
1719
  }, (0, react.createElement)(AssistantRecordStyle), ...calls.map((call) => (0, react.createElement)(AssistantToolCallView, {
1690
1720
  key: call.id,
1691
1721
  call,
1692
- t
1722
+ t,
1723
+ compact
1693
1724
  })));
1694
1725
  }
1726
+ /** 一个 step 只显示摘要;展开后才加载其中的工具调用明细。 */
1727
+ function AssistantToolStepView({ calls, t }) {
1728
+ if (calls.length === 0) return null;
1729
+ const running = calls.some((call) => call.state === "running");
1730
+ const failed = calls.some((call) => call.state === "failed");
1731
+ const status = running ? "running" : failed ? "failed" : calls.every((call) => call.state === "cancelled") ? "cancelled" : "completed";
1732
+ const latestCall = calls[calls.length - 1];
1733
+ const latestArguments = assistantToolArgumentPreview(latestCall, t);
1734
+ const summary = calls.map((call) => assistantToolStepPreview(call, t)).filter((value, index, all) => all.indexOf(value) === index).join(t("awb.call.separator"));
1735
+ return (0, react.createElement)("div", {
1736
+ "data-codingns-assistant-tool-step": true,
1737
+ style: {
1738
+ marginBlock: 6,
1739
+ textAlign: "left",
1740
+ whiteSpace: "normal",
1741
+ minWidth: 0,
1742
+ color: require_theme.dshThemeColor.labelSecondary,
1743
+ fontSize: require_theme.uiFontSize(13),
1744
+ lineHeight: 1.6
1745
+ }
1746
+ }, (0, react.createElement)(AssistantRecordStyle), (0, react.createElement)("details", { className: "codingns-assistant-tool-step-details" }, (0, react.createElement)("summary", {
1747
+ className: "codingns-assistant-tool-step-summary",
1748
+ title: t("awb.call.stepDetails"),
1749
+ "aria-label": `${t("awb.call.step")} · ${summary} · ${t(`awb.call.tool.${status}`)}`,
1750
+ style: {
1751
+ display: "flex",
1752
+ alignItems: "center",
1753
+ gap: 8,
1754
+ minWidth: 0,
1755
+ padding: "2px 0",
1756
+ color: require_theme.dshThemeColor.labelSecondary
1757
+ }
1758
+ }, (0, react.createElement)(AssistantStepChevron), (0, react.createElement)("span", {
1759
+ className: "codingns-assistant-tool-step-preview",
1760
+ "data-latest-tool": latestCall.name,
1761
+ title: latestCall.name,
1762
+ style: {
1763
+ minWidth: 0,
1764
+ overflow: "hidden",
1765
+ textOverflow: "ellipsis",
1766
+ whiteSpace: "nowrap"
1767
+ }
1768
+ }, summary, " · ", (0, react.createElement)("code", { style: {
1769
+ color: require_theme.dshThemeColor.labelPrimary,
1770
+ fontFamily: require_theme.dshThemeColor.codeFont,
1771
+ fontSize: "0.92em"
1772
+ } }, latestCall.name), latestArguments ? ` · ${latestArguments}` : "")), (0, react.createElement)("div", {
1773
+ className: "codingns-assistant-tool-step-body",
1774
+ style: {
1775
+ display: "grid",
1776
+ gap: 1,
1777
+ padding: "4px 0 5px 21px"
1778
+ }
1779
+ }, (0, react.createElement)(AssistantToolCallsView, {
1780
+ calls,
1781
+ t,
1782
+ compact: true
1783
+ }))));
1784
+ }
1785
+ function assistantToolStepPreview(call, t) {
1786
+ if (call.name.includes("read") || call.kind === "attachment") return t("awb.call.stepRead");
1787
+ if (call.name.includes("search") || call.kind === "web-search") return t("awb.call.stepSearch");
1788
+ if (call.name.includes("workspace") || call.kind === "workspace") return t("awb.call.stepWorkspace");
1789
+ return t("awb.call.stepTool");
1790
+ }
1791
+ function assistantToolArgumentPreview(call, t) {
1792
+ try {
1793
+ const args = JSON.parse(call.arguments);
1794
+ if (args === null || typeof args !== "object" || Array.isArray(args)) return "";
1795
+ const record = args;
1796
+ for (const key of [
1797
+ "query",
1798
+ "queries",
1799
+ "text",
1800
+ "url",
1801
+ "fileName",
1802
+ "filename",
1803
+ "file",
1804
+ "title",
1805
+ "message"
1806
+ ]) {
1807
+ const value = record[key];
1808
+ const preview = typeof value === "string" ? value : Array.isArray(value) ? value.filter((item) => typeof item === "string").join(t("awb.call.separator")) : "";
1809
+ if (preview.trim()) return preview.trim().slice(0, 120);
1810
+ }
1811
+ } catch {}
1812
+ return "";
1813
+ }
1695
1814
  /** 整个标题栏就是展开入口;实时状态更新不替换 details,保留用户的展开状态。 */
1696
- function AssistantToolCallView({ call, t }) {
1815
+ function AssistantToolCallView({ call, t, compact = false }) {
1697
1816
  const label = t(call.kind === "web-search" ? "awb.call.webSearch" : call.kind === "attachment" ? "awb.call.attachment" : "awb.call.workspace");
1698
1817
  const status = t(`awb.call.tool.${call.state}`);
1699
- const color = call.state === "failed" ? require_theme.dshThemeColor.error : call.state === "completed" ? require_theme.dshThemeColor.success : call.state === "running" ? require_theme.dshThemeColor.accent : require_theme.dshThemeColor.labelSecondary;
1700
- const startedAt = new Date(call.startedAt);
1701
- return (0, react.createElement)("article", {
1818
+ const argumentPreview = compact ? assistantToolArgumentPreview(call, t) : "";
1819
+ const rowColor = call.state === "failed" ? require_theme.dshThemeColor.error : require_theme.dshThemeColor.labelSecondary;
1820
+ return (0, react.createElement)("div", {
1821
+ "data-codingns-assistant-tool-row": call.name,
1702
1822
  "data-codingns-assistant-tool": call.name,
1703
1823
  "data-state": call.state,
1704
1824
  style: {
1705
- borderRadius: 10,
1706
- border: `1px solid ${require_theme.dshThemeColor.border}`,
1707
- background: require_theme.dshThemeColor.surfaceSubtle,
1708
- color: require_theme.dshThemeColor.labelPrimary,
1709
- fontSize: require_theme.uiFontSize(12),
1710
- lineHeight: 1.4,
1711
- minWidth: 0
1825
+ minWidth: 0,
1826
+ color: rowColor,
1827
+ fontSize: require_theme.uiFontSize(13),
1828
+ lineHeight: 1.65
1712
1829
  }
1713
1830
  }, (0, react.createElement)("details", { className: "codingns-assistant-tool-details" }, (0, react.createElement)("summary", {
1714
1831
  className: "codingns-assistant-tool-summary",
@@ -1718,98 +1835,53 @@ window.__ModuleLoader__.load({
1718
1835
  display: "flex",
1719
1836
  alignItems: "center",
1720
1837
  gap: 8,
1721
- padding: "8px 10px",
1722
- minWidth: 0
1838
+ minWidth: 0,
1839
+ padding: "1px 0"
1723
1840
  }
1724
- }, (0, react.createElement)("span", { style: {
1725
- display: "grid",
1726
- placeItems: "center",
1727
- flexShrink: 0,
1728
- width: 28,
1729
- height: 28,
1730
- borderRadius: 8,
1731
- color,
1732
- background: `color-mix(in srgb, ${color} 9%, transparent)`
1733
- } }, (0, react.createElement)(AssistantToolIcon, { kind: call.kind })), (0, react.createElement)("span", { style: {
1734
- flex: "1 1 auto",
1735
- minWidth: 0,
1736
- display: "grid",
1737
- gap: 1
1738
- } }, (0, react.createElement)("strong", { style: {
1739
- fontSize: require_theme.uiFontSize(12),
1740
- fontWeight: 600
1741
- } }, label), (0, react.createElement)("span", {
1742
- className: "codingns-assistant-tool-name",
1841
+ }, (0, react.createElement)(AssistantRecordChevron), (0, react.createElement)("span", { style: { flexShrink: 0 } }, label), (0, react.createElement)("span", { style: {
1842
+ color: require_theme.dshThemeColor.labelTertiary,
1843
+ flexShrink: 0
1844
+ } }, "·"), (0, react.createElement)("span", {
1743
1845
  title: call.name,
1744
1846
  style: {
1745
- color: require_theme.dshThemeColor.labelSecondary,
1746
- fontFamily: require_theme.dshThemeColor.codeFont,
1747
- fontSize: require_theme.uiFontSize(11),
1847
+ minWidth: 0,
1748
1848
  overflow: "hidden",
1749
1849
  textOverflow: "ellipsis",
1750
- whiteSpace: "nowrap"
1751
- }
1752
- }, call.name)), (0, react.createElement)("span", { style: {
1753
- display: "grid",
1754
- justifyItems: "end",
1755
- gap: 3,
1756
- flexShrink: 0
1757
- } }, (0, react.createElement)("span", {
1758
- role: "status",
1759
- style: {
1760
- display: "inline-flex",
1761
- alignItems: "center",
1762
- gap: 4,
1763
- color,
1764
- padding: "1px 6px",
1765
- borderRadius: 5,
1766
- background: `color-mix(in srgb, ${color} 9%, transparent)`,
1767
- fontSize: require_theme.uiFontSize(11),
1768
- whiteSpace: "nowrap"
1850
+ whiteSpace: "nowrap",
1851
+ fontFamily: require_theme.dshThemeColor.codeFont
1769
1852
  }
1770
- }, (0, react.createElement)("span", {
1771
- "aria-hidden": true,
1853
+ }, call.name, argumentPreview ? ` · ${argumentPreview}` : "")), (0, react.createElement)("div", {
1854
+ className: "codingns-assistant-tool-body",
1772
1855
  style: {
1773
- width: 4,
1774
- height: 4,
1775
- borderRadius: "50%",
1776
- background: "currentColor"
1856
+ display: "grid",
1857
+ gap: 0,
1858
+ margin: "2px 0 4px 22px",
1859
+ border: `0.5px solid ${require_theme.dshThemeColor.border}`,
1860
+ borderRadius: 6,
1861
+ overflow: "hidden",
1862
+ minWidth: 0
1777
1863
  }
1778
- }), status), (0, react.createElement)("time", {
1779
- dateTime: Number.isNaN(startedAt.valueOf()) ? void 0 : startedAt.toISOString(),
1780
- title: startedAt.toLocaleString(),
1864
+ }, ...[[t("awb.call.arguments"), call.arguments], [t("awb.call.result"), call.result]].map(([heading, value], index) => (0, react.createElement)("div", {
1865
+ key: heading,
1781
1866
  style: {
1782
- color: require_theme.dshThemeColor.labelTertiary,
1783
- fontSize: require_theme.uiFontSize(10),
1784
- fontVariantNumeric: "tabular-nums",
1785
- whiteSpace: "nowrap"
1867
+ display: "grid",
1868
+ gridTemplateColumns: "max-content minmax(0, 1fr)",
1869
+ gap: 12,
1870
+ alignItems: "baseline",
1871
+ padding: "7px 10px",
1872
+ minWidth: 0,
1873
+ ...index === 0 ? {} : { borderTop: `0.5px solid ${require_theme.dshThemeColor.border}` }
1786
1874
  }
1787
- }, startedAt.toLocaleTimeString([], {
1788
- hour: "2-digit",
1789
- minute: "2-digit",
1790
- second: "2-digit",
1791
- hour12: false
1792
- }))), (0, react.createElement)(AssistantRecordChevron)), (0, react.createElement)("div", { style: {
1793
- display: "grid",
1794
- gap: 8,
1795
- padding: "9px 10px 10px",
1796
- borderTop: `1px solid ${require_theme.dshThemeColor.border}`,
1797
- minWidth: 0
1798
- } }, ...[[t("awb.call.arguments"), call.arguments], [t("awb.call.result"), call.result]].map(([heading, value]) => (0, react.createElement)("div", {
1799
- key: heading,
1800
- style: { minWidth: 0 }
1801
1875
  }, (0, react.createElement)("small", { style: {
1802
- color: require_theme.dshThemeColor.labelSecondary,
1876
+ color: require_theme.dshThemeColor.labelTertiary,
1803
1877
  fontSize: require_theme.uiFontSize(11),
1804
- fontWeight: 500
1878
+ whiteSpace: "nowrap"
1805
1879
  } }, heading), (0, react.createElement)("pre", {
1806
1880
  tabIndex: 0,
1807
1881
  "aria-label": heading,
1808
1882
  style: {
1809
- margin: "4px 0 0",
1810
- padding: "6px 8px",
1811
- borderRadius: 6,
1812
- background: require_theme.dshThemeColor.cardBackground,
1883
+ margin: 0,
1884
+ color: require_theme.dshThemeColor.labelSecondary,
1813
1885
  maxHeight: 160,
1814
1886
  overflowY: "auto",
1815
1887
  overscrollBehavior: "contain",
@@ -1822,18 +1894,23 @@ window.__ModuleLoader__.load({
1822
1894
  }
1823
1895
  }, value || "—"))))));
1824
1896
  }
1825
- function AssistantToolIcon({ kind }) {
1897
+ function AssistantStepChevron() {
1826
1898
  return (0, react.createElement)("svg", {
1827
- width: 16,
1828
- height: 16,
1899
+ className: "codingns-assistant-step-chevron",
1900
+ width: 14,
1901
+ height: 14,
1829
1902
  viewBox: "0 0 24 24",
1830
1903
  fill: "none",
1831
1904
  stroke: "currentColor",
1832
- strokeWidth: 1.7,
1905
+ strokeWidth: 1.8,
1833
1906
  strokeLinecap: "round",
1834
1907
  strokeLinejoin: "round",
1835
- "aria-hidden": true
1836
- }, (0, react.createElement)("path", { d: kind === "web-search" ? "M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM3 12h18M12 3a17 17 0 0 1 0 18 17 17 0 0 1 0-18Z" : kind === "attachment" ? "M14 3H6v18h12V7l-4-4Zm0 0v5h4M9 12h6m-6 4h6" : "M3 6h7l2 2h9v12H3V6Zm0 4h18" }));
1908
+ "aria-hidden": true,
1909
+ style: {
1910
+ flexShrink: 0,
1911
+ color: require_theme.dshThemeColor.labelTertiary
1912
+ }
1913
+ }, (0, react.createElement)("path", { d: "m6 9 6 6 6-6" }));
1837
1914
  }
1838
1915
  //#endregion
1839
1916
  //#region src/client/features/assistant-realtime-call.ts
@@ -2968,12 +3045,7 @@ window.__ModuleLoader__.load({
2968
3045
  flexDirection: "column",
2969
3046
  gap: configuring ? 11 : 16
2970
3047
  }
2971
- }, !loaded ? (0, react.createElement)("div", {
2972
- role: "status",
2973
- style: require_theme.dshSettingsHelpStyle
2974
- }, t("awb.loading"), " ", button(t("awb.retry"), () => {
2975
- refresh().catch((cause) => setError(message(cause)));
2976
- })) : null, noticeText ? (0, react.createElement)("div", {
3048
+ }, !loaded ? (0, react.createElement)(AssistantLoadingView, { t }) : null, noticeText ? (0, react.createElement)("div", {
2977
3049
  role: "alert",
2978
3050
  style: {
2979
3051
  color: require_theme.dshThemeColor.error,
@@ -3176,6 +3248,19 @@ window.__ModuleLoader__.load({
3176
3248
  model
3177
3249
  }));
3178
3250
  }
3251
+ /** 首次读取期间使用居中的动态状态,避免把正常等待误显示成失败或重试入口。 */
3252
+ function AssistantLoadingView({ t }) {
3253
+ return (0, react.createElement)("div", {
3254
+ "data-codingns-assistant-loading": true,
3255
+ role: "status",
3256
+ "aria-live": "polite",
3257
+ "aria-label": t("awb.loading"),
3258
+ style: assistantLoadingStyle
3259
+ }, (0, react.createElement)("style", null, assistantLoadingCss), (0, react.createElement)("div", {
3260
+ "aria-hidden": true,
3261
+ style: assistantLoadingOrbStyle
3262
+ }, (0, react.createElement)("span", { className: "codingns-assistant-loading-ring" }), (0, react.createElement)("span", { className: "codingns-assistant-loading-core" }), (0, react.createElement)("span", { className: "codingns-assistant-loading-dot codingns-assistant-loading-dot-one" }), (0, react.createElement)("span", { className: "codingns-assistant-loading-dot codingns-assistant-loading-dot-two" }), (0, react.createElement)("span", { className: "codingns-assistant-loading-dot codingns-assistant-loading-dot-three" })), (0, react.createElement)("div", { style: assistantLoadingLabelStyle }, t("awb.loadingHint")));
3263
+ }
3179
3264
  /** 内层菜单先消费 Escape,外层窗口只处理尚未消费的关闭按键。 */
3180
3265
  function handleAssistantWorkbenchEscape(event, onClose) {
3181
3266
  if (event.key !== "Escape" || event.defaultPrevented) return;
@@ -3210,6 +3295,47 @@ window.__ModuleLoader__.load({
3210
3295
  gap: 8,
3211
3296
  justifyItems: "center"
3212
3297
  };
3298
+ const assistantLoadingStyle = {
3299
+ flex: "1 1 auto",
3300
+ minHeight: "min(420px, 45vh)",
3301
+ display: "flex",
3302
+ flexDirection: "column",
3303
+ alignItems: "center",
3304
+ justifyContent: "center",
3305
+ gap: 18,
3306
+ color: require_theme.dshThemeColor.labelSecondary
3307
+ };
3308
+ const assistantLoadingOrbStyle = {
3309
+ position: "relative",
3310
+ width: 76,
3311
+ height: 76,
3312
+ borderRadius: "50%",
3313
+ background: `radial-gradient(circle at 35% 28%, ${require_theme.dshThemeColor.accent}33, transparent 58%)`,
3314
+ boxShadow: `0 0 0 1px ${require_theme.dshThemeColor.border}, 0 0 42px ${require_theme.dshThemeColor.accent}24`
3315
+ };
3316
+ const assistantLoadingLabelStyle = {
3317
+ fontSize: require_theme.uiFontSize(13),
3318
+ letterSpacing: "0.04em"
3319
+ };
3320
+ const assistantLoadingCss = `
3321
+ [data-codingns-assistant-loading] .codingns-assistant-loading-ring,
3322
+ [data-codingns-assistant-loading] .codingns-assistant-loading-core,
3323
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot{position:absolute;display:block;border-radius:50%}
3324
+ [data-codingns-assistant-loading] .codingns-assistant-loading-ring{inset:7px;border:1px solid ${require_theme.dshThemeColor.accent}88;border-top-color:transparent;border-left-color:${require_theme.dshThemeColor.accent};animation:codingns-assistant-loading-spin 2.8s linear infinite}
3325
+ [data-codingns-assistant-loading] .codingns-assistant-loading-core{inset:22px;background:${require_theme.dshThemeColor.accent};box-shadow:0 0 18px ${require_theme.dshThemeColor.accent}aa;animation:codingns-assistant-loading-breathe 1.8s ease-in-out infinite}
3326
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot{width:6px;height:6px;background:${require_theme.dshThemeColor.labelPrimary};box-shadow:0 0 10px ${require_theme.dshThemeColor.accent};animation:codingns-assistant-loading-pulse 1.8s ease-in-out infinite}
3327
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot-one{top:4px;left:35px}
3328
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot-two{right:7px;bottom:20px;animation-delay:.22s}
3329
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot-three{left:7px;bottom:20px;animation-delay:.44s}
3330
+ @keyframes codingns-assistant-loading-spin{to{transform:rotate(360deg)}}
3331
+ @keyframes codingns-assistant-loading-breathe{0%,100%{transform:scale(.82);opacity:.72}50%{transform:scale(1.08);opacity:1}}
3332
+ @keyframes codingns-assistant-loading-pulse{0%,100%{transform:scale(.65);opacity:.36}50%{transform:scale(1.15);opacity:1}}
3333
+ @media (prefers-reduced-motion:reduce){
3334
+ [data-codingns-assistant-loading] .codingns-assistant-loading-ring,
3335
+ [data-codingns-assistant-loading] .codingns-assistant-loading-core,
3336
+ [data-codingns-assistant-loading] .codingns-assistant-loading-dot{animation:none}
3337
+ }
3338
+ `;
3213
3339
  const backdrop = {
3214
3340
  position: "fixed",
3215
3341
  inset: 0,
@@ -4236,6 +4362,14 @@ window.__ModuleLoader__.load({
4236
4362
  question: t("awb.notifications.question"),
4237
4363
  approval: t("awb.notifications.approval")
4238
4364
  };
4365
+ const icon = reaction === "question" ? (0, react.createElement)("span", {
4366
+ "data-codingns-avatar-reaction-glyph": "speech",
4367
+ style: { display: "inline-flex" }
4368
+ }, speechIcon()) : {
4369
+ success: "✓",
4370
+ concerned: "!",
4371
+ approval: "…"
4372
+ }[reaction];
4239
4373
  return (0, react.createElement)("span", {
4240
4374
  role: "status",
4241
4375
  "aria-label": labels[reaction],
@@ -4243,21 +4377,50 @@ window.__ModuleLoader__.load({
4243
4377
  "data-codingns-avatar-reaction": reaction,
4244
4378
  style: {
4245
4379
  position: "absolute",
4246
- right: 0,
4380
+ left: "50%",
4247
4381
  top: 0,
4248
- padding: "2px 7px",
4249
- borderRadius: 12,
4382
+ transform: "translateX(-50%)",
4383
+ width: 30,
4384
+ height: 26,
4385
+ boxSizing: "border-box",
4386
+ display: "grid",
4387
+ placeItems: "center",
4388
+ padding: 0,
4389
+ borderRadius: 11,
4250
4390
  background: "#fff",
4251
4391
  color: "#242424",
4252
4392
  border: "1px solid #b8c3d3",
4393
+ lineHeight: 1,
4253
4394
  pointerEvents: "none"
4254
4395
  }
4255
- }, {
4256
- success: "✓",
4257
- concerned: "!",
4258
- question: "?",
4259
- approval: "…"
4260
- }[reaction]);
4396
+ }, icon);
4397
+ }
4398
+ /** 提问状态使用发言气泡:圆角轮廓、右下尾巴和三个空心圆点。 */
4399
+ function speechIcon() {
4400
+ return (0, react.createElement)("svg", {
4401
+ width: 20,
4402
+ height: 20,
4403
+ viewBox: "0 0 24 24",
4404
+ fill: "none",
4405
+ stroke: "currentColor",
4406
+ strokeWidth: 1.9,
4407
+ strokeLinecap: "round",
4408
+ strokeLinejoin: "round",
4409
+ "aria-hidden": true,
4410
+ focusable: false
4411
+ }, (0, react.createElement)("path", { d: "M12 3H9a7 7 0 0 0-7 7v2a7 7 0 0 0 7 7h5.5l3.5 2.5.8-4.45A7 7 0 0 0 21 12v-2a7 7 0 0 0-7-7h-2Z" }), (0, react.createElement)("circle", {
4412
+ cx: 7.5,
4413
+ cy: 11,
4414
+ r: 1.45
4415
+ }), (0, react.createElement)("circle", {
4416
+ cx: 12,
4417
+ cy: 11,
4418
+ r: 1.45
4419
+ }), (0, react.createElement)("circle", {
4420
+ cx: 16.5,
4421
+ cy: 11,
4422
+ r: 1.45
4423
+ }));
4261
4424
  }
4262
4425
  //#endregion
4263
4426
  //#region src/client/avatar/spritesheet.ts
@@ -7425,7 +7588,7 @@ window.__ModuleLoader__.load({
7425
7588
  return /^0\.1\.5(?:-|$)/u.test(version);
7426
7589
  }
7427
7590
  /** Codingns4DSH 插件自身的 npm 版本。 */
7428
- const CODINGNS_VERSION = "0.2.1-beta.7";
7591
+ const CODINGNS_VERSION = "0.2.1-beta.8";
7429
7592
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
7430
7593
  function isDshVersionCompatible(version) {
7431
7594
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -16092,6 +16255,8 @@ window.__ModuleLoader__.load({
16092
16255
  primaryForeground: "var(--dsw-alias-label-primary-foreground, #fff)",
16093
16256
  success: "var(--dsw-alias-state-success-primary, #16803c)",
16094
16257
  error: "var(--dsw-alias-state-error-primary, #b42318)",
16258
+ warning: "var(--dsw-alias-state-warning-primary, #d99a00)",
16259
+ warningForeground: "#3d2c00",
16095
16260
  fieldBorder: "var(--dsw-alias-border-l4, #d9d9d9)",
16096
16261
  menuBorder: "var(--dsw-alias-border-l3, #d9d9d9)",
16097
16262
  switchThumb: "var(--dsw-static-neutral-00, #fff)",
@@ -18622,7 +18787,9 @@ window.__ModuleLoader__.load({
18622
18787
  "awb.notifications.question": "需要回答",
18623
18788
  "awb.notifications.approval": "等待审批",
18624
18789
  "awb.notifications.questionTag": "问题",
18625
- "awb.notifications.approvalTag": "权限请求",
18790
+ "awb.notifications.approvalTag": "权限申请",
18791
+ "awb.notifications.requestPrefix": "有",
18792
+ "awb.notifications.requestSuffix": "需要你来处理",
18626
18793
  "awb.notifications.autoClose": "通知自动关闭",
18627
18794
  "awb.notifications.autoCloseHint": "启用后,失败、提问与审批的气泡在设定时间后自动收起;完成提示始终固定 10 秒关闭。未读记录仍会保留。",
18628
18795
  "awb.notifications.autoCloseDuration": "自动关闭时间",
@@ -18630,13 +18797,16 @@ window.__ModuleLoader__.load({
18630
18797
  "awb.notifications.seconds": "秒",
18631
18798
  "awb.notifications.open": "查看会话",
18632
18799
  "awb.notifications.dismiss": "收起提醒",
18800
+ "awb.notifications.collapse": "收起通知",
18801
+ "awb.notifications.expand": "展开通知",
18633
18802
  "awb.notifications.list": "提醒列表",
18803
+ "awb.notifications.clearAll": "一键清理",
18804
+ "awb.notifications.clearAllLabel": "一键清理全部通知",
18634
18805
  "awb.notifications.unread": "{count} 条未读",
18635
18806
  "awb.notifications.pending": "{count} 项待处理",
18807
+ "awb.notifications.unreadFilterLabel": "筛选未读通知:{count} 条未读",
18808
+ "awb.notifications.pendingFilterLabel": "筛选待处理通知:{count} 项待处理",
18636
18809
  "awb.notifications.empty": "暂无提醒",
18637
- "awb.notifications.next": "下一页",
18638
- "awb.notifications.previous": "上一页",
18639
- "awb.notifications.closeList": "关闭提醒列表",
18640
18810
  "awb.notifications.disconnected": "远端暂不可达",
18641
18811
  "awb.notifications.expired": "提醒已失效",
18642
18812
  "awb.notifications.actionUnavailable": "通知操作暂不可用,请重试",
@@ -18681,6 +18851,14 @@ window.__ModuleLoader__.load({
18681
18851
  "awb.call.arguments": "调用参数",
18682
18852
  "awb.call.result": "返回结果",
18683
18853
  "awb.call.toolDetails": "查看参数与结果",
18854
+ "awb.call.step": "执行步骤",
18855
+ "awb.call.stepDetails": "展开查看步骤中的工具调用",
18856
+ "awb.call.separator": "、",
18857
+ "awb.call.toolCount": "{count} 次调用",
18858
+ "awb.call.stepRead": "已读取文件",
18859
+ "awb.call.stepSearch": "已搜索网页",
18860
+ "awb.call.stepWorkspace": "已调用工具",
18861
+ "awb.call.stepTool": "已执行操作",
18684
18862
  "awb.preparationUnsupported": "当前 Host 不支持仅准备资源,请更新 Host 后再操作。",
18685
18863
  "awb.title": "智能助理",
18686
18864
  "awb.create": "创建助理",
@@ -18750,7 +18928,8 @@ window.__ModuleLoader__.load({
18750
18928
  "awb.resetFinalConfirm": "确定要重置助理吗?助理配置、对话和派生索引将被清空,无法从此界面撤销。原始项目会话和下载素材会保留。",
18751
18929
  "awb.confirm": "确认",
18752
18930
  "awb.busy": "处理中…",
18753
- "awb.loading": "正在读取助理…",
18931
+ "awb.loading": "正在准备助理",
18932
+ "awb.loadingHint": "正在准备你的对话…",
18754
18933
  "awb.retry": "重试",
18755
18934
  "awb.summary": "历史交流摘要",
18756
18935
  "awb.saved": "配置已保存",
@@ -18777,6 +18956,8 @@ window.__ModuleLoader__.load({
18777
18956
  "awb.notifications.approval": "Approval needed",
18778
18957
  "awb.notifications.questionTag": "Question",
18779
18958
  "awb.notifications.approvalTag": "Permission request",
18959
+ "awb.notifications.requestPrefix": "There is a",
18960
+ "awb.notifications.requestSuffix": "waiting for your response",
18780
18961
  "awb.notifications.autoClose": "Auto-close notices",
18781
18962
  "awb.notifications.autoCloseHint": "When enabled, failure, question and approval notices collapse after the selected time; completion notices always close after 10 seconds. Unread records remain available.",
18782
18963
  "awb.notifications.autoCloseDuration": "Auto-close time",
@@ -18784,13 +18965,16 @@ window.__ModuleLoader__.load({
18784
18965
  "awb.notifications.seconds": " seconds",
18785
18966
  "awb.notifications.open": "View session",
18786
18967
  "awb.notifications.dismiss": "Collapse notice",
18968
+ "awb.notifications.collapse": "Collapse notifications",
18969
+ "awb.notifications.expand": "Expand notifications",
18787
18970
  "awb.notifications.list": "Notice list",
18971
+ "awb.notifications.clearAll": "Clear all",
18972
+ "awb.notifications.clearAllLabel": "Clear all notifications",
18788
18973
  "awb.notifications.unread": "{count} unread",
18789
18974
  "awb.notifications.pending": "{count} pending",
18975
+ "awb.notifications.unreadFilterLabel": "Filter unread notifications: {count} unread",
18976
+ "awb.notifications.pendingFilterLabel": "Filter pending notifications: {count} pending",
18790
18977
  "awb.notifications.empty": "No notices",
18791
- "awb.notifications.next": "Next page",
18792
- "awb.notifications.previous": "Previous page",
18793
- "awb.notifications.closeList": "Close notice list",
18794
18978
  "awb.notifications.disconnected": "Remote host unavailable",
18795
18979
  "awb.notifications.expired": "Notice expired",
18796
18980
  "awb.notifications.actionUnavailable": "Notice action is unavailable. Please try again.",
@@ -18835,6 +19019,14 @@ window.__ModuleLoader__.load({
18835
19019
  "awb.call.arguments": "Arguments",
18836
19020
  "awb.call.result": "Result",
18837
19021
  "awb.call.toolDetails": "View arguments and result",
19022
+ "awb.call.step": "Execution step",
19023
+ "awb.call.stepDetails": "Expand to view the tools in this step",
19024
+ "awb.call.separator": ", ",
19025
+ "awb.call.toolCount": "{count} calls",
19026
+ "awb.call.stepRead": "Read files",
19027
+ "awb.call.stepSearch": "Searched the web",
19028
+ "awb.call.stepWorkspace": "Called tools",
19029
+ "awb.call.stepTool": "Completed an action",
18838
19030
  "awb.preparationUnsupported": "This Host does not support preparing resources without applying settings. Update the Host before proceeding.",
18839
19031
  "awb.title": "Assistant",
18840
19032
  "awb.create": "Create assistant",
@@ -18904,7 +19096,8 @@ window.__ModuleLoader__.load({
18904
19096
  "awb.resetFinalConfirm": "Reset your assistant? Settings, conversation, and derived indexes will be cleared and cannot be restored from this page. Original project sessions and downloaded assets are kept.",
18905
19097
  "awb.confirm": "Confirm",
18906
19098
  "awb.busy": "Working…",
18907
- "awb.loading": "Reading assistant…",
19099
+ "awb.loading": "Preparing assistant",
19100
+ "awb.loadingHint": "Preparing your conversation…",
18908
19101
  "awb.retry": "Retry",
18909
19102
  "awb.summary": "Conversation summary",
18910
19103
  "awb.saved": "Configuration saved",
@@ -27448,7 +27641,7 @@ window.__ModuleLoader__.load({
27448
27641
  const method = channel === "/codingns" ? endpoint : channel === "/api" ? endpoint.replace(/^codingns\//u, "") : "";
27449
27642
  if (peerHostId === null) {
27450
27643
  const input = CATALOG_ENDPOINTS.has(method) ? {
27451
- ...asRecord$6(payload),
27644
+ ...asRecord$7(payload),
27452
27645
  catalogHostId: "local"
27453
27646
  } : payload;
27454
27647
  return rpc.call(channel, endpoint, input, signal);
@@ -27472,18 +27665,18 @@ window.__ModuleLoader__.load({
27472
27665
  });
27473
27666
  let envelope = null;
27474
27667
  try {
27475
- envelope = asRecord$6(JSON.parse(response.body));
27668
+ envelope = asRecord$7(JSON.parse(response.body));
27476
27669
  } catch {}
27477
27670
  if (response.status < 200 || response.status >= 300) {
27478
- const error = asRecord$6(envelope?.error);
27671
+ const error = asRecord$7(envelope?.error);
27479
27672
  return failure$1(typeof error?.code === "string" ? error.code : "PEER_HOST_PROXY_UNREACHABLE", typeof error?.message === "string" ? error.message : require_transport.resolveCodingNsTranslator(locale)("cli.peerHostRpcFailed", { status: response.status }));
27480
27673
  }
27481
- const result = asRecord$6(envelope?.result);
27674
+ const result = asRecord$7(envelope?.result);
27482
27675
  if (result?.ok === true && Object.hasOwn(result, "value")) return {
27483
27676
  ok: true,
27484
27677
  value: result.value
27485
27678
  };
27486
- const error = asRecord$6(result?.error);
27679
+ const error = asRecord$7(result?.error);
27487
27680
  if (result?.ok === false && typeof error?.code === "string" && typeof error.message === "string") return failure$1(error.code, error.message);
27488
27681
  return failure$1("PEER_HOST_RESPONSE_INVALID", require_transport.resolveCodingNsTranslator(locale)("cli.peerHostRpcInvalid"));
27489
27682
  } };
@@ -27502,7 +27695,7 @@ window.__ModuleLoader__.load({
27502
27695
  }
27503
27696
  };
27504
27697
  }
27505
- function asRecord$6(value) {
27698
+ function asRecord$7(value) {
27506
27699
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
27507
27700
  }
27508
27701
  //#endregion
@@ -28930,11 +29123,11 @@ window.__ModuleLoader__.load({
28930
29123
  const iterator = (await api.follow())[Symbol.asyncIterator]();
28931
29124
  const first = await iterator.next();
28932
29125
  await iterator.return?.();
28933
- const value = asRecord$5(asRecord$5(first.value)?.value);
29126
+ const value = asRecord$6(asRecord$6(first.value)?.value);
28934
29127
  const records = Array.isArray(value?.items) ? value.items : [];
28935
29128
  const globalArchived = readStringArray(value?.archivedSessionIds);
28936
29129
  return records.flatMap((item) => {
28937
- const record = asRecord$5(item);
29130
+ const record = asRecord$6(item);
28938
29131
  const workspaceId = readString$1(record?.workspaceId);
28939
29132
  if (workspaceId === void 0) return [];
28940
29133
  const path = readString$1(record?.path);
@@ -28950,12 +29143,12 @@ window.__ModuleLoader__.load({
28950
29143
  }
28951
29144
  async function readSessionList(api) {
28952
29145
  if (api?.list === void 0) return [];
28953
- const result = asRecord$5(unwrapRemoteValue$1(await api.list({})));
29146
+ const result = asRecord$6(unwrapRemoteValue$1(await api.list({})));
28954
29147
  return (Array.isArray(result?.items) ? result.items : []).flatMap((item) => {
28955
- const record = asRecord$5(item);
29148
+ const record = asRecord$6(item);
28956
29149
  const sessionId = readString$1(record?.sessionId);
28957
29150
  if (sessionId === void 0) return [];
28958
- const titleValue = asRecord$5(asRecord$5(record?.projections)?.values)?.title;
29151
+ const titleValue = asRecord$6(asRecord$6(record?.projections)?.values)?.title;
28959
29152
  const cwd = readString$1(record?.cwd);
28960
29153
  const workspaceIdValue = readString$1(record?.workspaceId);
28961
29154
  const archivedAt = typeof record?.archivedAt === "number" && Number.isFinite(record.archivedAt) ? record.archivedAt : 0;
@@ -29027,7 +29220,7 @@ window.__ModuleLoader__.load({
29027
29220
  "value",
29028
29221
  "data"
29029
29222
  ]) {
29030
- const workspace = asRecord$5(value[key]);
29223
+ const workspace = asRecord$6(value[key]);
29031
29224
  const id = readString$1(workspace?.workspaceId) ?? readString$1(workspace?.workspaceID) ?? readString$1(workspace?.id);
29032
29225
  if (id !== void 0) return id;
29033
29226
  }
@@ -29414,8 +29607,8 @@ window.__ModuleLoader__.load({
29414
29607
  }
29415
29608
  function normalizeRemote(value) {
29416
29609
  if (!isRecord$5(value)) return {};
29417
- const workspace = asRecord$5(readRemoteProperty(value, "workspace")) ?? asRecord$5(readRemoteProperty(value, "workspaceController"));
29418
- const session = asRecord$5(readRemoteProperty(value, "session")) ?? asRecord$5(readRemoteProperty(value, "sessionController"));
29610
+ const workspace = asRecord$6(readRemoteProperty(value, "workspace")) ?? asRecord$6(readRemoteProperty(value, "workspaceController"));
29611
+ const session = asRecord$6(readRemoteProperty(value, "session")) ?? asRecord$6(readRemoteProperty(value, "sessionController"));
29419
29612
  return {
29420
29613
  ...workspace ? { workspace } : {},
29421
29614
  ...session ? { session } : {}
@@ -29438,12 +29631,12 @@ window.__ModuleLoader__.load({
29438
29631
  return result === void 0 ? [] : [result];
29439
29632
  }) : [];
29440
29633
  }
29441
- function asRecord$5(value) {
29634
+ function asRecord$6(value) {
29442
29635
  return isRecord$5(value) ? value : void 0;
29443
29636
  }
29444
29637
  /** DSH Remote 的直接调用返回 RemoteResult;测试桩和旧宿主可能直接返回 value。 */
29445
29638
  function unwrapRemoteValue$1(value) {
29446
- const record = asRecord$5(value);
29639
+ const record = asRecord$6(value);
29447
29640
  if (record === void 0 || typeof record.ok !== "boolean") return value;
29448
29641
  return record.ok ? record.value : void 0;
29449
29642
  }
@@ -29462,8 +29655,8 @@ window.__ModuleLoader__.load({
29462
29655
  const WORKSPACE_SESSION_HIDDEN_FILTER_CHECK_ATTRIBUTE = "data-codingns-hidden-workspace-filter-check";
29463
29656
  const WORKSPACE_SESSION_HIDDEN_FILTER_BOUND_ATTRIBUTE = "data-codingns-hidden-workspace-filter-bound";
29464
29657
  const MENU_ATTRIBUTE$1 = "aria-haspopup";
29465
- const WORKSPACE_MENU_PATTERN = /(?:更多|菜单|选项|more|menu|option)/iu;
29466
- const WORKSPACE_FILTER_PATTERN = /(?:视图选项|筛选选项|view\s*options|filter\s*options)/iu;
29658
+ const WORKSPACE_MENU_PATTERN = /(?:更多|菜单|选项|操作|more|menu|option|action)/iu;
29659
+ const WORKSPACE_FILTER_PATTERN = /(?:视图选项|筛选选项|筛选会话|分组方式|排序方式|view\s*options?|filter\s*(?:options?|sessions?)|group\s*by|sort\s*by)/iu;
29467
29660
  /**
29468
29661
  * 给原生工作区菜单增加隐藏动作,并通过工作区筛选菜单控制恢复列表。
29469
29662
  *
@@ -29536,6 +29729,7 @@ window.__ModuleLoader__.load({
29536
29729
  workspaceIds.add(workspaceId);
29537
29730
  bindWorkspaceMenuTriggers(header, workspaceId, () => {
29538
29731
  activeMenuWorkspaceId = workspaceId;
29732
+ activeFilterTrigger = void 0;
29539
29733
  activeMenuKind = "workspace";
29540
29734
  menuContextPending = true;
29541
29735
  scheduleScan();
@@ -29546,6 +29740,7 @@ window.__ModuleLoader__.load({
29546
29740
  bindWorkspaceFilterTriggers(dom, (trigger) => {
29547
29741
  if (suppressFilterTrigger) return;
29548
29742
  activeFilterTrigger = trigger;
29743
+ activeMenuWorkspaceId = void 0;
29549
29744
  activeMenuKind = "filter";
29550
29745
  menuContextPending = true;
29551
29746
  scheduleScan();
@@ -29554,7 +29749,8 @@ window.__ModuleLoader__.load({
29554
29749
  const menus = findWorkspaceMenus(dom);
29555
29750
  knownNativeMenus = new Set(menus);
29556
29751
  if (menus.length > 0) menuContextPending = false;
29557
- if (activeMenuKind === "filter") injectFilterMenuAction(dom, selectFilterMenus(menus, menuWorkspaceIds, activeMenuWorkspaceId), showHiddenWorkspaces, () => {
29752
+ const currentMenu = [...menus].reverse().find(isVisibleMenu);
29753
+ if ((currentMenu === void 0 ? activeMenuKind : isWorkspaceFilterMenu(currentMenu) ? "filter" : "workspace") === "filter") injectFilterMenuAction(dom, selectFilterMenus(menus, menuWorkspaceIds, activeMenuWorkspaceId), showHiddenWorkspaces, () => {
29558
29754
  showHiddenWorkspaces = !showHiddenWorkspaces;
29559
29755
  scheduleScan();
29560
29756
  }, (menu) => closeFilterMenu(activeFilterTrigger, menu, () => {
@@ -29567,6 +29763,7 @@ window.__ModuleLoader__.load({
29567
29763
  if (menus.length === 0 && !menuContextPending) {
29568
29764
  activeMenuWorkspaceId = void 0;
29569
29765
  activeMenuKind = void 0;
29766
+ activeFilterTrigger = void 0;
29570
29767
  }
29571
29768
  if (showHiddenWorkspaces) injectHiddenWorkspaceFooter(dom, headers, workspaces, hiddenWorkspaceIds, (workspaceId) => updateVisibility(workspaceId, false), t);
29572
29769
  } finally {
@@ -29674,7 +29871,7 @@ window.__ModuleLoader__.load({
29674
29871
  let current = item.parentElement;
29675
29872
  for (let depth = 0; depth < 8 && current !== null; depth += 1, current = current.parentElement) counts.set(current, (counts.get(current) ?? 0) + 1);
29676
29873
  }
29677
- const candidates = [...counts.keys()].filter((element) => (counts.get(element) ?? 0) >= 3 && /(?:分组方式|排序方式|筛选会话|group(?:ing)?|sort|filter)/iu.test(element.textContent ?? ""));
29874
+ const candidates = [...counts.keys()].filter((element) => (counts.get(element) ?? 0) >= 3 && isWorkspaceFilterMenu(element));
29678
29875
  return candidates.filter((element) => !candidates.some((other) => other !== element && element.contains(other)));
29679
29876
  }
29680
29877
  /**
@@ -29683,16 +29880,14 @@ window.__ModuleLoader__.load({
29683
29880
  */
29684
29881
  function selectFilterMenus(menus, menuWorkspaceIds, activeWorkspaceId) {
29685
29882
  const visible = menus.filter(isVisibleMenu);
29686
- const candidates = (visible.length > 0 ? visible : menus).filter(isWorkspaceFilterMenu);
29883
+ const candidates = visible.filter(isWorkspaceFilterMenu);
29687
29884
  if (candidates.length > 0) return [candidates[candidates.length - 1]];
29688
- const fallback = (visible.length > 0 ? visible : menus).filter((menu) => menuWorkspaceIds.get(menu) === void 0 && (activeWorkspaceId === void 0 || resolveWorkspaceId(menu) !== activeWorkspaceId) && menu.querySelector(`[data-codingns-hidden-workspace-menu]`) === null);
29885
+ const fallback = visible.filter((menu) => menuWorkspaceIds.get(menu) === void 0 && (activeWorkspaceId === void 0 || resolveWorkspaceId(menu) !== activeWorkspaceId) && menu.querySelector(`[data-codingns-hidden-workspace-menu]`) === null);
29689
29886
  return fallback.length > 0 ? [fallback[fallback.length - 1]] : [];
29690
29887
  }
29691
29888
  function selectWorkspaceMenus(menus) {
29692
- const visible = menus.filter(isVisibleMenu);
29693
- const candidates = (visible.length > 0 ? visible : menus).filter((menu) => !isWorkspaceFilterMenu(menu));
29694
- const available = candidates.length > 0 ? candidates : visible.length > 0 ? visible : menus;
29695
- return available.length > 0 ? [available[available.length - 1]] : [];
29889
+ const candidates = menus.filter(isVisibleMenu).filter((menu) => !isWorkspaceFilterMenu(menu));
29890
+ return candidates.length > 0 ? [candidates[candidates.length - 1]] : [];
29696
29891
  }
29697
29892
  function isVisibleMenu(menu) {
29698
29893
  if (menu.hasAttribute("hidden") || menu.getAttribute("aria-hidden") === "true" || menu.getAttribute("data-state") === "closed") return false;
@@ -29700,7 +29895,8 @@ window.__ModuleLoader__.load({
29700
29895
  return style.display !== "none" && style.visibility !== "hidden";
29701
29896
  }
29702
29897
  function isWorkspaceFilterMenu(element) {
29703
- return /(?:分组方式|排序方式|筛选会话|group(?:ing)?|sort(?:ing)?|filter(?:\s+sessions?)?)/iu.test(element.textContent ?? "");
29898
+ const label = `${element.textContent ?? ""} ${element.getAttribute("aria-label") ?? ""} ${element.getAttribute("title") ?? ""}`;
29899
+ return WORKSPACE_FILTER_PATTERN.test(label);
29704
29900
  }
29705
29901
  function injectWorkspaceMenuActions(menus, dom, activeWorkspaceId, workspaceIds, menuWorkspaceIds, onHide, t) {
29706
29902
  for (const menu of menus) {
@@ -30550,13 +30746,14 @@ window.__ModuleLoader__.load({
30550
30746
  setProviderId(selection.providerId ?? null);
30551
30747
  }
30552
30748
  const intervalMins = props.getRefreshIntervalMins?.() ?? require_native_workspace_store.DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
30553
- const cacheKey = `${adapterId}|${selection.providerId ?? ""}|${selection.modelId ?? ""}`;
30749
+ const cacheKey = `${adapterId}|${selection.providerId ?? ""}|${selection.modelId ?? ""}|${sessionId}`;
30554
30750
  const cached = subscriptionUsageCache.get(cacheKey);
30555
30751
  if (cached !== void 0 && cached.usage.provider?.capability !== "new-api" && isSubscriptionUsageFresh(cached.capturedAt, Date.now(), intervalMins)) {
30556
30752
  if (active) setUsage(cached.usage);
30557
30753
  return;
30558
30754
  }
30559
30755
  const next = await loadUsage(props.rpc, cacheKey, {
30756
+ sessionId,
30560
30757
  adapterId,
30561
30758
  ...selection.providerId ? { providerId: selection.providerId } : {},
30562
30759
  ...selection.modelId ? { modelId: selection.modelId } : {}
@@ -30609,6 +30806,7 @@ window.__ModuleLoader__.load({
30609
30806
  (async () => {
30610
30807
  try {
30611
30808
  const result = await require_model_catalog_cache.callCliRpc(props.rpc, "subscription/reset", {
30809
+ sessionId: props.sessionId?.trim() ?? "",
30612
30810
  adapterId,
30613
30811
  ...providerId === null ? {} : { providerId }
30614
30812
  });
@@ -38816,10 +39014,10 @@ ${scope} [data-dockkit-strip-tabs] {
38816
39014
  }));
38817
39015
  }
38818
39016
  function readSessionIds(value) {
38819
- const record = asRecord$4(value);
39017
+ const record = asRecord$5(value);
38820
39018
  if (record === void 0) return [];
38821
39019
  const result = /* @__PURE__ */ new Set();
38822
- const byId = asRecord$4(record.byId);
39020
+ const byId = asRecord$5(record.byId);
38823
39021
  if (byId !== void 0) {
38824
39022
  for (const sessionId of Object.keys(byId)) if (sessionId.trim() !== "") result.add(sessionId);
38825
39023
  }
@@ -38835,7 +39033,7 @@ ${scope} [data-dockkit-strip-tabs] {
38835
39033
  const items = record[key];
38836
39034
  if (!Array.isArray(items)) continue;
38837
39035
  for (const item of items) {
38838
- const itemRecord = asRecord$4(item);
39036
+ const itemRecord = asRecord$5(item);
38839
39037
  const candidate = itemRecord?.sessionId ?? itemRecord?.id;
38840
39038
  if (typeof candidate === "string" && candidate.trim() !== "") result.add(candidate);
38841
39039
  }
@@ -38876,10 +39074,10 @@ ${scope} [data-dockkit-strip-tabs] {
38876
39074
  const iterator = (await api.follow())[Symbol.asyncIterator]();
38877
39075
  const first = await iterator.next();
38878
39076
  await iterator.return?.();
38879
- const unwrapped = asRecord$4(unwrapRemoteValue(first.value));
38880
- const value = Array.isArray(unwrapped?.items) ? unwrapped : asRecord$4(unwrapped?.value);
39077
+ const unwrapped = asRecord$5(unwrapRemoteValue(first.value));
39078
+ const value = Array.isArray(unwrapped?.items) ? unwrapped : asRecord$5(unwrapped?.value);
38881
39079
  return (Array.isArray(value?.items) ? value.items : []).flatMap((item) => {
38882
- const record = asRecord$4(item);
39080
+ const record = asRecord$5(item);
38883
39081
  const workspaceId = record?.workspaceId;
38884
39082
  if (typeof workspaceId !== "string" || workspaceId.trim() === "") return [];
38885
39083
  const rawSessionIds = record?.sessionIds;
@@ -38893,16 +39091,16 @@ ${scope} [data-dockkit-strip-tabs] {
38893
39091
  });
38894
39092
  }
38895
39093
  async function readCurrentSession(api, sessionId, uiContext) {
38896
- const store = asRecord$4(require_native_workspace_store.readNativeService(uiContext, "sessions", "list"));
39094
+ const store = asRecord$5(require_native_workspace_store.readNativeService(uiContext, "sessions", "list"));
38897
39095
  if (typeof store?.getSnapshot === "function") {
38898
- const snapshot = asRecord$4(store.getSnapshot());
38899
- const byId = asRecord$4(snapshot?.byId);
38900
- if (byId !== void 0) return sessionItem(asRecord$4(byId[sessionId]));
38901
- return sessionItem(asRecord$4((Array.isArray(snapshot?.items) ? snapshot.items : []).find((item) => asRecord$4(item)?.sessionId === sessionId)));
39096
+ const snapshot = asRecord$5(store.getSnapshot());
39097
+ const byId = asRecord$5(snapshot?.byId);
39098
+ if (byId !== void 0) return sessionItem(asRecord$5(byId[sessionId]));
39099
+ return sessionItem(asRecord$5((Array.isArray(snapshot?.items) ? snapshot.items : []).find((item) => asRecord$5(item)?.sessionId === sessionId)));
38902
39100
  }
38903
39101
  if (api?.list === void 0) return void 0;
38904
39102
  const result = await readLegacySessionList(api);
38905
- return sessionItem(asRecord$4((Array.isArray(result?.items) ? result.items : []).find((item) => asRecord$4(item)?.sessionId === sessionId)));
39103
+ return sessionItem(asRecord$5((Array.isArray(result?.items) ? result.items : []).find((item) => asRecord$5(item)?.sessionId === sessionId)));
38906
39104
  }
38907
39105
  function sessionItem(session) {
38908
39106
  if (session === void 0) return void 0;
@@ -38917,7 +39115,7 @@ ${scope} [data-dockkit-strip-tabs] {
38917
39115
  async function readLegacySessionList(api) {
38918
39116
  const previous = legacySessionLists.get(api);
38919
39117
  if (previous !== void 0 && Date.now() < previous.expiresAt) return previous.promise;
38920
- const promise = Promise.resolve().then(() => api.list({})).then((value) => asRecord$4(unwrapRemoteValue(value)));
39118
+ const promise = Promise.resolve().then(() => api.list({})).then((value) => asRecord$5(unwrapRemoteValue(value)));
38921
39119
  const entry = {
38922
39120
  promise,
38923
39121
  expiresAt: Infinity
@@ -38941,11 +39139,11 @@ ${scope} [data-dockkit-strip-tabs] {
38941
39139
  const result = value.replaceAll("\\", "/").replace(/\/+/u, "/").replace(/\/+$/u, "") || "/";
38942
39140
  return /^[A-Za-z]:\//u.test(result) ? result.toLowerCase() : result;
38943
39141
  }
38944
- function asRecord$4(value) {
39142
+ function asRecord$5(value) {
38945
39143
  return typeof value === "object" && value !== null ? value : void 0;
38946
39144
  }
38947
39145
  function unwrapRemoteValue(value) {
38948
- const record = asRecord$4(value);
39146
+ const record = asRecord$5(value);
38949
39147
  if (record === void 0 || typeof record.ok !== "boolean") return value;
38950
39148
  return record.ok ? record.value : void 0;
38951
39149
  }
@@ -40682,7 +40880,7 @@ ${scope} [data-dockkit-strip-tabs] {
40682
40880
  function registerSessionChangedFilesView(ctx, rpc, remote, locale) {
40683
40881
  const runtime = globalThis;
40684
40882
  if (runtime.__CODINGNS4DSH_SESSION_CHANGED_FILES_VIEW__ !== void 0) return void 0;
40685
- const slots = asRecord$3(ctx)?.slots;
40883
+ const slots = asRecord$4(ctx)?.slots;
40686
40884
  if (typeof slots?.inject !== "function" || typeof slots.register !== "function") return void 0;
40687
40885
  if (isSlotIdRegistered(slots, "conversation.view", "codingns4dsh/session-changed-files")) return void 0;
40688
40886
  if (isSlotIdRegistered(slots, "conversation.session.header.actions", `codingns4dsh/session-changed-files/counter`)) return void 0;
@@ -40997,7 +41195,7 @@ ${scope} [data-dockkit-strip-tabs] {
40997
41195
  function fileIcon(name) {
40998
41196
  return name.includes(".") ? "·" : "□";
40999
41197
  }
41000
- function asRecord$3(value) {
41198
+ function asRecord$4(value) {
41001
41199
  return typeof value === "object" && value !== null ? value : void 0;
41002
41200
  }
41003
41201
  async function call(rpc, endpoint, payload) {
@@ -43059,6 +43257,8 @@ ${scope} [data-dockkit-strip-tabs] {
43059
43257
  let localHostId;
43060
43258
  let hasAggregate = false;
43061
43259
  let sessionWorkspaceIds = /* @__PURE__ */ new Map();
43260
+ const sessionRunningOverrides = /* @__PURE__ */ new Map();
43261
+ const completedSessionTransitions = /* @__PURE__ */ new Set();
43062
43262
  const listeners = /* @__PURE__ */ new Set();
43063
43263
  return {
43064
43264
  hasAggregate: () => hasAggregate,
@@ -43066,6 +43266,11 @@ ${scope} [data-dockkit-strip-tabs] {
43066
43266
  const next = projectAggregate(results);
43067
43267
  const nextWorkspaceIds = new Set(next.workspaces.map((workspace) => workspace.workspaceId));
43068
43268
  const nextSessionIds = new Set(next.sessions.map((session) => session.sessionId));
43269
+ for (const candidate of next.sessions) {
43270
+ const previous = sessions.find((session) => session.sessionId === candidate.sessionId);
43271
+ if (previous?.running !== true || candidate.running !== false) continue;
43272
+ if (sessionRunningOverrides.get(candidate.sessionId) !== true || candidate.updatedAt > previous.updatedAt) completedSessionTransitions.add(candidate.sessionId);
43273
+ }
43069
43274
  const retainedSessions = [...next.sessions];
43070
43275
  const retainedSessionWorkspaceIds = new Map(next.sessionWorkspaceIds);
43071
43276
  const retainedWorkspaces = next.workspaces.map((workspace) => ({
@@ -43094,7 +43299,7 @@ ${scope} [data-dockkit-strip-tabs] {
43094
43299
  const projectedNext = {
43095
43300
  ...next,
43096
43301
  workspaces: retainedWorkspaces,
43097
- sessions: retainedSessions,
43302
+ sessions: retainedSessions.map((session) => applyRunningOverride(session, sessionRunningOverrides)),
43098
43303
  sessionWorkspaceIds: retainedSessionWorkspaceIds
43099
43304
  };
43100
43305
  const nextLocalHostId = projectedNext.localHostId ?? localHostId;
@@ -43109,6 +43314,23 @@ ${scope} [data-dockkit-strip-tabs] {
43109
43314
  for (const listener of [...listeners]) listener();
43110
43315
  return true;
43111
43316
  },
43317
+ setSessionRunning(sessionId, running) {
43318
+ if (sessionRunningOverrides.get(sessionId) === running) return false;
43319
+ sessionRunningOverrides.set(sessionId, running);
43320
+ const current = sessions.find((session) => session.sessionId === sessionId);
43321
+ if (current === void 0 || current.running === running) return false;
43322
+ sessions = sessions.map((session) => session.sessionId === sessionId ? {
43323
+ ...session,
43324
+ running
43325
+ } : session);
43326
+ for (const listener of [...listeners]) listener();
43327
+ return true;
43328
+ },
43329
+ consumeCompletedSessionTransitions() {
43330
+ const result = [...completedSessionTransitions];
43331
+ completedSessionTransitions.clear();
43332
+ return result;
43333
+ },
43112
43334
  setWorkspaceOrder(nextOrderedWorkspaceIds) {
43113
43335
  const next = normalizeWorkspaceOrder(nextOrderedWorkspaceIds);
43114
43336
  if (sameIds(orderedWorkspaceIds, next)) return false;
@@ -43215,6 +43437,13 @@ ${scope} [data-dockkit-strip-tabs] {
43215
43437
  ...session.parentSessionId === void 0 ? {} : { parentSessionId: require_primitives_adapter.createVirtualSessionId(session.scope.targetHostId ?? session.scope.hostId, session.parentSessionId) }
43216
43438
  };
43217
43439
  }
43440
+ function applyRunningOverride(session, overrides) {
43441
+ const running = overrides.get(session.sessionId);
43442
+ return running === void 0 || running === session.running ? session : {
43443
+ ...session,
43444
+ running
43445
+ };
43446
+ }
43218
43447
  function sameWorkspaces(previous, next) {
43219
43448
  if (previous.length !== next.length) return false;
43220
43449
  return previous.every((workspace, index) => {
@@ -43335,12 +43564,12 @@ ${scope} [data-dockkit-strip-tabs] {
43335
43564
  const refreshStates = /* @__PURE__ */ new WeakMap();
43336
43565
  /** 合并并按 Host 侧顺序排列工作区;快照形状不符时原样返回,注入失败不影响本机数据。 */
43337
43566
  function mergeWorkspaceSnapshot(snapshot, virtual, orderedWorkspaceIds, localHostId, hasAggregate) {
43338
- const record = asRecord$2(snapshot);
43567
+ const record = asRecord$3(snapshot);
43339
43568
  if (record === null || !Array.isArray(record.items)) return snapshot;
43340
43569
  const baseItems = record.items;
43341
43570
  const byId = new Map(virtual.map((workspace) => [workspace.workspaceId, workspace]));
43342
43571
  const items = hasAggregate ? baseItems.flatMap((item) => {
43343
- const workspace = asRecord$2(item);
43572
+ const workspace = asRecord$3(item);
43344
43573
  const id = workspace?.workspaceId;
43345
43574
  const ref = typeof id === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(id) : null;
43346
43575
  if (ref === null || ref.hostId === localHostId || ref.targetHostId === null) return [item];
@@ -43351,7 +43580,7 @@ ${scope} [data-dockkit-strip-tabs] {
43351
43580
  }];
43352
43581
  }) : baseItems;
43353
43582
  const known = new Set(items.flatMap((item) => {
43354
- const workspaceId = asRecord$2(item)?.workspaceId;
43583
+ const workspaceId = asRecord$3(item)?.workspaceId;
43355
43584
  if (typeof workspaceId !== "string") return [];
43356
43585
  const normalized = normalizeWorkspaceId(workspaceId, localHostId);
43357
43586
  return normalized === workspaceId ? [workspaceId] : [workspaceId, normalized];
@@ -43370,7 +43599,7 @@ ${scope} [data-dockkit-strip-tabs] {
43370
43599
  function normalizeRemoteWorkspaceDisplayPaths(items) {
43371
43600
  let changed = false;
43372
43601
  const normalized = items.map((item) => {
43373
- const record = asRecord$2(item);
43602
+ const record = asRecord$3(item);
43374
43603
  const workspaceId = record?.workspaceId;
43375
43604
  if (record === null || typeof workspaceId !== "string" || require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null) return item;
43376
43605
  const displayPath = createPeerHostWorkspaceDisplayPath(workspaceId);
@@ -43427,18 +43656,18 @@ ${scope} [data-dockkit-strip-tabs] {
43427
43656
  };
43428
43657
  }
43429
43658
  function mergeBlankSessionCwds(snapshot, workspaceSnapshot) {
43430
- const state = asRecord$2(snapshot);
43659
+ const state = asRecord$3(snapshot);
43431
43660
  const byId = state?.byId;
43432
- const workspaceState = asRecord$2(workspaceSnapshot);
43661
+ const workspaceState = asRecord$3(workspaceSnapshot);
43433
43662
  const items = Array.isArray(workspaceState?.items) ? workspaceState.items : [];
43434
43663
  if (state === null || !isRecord$4(byId) || items.length === 0) return snapshot;
43435
43664
  let changed = false;
43436
43665
  const nextById = { ...byId };
43437
43666
  for (const [id, value] of Object.entries(byId)) {
43438
- const session = asRecord$2(value);
43667
+ const session = asRecord$3(value);
43439
43668
  if (session === null || session.blank !== true) continue;
43440
- const displayPath = asRecord$2(items.find((item) => {
43441
- const record = asRecord$2(item);
43669
+ const displayPath = asRecord$3(items.find((item) => {
43670
+ const record = asRecord$3(item);
43442
43671
  return Array.isArray(record?.sessionIds) && record.sessionIds.includes(id);
43443
43672
  }))?.path;
43444
43673
  if (typeof displayPath !== "string" || displayPath === "" || session.cwd === displayPath) continue;
@@ -43531,18 +43760,18 @@ ${scope} [data-dockkit-strip-tabs] {
43531
43760
  function orderWorkspaceItems(items, orderedWorkspaceIds, localHostId) {
43532
43761
  if (orderedWorkspaceIds.length === 0 || items.length < 2) return items;
43533
43762
  if (localHostId === void 0 && items.some((item) => {
43534
- const workspaceId = asRecord$2(item)?.workspaceId;
43763
+ const workspaceId = asRecord$3(item)?.workspaceId;
43535
43764
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null;
43536
43765
  })) return items;
43537
43766
  const hasLocalItem = localHostId !== void 0 && items.some((item) => {
43538
- const workspaceId = asRecord$2(item)?.workspaceId;
43767
+ const workspaceId = asRecord$3(item)?.workspaceId;
43539
43768
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null;
43540
43769
  });
43541
43770
  const hasLocalOrder = localHostId !== void 0 && orderedWorkspaceIds.some((id) => require_primitives_adapter.parseVirtualWorkspaceId(id)?.hostId === localHostId);
43542
43771
  if (hasLocalItem && !hasLocalOrder) return items;
43543
43772
  const ranks = new Map(orderedWorkspaceIds.map((id, index) => [id, index]));
43544
43773
  const entries = items.map((item, index) => {
43545
- const workspaceId = asRecord$2(item)?.workspaceId;
43774
+ const workspaceId = asRecord$3(item)?.workspaceId;
43546
43775
  return {
43547
43776
  item,
43548
43777
  index,
@@ -43580,7 +43809,7 @@ ${scope} [data-dockkit-strip-tabs] {
43580
43809
  }
43581
43810
  return merged.length === original.length && merged.every((id, index) => id === original[index]) ? void 0 : merged;
43582
43811
  }
43583
- function asRecord$2(value) {
43812
+ function asRecord$3(value) {
43584
43813
  return isRecord$4(value) ? value : null;
43585
43814
  }
43586
43815
  function isRecord$4(value) {
@@ -44400,6 +44629,8 @@ ${scope} [data-dockkit-strip-tabs] {
44400
44629
  peers = /* @__PURE__ */ new Map();
44401
44630
  routes = /* @__PURE__ */ new Map();
44402
44631
  generations = /* @__PURE__ */ new Set();
44632
+ /** 事件早于聚合摘要到达时暂存,待会话进入可见作用域后重放。 */
44633
+ pendingSessionStatuses = /* @__PURE__ */ new Map();
44403
44634
  sequence = 0;
44404
44635
  instanceId = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
44405
44636
  constructor(options) {
@@ -44408,8 +44639,35 @@ ${scope} [data-dockkit-strip-tabs] {
44408
44639
  setPeers(scopes) {
44409
44640
  this.peers.clear();
44410
44641
  for (const scope of scopes) if (scope.targetHostId !== null) this.peers.set(scope.targetHostId, scope);
44642
+ for (const [key, pending] of this.pendingSessionStatuses) if (pending.scope.targetHostId === null || !this.peers.has(pending.scope.targetHostId)) this.pendingSessionStatuses.delete(key);
44411
44643
  for (const generation of this.generations) this.sync(generation);
44412
44644
  }
44645
+ /** 聚合摘要建立会话作用域后调用,补发此前因作用域未知而暂存的状态事件。 */
44646
+ replayPendingSessionStatuses() {
44647
+ for (const generation of this.generations) {
44648
+ if (generation.clientId === void 0 || generation.controller.signal.aborted) continue;
44649
+ this.replayPendingSessionStatusesForGeneration(generation);
44650
+ }
44651
+ }
44652
+ /**
44653
+ * 摘要从 running 变为 idle、但事件流没有覆盖到这次变化时,补投递完成边沿。
44654
+ * 调用方必须只对确认发生过 true -> false 的会话调用,不能把普通 idle 摘要当未读。
44655
+ */
44656
+ replayCompletedSessionStatus(sessionId, scope) {
44657
+ const frame = {
44658
+ type: "emit",
44659
+ event: "api-session/status",
44660
+ args: [sessionId, false]
44661
+ };
44662
+ let delivered = false;
44663
+ for (const generation of this.generations) {
44664
+ if (generation.clientId === void 0 || generation.controller.signal.aborted || !this.options.accepts(sessionId, scope)) continue;
44665
+ generation.sessionStatuses.delete(sessionId);
44666
+ this.deliverSessionStatus(generation, scope, sessionId, false, frame);
44667
+ delivered = true;
44668
+ }
44669
+ if (!delivered) this.rememberPendingSessionStatus(scope, sessionId, frame);
44670
+ }
44413
44671
  ownsResult(payload) {
44414
44672
  const eventId = record$1(record$1(payload)?.args)?.eventId;
44415
44673
  return typeof eventId === "string" && eventId.startsWith(EVENT_PREFIX);
@@ -44435,6 +44693,7 @@ ${scope} [data-dockkit-strip-tabs] {
44435
44693
  controller: new AbortController(),
44436
44694
  queue: new EventQueue(),
44437
44695
  workers: /* @__PURE__ */ new Map(),
44696
+ sessionStatuses: /* @__PURE__ */ new Map(),
44438
44697
  prepared: false
44439
44698
  };
44440
44699
  const abort = () => {
@@ -44479,6 +44738,7 @@ ${scope} [data-dockkit-strip-tabs] {
44479
44738
  for (const worker of generation.workers.values()) this.stop(generation, worker);
44480
44739
  }
44481
44740
  this.routes.clear();
44741
+ this.pendingSessionStatuses.clear();
44482
44742
  }
44483
44743
  sync(generation) {
44484
44744
  if (generation.clientId === void 0 || generation.controller.signal.aborted) return;
@@ -44512,6 +44772,7 @@ ${scope} [data-dockkit-strip-tabs] {
44512
44772
  if (frame?.type !== "ready" || typeof frame.clientId !== "string") throw new Error("远端事件流缺少 ready 帧");
44513
44773
  clientId = frame.clientId;
44514
44774
  attempt = 0;
44775
+ this.replayPendingSessionStatusesForGeneration(generation);
44515
44776
  if (!generation.prepared) {
44516
44777
  generation.prepared = true;
44517
44778
  try {
@@ -44532,7 +44793,12 @@ ${scope} [data-dockkit-strip-tabs] {
44532
44793
  async deliver(generation, worker, scope, clientId, frame, signal) {
44533
44794
  if (frame?.type === "emit" && frame.event === "api-session/status") {
44534
44795
  const args = frame.args;
44535
- if (Array.isArray(args) && typeof args[0] === "string" && typeof args[1] === "boolean" && this.options.accepts(args[0], scope)) generation.queue.push(frame);
44796
+ if (!Array.isArray(args) || typeof args[0] !== "string" || typeof args[1] !== "boolean") return;
44797
+ if (!this.options.accepts(args[0], scope)) {
44798
+ this.rememberPendingSessionStatus(scope, args[0], frame);
44799
+ return;
44800
+ }
44801
+ this.deliverSessionStatus(generation, scope, args[0], args[1], frame);
44536
44802
  return;
44537
44803
  }
44538
44804
  if (frame?.type === "cancel" && typeof frame.eventId === "string") {
@@ -44566,6 +44832,42 @@ ${scope} [data-dockkit-strip-tabs] {
44566
44832
  eventId: id
44567
44833
  });
44568
44834
  }
44835
+ deliverSessionStatus(generation, scope, sessionId, running, frame) {
44836
+ const previous = generation.sessionStatuses.get(sessionId);
44837
+ if (!running && previous !== true) generation.queue.push({
44838
+ ...record$1(frame),
44839
+ args: [sessionId, true]
44840
+ });
44841
+ this.options.onSessionStatus?.(sessionId, running, scope);
44842
+ generation.queue.push(frame);
44843
+ generation.sessionStatuses.set(sessionId, running);
44844
+ }
44845
+ rememberPendingSessionStatus(scope, sessionId, frame) {
44846
+ if (scope.targetHostId === null) return;
44847
+ const key = `${scope.targetHostId}:${sessionId}`;
44848
+ const pending = this.pendingSessionStatuses.get(key) ?? {
44849
+ scope,
44850
+ sessionId,
44851
+ frames: []
44852
+ };
44853
+ const previousArgs = record$1(pending.frames.at(-1))?.args;
44854
+ const args = record$1(frame)?.args;
44855
+ if (Array.isArray(previousArgs) && Array.isArray(args) && previousArgs[1] === args[1]) return;
44856
+ pending.frames.push(frame);
44857
+ if (pending.frames.length > 8) pending.frames.shift();
44858
+ this.pendingSessionStatuses.set(key, pending);
44859
+ }
44860
+ replayPendingSessionStatusesForGeneration(generation) {
44861
+ for (const pending of [...this.pendingSessionStatuses.values()]) {
44862
+ if (!this.options.accepts(pending.sessionId, pending.scope)) continue;
44863
+ this.pendingSessionStatuses.delete(`${pending.scope.targetHostId}:${pending.sessionId}`);
44864
+ for (const frame of pending.frames) {
44865
+ const args = record$1(frame)?.args;
44866
+ if (!Array.isArray(args) || typeof args[1] !== "boolean") continue;
44867
+ this.deliverSessionStatus(generation, pending.scope, pending.sessionId, args[1], frame);
44868
+ }
44869
+ }
44870
+ }
44569
44871
  cancel(generation, worker, eventId, id) {
44570
44872
  worker.pending.delete(eventId);
44571
44873
  this.routes.delete(id);
@@ -44832,15 +45134,15 @@ ${scope} [data-dockkit-strip-tabs] {
44832
45134
  async function readRemoteCandidates(value) {
44833
45135
  const result = await value;
44834
45136
  if (Array.isArray(result)) return result.flatMap(asRemoteCandidate);
44835
- const record = asRecord$1(result);
45137
+ const record = asRecord$2(result);
44836
45138
  if (record?.ok === true && Array.isArray(record.value)) return record.value.flatMap(asRemoteCandidate);
44837
- const nested = asRecord$1(record?.ok === true ? record.value : void 0);
45139
+ const nested = asRecord$2(record?.ok === true ? record.value : void 0);
44838
45140
  if (Array.isArray(nested?.candidates)) return nested.candidates.flatMap(asRemoteCandidate);
44839
45141
  if (Array.isArray(record?.candidates)) return record.candidates.flatMap(asRemoteCandidate);
44840
45142
  return [];
44841
45143
  }
44842
45144
  function asRemoteCandidate(value) {
44843
- const record = asRecord$1(value);
45145
+ const record = asRecord$2(value);
44844
45146
  if (record === null || typeof record.sessionId !== "string" || typeof record.mention !== "string" || typeof record.label !== "string") return [];
44845
45147
  return [{
44846
45148
  sessionId: record.sessionId,
@@ -44874,14 +45176,14 @@ ${scope} [data-dockkit-strip-tabs] {
44874
45176
  value: formatSessionReferenceMention(title, session.sessionId)
44875
45177
  };
44876
45178
  }
44877
- function asRecord$1(value) {
45179
+ function asRecord$2(value) {
44878
45180
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
44879
45181
  }
44880
45182
  function readSelectedRemoteHost(service, sessionId) {
44881
45183
  const selection = service?.selection?.getSnapshot();
44882
- const record = asRecord$1(selection);
45184
+ const record = asRecord$2(selection);
44883
45185
  if (record === null) return void 0;
44884
- const selectedSessionId = typeof record.sessionId === "string" ? record.sessionId : asRecord$1(record.subagentAddress)?.parentSessionId;
45186
+ const selectedSessionId = typeof record.sessionId === "string" ? record.sessionId : asRecord$2(record.subagentAddress)?.parentSessionId;
44885
45187
  if (selectedSessionId !== void 0 && selectedSessionId !== sessionId) return void 0;
44886
45188
  const workspaceId = record.workspaceId;
44887
45189
  if (typeof workspaceId !== "string") return void 0;
@@ -45126,9 +45428,9 @@ ${scope} [data-dockkit-strip-tabs] {
45126
45428
  return (await readPageRpcResponse(response)).result;
45127
45429
  };
45128
45430
  const codingNsCall = async (endpoint, payload, signal) => {
45129
- const result = asRecord(await request("/codingns", endpoint, payload, signal));
45431
+ const result = asRecord$1(await request("/codingns", endpoint, payload, signal));
45130
45432
  if (result?.ok === true) return result.value;
45131
- const error = asRecord(result?.error);
45433
+ const error = asRecord$1(result?.error);
45132
45434
  const failure = new Error(typeof error?.message === "string" ? error.message : `CodingNS RPC 失败: ${endpoint}`);
45133
45435
  if (typeof error?.code === "string") failure.code = error.code;
45134
45436
  throw failure;
@@ -45161,7 +45463,7 @@ ${scope} [data-dockkit-strip-tabs] {
45161
45463
  const scope = scopeForSessionExport(url);
45162
45464
  if (scope === void 0 || scope.targetHostId === null) return fetchImpl(input, init);
45163
45465
  const headers = init?.headers === void 0 && request === void 0 ? void 0 : Object.fromEntries(new Headers(init?.headers ?? request?.headers).entries());
45164
- const response = asRecord(await codingNsCall("peerHost/request", {
45466
+ const response = asRecord$1(await codingNsCall("peerHost/request", {
45165
45467
  peerHostId: scope.targetHostId,
45166
45468
  scope,
45167
45469
  path: sessionExportPath(url, scope),
@@ -45193,7 +45495,7 @@ ${scope} [data-dockkit-strip-tabs] {
45193
45495
  }
45194
45496
  return;
45195
45497
  }
45196
- const object = asRecord(value);
45498
+ const object = asRecord$1(value);
45197
45499
  if (object === null) return void 0;
45198
45500
  for (const item of Object.values(object)) {
45199
45501
  const found = findScope(item);
@@ -45203,8 +45505,8 @@ ${scope} [data-dockkit-strip-tabs] {
45203
45505
  const scopeForNativeRequest = (method, value) => {
45204
45506
  if (method === "userQuestions/answer" || method === "userQuestions/attachWait") return findScope(questionAgentId(value));
45205
45507
  if (method.startsWith("messageFeedback/") || method === "sessionFeedback/record") {
45206
- const input = asRecord(value);
45207
- const request = asRecord(asRecord(input?.args)?.request ?? input?.request);
45508
+ const input = asRecord$1(value);
45509
+ const request = asRecord$1(asRecord$1(input?.args)?.request ?? input?.request);
45208
45510
  return findScope(request?.sessionId);
45209
45511
  }
45210
45512
  const direct = findScope(value);
@@ -45212,9 +45514,9 @@ ${scope} [data-dockkit-strip-tabs] {
45212
45514
  return method === "session/modelCatalog" && !containsResourceId(value) ? navigationScope() : void 0;
45213
45515
  };
45214
45516
  const scopeForPluginRequest = (endpoint, value) => {
45215
- if ((endpoint === "cli/catalog" || endpoint === "cli/models" || endpoint === "cli/catalog/refresh") && asRecord(value)?.catalogHostId === "local") return void 0;
45517
+ if ((endpoint === "cli/catalog" || endpoint === "cli/models" || endpoint === "cli/catalog/refresh") && asRecord$1(value)?.catalogHostId === "local") return void 0;
45216
45518
  if (endpoint.startsWith("fileManagement/")) {
45217
- const input = asRecord(value);
45519
+ const input = asRecord$1(value);
45218
45520
  const workspace = findScope(input?.workspaceId);
45219
45521
  const session = findScope(input?.sessionId);
45220
45522
  if (hasVirtualResourceScope(value)) {
@@ -45225,7 +45527,7 @@ ${scope} [data-dockkit-strip-tabs] {
45225
45527
  return workspace ?? session;
45226
45528
  }
45227
45529
  if (isDebugPluginEndpoint(endpoint)) {
45228
- const input = asRecord(value);
45530
+ const input = asRecord$1(value);
45229
45531
  return findScope(input?.workspaceId) ?? findScope(input?.sessionId);
45230
45532
  }
45231
45533
  const direct = findScope(value);
@@ -45238,8 +45540,8 @@ ${scope} [data-dockkit-strip-tabs] {
45238
45540
  if (selection !== void 0) {
45239
45541
  const direct = findScope(selection);
45240
45542
  if (direct !== void 0) return direct;
45241
- const selected = asRecord(selection);
45242
- const sessionId = selected?.sessionId ?? asRecord(selected?.subagentAddress)?.parentSessionId;
45543
+ const selected = asRecord$1(selection);
45544
+ const sessionId = selected?.sessionId ?? asRecord$1(selected?.subagentAddress)?.parentSessionId;
45243
45545
  const session = typeof sessionId === "string" ? require_primitives_adapter.parseVirtualSessionId(sessionId) : null;
45244
45546
  const workspace = typeof selected?.workspaceId === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(selected.workspaceId) : null;
45245
45547
  const hostId = session?.hostId ?? workspace?.targetHostId;
@@ -45263,7 +45565,7 @@ ${scope} [data-dockkit-strip-tabs] {
45263
45565
  };
45264
45566
  const containsResourceId = (value) => {
45265
45567
  if (Array.isArray(value)) return value.some(containsResourceId);
45266
- const record = asRecord(value);
45568
+ const record = asRecord$1(value);
45267
45569
  if (record === null) return false;
45268
45570
  for (const [key, child] of Object.entries(record)) {
45269
45571
  if ((key === "workspaceId" || key === "sessionId" || key === "parentSessionId") && typeof child === "string" && child !== "") return true;
@@ -45275,14 +45577,14 @@ ${scope} [data-dockkit-strip-tabs] {
45275
45577
  const containsVirtualResourceId = (value) => {
45276
45578
  if (typeof value === "string") return require_primitives_adapter.parseVirtualSessionId(value) !== null || require_primitives_adapter.parseVirtualWorkspaceId(value) !== null;
45277
45579
  if (Array.isArray(value)) return value.some(containsVirtualResourceId);
45278
- const record = asRecord(value);
45580
+ const record = asRecord$1(value);
45279
45581
  return record !== null && Object.values(record).some(containsVirtualResourceId);
45280
45582
  };
45281
45583
  const hasUnresolvedVirtualNativeScope = (method, value) => {
45282
45584
  if (method === "userQuestions/answer" || method === "userQuestions/attachWait") return false;
45283
45585
  if (method.startsWith("messageFeedback/") || method === "sessionFeedback/record") {
45284
- const input = asRecord(value);
45285
- const request = asRecord(asRecord(input?.args)?.request ?? input?.request);
45586
+ const input = asRecord$1(value);
45587
+ const request = asRecord$1(asRecord$1(input?.args)?.request ?? input?.request);
45286
45588
  return typeof request?.sessionId === "string" && require_primitives_adapter.parseVirtualSessionId(request.sessionId) !== null;
45287
45589
  }
45288
45590
  return containsVirtualResourceId(value);
@@ -45293,13 +45595,13 @@ ${scope} [data-dockkit-strip-tabs] {
45293
45595
  return (key === "sessionId" || key === "parentSessionId" || key === "childSessionId") && parsed !== null && parsed.hostId === (scope.targetHostId ?? scope.hostId) ? parsed.sessionId : value;
45294
45596
  }
45295
45597
  if (Array.isArray(value)) return value.map((item) => rewriteCliPayload(item, scope, key));
45296
- const record = asRecord(value);
45598
+ const record = asRecord$1(value);
45297
45599
  if (record === null) return value;
45298
45600
  return Object.fromEntries(Object.entries(record).map(([childKey, child]) => [childKey, rewriteCliPayload(child, scope, childKey)]));
45299
45601
  };
45300
45602
  const remotePluginRpc = async (scope, endpoint, payload, signal) => {
45301
45603
  if (scope.targetHostId === null) throw new Error("PeerHost 插件请求缺少目标 Host");
45302
- const response = asRecord(await codingNsCall("peerHost/request", {
45604
+ const response = asRecord$1(await codingNsCall("peerHost/request", {
45303
45605
  peerHostId: scope.targetHostId,
45304
45606
  scope,
45305
45607
  path: `/api/codingns/${endpoint}`,
@@ -45308,7 +45610,7 @@ ${scope} [data-dockkit-strip-tabs] {
45308
45610
  rpcId: createRequestId(),
45309
45611
  method: endpoint,
45310
45612
  payload: endpoint.startsWith("git/") ? {
45311
- ...asRecord(payload),
45613
+ ...asRecord$1(payload),
45312
45614
  workspaceId: scope.workspaceId
45313
45615
  } : endpoint.startsWith("cli/") ? rewriteCliPayload(payload, scope) : rewritePluginResourcePayload(payload, scope)
45314
45616
  })
@@ -45318,7 +45620,7 @@ ${scope} [data-dockkit-strip-tabs] {
45318
45620
  if (status < 200 || status >= 300) {
45319
45621
  let error = null;
45320
45622
  try {
45321
- error = asRecord(asRecord(JSON.parse(body))?.error);
45623
+ error = asRecord$1(asRecord$1(JSON.parse(body))?.error);
45322
45624
  } catch {}
45323
45625
  if (typeof error?.code === "string" && typeof error.message === "string") return {
45324
45626
  ok: false,
@@ -45330,21 +45632,21 @@ ${scope} [data-dockkit-strip-tabs] {
45330
45632
  throw new Error(`远端 Host 插件 RPC 失败: HTTP ${status}`);
45331
45633
  }
45332
45634
  try {
45333
- const envelope = asRecord(JSON.parse(body));
45635
+ const envelope = asRecord$1(JSON.parse(body));
45334
45636
  return endpoint.startsWith("git/") ? projectGitWorkspaceIds(envelope?.result, scope.workspaceId, require_primitives_adapter.createVirtualWorkspaceId(scope.targetHostId, scope.workspaceId)) : envelope?.result;
45335
45637
  } catch {
45336
45638
  throw new Error("远端 Host 插件 RPC 响应不是 JSON");
45337
45639
  }
45338
45640
  };
45339
45641
  const mergeRemoteAdapterMap = async (localResult, signal) => {
45340
- const localEnvelope = asRecord(localResult);
45642
+ const localEnvelope = asRecord$1(localResult);
45341
45643
  if (localEnvelope?.ok !== true || !Array.isArray(localEnvelope.value)) return localResult;
45342
45644
  const rows = [...localEnvelope.value];
45343
45645
  for (const [targetHostId, scope] of remoteHostScopes) try {
45344
- const remoteEnvelope = asRecord(await remotePluginRpc(scope, "cli/session/adapter-map", {}, signal));
45646
+ const remoteEnvelope = asRecord$1(await remotePluginRpc(scope, "cli/session/adapter-map", {}, signal));
45345
45647
  if (remoteEnvelope?.ok !== true || !Array.isArray(remoteEnvelope.value)) continue;
45346
45648
  for (const raw of remoteEnvelope.value) {
45347
- const row = asRecord(raw);
45649
+ const row = asRecord$1(raw);
45348
45650
  const sessionId = typeof row?.sessionId === "string" ? row.sessionId : "";
45349
45651
  const adapterId = typeof row?.adapterId === "string" ? row.adapterId : "";
45350
45652
  if (sessionId !== "" && adapterId !== "") rows.push({
@@ -45359,7 +45661,7 @@ ${scope} [data-dockkit-strip-tabs] {
45359
45661
  };
45360
45662
  };
45361
45663
  const openRemoteStream = (method, payload, scope, signal) => (async function* () {
45362
- const opened = asRecord(await codingNsCall("peerHost/nativeStream", {
45664
+ const opened = asRecord$1(await codingNsCall("peerHost/nativeStream", {
45363
45665
  method,
45364
45666
  payload,
45365
45667
  scope
@@ -45368,7 +45670,7 @@ ${scope} [data-dockkit-strip-tabs] {
45368
45670
  if (streamId === "") throw new Error("PeerHost 原生 Remote 未返回 streamId");
45369
45671
  try {
45370
45672
  while (!(signal?.aborted ?? false)) {
45371
- const next = asRecord(await codingNsCall("peerHost/nativeStreamNext", {
45673
+ const next = asRecord$1(await codingNsCall("peerHost/nativeStreamNext", {
45372
45674
  streamId,
45373
45675
  scope
45374
45676
  }, signal));
@@ -45392,6 +45694,9 @@ ${scope} [data-dockkit-strip-tabs] {
45392
45694
  scope
45393
45695
  }, signal),
45394
45696
  accepts: (agentId, scope) => scopes.get(agentId)?.targetHostId === scope.targetHostId,
45697
+ onSessionStatus: (sessionId, running) => {
45698
+ if (projection.setSessionRunning(sessionId, running)) refreshPeerHostNativeSessions(uiContext);
45699
+ },
45395
45700
  prepare: async () => {
45396
45701
  if (nativeSessionPrepared) return;
45397
45702
  nativeSessionPrepared = true;
@@ -45407,7 +45712,7 @@ ${scope} [data-dockkit-strip-tabs] {
45407
45712
  return pending;
45408
45713
  };
45409
45714
  const rememberCreatedSession = (scope, value) => {
45410
- const sessionId = asRecord(value)?.sessionId;
45715
+ const sessionId = asRecord$1(value)?.sessionId;
45411
45716
  if (typeof sessionId !== "string") return;
45412
45717
  const parsed = require_primitives_adapter.parseVirtualSessionId(sessionId);
45413
45718
  if (parsed === null) return;
@@ -45437,17 +45742,17 @@ ${scope} [data-dockkit-strip-tabs] {
45437
45742
  };
45438
45743
  /** 父会话目录早于聚合到达时,复用新建会话的临时作用域与清理机制。 */
45439
45744
  const rememberSubagentCatalog = (scope, value) => {
45440
- const catalog = asRecord(asRecord(asRecord(value)?.projections)?.values)?.subagentCatalog;
45745
+ const catalog = asRecord$1(asRecord$1(asRecord$1(value)?.projections)?.values)?.subagentCatalog;
45441
45746
  if (!Array.isArray(catalog)) return;
45442
45747
  for (const child of catalog) {
45443
- const id = asRecord(child)?.id;
45748
+ const id = asRecord$1(child)?.id;
45444
45749
  if (typeof id === "string" && !scopes.has(id)) rememberCreatedSession(scope, { sessionId: id });
45445
45750
  }
45446
45751
  };
45447
45752
  return {
45448
45753
  hooks: {
45449
45754
  rpc: async ({ method, payload, signal }) => {
45450
- const value = asRecord(payload);
45755
+ const value = asRecord$1(payload);
45451
45756
  const channel = typeof value?.channel === "string" ? value.channel : "/codingns";
45452
45757
  const body = value?.payload;
45453
45758
  if (channel === "/api" && method === "$events/result" && events.ownsResult(body)) try {
@@ -45482,7 +45787,7 @@ ${scope} [data-dockkit-strip-tabs] {
45482
45787
  message: t("peerHost.debugWorkspaceUnavailable")
45483
45788
  }
45484
45789
  };
45485
- const workspaceId = asRecord(body)?.workspaceId;
45790
+ const workspaceId = asRecord$1(body)?.workspaceId;
45486
45791
  const scope = endpoint.startsWith("git/") ? findScope(workspaceId) : scopeForPluginRequest(endpoint, body);
45487
45792
  if (endpoint.startsWith("git/") && typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) !== null && scope === void 0) return {
45488
45793
  ok: false,
@@ -45525,9 +45830,17 @@ ${scope} [data-dockkit-strip-tabs] {
45525
45830
  payload: body,
45526
45831
  scope
45527
45832
  }, signal));
45528
- if (method === "session/create" || method === "session/fork") {
45529
- rememberCreatedSession(scope, created);
45530
- Promise.resolve(requestPeerHostAggregateRefresh()).catch(() => void 0);
45833
+ const createsSession = method === "session/create" || method === "session/fork";
45834
+ const refreshesNativeList = method === "session/rename" || method === "workspace/archiveSession" || method === "workspace/unarchiveSession";
45835
+ if (createsSession) rememberCreatedSession(scope, created);
45836
+ if (createsSession || refreshesNativeList) {
45837
+ let aggregateRefresh;
45838
+ try {
45839
+ aggregateRefresh = requestPeerHostAggregateRefresh();
45840
+ } catch {
45841
+ aggregateRefresh = void 0;
45842
+ }
45843
+ if (refreshesNativeList) Promise.resolve(aggregateRefresh).then(() => refreshPeerHostNativeSessions(uiContext)).catch(() => void 0);
45531
45844
  }
45532
45845
  return {
45533
45846
  ok: true,
@@ -45549,7 +45862,7 @@ ${scope} [data-dockkit-strip-tabs] {
45549
45862
  return result;
45550
45863
  },
45551
45864
  openStream: ({ method, payload, signal }) => {
45552
- const value = asRecord(payload);
45865
+ const value = asRecord$1(payload);
45553
45866
  const channel = typeof value?.channel === "string" ? value.channel : "/api";
45554
45867
  const body = value?.payload;
45555
45868
  if (channel === "/api" && method === "$events") return events.open((localSignal) => openDshGatewayStream(method, body, localSignal), signal);
@@ -45608,7 +45921,7 @@ ${scope} [data-dockkit-strip-tabs] {
45608
45921
  return scope === void 0 ? hasVirtualResourceScope(value) : scope.targetHostId !== null;
45609
45922
  }
45610
45923
  if (method?.startsWith("git/") || method?.startsWith("codingns/git/")) {
45611
- const workspaceId = asRecord(value)?.workspaceId;
45924
+ const workspaceId = asRecord$1(value)?.workspaceId;
45612
45925
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) !== null;
45613
45926
  }
45614
45927
  const cli = method === void 0 ? void 0 : method === "cli/catalog" || method === "cli/models" ? method : method.startsWith("codingns/cli/") ? method.slice(9) : void 0;
@@ -45681,6 +45994,13 @@ ${scope} [data-dockkit-strip-tabs] {
45681
45994
  }
45682
45995
  refreshModelCatalogForScope(navigationScope());
45683
45996
  const changed = projection.setAggregate(aggregate, orderedWorkspaceIds);
45997
+ for (const sessionId of projection.consumeCompletedSessionTransitions()) {
45998
+ const scope = scopes.get(sessionId);
45999
+ if (scope === void 0) continue;
46000
+ projection.setSessionRunning(sessionId, false);
46001
+ events.replayCompletedSessionStatus(sessionId, scope);
46002
+ }
46003
+ events.replayPendingSessionStatuses();
45684
46004
  const readyHosts = new Set(aggregate.filter((host) => host.availability === "ready" && host.workspaces.length > 0).map((host) => host.targetHostId));
45685
46005
  events.setPeers([...remoteHostScopes.values()].filter((scope) => readyHosts.has(scope.targetHostId)));
45686
46006
  return changed;
@@ -45693,8 +46013,8 @@ ${scope} [data-dockkit-strip-tabs] {
45693
46013
  return endpoint.startsWith("cli/") || endpoint.startsWith("git/") || endpoint.startsWith("debug/") || endpoint.startsWith("fileManagement/") || endpoint === "terminal/status" ? endpoint : void 0;
45694
46014
  }
45695
46015
  function questionAgentId(value) {
45696
- const input = asRecord(value);
45697
- return asRecord(input?.args)?.agentId ?? input?.agentId;
46016
+ const input = asRecord$1(value);
46017
+ return asRecord$1(input?.args)?.agentId ?? input?.agentId;
45698
46018
  }
45699
46019
  function hasVirtualQuestionAgent(method, value) {
45700
46020
  if (method !== "userQuestions/answer" && method !== "userQuestions/attachWait") return false;
@@ -45705,19 +46025,19 @@ ${scope} [data-dockkit-strip-tabs] {
45705
46025
  return endpoint.startsWith("debug/") || endpoint === "terminal/status";
45706
46026
  }
45707
46027
  function hasVirtualResourceScope(value) {
45708
- const input = asRecord(value);
46028
+ const input = asRecord$1(value);
45709
46029
  return typeof input?.workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(input.workspaceId) !== null || typeof input?.sessionId === "string" && require_primitives_adapter.parseVirtualSessionId(input.sessionId) !== null;
45710
46030
  }
45711
46031
  /** 只投影响应中的工作区标识;Diff、提交正文和文件路径均保持原文。 */
45712
46032
  function projectGitWorkspaceIds(value, workspaceId, virtualWorkspaceId) {
45713
46033
  if (Array.isArray(value)) return value.map((item) => projectGitWorkspaceIds(item, workspaceId, virtualWorkspaceId));
45714
- const record = asRecord(value);
46034
+ const record = asRecord$1(value);
45715
46035
  if (record === null) return value;
45716
46036
  return Object.fromEntries(Object.entries(record).map(([key, child]) => [key, key === "workspaceId" && child === workspaceId ? virtualWorkspaceId : projectGitWorkspaceIds(child, workspaceId, virtualWorkspaceId)]));
45717
46037
  }
45718
46038
  /** 只还原调试与文件请求的顶层资源标识,配置、文件正文和路径必须原样保存。 */
45719
46039
  function rewritePluginResourcePayload(value, scope) {
45720
- const input = asRecord(value);
46040
+ const input = asRecord$1(value);
45721
46041
  if (input === null) return value;
45722
46042
  const result = { ...input };
45723
46043
  const workspace = typeof input.workspaceId === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(input.workspaceId) : null;
@@ -45818,7 +46138,7 @@ ${scope} [data-dockkit-strip-tabs] {
45818
46138
  /** 只借用原生导航数据,不修改选择策略,也不从后台保留会话推断前台。 */
45819
46139
  function readNativeNavigationStore(uiContext) {
45820
46140
  try {
45821
- const store = asRecord(asRecord(uiContext?.get("uiWorkspace"))?.selection);
46141
+ const store = asRecord$1(asRecord$1(uiContext?.get("uiWorkspace"))?.selection);
45822
46142
  if (typeof store?.getSnapshot !== "function" || typeof store.subscribe !== "function") return void 0;
45823
46143
  return store;
45824
46144
  } catch {
@@ -45827,14 +46147,14 @@ ${scope} [data-dockkit-strip-tabs] {
45827
46147
  }
45828
46148
  /** 把虚拟会话摘要并入 session/list 结果;形状不符时保持本机结果不变。 */
45829
46149
  function mergeSessionListResult(result, projection) {
45830
- const envelope = asRecord(result);
46150
+ const envelope = asRecord$1(result);
45831
46151
  if (envelope?.ok !== true) return result;
45832
- const value = asRecord(envelope.value);
46152
+ const value = asRecord$1(envelope.value);
45833
46153
  if (value === null || !Array.isArray(value.items)) return result;
45834
46154
  const virtual = projection.sessions();
45835
46155
  if (virtual.length === 0) return result;
45836
46156
  const known = new Set(value.items.flatMap((item) => {
45837
- const id = asRecord(item)?.sessionId;
46157
+ const id = asRecord$1(item)?.sessionId;
45838
46158
  return typeof id === "string" ? [id] : [];
45839
46159
  }));
45840
46160
  for (const session of virtual) if (session.adapterId !== void 0) publishSessionAdapter(session.sessionId, session.adapterId);
@@ -45850,7 +46170,7 @@ ${scope} [data-dockkit-strip-tabs] {
45850
46170
  function createRequestId() {
45851
46171
  return typeof globalThis.crypto?.randomUUID === "function" ? globalThis.crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
45852
46172
  }
45853
- function asRecord(value) {
46173
+ function asRecord$1(value) {
45854
46174
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
45855
46175
  }
45856
46176
  /**
@@ -45869,8 +46189,8 @@ ${scope} [data-dockkit-strip-tabs] {
45869
46189
  }
45870
46190
  const metadata = fields.get("metadata");
45871
46191
  if (typeof metadata !== "string") throw new TypeError("connection: invalid binary response fields");
45872
- const envelope = asRecord(JSON.parse(metadata));
45873
- const result = asRecord(envelope?.result);
46192
+ const envelope = asRecord$1(JSON.parse(metadata));
46193
+ const result = asRecord$1(envelope?.result);
45874
46194
  if (envelope === null || result === null) throw new TypeError("connection: invalid server-response envelope");
45875
46195
  fields.delete("metadata");
45876
46196
  if (result.ok !== true) {
@@ -45881,7 +46201,7 @@ ${scope} [data-dockkit-strip-tabs] {
45881
46201
  if (!Array.isArray(attachments) || attachments.length === 0) throw new TypeError("connection: invalid binary response result");
45882
46202
  const root = { value: result.value };
45883
46203
  for (const rawAttachment of attachments) {
45884
- const attachment = asRecord(rawAttachment);
46204
+ const attachment = asRecord$1(rawAttachment);
45885
46205
  const path = attachment?.path;
45886
46206
  const part = attachment?.part;
45887
46207
  if (attachment?.codec !== "bytes" || typeof part !== "string" || !Array.isArray(path)) throw new TypeError("connection: invalid binary response attachment");
@@ -45926,8 +46246,8 @@ ${scope} [data-dockkit-strip-tabs] {
45926
46246
  function refreshDshModelCatalog(uiContext) {
45927
46247
  if (uiContext === void 0) return;
45928
46248
  try {
45929
- const service = asRecord(uiContext.get("modelDirectories"));
45930
- const catalog = service === null ? null : asRecord(service.catalog);
46249
+ const service = asRecord$1(uiContext.get("modelDirectories"));
46250
+ const catalog = service === null ? null : asRecord$1(service.catalog);
45931
46251
  if (catalog === null) return;
45932
46252
  const resetGeneration = catalog.resetGeneration;
45933
46253
  const refresh = catalog.refresh;
@@ -47917,15 +48237,39 @@ ${scope} [data-dockkit-strip-tabs] {
47917
48237
  }
47918
48238
  //#endregion
47919
48239
  //#region src/client/avatar/notification-bubble.ts
47920
- function AssistantNotificationBubble({ frame, t, error, onOpen, onDismiss, onPresented, autoClose = false, autoCloseSeconds = 30, onPage, onExpandedChange }) {
48240
+ /** 返回形象中心在通知面板坐标系中的投影;仅供旧调用方和布局测试使用。 */
48241
+ function assistantNotificationTailStyle(avatarCenter, regionStart, regionSize, side = "bottom") {
48242
+ if (side === "left" || side === "right") return {};
48243
+ const margin = 36;
48244
+ const target = avatarCenter - regionStart;
48245
+ const rootTarget = target - Math.sign(target - regionSize / 2) * 10;
48246
+ const center = Math.max(margin, Math.min(Math.max(margin, regionSize - margin), rootTarget));
48247
+ const bottomAngle = Math.max(-20, Math.min(20, -Math.atan2(target - center, 30) * 180 / Math.PI));
48248
+ const angle = side === "top" ? -bottomAngle : bottomAngle;
48249
+ return {
48250
+ "--codingns-assistant-tail-offset": `${Math.round(center)}px`,
48251
+ "--codingns-assistant-tail-target": `${Math.round(target)}px`,
48252
+ "--codingns-assistant-tail-angle": `${Math.round(angle * 10) / 10}deg`
48253
+ };
48254
+ }
48255
+ /** 实际面板边缘使用的目标投影,允许目标落在圆角外侧后由轮廓算法自然收敛。 */
48256
+ function assistantNotificationTailTarget(avatarCenter, regionStart) {
48257
+ return avatarCenter - regionStart;
48258
+ }
48259
+ function isPendingNotice(notice) {
48260
+ return (notice.kind === "question" || notice.kind === "approval") && notice.lifecycle === "active";
48261
+ }
48262
+ function AssistantNotificationBubble({ frame, t, error, onOpen, onDismiss, onPresented, autoClose = false, autoCloseSeconds = 30, onExpandedChange, onClearAll, tailSide = "bottom", tailTarget, tailStyle }) {
47921
48263
  const [expanded, setExpanded] = (0, react.useState)(false);
47922
- const [cursors, setCursors] = (0, react.useState)([void 0]);
48264
+ const [collapsed, setCollapsed] = (0, react.useState)(false);
48265
+ const [listFilter, setListFilter] = (0, react.useState)("all");
48266
+ const [processing, setProcessing] = (0, react.useState)(false);
47923
48267
  const bubble = (0, react.useRef)(null);
47924
48268
  const autoCloseTimer = (0, react.useRef)(void 0);
47925
48269
  const snapshot = "items" in frame ? frame : void 0;
47926
48270
  const primary = snapshot === void 0 ? frame : snapshot.primary;
47927
- const items = snapshot?.items.filter((notice) => !notice.read || (notice.kind === "question" || notice.kind === "approval") && notice.lifecycle === "active") ?? [];
47928
- const attentionItems = snapshot === void 0 ? primary === void 0 || primary === null ? [] : [primary] : [...snapshot.primary === null || snapshot.primary.presentation === "collapsed" ? [] : [snapshot.primary], ...items.filter((notice) => notice.presentation !== "collapsed" && (!notice.read || (notice.kind === "question" || notice.kind === "approval") && notice.lifecycle === "active") && notice.noticeId !== snapshot.primary?.noticeId)];
48271
+ const items = snapshot?.items.filter((notice) => !notice.read || isPendingNotice(notice)) ?? [];
48272
+ const attentionItems = snapshot === void 0 ? primary === void 0 || primary === null ? [] : [primary] : [...snapshot.primary === null || snapshot.primary.presentation === "collapsed" ? [] : [snapshot.primary], ...items.filter((notice) => notice.presentation !== "collapsed" && (!notice.read || isPendingNotice(notice)) && notice.noticeId !== snapshot.primary?.noticeId)];
47929
48273
  const multiple = attentionItems.length > 1 || snapshot !== void 0 && Math.max(snapshot.unreadCount, snapshot.pendingCount) > 1;
47930
48274
  const mainNotice = attentionItems[0] ?? (snapshot === void 0 ? primary ?? void 0 : void 0);
47931
48275
  const presented = attentionItems[0] ?? (snapshot === void 0 ? primary ?? void 0 : void 0);
@@ -47934,7 +48278,10 @@ ${scope} [data-dockkit-strip-tabs] {
47934
48278
  onExpandedChange?.(expanded);
47935
48279
  }, [expanded, onExpandedChange]);
47936
48280
  (0, react.useEffect)(() => {
47937
- setCursors([void 0]);
48281
+ setCollapsed(false);
48282
+ }, [frame.generation]);
48283
+ (0, react.useEffect)(() => {
48284
+ setListFilter("all");
47938
48285
  }, [frame.generation, snapshot?.reset]);
47939
48286
  (0, react.useEffect)(() => {
47940
48287
  if (presented === void 0 || presented === null) return;
@@ -47983,26 +48330,60 @@ ${scope} [data-dockkit-strip-tabs] {
47983
48330
  presented?.connectionGeneration,
47984
48331
  createdAt,
47985
48332
  frame.generation,
48333
+ expanded,
48334
+ collapsed,
47986
48335
  autoClose,
47987
48336
  autoCloseSeconds,
47988
48337
  onPresented,
47989
48338
  onDismiss
47990
48339
  ]);
47991
- const page = (next) => {
47992
- const updated = next ? [...cursors, snapshot.cursor] : cursors.slice(0, -1);
47993
- setCursors(updated);
47994
- onPage?.(updated.at(-1));
48340
+ const clearableCount = snapshot === void 0 ? 0 : [...snapshot.items, ...snapshot.primary === null ? [] : [snapshot.primary]].filter((notice) => !notice.read && !isPendingNotice(notice)).length;
48341
+ const showClearAll = snapshot !== void 0 && clearableCount > 0 && onClearAll !== void 0;
48342
+ const hasNotificationCounts = snapshot !== void 0 && (snapshot.unreadCount > 0 || snapshot.pendingCount > 0);
48343
+ const showCollapseButton = !collapsed && (mainNotice !== void 0 || hasNotificationCounts);
48344
+ const showExpandButton = collapsed && (mainNotice !== void 0 || hasNotificationCounts);
48345
+ const showTopRow = showCollapseButton || showExpandButton || showClearAll || hasNotificationCounts;
48346
+ const showBubble = !collapsed && (!expanded || snapshot === void 0) && mainNotice !== void 0;
48347
+ const showFilterTags = snapshot !== void 0 && (multiple || collapsed);
48348
+ const listItems = listFilter === "unread" ? items.filter((notice) => !notice.read && !isPendingNotice(notice)) : listFilter === "pending" ? items.filter((notice) => isPendingNotice(notice)) : items;
48349
+ const tail = tailSide !== "top" && (showBubble || expanded && snapshot !== void 0) ? (0, react.createElement)("span", {
48350
+ "aria-hidden": true,
48351
+ "data-codingns-notification-tail": tailSide,
48352
+ style: {
48353
+ ...tailBox(tailSide),
48354
+ ...tailStyle
48355
+ }
48356
+ }, (0, react.createElement)("svg", {
48357
+ width: 56,
48358
+ height: 36,
48359
+ viewBox: `0 0 56 36`,
48360
+ "aria-hidden": true,
48361
+ style: tailSvg(tailSide)
48362
+ }, (0, react.createElement)("path", {
48363
+ d: `${notificationTailCurve} Z`,
48364
+ fill: require_theme.dshThemeColor.menuBackground
48365
+ }))) : null;
48366
+ const toggleFilter = (filter) => {
48367
+ setCollapsed(false);
48368
+ setListFilter(listFilter === filter ? "all" : filter);
48369
+ setExpanded(true);
48370
+ };
48371
+ const requestLine = (notice, compact = false) => {
48372
+ const approval = notice.kind === "approval";
48373
+ const tagStyle = compact ? approval ? compactApprovalTag : compactRequestTag : approval ? approvalInlineTag : requestInlineTag;
48374
+ return (0, react.createElement)("span", { style: requestPrompt }, t("awb.notifications.requestPrefix"), (0, react.createElement)("span", { style: tagStyle }, approval ? t("awb.notifications.approvalTag") : t("awb.notifications.questionTag")), t("awb.notifications.requestSuffix"));
47995
48375
  };
47996
- const row = (notice, variant = "list") => (0, react.createElement)("section", {
48376
+ const row = (notice, variant) => (0, react.createElement)("section", {
47997
48377
  key: notice.noticeId,
47998
48378
  "data-codingns-notice-id": notice.noticeId,
47999
48379
  "data-codingns-notice-kind": notice.kind,
48000
- style: variant === "primary" ? primaryCard : variant === "compact" ? compactCard : listRow
48001
- }, (0, react.createElement)("div", { style: cardHeading }, (0, react.createElement)("span", {
48380
+ style: variant === "primary" ? primaryCard : compactCard
48381
+ }, (0, react.createElement)("div", { style: cardBody }, (0, react.createElement)("div", { style: cardHeading }, (0, react.createElement)("span", {
48002
48382
  "aria-hidden": true,
48003
48383
  style: {
48004
48384
  ...kindMark,
48005
- background: noticeKindColor[notice.kind]
48385
+ background: noticeKindColor[notice.kind],
48386
+ ...noticeKindForeground[notice.kind] === void 0 ? {} : { color: noticeKindForeground[notice.kind] }
48006
48387
  }
48007
48388
  }, icons[notice.kind]), (0, react.createElement)("div", {
48008
48389
  style: {
@@ -48010,9 +48391,9 @@ ${scope} [data-dockkit-strip-tabs] {
48010
48391
  flex: "1 1 auto"
48011
48392
  },
48012
48393
  title: `${notice.hostLabel} · ${notice.workspaceLabel} · ${notice.sessionTitle}`
48013
- }, (0, react.createElement)("div", { style: cardMeta }, `${notice.hostLabel} · ${notice.workspaceLabel}`), (0, react.createElement)("div", { style: cardTitle }, notice.sessionTitle))), variant === "compact" ? (0, react.createElement)("span", { style: notice.kind === "question" || notice.kind === "approval" ? requestTag : compactStatus }, notice.kind === "question" ? t("awb.notifications.questionTag") : notice.kind === "approval" ? t("awb.notifications.approvalTag") : notificationStatus(notice, t)) : null, variant !== "compact" ? (0, react.createElement)("div", { style: messageText }, (0, react.createElement)("span", { "aria-hidden": true }, icons[notice.kind] + " "), notice.kind === "question" || notice.kind === "approval" ? (0, react.createElement)("span", { style: requestInlineTag }, notice.kind === "question" ? t("awb.notifications.questionTag") : t("awb.notifications.approvalTag")) : null, notice.text, "errorExcerpt" in notice && notice.errorExcerpt ? (0, react.createElement)("div", null, notice.errorExcerpt) : null) : null, notice.availability !== "ready" ? (0, react.createElement)("span", { role: "status" }, t(notice.availability === "disconnected" ? "awb.notifications.disconnected" : "awb.notifications.expired")) : null, (0, react.createElement)("div", { style: actionRow }, (0, react.createElement)("button", {
48394
+ }, (0, react.createElement)("div", { style: cardMeta }, `${notice.hostLabel} · ${notice.workspaceLabel}`), (0, react.createElement)("div", { style: cardTitle }, notice.sessionTitle))), variant === "compact" ? notice.kind === "question" || notice.kind === "approval" ? (0, react.createElement)("div", { style: compactPrompt }, requestLine(notice, true)) : (0, react.createElement)("span", { style: compactStatus }, notificationStatus(notice, t)) : null, variant !== "compact" ? (0, react.createElement)("div", { style: messageText }, notice.kind === "question" || notice.kind === "approval" ? requestLine(notice) : (0, react.createElement)("span", null, (0, react.createElement)("span", { "aria-hidden": true }, icons[notice.kind] + " "), notice.text), "errorExcerpt" in notice && notice.errorExcerpt ? (0, react.createElement)("div", null, notice.errorExcerpt) : null) : null, notice.availability !== "ready" ? (0, react.createElement)("span", { role: "status" }, t(notice.availability === "disconnected" ? "awb.notifications.disconnected" : "awb.notifications.expired")) : null), (0, react.createElement)("div", { style: actionRow }, (0, react.createElement)("button", {
48014
48395
  type: "button",
48015
- style: variant === "compact" ? compactButton : button,
48396
+ style: notificationActionButton,
48016
48397
  disabled: notice.availability !== "ready",
48017
48398
  "aria-label": [
48018
48399
  t("awb.notifications.open"),
@@ -48020,94 +48401,104 @@ ${scope} [data-dockkit-strip-tabs] {
48020
48401
  notice.workspaceLabel,
48021
48402
  notice.sessionTitle
48022
48403
  ].join(" · "),
48404
+ title: t("awb.notifications.open"),
48405
+ "data-codingns-notification-action": "open",
48023
48406
  onClick: () => onOpen(notice.noticeId, frame.generation, "connectionGeneration" in notice ? notice.connectionGeneration : void 0)
48024
- }, t("awb.notifications.open")), (0, react.createElement)("button", {
48407
+ }, notificationActionIcon("open")), (0, react.createElement)("button", {
48025
48408
  type: "button",
48026
- style: variant === "compact" ? compactButton : button,
48409
+ style: notificationActionButton,
48027
48410
  "aria-label": [
48028
48411
  t("awb.notifications.dismiss"),
48029
48412
  notice.hostLabel,
48030
48413
  notice.workspaceLabel,
48031
48414
  notice.sessionTitle
48032
48415
  ].join(" · "),
48416
+ title: t("awb.notifications.dismiss"),
48417
+ "data-codingns-notification-action": "dismiss",
48033
48418
  onClick: () => {
48034
48419
  clearTimeout(autoCloseTimer.current);
48035
48420
  autoCloseTimer.current = void 0;
48036
48421
  onDismiss(notice.noticeId, frame.generation, "connectionGeneration" in notice ? notice.connectionGeneration : void 0);
48037
48422
  }
48038
- }, t("awb.notifications.dismiss"))));
48423
+ }, notificationActionIcon("dismiss"))));
48424
+ const capabilityNotices = collapsed ? [] : snapshot?.capabilities?.filter((capability) => capability.reason && (!capability.completed || !capability.error || !capability.requests || !capability.resolve || !capability.navigation)).map((capability) => (0, react.createElement)("div", {
48425
+ key: capability.hostId,
48426
+ role: "status",
48427
+ style: panel
48428
+ }, capability.reason)) ?? [];
48039
48429
  return (0, react.createElement)("div", {
48040
48430
  "data-codingns-assistant-notifications": true,
48041
48431
  style: shell,
48042
48432
  onPointerDown: (event) => event.stopPropagation(),
48043
48433
  onClick: (event) => event.stopPropagation()
48044
- }, snapshot && multiple ? (0, react.createElement)("button", {
48434
+ }, (0, react.createElement)("style", null, notificationBubbleCss), tail, showTopRow ? (0, react.createElement)("div", {
48435
+ "data-codingns-notification-toolbar": true,
48436
+ style: topRow
48437
+ }, showCollapseButton || showExpandButton ? (0, react.createElement)("button", {
48045
48438
  type: "button",
48046
- style: summaryButton,
48047
- "aria-expanded": expanded,
48048
- "aria-label": [
48049
- t("awb.notifications.list"),
48050
- t("awb.notifications.unread", { count: snapshot.unreadCount }),
48051
- t("awb.notifications.pending", { count: snapshot.pendingCount })
48052
- ].join(" · "),
48439
+ style: toolbarIconButton,
48440
+ "aria-expanded": !collapsed,
48441
+ "aria-label": t(collapsed ? "awb.notifications.expand" : "awb.notifications.collapse"),
48442
+ title: t(collapsed ? "awb.notifications.expand" : "awb.notifications.collapse"),
48053
48443
  onClick: () => {
48054
- setExpanded(!expanded);
48055
- if (!expanded) {
48056
- setCursors([void 0]);
48057
- onPage?.();
48058
- }
48444
+ setExpanded(false);
48445
+ setCollapsed((value) => !value);
48446
+ }
48447
+ }, notificationToolbarIcon(collapsed ? "expand" : "collapse")) : null, !collapsed && showClearAll ? (0, react.createElement)("button", {
48448
+ type: "button",
48449
+ style: processing ? clearAllButtonBusy : clearAllButton,
48450
+ disabled: processing,
48451
+ "aria-label": t("awb.notifications.clearAllLabel"),
48452
+ title: t("awb.notifications.clearAllLabel"),
48453
+ onClick: () => {
48454
+ if (processing || snapshot === void 0 || onClearAll === void 0) return;
48455
+ setProcessing(true);
48456
+ Promise.resolve(onClearAll(snapshot.generation)).catch(() => void 0).finally(() => setProcessing(false));
48059
48457
  }
48060
- }, `${t("awb.notifications.unread", { count: snapshot.unreadCount })} · ${t("awb.notifications.pending", { count: snapshot.pendingCount })}`) : null, (!expanded || snapshot === void 0) && mainNotice !== void 0 ? (0, react.createElement)("div", {
48458
+ }, notificationToolbarIcon("clear")) : null, showFilterTags ? [snapshot.unreadCount > 0 ? (0, react.createElement)("button", {
48459
+ key: "unread-filter",
48460
+ type: "button",
48461
+ style: listFilter === "unread" ? filterButtonActive : filterButton,
48462
+ "data-codingns-notification-filter": true,
48463
+ "aria-expanded": expanded,
48464
+ "aria-pressed": listFilter === "unread",
48465
+ "aria-label": t("awb.notifications.unreadFilterLabel", { count: snapshot.unreadCount }),
48466
+ title: t("awb.notifications.unreadFilterLabel", { count: snapshot.unreadCount }),
48467
+ onClick: () => toggleFilter("unread")
48468
+ }, notificationToolbarIcon("unread"), (0, react.createElement)("span", { style: notificationCountBadge }, formatNotificationCount(snapshot.unreadCount))) : null, snapshot.pendingCount > 0 ? (0, react.createElement)("button", {
48469
+ key: "pending-filter",
48470
+ type: "button",
48471
+ style: listFilter === "pending" ? filterButtonActive : filterButton,
48472
+ "data-codingns-notification-filter": true,
48473
+ "aria-expanded": expanded,
48474
+ "aria-pressed": listFilter === "pending",
48475
+ "aria-label": t("awb.notifications.pendingFilterLabel", { count: snapshot.pendingCount }),
48476
+ title: t("awb.notifications.pendingFilterLabel", { count: snapshot.pendingCount }),
48477
+ onClick: () => toggleFilter("pending")
48478
+ }, notificationToolbarIcon("pending"), (0, react.createElement)("span", { style: notificationPendingBadge }, formatNotificationCount(snapshot.pendingCount))) : null] : null) : null, showBubble ? (0, react.createElement)("div", {
48061
48479
  ref: bubble,
48062
48480
  role: "status",
48063
48481
  "aria-live": "polite",
48064
48482
  style: bubblePanel
48065
- }, (0, react.createElement)("span", {
48066
- "aria-hidden": true,
48067
- style: bubbleTail
48068
- }, (0, react.createElement)("svg", {
48069
- width: 36,
48070
- height: 22,
48071
- viewBox: "0 0 36 22",
48072
- fill: require_theme.dshThemeColor.menuBackground,
48073
- stroke: require_theme.dshThemeColor.accent,
48074
- strokeWidth: 1.5,
48075
- strokeLinecap: "round",
48076
- strokeLinejoin: "round",
48077
- style: { display: "block" }
48078
- }, (0, react.createElement)("path", { d: "M2 1 C7 2 12 8 18 19 C19 21 21 21 22 19 C27 9 31 3 34 1" }))), (0, react.createElement)("div", { style: bubbleContent }, multiple ? attentionItems.map((notice) => row(notice, "compact")) : row(mainNotice, "primary"))) : null, expanded && snapshot ? (0, react.createElement)("div", {
48483
+ }, (0, react.createElement)("div", {
48484
+ "data-codingns-notification-scroll": true,
48485
+ style: bubbleContent
48486
+ }, multiple ? attentionItems.map((notice) => row(notice, "compact")) : row(mainNotice, "primary"))) : null, !collapsed && expanded && snapshot ? (0, react.createElement)("div", {
48487
+ ref: bubble,
48079
48488
  role: "region",
48080
48489
  "aria-label": t("awb.notifications.list"),
48081
- style: panel
48082
- }, (0, react.createElement)("button", {
48083
- type: "button",
48084
- style: button,
48085
- onClick: () => setExpanded(false)
48086
- }, t("awb.notifications.closeList")), (0, react.createElement)("div", { style: {
48087
- maxHeight: 180,
48088
- overflowY: "auto",
48089
- overscrollBehavior: "contain"
48090
- } }, ...items.map((notice) => row(notice, "list"))), items.length === 0 ? (0, react.createElement)("p", null, t("awb.notifications.empty")) : null, onPage ? (0, react.createElement)("div", { style: {
48091
- display: "flex",
48092
- gap: 6
48093
- } }, (0, react.createElement)("button", {
48094
- type: "button",
48095
- style: button,
48096
- disabled: cursors.length <= 1,
48097
- onClick: () => page(false)
48098
- }, t("awb.notifications.previous")), (0, react.createElement)("button", {
48099
- type: "button",
48100
- style: button,
48101
- disabled: !snapshot.cursor,
48102
- onClick: () => page(true)
48103
- }, t("awb.notifications.next"))) : null) : null, error ? (0, react.createElement)("div", {
48490
+ "data-codingns-notification-scroll": true,
48491
+ style: bubblePanel
48492
+ }, (0, react.createElement)("div", {
48493
+ "data-codingns-notification-scroll": true,
48494
+ style: {
48495
+ ...bubbleContent,
48496
+ maxHeight: 180
48497
+ }
48498
+ }, ...listItems.map((notice) => row(notice, "compact"))), listItems.length === 0 ? (0, react.createElement)("p", null, t("awb.notifications.empty")) : null) : null, !collapsed && error ? (0, react.createElement)("div", {
48104
48499
  role: "alert",
48105
48500
  style: panel
48106
- }, error) : null, ...snapshot?.capabilities?.filter((capability) => capability.reason && (!capability.completed || !capability.error || !capability.requests || !capability.resolve || !capability.navigation)).map((capability) => (0, react.createElement)("div", {
48107
- key: capability.hostId,
48108
- role: "status",
48109
- style: panel
48110
- }, capability.reason)) ?? []);
48501
+ }, error) : null, ...capabilityNotices);
48111
48502
  }
48112
48503
  /** 可见 DOM 与视口相交后才确认首展;后台挂载和零面积节点不消耗提醒时长。 */
48113
48504
  function assistantNotificationIsVisible(node) {
@@ -48142,53 +48533,62 @@ ${scope} [data-dockkit-strip-tabs] {
48142
48533
  /** 网页气泡作为形象的兄弟区域定位;字幕优先保留原侧,通知避让到另一侧或形象旁。 */
48143
48534
  function floatingAssistantNotificationLayout(x, y, width, height, viewportWidth, viewportHeight, captionAbove) {
48144
48535
  const bubbleWidth = Math.max(0, Math.min(320, viewportWidth - 24));
48145
- const aboveSpace = Math.max(0, y - 22), belowSpace = Math.max(0, viewportHeight - y - height - 22);
48536
+ const clearance = 30;
48537
+ const aboveSpace = Math.max(0, y - 22 - clearance), belowSpace = Math.max(0, viewportHeight - y - height - 22 - clearance);
48146
48538
  const above = captionAbove === void 0 ? aboveSpace >= belowSpace : !captionAbove;
48147
48539
  const space = above ? aboveSpace : belowSpace;
48148
48540
  const left = Math.max(12 - x, Math.min((width - bubbleWidth) / 2, viewportWidth - x - bubbleWidth - 12));
48149
48541
  if (captionAbove !== void 0 && space < 72) {
48150
48542
  const leftSpace = Math.max(0, x - 22), rightSpace = Math.max(0, viewportWidth - x - width - 22);
48151
48543
  const sideWidth = Math.min(320, Math.max(leftSpace, rightSpace));
48152
- if (sideWidth >= 150) return {
48153
- left: leftSpace >= rightSpace ? -sideWidth - 10 : width + 10,
48154
- top: 0,
48155
- width: sideWidth,
48156
- maxHeight: Math.min(276, height, Math.max(0, viewportHeight - y - 12))
48157
- };
48544
+ if (sideWidth >= 150) {
48545
+ const onLeft = leftSpace >= rightSpace;
48546
+ return {
48547
+ style: {
48548
+ left: onLeft ? -sideWidth - 10 : width + 10,
48549
+ top: 0,
48550
+ width: sideWidth,
48551
+ maxHeight: Math.min(276, height, Math.max(0, viewportHeight - y - 12))
48552
+ },
48553
+ tail: onLeft ? "right" : "left"
48554
+ };
48555
+ }
48158
48556
  const stackedAbove = captionAbove;
48159
48557
  const stackedSpace = (stackedAbove ? aboveSpace : belowSpace) - 190;
48160
48558
  if (stackedSpace >= 36) return {
48161
- left,
48162
- width: bubbleWidth,
48163
- maxHeight: Math.min(276, stackedSpace),
48164
- ...stackedAbove ? { bottom: height + 200 } : { top: height + 200 }
48559
+ style: {
48560
+ left,
48561
+ width: bubbleWidth,
48562
+ maxHeight: Math.min(276, stackedSpace),
48563
+ ...stackedAbove ? { bottom: height + 200 } : { top: height + 200 }
48564
+ },
48565
+ tail: stackedAbove ? "bottom" : "top"
48165
48566
  };
48166
48567
  }
48167
48568
  return {
48168
- left,
48169
- width: bubbleWidth,
48170
- maxHeight: Math.min(276, space),
48171
- ...above ? { bottom: height + 10 } : { top: height + 10 }
48569
+ style: {
48570
+ left,
48571
+ width: bubbleWidth,
48572
+ maxHeight: Math.min(276, space),
48573
+ ...above ? { bottom: height + clearance } : { top: height + clearance }
48574
+ },
48575
+ tail: above ? "bottom" : "top"
48172
48576
  };
48173
48577
  }
48174
- /** 将气泡尾巴指向头像中心;侧置气泡也不能固定在自己的左边角。 */
48175
- function assistantNotificationTailStyle(avatarCenter, regionLeft, regionWidth) {
48176
- const min = 20, max = Math.max(min, regionWidth - 20);
48177
- const center = Math.max(min, Math.min(max, avatarCenter - regionLeft));
48178
- return { "--codingns-assistant-tail-left": `${Math.round(center)}px` };
48179
- }
48180
48578
  const icons = {
48181
48579
  completed: "✓",
48182
48580
  error: "!",
48183
48581
  question: "?",
48184
- approval: "◇"
48582
+ approval: "!"
48185
48583
  };
48186
48584
  const noticeKindColor = {
48187
48585
  completed: require_theme.dshThemeColor.success,
48188
48586
  error: require_theme.dshThemeColor.error,
48189
48587
  question: require_theme.dshThemeColor.accent,
48190
- approval: require_theme.dshThemeColor.accent
48588
+ approval: require_theme.dshThemeColor.warning
48191
48589
  };
48590
+ /** 黄色填充上的图标与标签改用深色前景,避免白字对比度不足。 */
48591
+ const noticeKindForeground = { approval: require_theme.dshThemeColor.warningForeground };
48192
48592
  function notificationStatus(notice, t) {
48193
48593
  if (notice.kind === "completed") return t("awb.notifications.completed");
48194
48594
  if (notice.kind === "error") return t("awb.notifications.error");
@@ -48204,8 +48604,13 @@ ${scope} [data-dockkit-strip-tabs] {
48204
48604
  fontWeight: 650
48205
48605
  };
48206
48606
  const shell = {
48207
- width: "min(320px, calc(100vw - 24px))",
48208
- maxWidth: "100%",
48607
+ position: "relative",
48608
+ isolation: "isolate",
48609
+ width: "100%",
48610
+ maxWidth: 320,
48611
+ height: "100%",
48612
+ maxHeight: "var(--codingns-notification-max-height, min(276px, calc(100vh - 24px)))",
48613
+ minHeight: 0,
48209
48614
  display: "flex",
48210
48615
  flexDirection: "column",
48211
48616
  gap: 6,
@@ -48214,7 +48619,9 @@ ${scope} [data-dockkit-strip-tabs] {
48214
48619
  fontSize: require_theme.uiFontSize(13)
48215
48620
  };
48216
48621
  const panel = {
48217
- padding: 12,
48622
+ position: "relative",
48623
+ zIndex: 1,
48624
+ padding: 10,
48218
48625
  background: require_theme.dshThemeColor.menuBackground,
48219
48626
  border: `1px solid ${require_theme.dshThemeColor.border}`,
48220
48627
  borderRadius: 18,
@@ -48227,41 +48634,107 @@ ${scope} [data-dockkit-strip-tabs] {
48227
48634
  const bubblePanel = {
48228
48635
  ...panel,
48229
48636
  position: "relative",
48637
+ display: "flex",
48638
+ flexDirection: "column",
48639
+ flex: "1 1 auto",
48640
+ minWidth: 0,
48641
+ minHeight: 0,
48230
48642
  padding: 10,
48231
48643
  overflow: "visible",
48644
+ border: "none",
48232
48645
  borderRadius: "24px 24px 24px 8px",
48233
- borderColor: require_theme.dshThemeColor.accent,
48646
+ maxHeight: "100%",
48234
48647
  background: require_theme.dshThemeColor.menuBackground,
48235
- boxShadow: require_theme.dshThemeColor.prominentShadow
48648
+ borderColor: "transparent",
48649
+ boxShadow: "none",
48650
+ outline: "none"
48236
48651
  };
48237
48652
  const bubbleContent = {
48238
48653
  position: "relative",
48239
48654
  zIndex: 1,
48240
48655
  display: "grid",
48241
48656
  gap: 8,
48242
- maxHeight: "min(252px, calc(100vh - 48px))",
48657
+ minHeight: 0,
48658
+ flex: "1 1 auto",
48243
48659
  overflowY: "auto",
48244
48660
  overscrollBehavior: "contain",
48245
- padding: "2px 2px 4px"
48246
- };
48247
- const bubbleTail = {
48248
- position: "absolute",
48249
- left: "var(--codingns-assistant-tail-left, 50%)",
48250
- bottom: -21,
48251
- width: 36,
48252
- height: 22,
48253
- marginLeft: -18,
48254
- zIndex: 0,
48255
- pointerEvents: "none"
48661
+ boxSizing: "border-box",
48662
+ padding: 0
48256
48663
  };
48664
+ const notificationTailCurve = "M1 0 C12 0 20 8 23 18 C24 24 25 30 28 36 C31 30 32 24 33 18 C36 8 44 0 55 0";
48665
+ function tailBox(side) {
48666
+ const base = {
48667
+ position: "absolute",
48668
+ zIndex: 0,
48669
+ pointerEvents: "none"
48670
+ };
48671
+ const renderHeight = 36;
48672
+ if (side === "top") return {
48673
+ ...base,
48674
+ top: -24,
48675
+ left: "var(--codingns-assistant-tail-offset, 50%)",
48676
+ width: 56,
48677
+ height: renderHeight,
48678
+ marginLeft: -28
48679
+ };
48680
+ if (side === "left") return {
48681
+ ...base,
48682
+ left: -24,
48683
+ top: "var(--codingns-assistant-tail-offset, 50%)",
48684
+ width: renderHeight,
48685
+ height: 56,
48686
+ marginTop: -28
48687
+ };
48688
+ if (side === "right") return {
48689
+ ...base,
48690
+ right: -24,
48691
+ top: "var(--codingns-assistant-tail-offset, 50%)",
48692
+ width: renderHeight,
48693
+ height: 56,
48694
+ marginTop: -28
48695
+ };
48696
+ return {
48697
+ ...base,
48698
+ bottom: -24,
48699
+ left: "var(--codingns-assistant-tail-offset, 50%)",
48700
+ width: 56,
48701
+ height: renderHeight,
48702
+ marginLeft: -28
48703
+ };
48704
+ }
48705
+ function tailSvg(side) {
48706
+ const angle = "var(--codingns-assistant-tail-angle, 0deg)";
48707
+ if (side === "bottom") return {
48708
+ display: "block",
48709
+ transformOrigin: "50% 0%",
48710
+ transform: `rotate(${angle})`
48711
+ };
48712
+ if (side === "top") return {
48713
+ display: "block",
48714
+ transformOrigin: "50% 50%",
48715
+ transform: `rotate(180deg) rotate(${angle})`
48716
+ };
48717
+ return {
48718
+ display: "block",
48719
+ position: "absolute",
48720
+ left: "50%",
48721
+ top: "50%",
48722
+ transform: `translate(-50%, -50%) rotate(${side === "left" ? 90 : -90}deg)`
48723
+ };
48724
+ }
48725
+ const notificationBubbleCss = "[data-codingns-notification-scroll]{scrollbar-width:none;-ms-overflow-style:none}[data-codingns-notification-scroll]::-webkit-scrollbar{display:none;width:0;height:0}[data-codingns-notification-filter], [data-codingns-notification-filter]:focus, [data-codingns-notification-filter]:focus-visible{border:1px solid var(--dsw-alias-border-l2,#d9d9d9)!important;outline:none!important;box-shadow:none!important}";
48257
48726
  const primaryCard = {
48258
48727
  display: "grid",
48728
+ gridTemplateColumns: "minmax(0, 1fr) auto",
48729
+ alignItems: "center",
48259
48730
  gap: 9,
48260
48731
  padding: 5,
48261
48732
  minWidth: 0
48262
48733
  };
48263
48734
  const compactCard = {
48264
48735
  display: "grid",
48736
+ gridTemplateColumns: "minmax(0, 1fr) auto",
48737
+ alignItems: "center",
48265
48738
  gap: 7,
48266
48739
  padding: "10px 11px",
48267
48740
  minWidth: 0,
@@ -48270,12 +48743,11 @@ ${scope} [data-dockkit-strip-tabs] {
48270
48743
  borderRadius: 15,
48271
48744
  boxShadow: require_theme.dshThemeColor.subtleShadow
48272
48745
  };
48273
- const listRow = {
48746
+ const cardBody = {
48274
48747
  display: "grid",
48275
- gap: 7,
48276
- padding: "10px 0",
48748
+ gap: 8,
48277
48749
  minWidth: 0,
48278
- borderBottom: `1px solid ${require_theme.dshThemeColor.border}`
48750
+ minInlineSize: 0
48279
48751
  };
48280
48752
  const cardHeading = {
48281
48753
  display: "flex",
@@ -48315,30 +48787,90 @@ ${scope} [data-dockkit-strip-tabs] {
48315
48787
  maxHeight: 120,
48316
48788
  overflowY: "auto"
48317
48789
  };
48318
- const summaryButton = {
48790
+ const topRowButton = {
48319
48791
  ...button,
48792
+ height: 28,
48793
+ minHeight: 28,
48794
+ padding: "2px 10px",
48795
+ fontSize: require_theme.uiFontSize(12)
48796
+ };
48797
+ const toolbarIconButton = {
48798
+ ...topRowButton,
48799
+ width: 28,
48800
+ minWidth: 28,
48801
+ padding: 4,
48802
+ display: "inline-grid",
48803
+ placeItems: "center"
48804
+ };
48805
+ const filterButton = {
48806
+ ...topRowButton,
48320
48807
  alignSelf: "end",
48321
- padding: "8px 14px",
48808
+ display: "inline-flex",
48809
+ alignItems: "center",
48810
+ justifyContent: "center",
48811
+ gap: 4,
48812
+ minWidth: 46,
48813
+ padding: "2px 7px",
48322
48814
  background: require_theme.dshThemeColor.menuBackground,
48323
48815
  boxShadow: require_theme.dshThemeColor.subtleShadow
48324
48816
  };
48325
- const requestTag = {
48326
- justifySelf: "start",
48327
- padding: "4px 9px",
48328
- borderRadius: 999,
48329
- color: require_theme.dshThemeColor.primaryForeground,
48817
+ const filterButtonActive = {
48818
+ ...filterButton,
48330
48819
  background: require_theme.dshThemeColor.accent,
48331
- fontSize: require_theme.uiFontSize(11),
48332
- lineHeight: 1.2,
48333
- fontWeight: 750,
48334
- letterSpacing: "0.02em",
48335
- boxShadow: require_theme.dshThemeColor.subtleShadow
48820
+ borderColor: require_theme.dshThemeColor.accent,
48821
+ color: require_theme.dshThemeColor.primaryForeground
48822
+ };
48823
+ const notificationCountBadge = {
48824
+ display: "inline-grid",
48825
+ placeItems: "center",
48826
+ minWidth: 16,
48827
+ height: 16,
48828
+ padding: "0 4px",
48829
+ boxSizing: "border-box",
48830
+ borderRadius: 8,
48831
+ color: require_theme.dshThemeColor.labelPrimary,
48832
+ background: require_theme.dshThemeColor.cardBackground,
48833
+ fontSize: require_theme.uiFontSize(10),
48834
+ lineHeight: 1,
48835
+ fontWeight: 750
48836
+ };
48837
+ const notificationPendingBadge = {
48838
+ ...notificationCountBadge,
48839
+ color: require_theme.dshThemeColor.warningForeground,
48840
+ background: require_theme.dshThemeColor.warning
48841
+ };
48842
+ const topRow = {
48843
+ display: "flex",
48844
+ flexShrink: 0,
48845
+ alignItems: "center",
48846
+ justifyContent: "center",
48847
+ flexWrap: "wrap",
48848
+ gap: 6
48849
+ };
48850
+ const clearAllButton = {
48851
+ ...toolbarIconButton,
48852
+ alignSelf: "end",
48853
+ background: require_theme.dshThemeColor.buttonBackground,
48854
+ borderColor: require_theme.dshThemeColor.border,
48855
+ color: require_theme.dshThemeColor.labelPrimary,
48856
+ borderRadius: 10,
48857
+ boxShadow: "none"
48858
+ };
48859
+ const clearAllButtonBusy = {
48860
+ ...clearAllButton,
48861
+ opacity: .6,
48862
+ cursor: "default"
48863
+ };
48864
+ const requestPrompt = {
48865
+ display: "inline-flex",
48866
+ alignItems: "center",
48867
+ flexWrap: "wrap",
48868
+ gap: 6,
48869
+ lineHeight: 1.5
48336
48870
  };
48337
48871
  const requestInlineTag = {
48338
48872
  display: "inline-flex",
48339
48873
  alignItems: "center",
48340
- verticalAlign: "middle",
48341
- margin: "0 6px 2px 2px",
48342
48874
  padding: "3px 8px",
48343
48875
  borderRadius: 999,
48344
48876
  color: require_theme.dshThemeColor.primaryForeground,
@@ -48349,6 +48881,26 @@ ${scope} [data-dockkit-strip-tabs] {
48349
48881
  letterSpacing: "0.02em",
48350
48882
  boxShadow: require_theme.dshThemeColor.subtleShadow
48351
48883
  };
48884
+ const compactPrompt = {
48885
+ fontSize: require_theme.uiFontSize(12),
48886
+ lineHeight: 1.4,
48887
+ color: require_theme.dshThemeColor.labelPrimary
48888
+ };
48889
+ const compactRequestTag = {
48890
+ ...requestInlineTag,
48891
+ padding: "2px 7px",
48892
+ fontSize: require_theme.uiFontSize(10)
48893
+ };
48894
+ const approvalInlineTag = {
48895
+ ...requestInlineTag,
48896
+ background: require_theme.dshThemeColor.warning,
48897
+ color: require_theme.dshThemeColor.warningForeground
48898
+ };
48899
+ const compactApprovalTag = {
48900
+ ...compactRequestTag,
48901
+ background: require_theme.dshThemeColor.warning,
48902
+ color: require_theme.dshThemeColor.warningForeground
48903
+ };
48352
48904
  const compactStatus = {
48353
48905
  color: require_theme.dshThemeColor.labelSecondary,
48354
48906
  fontSize: require_theme.uiFontSize(11),
@@ -48357,15 +48909,86 @@ ${scope} [data-dockkit-strip-tabs] {
48357
48909
  };
48358
48910
  const actionRow = {
48359
48911
  display: "flex",
48360
- flexWrap: "wrap",
48361
- gap: 7
48912
+ flexDirection: "column",
48913
+ alignItems: "stretch",
48914
+ justifyContent: "center",
48915
+ gap: 6,
48916
+ flex: "0 0 auto"
48362
48917
  };
48363
- const compactButton = {
48918
+ const notificationActionButton = {
48364
48919
  ...button,
48365
- minHeight: 30,
48366
- padding: "6px 10px",
48920
+ width: 28,
48921
+ height: 28,
48922
+ minHeight: 28,
48923
+ padding: 0,
48924
+ display: "inline-grid",
48925
+ placeItems: "center",
48926
+ borderRadius: 10,
48367
48927
  fontSize: require_theme.uiFontSize(12)
48368
48928
  };
48929
+ /** 操作按钮只保留图标,文字语义通过 aria-label 和 title 传达,避免气泡底部堆叠长文案。 */
48930
+ function notificationActionIcon(action) {
48931
+ if (action === "dismiss") return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, { size: 16 });
48932
+ return (0, react.createElement)("svg", {
48933
+ width: 16,
48934
+ height: 16,
48935
+ viewBox: "0 0 24 24",
48936
+ fill: "none",
48937
+ stroke: "currentColor",
48938
+ strokeWidth: 2,
48939
+ strokeLinecap: "round",
48940
+ strokeLinejoin: "round",
48941
+ "aria-hidden": true,
48942
+ focusable: false
48943
+ }, (0, react.createElement)("path", { d: "M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z" }), (0, react.createElement)("circle", {
48944
+ cx: 12,
48945
+ cy: 12,
48946
+ r: 2.5
48947
+ }));
48948
+ }
48949
+ function notificationToolbarIcon(icon) {
48950
+ if (icon === "clear") return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, { size: 16 });
48951
+ if (icon === "pending") return (0, react.createElement)("svg", {
48952
+ width: 16,
48953
+ height: 16,
48954
+ viewBox: "0 0 24 24",
48955
+ fill: "none",
48956
+ stroke: "currentColor",
48957
+ strokeWidth: 1.8,
48958
+ strokeLinecap: "round",
48959
+ strokeLinejoin: "round",
48960
+ "aria-hidden": true,
48961
+ focusable: false
48962
+ }, [
48963
+ (0, react.createElement)("path", {
48964
+ key: "hand",
48965
+ d: "M9 14V6.5a1.5 1.5 0 0 1 3 0v4a1.5 1.5 0 0 1 3 0v1a1.5 1.5 0 0 1 3 0v1a1.5 1.5 0 0 1 3 0v4c0 4-2.5 6-6.5 6h-1c-2.2 0-3.6-.8-5.1-2.3L4.2 15a1.7 1.7 0 0 1 2.4-2.4L9 15Z"
48966
+ }),
48967
+ (0, react.createElement)("path", {
48968
+ key: "fingers",
48969
+ d: "M12 10.5v3M15 11.5v3M18 12.5V15"
48970
+ }),
48971
+ (0, react.createElement)("path", {
48972
+ key: "tap",
48973
+ d: "M6.7 8.9a4.5 4.5 0 1 1 8.2-1.6"
48974
+ })
48975
+ ]);
48976
+ return (0, react.createElement)("svg", {
48977
+ width: 16,
48978
+ height: 16,
48979
+ viewBox: "0 0 24 24",
48980
+ fill: "none",
48981
+ stroke: "currentColor",
48982
+ strokeWidth: 1.8,
48983
+ strokeLinecap: "round",
48984
+ strokeLinejoin: "round",
48985
+ "aria-hidden": true,
48986
+ focusable: false
48987
+ }, (0, react.createElement)("path", { d: icon === "collapse" ? "M6 9l6 6 6-6" : icon === "expand" ? "M6 15l6-6 6 6" : icon === "unread" ? "M6 10a6 6 0 0 1 12 0c0 5 2 5 2 7H4c0-2 2-2 2-7Zm3 10h6" : "" }));
48988
+ }
48989
+ function formatNotificationCount(count) {
48990
+ return count > 99 ? "99+" : String(count);
48991
+ }
48369
48992
  //#endregion
48370
48993
  //#region src/client/avatar/floating.ts
48371
48994
  const POSITION_KEY = "codingns-assistant-avatar-position";
@@ -48482,11 +49105,15 @@ ${scope} [data-dockkit-strip-tabs] {
48482
49105
  };
48483
49106
  const captionLayout = floatingCallCaptionLayout(position.x, position.y, size, height, viewport.width, viewport.height);
48484
49107
  const notificationLayout = notification === void 0 ? void 0 : floatingAssistantNotificationLayout(position.x, position.y, size, height, viewport.width, viewport.height, call ? captionLayout.above : void 0);
49108
+ const notificationTailStyle = notificationLayout === void 0 ? {} : assistantNotificationTailStyle(size / 2, Number(notificationLayout.style.left ?? 0), Number(notificationLayout.style.width ?? size), notificationLayout.tail);
48485
49109
  const notificationStyle = notificationLayout === void 0 ? void 0 : {
48486
49110
  position: "absolute",
48487
- ...notificationLayout,
48488
- ...assistantNotificationTailStyle(size / 2, Number(notificationLayout.left ?? 0), Number(notificationLayout.width ?? size))
49111
+ ...notificationLayout.style,
49112
+ maxHeight: void 0,
49113
+ "--codingns-notification-max-height": `${Number(notificationLayout.style.maxHeight ?? 276)}px`,
49114
+ ...notificationTailStyle
48489
49115
  };
49116
+ const notificationNode = typeof notification === "function" ? notification(notificationLayout?.tail ?? "bottom", notificationLayout === void 0 ? void 0 : notificationLayout.tail === "left" || notificationLayout.tail === "right" ? assistantNotificationTailTarget(height / 2, Number(notificationLayout.style.top ?? 0)) : assistantNotificationTailTarget(size / 2, Number(notificationLayout.style.left ?? 0)), notificationTailStyle) : notification;
48490
49117
  return (0, react.createElement)("div", {
48491
49118
  ...kind === "avatar" ? { "data-codingns-floating-avatar": true } : { "data-codingns-floating-call": true },
48492
49119
  style: {
@@ -48544,7 +49171,7 @@ ${scope} [data-dockkit-strip-tabs] {
48544
49171
  t,
48545
49172
  ...captionLayout,
48546
49173
  onOpen
48547
- }) : null, notification && notificationStyle ? (0, react.createElement)("div", {
49174
+ }) : null, notificationNode && notificationStyle ? (0, react.createElement)("div", {
48548
49175
  "data-codingns-floating-notification-region": true,
48549
49176
  style: {
48550
49177
  ...notificationStyle,
@@ -48554,7 +49181,7 @@ ${scope} [data-dockkit-strip-tabs] {
48554
49181
  touchAction: "pan-y",
48555
49182
  userSelect: "text"
48556
49183
  }
48557
- }, notification) : null);
49184
+ }, notificationNode) : null);
48558
49185
  }
48559
49186
  function readPosition(width, height, positionKey) {
48560
49187
  if (typeof window === "undefined") return {
@@ -48757,7 +49384,7 @@ ${scope} [data-dockkit-strip-tabs] {
48757
49384
  for (const event of status.noticeEvents) {
48758
49385
  if (disposed) return;
48759
49386
  if (event.ownerId !== ownerId || event.generation !== status.generation || !Number.isSafeInteger(event.sequence) || event.sequence <= (noticeAck?.sequence ?? 0) || typeof event.noticeId !== "string" || !Number.isSafeInteger(event.noticeGeneration)) continue;
48760
- const handler = event.type === "notice-presented" ? hooks.onNoticePresented : event.type === "notice-action" && (event.action === "open" || event.action === "dismiss") ? hooks.onNoticeAction : void 0;
49387
+ const handler = event.type === "notice-presented" ? hooks.onNoticePresented : event.type === "notice-action" && (event.action === "open" || event.action === "dismiss" || event.action === "dismiss-all") ? hooks.onNoticeAction : void 0;
48761
49388
  if (!handler) break;
48762
49389
  try {
48763
49390
  await handler(event);
@@ -48911,6 +49538,8 @@ ${scope} [data-dockkit-strip-tabs] {
48911
49538
  presented = /* @__PURE__ */ new Set();
48912
49539
  opens = /* @__PURE__ */ new Map();
48913
49540
  knownNotices = /* @__PURE__ */ new Map();
49541
+ /** 最近一次前台选择;串行队列执行前再次校验,避免旧选择晚到时误读新会话。 */
49542
+ sessionSelectionKey;
48914
49543
  constructor(rpc, navigate, intervalMs = 750, now = Date.now) {
48915
49544
  this.rpc = rpc;
48916
49545
  this.navigate = navigate;
@@ -48944,6 +49573,7 @@ ${scope} [data-dockkit-strip-tabs] {
48944
49573
  this.presented.clear();
48945
49574
  this.opens.clear();
48946
49575
  this.knownNotices.clear();
49576
+ this.sessionSelectionKey = void 0;
48947
49577
  this.publish({ loading: enabled });
48948
49578
  if (enabled) {
48949
49579
  if (typeof this.rpc.open === "function") {
@@ -49104,6 +49734,52 @@ ${scope} [data-dockkit-strip-tabs] {
49104
49734
  });
49105
49735
  await this.refresh(true);
49106
49736
  }
49737
+ /** 一键清理只清空当前代次的气泡展示;DSH 侧未读、待处理与请求身份都由 Host 原样保留。 */
49738
+ async clearAll(generation) {
49739
+ const epoch = this.epoch;
49740
+ this.requireFrame(generation);
49741
+ await this.enqueue(async (signal) => {
49742
+ await this.call("clear-all", { generation }, signal);
49743
+ this.assertCurrent(epoch, signal);
49744
+ }, epoch).catch((error) => {
49745
+ if (epoch === this.epoch && this.enabled && !this.disposed) this.publish({
49746
+ ...this.snapshot,
49747
+ error: message(error),
49748
+ errorNoticeId: void 0,
49749
+ errorGeneration: void 0
49750
+ });
49751
+ throw error;
49752
+ });
49753
+ await this.refresh(true);
49754
+ }
49755
+ /** 当前会话一旦被 DSH 选中即提交会话级已读;空选择只取消尚未发出的旧选择。 */
49756
+ markSessionRead(target) {
49757
+ const key = target === void 0 ? void 0 : JSON.stringify([
49758
+ target.hostId,
49759
+ target.workspaceId,
49760
+ target.sessionId
49761
+ ]);
49762
+ this.sessionSelectionKey = key;
49763
+ if (target === void 0 || !this.enabled || this.disposed) return Promise.resolve();
49764
+ if (this.snapshot.frame === void 0) return this.refresh(true).then(() => this.sessionSelectionKey === key ? this.markSessionRead(target) : void 0);
49765
+ const epoch = this.epoch;
49766
+ return this.enqueue(async (signal) => {
49767
+ if (this.sessionSelectionKey !== key) return;
49768
+ const frame = this.snapshot.frame;
49769
+ if (frame === void 0) return;
49770
+ await this.call("read-session", {
49771
+ generation: frame.generation,
49772
+ ...target
49773
+ }, signal);
49774
+ this.assertCurrent(epoch, signal);
49775
+ }, epoch).then(() => this.refresh(true)).catch((error) => {
49776
+ if (epoch === this.epoch && this.enabled && !this.disposed) this.publish({
49777
+ ...this.snapshot,
49778
+ error: message(error)
49779
+ });
49780
+ throw error;
49781
+ });
49782
+ }
49107
49783
  /** 查看由 Host 返回可信目标,公开导航成功后才标记已读。 */
49108
49784
  open(noticeId, generation, expectedConnectionGeneration) {
49109
49785
  try {
@@ -49169,6 +49845,7 @@ ${scope} [data-dockkit-strip-tabs] {
49169
49845
  this.presented.clear();
49170
49846
  this.opens.clear();
49171
49847
  this.knownNotices.clear();
49848
+ this.sessionSelectionKey = void 0;
49172
49849
  this.listeners.clear();
49173
49850
  this.snapshot = { loading: false };
49174
49851
  }
@@ -49320,6 +49997,36 @@ ${scope} [data-dockkit-strip-tabs] {
49320
49997
  }
49321
49998
  //#endregion
49322
49999
  //#region src/dsh-capabilities/client/assistant-session-navigation-adapter.ts
50000
+ /** 读取 DSH 的唯一前台会话选择源;没有该能力的旧宿主不猜测当前会话。 */
50001
+ function readAssistantSessionSelectionStore(context) {
50002
+ try {
50003
+ const selection = (context?.get?.("uiWorkspace"))?.selection;
50004
+ if (typeof selection !== "object" || selection === null) return void 0;
50005
+ const store = selection;
50006
+ return typeof store.getSnapshot === "function" && typeof store.subscribe === "function" ? store : void 0;
50007
+ } catch {
50008
+ return;
50009
+ }
50010
+ }
50011
+ /** 将本地/远端虚拟选择归一化为 Host 可匹配的会话三元组。 */
50012
+ function normalizeAssistantSessionSelection(value) {
50013
+ const record = asRecord(value);
50014
+ if (record === void 0) return void 0;
50015
+ const rawSessionId = text$1(record.sessionId) ?? text$1(asRecord(record.subagentAddress)?.parentSessionId);
50016
+ const rawWorkspaceId = text$1(record.workspaceId);
50017
+ if (rawSessionId === void 0 || rawWorkspaceId === void 0) return void 0;
50018
+ const session = require_primitives_adapter.parseVirtualSessionId(rawSessionId);
50019
+ const workspace = require_primitives_adapter.parseVirtualWorkspaceId(rawWorkspaceId);
50020
+ if (session !== null && workspace !== null && session.hostId !== workspace.hostId) return void 0;
50021
+ const hostId = session?.hostId ?? workspace?.targetHostId ?? "local";
50022
+ const workspaceId = workspace?.workspaceId ?? (hostId !== "local" && rawWorkspaceId.startsWith(`${hostId}:`) ? rawWorkspaceId.slice(hostId.length + 1) : rawWorkspaceId);
50023
+ const sessionId = session?.sessionId ?? rawSessionId;
50024
+ return {
50025
+ hostId: hostId === "local" ? "local" : hostId,
50026
+ workspaceId,
50027
+ sessionId
50028
+ };
50029
+ }
49323
50030
  /** Host 负责目标与连接代次校验,本适配器只把可信目标交给原生导航。 */
49324
50031
  async function openAssistantNotificationSession(services, target, signal) {
49325
50032
  signal?.throwIfAborted();
@@ -49356,6 +50063,12 @@ ${scope} [data-dockkit-strip-tabs] {
49356
50063
  return;
49357
50064
  }
49358
50065
  }
50066
+ function asRecord(value) {
50067
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
50068
+ }
50069
+ function text$1(value) {
50070
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
50071
+ }
49359
50072
  //#endregion
49360
50073
  //#region src/client/features/global-voice-assistant.ts
49361
50074
  const GLOBAL_ASSISTANT_BUTTON_SIZE = 38;
@@ -49483,6 +50196,30 @@ ${scope} [data-dockkit-strip-tabs] {
49483
50196
  notificationsEnabled,
49484
50197
  notificationKey
49485
50198
  ]);
50199
+ (0, react.useEffect)(() => {
50200
+ const context = services.uiContext;
50201
+ if (context === void 0) return void 0;
50202
+ const attach = (scope) => {
50203
+ const selection = readAssistantSessionSelectionStore(scope);
50204
+ if (selection === void 0) return void 0;
50205
+ const sync = () => {
50206
+ notifications.markSessionRead(normalizeAssistantSessionSelection(selection.getSnapshot())).catch(() => void 0);
50207
+ };
50208
+ sync();
50209
+ return selection.subscribe(sync);
50210
+ };
50211
+ if (typeof context.inject === "function") {
50212
+ const fiber = context.inject(["uiWorkspace"], (scope) => {
50213
+ const unsubscribe = attach(scope);
50214
+ if (unsubscribe === void 0) return;
50215
+ scope.effect(() => unsubscribe, "codingns4dsh: assistant notification session read");
50216
+ });
50217
+ return () => {
50218
+ fiber.dispose();
50219
+ };
50220
+ }
50221
+ return attach(context);
50222
+ }, [notifications, services.uiContext]);
49486
50223
  const presentNotice = (0, react.useCallback)((noticeId, generation, kind) => {
49487
50224
  notifications.acknowledge(noticeId, generation, "presented", kind).catch(() => void 0);
49488
50225
  }, [notifications]);
@@ -49492,9 +50229,7 @@ ${scope} [data-dockkit-strip-tabs] {
49492
50229
  const openNotice = (0, react.useCallback)((noticeId, generation, connectionGeneration) => {
49493
50230
  notifications.open(noticeId, generation, connectionGeneration).catch(() => void 0);
49494
50231
  }, [notifications]);
49495
- const pageNotices = (0, react.useCallback)((cursor) => {
49496
- notifications.page(cursor);
49497
- }, [notifications]);
50232
+ const clearAllNotices = (0, react.useCallback)((generation) => notifications.clearAll(generation), [notifications]);
49498
50233
  (0, react.useEffect)(() => {
49499
50234
  if (adapter !== void 0) {
49500
50235
  setSnapshot({
@@ -49781,6 +50516,7 @@ ${scope} [data-dockkit-strip-tabs] {
49781
50516
  onNoticePresented: (event) => notifications.acknowledge(event.noticeId, event.noticeGeneration, "presented", event.noticeKind, event.connectionGeneration),
49782
50517
  onNoticeAction: async (event) => {
49783
50518
  await notifications.refresh(true);
50519
+ if (event.action === "dismiss-all") return notifications.clearAll(event.noticeGeneration);
49784
50520
  return event.action === "open" ? notifications.open(event.noticeId, event.noticeGeneration, event.connectionGeneration) : notifications.acknowledge(event.noticeId, event.noticeGeneration, "dismiss", void 0, event.connectionGeneration);
49785
50521
  }
49786
50522
  });
@@ -49793,7 +50529,7 @@ ${scope} [data-dockkit-strip-tabs] {
49793
50529
  borderRadius: 12,
49794
50530
  overflowWrap: "anywhere"
49795
50531
  }
49796
- }, notificationSnapshot.error) : void 0 : (0, react.createElement)(AssistantNotificationBubble, {
50532
+ }, notificationSnapshot.error) : void 0 : (tail, tailTarget, tailStyle) => (0, react.createElement)(AssistantNotificationBubble, {
49797
50533
  frame: noticeFrame,
49798
50534
  t,
49799
50535
  error: notificationSnapshot.error,
@@ -49802,7 +50538,10 @@ ${scope} [data-dockkit-strip-tabs] {
49802
50538
  onPresented: presentNotice,
49803
50539
  onDismiss: dismissNotice,
49804
50540
  onOpen: openNotice,
49805
- onPage: pageNotices
50541
+ onClearAll: clearAllNotices,
50542
+ tailSide: tail,
50543
+ tailTarget,
50544
+ tailStyle
49806
50545
  });
49807
50546
  return (0, react.createElement)("div", {
49808
50547
  "data-codingns-global-voice": "true",
@@ -64194,5 +64933,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
64194
64933
  });
64195
64934
 
64196
64935
  })();
64197
- // codingns-client-revision: 4d7925ece707008d1f018624dd2c7c8bef7c24acabe9f9379b923e4f10e1fd26
64936
+ // codingns-client-revision: 57b5a1913b81a5622939394cfb36c6a9b62c943b5dabb6f7b8e5b15dfaddb3da
64198
64937
  //# sourceMappingURL=bundle.js.map