@blade-hq/agent-react 2612.0.0-beta.7 → 2612.0.0-beta.71

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 (164) hide show
  1. package/README.md +33 -0
  2. package/dist/chat/AgentLoopBlock.d.ts +0 -2
  3. package/dist/chat/AskUserQuestionBlock.d.ts +3 -20
  4. package/dist/chat/AssistantTurnBlock.d.ts +1 -9
  5. package/dist/chat/AttachmentPreviewDialog.d.ts +0 -1
  6. package/dist/chat/ChatLoadingIndicator.d.ts +7 -0
  7. package/dist/chat/ContextAttachmentPills.d.ts +4 -0
  8. package/dist/chat/CurrentPlanPanel.d.ts +0 -3
  9. package/dist/chat/FileDeliveryCards.d.ts +0 -4
  10. package/dist/chat/FinalArtifactCards.d.ts +0 -1
  11. package/dist/chat/ImageLightbox.d.ts +1 -1
  12. package/dist/chat/LiteMessageList.d.ts +1 -3
  13. package/dist/chat/MessageFileAttachmentList.d.ts +0 -5
  14. package/dist/chat/QuestionnaireQuestionBlock.d.ts +11 -0
  15. package/dist/chat/SessionReplayBar.d.ts +0 -1
  16. package/dist/chat/TextAttachmentPills.d.ts +0 -3
  17. package/dist/chat/TurnNavRail.d.ts +0 -3
  18. package/dist/chat/WorkflowRunBlock.d.ts +21 -4
  19. package/dist/chat/ai-elements/shimmer.d.ts +0 -4
  20. package/dist/chat/customization.d.ts +1 -1
  21. package/dist/chat/index.d.ts +1 -1
  22. package/dist/chat/markdown/ExternalAnchor.d.ts +2 -2
  23. package/dist/chat/markdown/MarkdownContent.d.ts +3 -0
  24. package/dist/chat/message-list-blocks.d.ts +0 -1
  25. package/dist/chat/runtime/actions.d.ts +2 -2
  26. package/dist/chat/runtime/background-task-dismissals.d.ts +0 -1
  27. package/dist/chat/runtime/composer-channels.d.ts +0 -3
  28. package/dist/chat/runtime/input-cache-reset.d.ts +0 -5
  29. package/dist/chat/runtime/input-services.d.ts +10 -0
  30. package/dist/chat/runtime/session-source.d.ts +0 -5
  31. package/dist/chat/runtime/use-chat-actions.d.ts +0 -4
  32. package/dist/{chat-OCLOVB3H.css → chat-IHPRU35X.css} +5 -18
  33. package/dist/chat.css +5 -18
  34. package/dist/{chunk-MERN5XEM.js → chunk-2DPLLZOU.js} +2162 -13284
  35. package/dist/chunk-2DPLLZOU.js.map +1 -0
  36. package/dist/chunk-7MCGQH34.js +605 -0
  37. package/dist/chunk-7MCGQH34.js.map +1 -0
  38. package/dist/{chunk-67GHJQK5.js → chunk-HCW7SI5Q.js} +3897 -26116
  39. package/dist/chunk-HCW7SI5Q.js.map +1 -0
  40. package/dist/chunk-J72ZLILV.js +2317 -0
  41. package/dist/chunk-J72ZLILV.js.map +1 -0
  42. package/dist/chunk-QIR73CES.js +7917 -0
  43. package/dist/chunk-QIR73CES.js.map +1 -0
  44. package/dist/chunk-WRIMPZPN.js +4031 -0
  45. package/dist/chunk-WRIMPZPN.js.map +1 -0
  46. package/dist/chunk-XJ6ZA6LN.js +9480 -0
  47. package/dist/chunk-XJ6ZA6LN.js.map +1 -0
  48. package/dist/chunk-XP6T6SHZ.js +13622 -0
  49. package/dist/chunk-XP6T6SHZ.js.map +1 -0
  50. package/dist/components/AccountConnectors.d.ts +13 -0
  51. package/dist/components/BrowserConnectionDialog.d.ts +7 -0
  52. package/dist/components/ChatInput.d.ts +1 -15
  53. package/dist/components/ConnectorAuthorizationProgress.d.ts +6 -0
  54. package/dist/components/ConnectorConnection.d.ts +4 -0
  55. package/dist/components/ConnectorPanel.d.ts +3 -1
  56. package/dist/components/ConnectorRuntimeDiagnostics.d.ts +5 -0
  57. package/dist/components/DeviceConnection.d.ts +15 -0
  58. package/dist/components/FeishuCapabilitySelection.d.ts +14 -0
  59. package/dist/components/FeishuPermissionStatus.d.ts +5 -0
  60. package/dist/components/LlmAdvancedSettings.d.ts +0 -1
  61. package/dist/components/ManagedConnection.d.ts +9 -0
  62. package/dist/components/McpAppFrame.d.ts +17 -0
  63. package/dist/components/PlanUpdateBlock.d.ts +0 -1
  64. package/dist/components/SessionPluginConfigForm.d.ts +3 -1
  65. package/dist/components/SessionPluginIcon.d.ts +1 -0
  66. package/dist/components/plugin-connector.d.ts +1 -0
  67. package/dist/connectors.d.ts +2 -0
  68. package/dist/connectors.js +11 -0
  69. package/dist/connectors.js.map +1 -0
  70. package/dist/embed/blade-chat-element.d.ts +0 -8
  71. package/dist/embed/entry.d.ts +8 -19
  72. package/dist/hooks/use-message-pin.d.ts +1 -1
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.js +14 -3
  75. package/dist/internal.d.ts +6 -2
  76. package/dist/internal.js +49 -70
  77. package/dist/internal.js.map +1 -1
  78. package/dist/lib/message-shortcuts.d.ts +5 -0
  79. package/dist/questions.d.ts +7 -0
  80. package/dist/questions.js +908 -0
  81. package/dist/questions.js.map +1 -0
  82. package/dist/rich-input/ConnectButton.d.ts +7 -5
  83. package/dist/rich-input/FileCompletionMenu.d.ts +1 -2
  84. package/dist/rich-input/InputActionSubmenu.d.ts +10 -0
  85. package/dist/rich-input/SkillActionMenu.d.ts +10 -0
  86. package/dist/rich-input/SkillStatusBar.d.ts +0 -6
  87. package/dist/rich-input/extensions/skill-mention.d.ts +3 -20
  88. package/dist/rich-input/index.d.ts +3 -2
  89. package/dist/rich-input/lib/composer-content.d.ts +5 -1
  90. package/dist/rich-input/lib/plugin-suggestions.d.ts +5 -5
  91. package/dist/rich-input/lib/reference-candidates.d.ts +0 -1
  92. package/dist/rich-input/lib/skill-suggestions.d.ts +1 -1
  93. package/dist/rich-input/lib/user-home.d.ts +0 -17
  94. package/dist/rich-input/services.d.ts +1 -1
  95. package/dist/rich-input/voice/VoiceWaveform.d.ts +0 -3
  96. package/dist/rich-input.js +768 -1065
  97. package/dist/rich-input.js.map +1 -1
  98. package/dist/style.css +16 -55
  99. package/dist/style.full.css +23 -77
  100. package/dist/tool-details.d.ts +8 -0
  101. package/dist/tool-details.js +24 -0
  102. package/dist/tool-details.js.map +1 -0
  103. package/node_modules/@modelcontextprotocol/ext-apps/LICENSE +216 -0
  104. package/node_modules/@modelcontextprotocol/ext-apps/README.md +284 -0
  105. package/node_modules/@modelcontextprotocol/ext-apps/dist/docs/patterns.d.ts +9 -0
  106. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.d.ts +1348 -0
  107. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.examples.d.ts +9 -0
  108. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js +39 -0
  109. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.test.d.ts +1 -0
  110. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-with-deps.js +82 -0
  111. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.d.ts +1214 -0
  112. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.examples.d.ts +9 -0
  113. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.js +39 -0
  114. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.test.d.ts +1 -0
  115. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/constants.d.ts +65 -0
  116. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/events.d.ts +47 -0
  117. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/events.test.d.ts +1 -0
  118. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.d.ts +1047 -0
  119. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.json +6170 -0
  120. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.test.d.ts +41 -0
  121. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/interop-v1.test.d.ts +1 -0
  122. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/legacy-handlers.d.ts +66 -0
  123. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/legacy-handlers.test.d.ts +1 -0
  124. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.d.ts +126 -0
  125. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.examples.d.ts +9 -0
  126. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.test.d.ts +1 -0
  127. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.d.ts +37 -0
  128. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.examples.d.ts +6 -0
  129. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js +39 -0
  130. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/react-with-deps.js +82 -0
  131. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useApp.d.ts +115 -0
  132. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useApp.examples.d.ts +6 -0
  133. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useAutoResize.d.ts +54 -0
  134. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useAutoResize.examples.d.ts +6 -0
  135. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useDocumentTheme.d.ts +44 -0
  136. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useDocumentTheme.examples.d.ts +6 -0
  137. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useHostStyles.d.ts +113 -0
  138. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useHostStyles.examples.d.ts +6 -0
  139. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.d.ts +381 -0
  140. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.examples.d.ts +9 -0
  141. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.js +1 -0
  142. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.test.d.ts +1 -0
  143. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/spec.types.d.ts +698 -0
  144. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/standard-schema.d.ts +23 -0
  145. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/styles.d.ts +184 -0
  146. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/styles.examples.d.ts +9 -0
  147. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/types.d.ts +33 -0
  148. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/wire-compat.test.d.ts +1 -0
  149. package/node_modules/@modelcontextprotocol/ext-apps/package.json +144 -0
  150. package/node_modules/@standard-schema/spec/LICENSE +21 -0
  151. package/node_modules/@standard-schema/spec/README.md +198 -0
  152. package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
  153. package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
  154. package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
  155. package/node_modules/@standard-schema/spec/dist/index.js +0 -0
  156. package/node_modules/@standard-schema/spec/package.json +52 -0
  157. package/package.json +19 -3
  158. package/public-api.md +16 -4
  159. package/dist/chunk-67GHJQK5.js.map +0 -1
  160. package/dist/chunk-DPDXGYGM.js +0 -258
  161. package/dist/chunk-DPDXGYGM.js.map +0 -1
  162. package/dist/chunk-MERN5XEM.js.map +0 -1
  163. package/dist/lib/agent-computer-command.d.ts +0 -32
  164. package/dist/rich-input/extensions/workflow-mention.d.ts +0 -10
@@ -0,0 +1,605 @@
1
+ import {
2
+ PluginConnectorList,
3
+ SessionPluginConfigForm,
4
+ SessionPluginIcon,
5
+ catalogToConnectorItems,
6
+ filterConnectorItems,
7
+ useSessionPluginActivation
8
+ } from "./chunk-2DPLLZOU.js";
9
+ import {
10
+ ConnectorConnection
11
+ } from "./chunk-J72ZLILV.js";
12
+ import {
13
+ BrowserConnectionDialog
14
+ } from "./chunk-WRIMPZPN.js";
15
+ import {
16
+ Check,
17
+ LoaderCircle,
18
+ Pencil,
19
+ Plug,
20
+ RefreshCw,
21
+ Search,
22
+ Trash2,
23
+ Unplug
24
+ } from "./chunk-QIR73CES.js";
25
+
26
+ // src/components/connector-panel-types.ts
27
+ function selectionFromItem(item) {
28
+ return {
29
+ name: item.name,
30
+ displayName: item.display_name ?? null,
31
+ icon: item.icon,
32
+ iconSource: item.iconSource
33
+ };
34
+ }
35
+ var TRIGGER_ICON_LIMIT = 3;
36
+ function triggerSummary(items) {
37
+ const visible = items.slice(0, TRIGGER_ICON_LIMIT);
38
+ return {
39
+ visible,
40
+ overflow: items.length - visible.length,
41
+ total: items.length
42
+ };
43
+ }
44
+
45
+ // src/components/AccountConnectors.tsx
46
+ import { isLocalConnectorName } from "@blade-hq/agent-client/internal";
47
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
48
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
49
+ var actionBaseClass = "inline-flex h-8 shrink-0 items-center justify-center gap-1.5 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--background))] text-xs font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))] focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50";
50
+ var actionClass = `${actionBaseClass} px-3`;
51
+ var iconActionClass = `${actionBaseClass} w-8 p-0`;
52
+ async function failureMessage(error) {
53
+ const response = error?.response;
54
+ if (response) {
55
+ try {
56
+ const body = await response.json();
57
+ if (typeof body.detail === "string") return body.detail;
58
+ if (typeof body.detail?.message === "string") return body.detail.message;
59
+ } catch {
60
+ }
61
+ }
62
+ return "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5";
63
+ }
64
+ function DeviceDialog({ client, connector, onChanged, onClose }) {
65
+ const dialog = useRef(null);
66
+ useEffect(() => {
67
+ const element = dialog.current;
68
+ element?.showModal();
69
+ return () => element?.close();
70
+ }, []);
71
+ return /* @__PURE__ */ jsxs("dialog", { ref: dialog, "aria-label": `\u8FDE\u63A5 ${connector.display_name || connector.name}`, onCancel: (event) => {
72
+ event.preventDefault();
73
+ onClose();
74
+ }, className: "fixed inset-0 m-auto max-h-[85vh] w-[min(640px,90vw)] overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background))] p-6 text-[hsl(var(--foreground))] backdrop:bg-black/40", children: [
75
+ /* @__PURE__ */ jsx(ConnectorConnection, { type: connector.authorization?.type === "managed" ? "managed" : "device", read: () => client.connectors.authorization(connector.name), act: (action, options) => client.connectors.authorize(connector.name, action, void 0, options), plan: (capabilities) => client.connectors.authorizationPlan(connector.name, capabilities), diagnostics: () => client.connectors.diagnostics(connector.name), onChanged, onDisable: () => client.connectors.disconnect(connector.name) }),
76
+ /* @__PURE__ */ jsx("button", { type: "button", className: actionClass, onClick: onClose, children: "\u8FD4\u56DE\u8FDE\u63A5\u5668" })
77
+ ] });
78
+ }
79
+ function ConnectionDialog({ client, connector, onConnected, onClose }) {
80
+ const [view, setView] = useState(null);
81
+ const [failure, setFailure] = useState(null);
82
+ const [submitting, setSubmitting] = useState(false);
83
+ const [connected, setConnected] = useState(false);
84
+ const dialog = useRef(null);
85
+ const connectionRequest = useRef(null);
86
+ useEffect(() => () => connectionRequest.current?.abort(), []);
87
+ useEffect(() => {
88
+ const element = dialog.current;
89
+ element?.showModal();
90
+ return () => element?.close();
91
+ }, []);
92
+ useEffect(() => {
93
+ const abort = new AbortController();
94
+ client.connectors.read(connector.name, { signal: abort.signal }).then((value) => {
95
+ if (!abort.signal.aborted) setView(value);
96
+ }).catch(async (error) => {
97
+ const message = await failureMessage(error);
98
+ if (!abort.signal.aborted) setFailure(message);
99
+ });
100
+ return () => abort.abort();
101
+ }, [client, connector.name]);
102
+ return /* @__PURE__ */ jsx(
103
+ "dialog",
104
+ {
105
+ ref: dialog,
106
+ "aria-label": `\u8FDE\u63A5 ${connector.display_name || connector.name}`,
107
+ className: "fixed inset-0 m-0 h-full max-h-none w-full max-w-none items-center justify-center border-0 bg-black/40 p-0 open:flex",
108
+ onCancel: (event) => {
109
+ event.preventDefault();
110
+ if (!submitting) onClose();
111
+ },
112
+ children: /* @__PURE__ */ jsxs("div", { className: "max-h-[80vh] w-[min(448px,calc(100%_-_32px))] overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-4 text-[hsl(var(--popover-foreground))] shadow-lg", children: [
113
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 text-sm font-medium", children: [
114
+ "\u8FDE\u63A5 ",
115
+ connector.display_name || connector.name
116
+ ] }),
117
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-[hsl(var(--muted-foreground))]", children: view?.config.state === "not_required" ? "\u65E0\u9700\u586B\u5199\u8D26\u53F7\uFF0C\u9A8C\u8BC1\u8FDE\u63A5\u540E\u5373\u53EF\u4F7F\u7528\u3002" : "\u586B\u5199\u4F60\u7684\u8D26\u53F7\u4FE1\u606F\uFF0C\u9A8C\u8BC1\u901A\u8FC7\u540E\u53EF\u5728\u5BF9\u8BDD\u4E2D\u4F7F\u7528\u3002" }),
118
+ !view ? /* @__PURE__ */ jsx("div", { className: "text-xs", children: failure || "\u6B63\u5728\u83B7\u53D6\u8BA4\u8BC1\u8868\u5355\u2026" }) : !connected ? /* @__PURE__ */ jsx(
119
+ SessionPluginConfigForm,
120
+ {
121
+ config: view.config,
122
+ submitting,
123
+ errors: [],
124
+ failure,
125
+ submitLabel: "\u8FDE\u63A5\u5E76\u9A8C\u8BC1",
126
+ submittingLabel: "\u6B63\u5728\u8FDE\u63A5\u2026",
127
+ onCancel: onClose,
128
+ onSubmit: async (draft) => {
129
+ setSubmitting(true);
130
+ setFailure(null);
131
+ const request = new AbortController();
132
+ connectionRequest.current = request;
133
+ try {
134
+ const connected2 = await client.connectors.connect(connector.name, {
135
+ expected_revision: view.config.revision,
136
+ set: draft.set,
137
+ remove: draft.remove
138
+ }, { signal: request.signal });
139
+ if (request.signal.aborted) return;
140
+ setView(connected2);
141
+ setConnected(true);
142
+ try {
143
+ await onConnected();
144
+ } catch {
145
+ if (!request.signal.aborted) setFailure("\u5DF2\u8FDE\u63A5\uFF0C\u4F46\u5217\u8868\u6216\u5BF9\u8BDD\u72B6\u6001\u672A\u80FD\u5237\u65B0\u3002\u8BF7\u8FD4\u56DE\u540E\u91CD\u8BD5\u5237\u65B0\u6216\u542F\u7528\u3002");
146
+ return;
147
+ }
148
+ if (!request.signal.aborted) onClose();
149
+ } catch (error) {
150
+ if (request.signal.aborted) return;
151
+ setFailure(await failureMessage(error));
152
+ try {
153
+ setView(await client.connectors.read(connector.name));
154
+ } catch {
155
+ }
156
+ } finally {
157
+ if (!request.signal.aborted) setSubmitting(false);
158
+ }
159
+ }
160
+ }
161
+ ) : null,
162
+ connected ? /* @__PURE__ */ jsx("output", { className: "block text-sm", children: failure || "\u8D26\u53F7\u5DF2\u8FDE\u63A5\u3002" }) : null,
163
+ !view || connected ? /* @__PURE__ */ jsx("button", { type: "button", className: `${actionClass} mt-3`, onClick: onClose, children: "\u5173\u95ED" }) : null
164
+ ] })
165
+ }
166
+ );
167
+ }
168
+ function AccountConnectors({ client, query = "", sessionId = null, pending, onUse, onSelectedChange, disabledReason, catalog = false, manage = false, onEdit }) {
169
+ const [items, setItems] = useState([]);
170
+ const [editing, setEditing] = useState(null);
171
+ const [failure, setFailure] = useState(null);
172
+ const [loading, setLoading] = useState(true);
173
+ const deleteDialog = useRef(null);
174
+ const [deleting, setDeleting] = useState(null);
175
+ const [busy, setBusy] = useState(false);
176
+ useEffect(() => {
177
+ if (!deleting) return;
178
+ const element = deleteDialog.current;
179
+ element?.showModal();
180
+ return () => element?.close();
181
+ }, [deleting]);
182
+ const lifetime = useRef(null);
183
+ const load = useCallback((signal) => sessionId ? client.connectors.listForSession(sessionId, { signal }) : client.connectors.list({ signal }), [client, sessionId]);
184
+ const reload = useCallback(async () => {
185
+ const scope = lifetime.current;
186
+ const result = await load(scope?.signal);
187
+ if (scope === lifetime.current && !scope?.signal.aborted) {
188
+ setItems(result.connectors);
189
+ setFailure(null);
190
+ }
191
+ }, [load]);
192
+ useEffect(() => {
193
+ const abort = new AbortController();
194
+ lifetime.current = abort;
195
+ setItems([]);
196
+ setEditing(null);
197
+ setLoading(true);
198
+ setFailure(null);
199
+ load(abort.signal).then((value) => {
200
+ if (!abort.signal.aborted) setItems(value.connectors);
201
+ }).catch(async (error) => {
202
+ const message = await failureMessage(error);
203
+ if (!abort.signal.aborted) setFailure(message);
204
+ }).finally(() => {
205
+ if (!abort.signal.aborted) setLoading(false);
206
+ });
207
+ return () => abort.abort();
208
+ }, [load]);
209
+ const visible = useMemo(() => {
210
+ const result = items.map((item) => ({ ...item, active: sessionId ? item.active : Boolean(pending?.has(item.name)) }));
211
+ if (!sessionId) {
212
+ for (const name of pending ?? []) if (isLocalConnectorName(name) && !result.some((item) => item.name === name)) result.push({ name, display_name: name.split(".").slice(2).join("."), description: "\u8FDE\u63A5\u5668\u5DF2\u79FB\u9664\u6216\u6682\u4E0D\u53EF\u7528\uFF0C\u53EF\u53D6\u6D88\u9009\u62E9\u540E\u7EE7\u7EED\u3002", source: name.startsWith("connector.builtin.") ? "builtin" : "personal", operations: 0, available: false, active: true, connection: { status: "disconnected", revision: 0, account_label: "", verified_at: "" } });
213
+ }
214
+ return result;
215
+ }, [items, pending, sessionId]);
216
+ const selected = useRef(onSelectedChange);
217
+ selected.current = onSelectedChange;
218
+ useEffect(() => {
219
+ selected.current?.(visible.filter((item) => item.active));
220
+ }, [visible]);
221
+ const matching = visible.filter((item) => `${item.display_name} ${item.description}`.toLowerCase().includes(query.trim().toLowerCase()));
222
+ return /* @__PURE__ */ jsxs("div", { className: catalog ? "grid gap-4 sm:grid-cols-2 xl:grid-cols-3" : void 0, children: [
223
+ !catalog ? /* @__PURE__ */ jsx("div", { className: "px-3 pt-1 pb-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children: "\u8FDE\u63A5\u5668" }) : null,
224
+ loading ? /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6B63\u5728\u8BFB\u53D6\u8FDE\u63A5\u5668\u2026" }) : null,
225
+ !loading && !failure && matching.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: query.trim() ? "\u6CA1\u6709\u5339\u914D\u7684\u8FDE\u63A5\u5668" : "\u6682\u65E0\u8FDE\u63A5\u5668" }) : null,
226
+ matching.map((item) => {
227
+ const connected = item.connection.status === "connected";
228
+ const label = item.display_name || item.name;
229
+ const ConnectIcon = connected ? RefreshCw : Plug;
230
+ const connectionClass = `${actionClass} ${!connected ? "border-transparent bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] hover:bg-[hsl(var(--primary)/0.9)]" : ""}`;
231
+ const connectAction = /* @__PURE__ */ jsxs("button", { type: "button", disabled: busy || item.available === false, className: connectionClass, onClick: () => {
232
+ setFailure(null);
233
+ setEditing(item);
234
+ }, children: [
235
+ /* @__PURE__ */ jsx(ConnectIcon, { size: 14, "aria-hidden": "true" }),
236
+ ["device", "managed"].includes(item.authorization?.type ?? "") ? "\u7BA1\u7406\u6388\u6743" : connected ? "\u91CD\u65B0\u8FDE\u63A5" : "\u8FDE\u63A5"
237
+ ] });
238
+ const useAction = onUse && (item.active || connected && item.operations > 0) ? /* @__PURE__ */ jsxs("button", { type: "button", disabled: busy || Boolean(disabledReason), title: disabledReason ?? void 0, className: actionClass, onClick: async () => {
239
+ const scope = lifetime.current;
240
+ setBusy(true);
241
+ setFailure(null);
242
+ try {
243
+ await onUse(item.name, label, !item.active, item.icon ?? null);
244
+ if (sessionId) await reload();
245
+ } catch (error) {
246
+ const message = await failureMessage(error);
247
+ if (scope === lifetime.current && !scope?.signal.aborted) setFailure(message);
248
+ } finally {
249
+ if (scope === lifetime.current && !scope?.signal.aborted) setBusy(false);
250
+ }
251
+ }, children: [
252
+ item.active ? /* @__PURE__ */ jsx(Check, { size: 14, "aria-hidden": "true" }) : null,
253
+ item.active ? "\u5DF2\u542F\u7528" : "\u4F7F\u7528"
254
+ ] }) : null;
255
+ return /* @__PURE__ */ jsxs("div", { className: catalog ? "flex flex-col rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-5" : "px-3 py-1.5", children: [
256
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-2 ${catalog ? "text-sm" : "text-[11px]"}`, children: [
257
+ /* @__PURE__ */ jsx(SessionPluginIcon, { client, sessionId: null, plugin: { name: item.name, icon: item.icon ?? null }, size: catalog ? 32 : 20 }),
258
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-medium", title: label, children: label }),
259
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-md bg-[hsl(var(--muted))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children: item.source === "builtin" ? "\u5185\u7F6E" : "\u6211\u521B\u5EFA\u7684" }),
260
+ !catalog ? /* @__PURE__ */ jsxs(Fragment, { children: [
261
+ connectAction,
262
+ useAction
263
+ ] }) : null
264
+ ] }),
265
+ catalog ? /* @__PURE__ */ jsx("p", { className: "mt-2 flex-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: item.description }) : null,
266
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
267
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `size-1.5 shrink-0 rounded-full ${connected ? "bg-emerald-500" : "bg-[hsl(var(--muted-foreground)/0.4)]"}` }),
268
+ connected ? `\u5DF2\u8FDE\u63A5${item.connection.account_label ? ` \xB7 ${item.connection.account_label}` : ""}${item.name === "connector.builtin.feishu" ? "\uFF0C\u6309\u5DF2\u5F00\u901A\u80FD\u529B\u63D0\u4F9B\u64CD\u4F5C" : item.operations === 0 ? "\uFF0C\u5C1A\u672A\u914D\u7F6E\u4E1A\u52A1\u64CD\u4F5C" : ""}` : item.connection.status === "auth_required" ? "\u9700\u8981\u91CD\u65B0\u8BA4\u8BC1" : "\u672A\u8FDE\u63A5"
269
+ ] }),
270
+ catalog ? /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2 border-t border-[hsl(var(--border))] pt-4", children: [
271
+ connectAction,
272
+ useAction,
273
+ manage ? /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [
274
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, "aria-label": ["device", "managed"].includes(item.authorization?.type ?? "") ? "\u505C\u7528 BA \u8FDE\u63A5" : "\u65AD\u5F00", title: ["device", "managed"].includes(item.authorization?.type ?? "") ? "\u4EC5\u505C\u7528 BA\uFF0CSuperWork \u8D26\u53F7\u548C\u6D88\u606F\u8BA2\u9605\u4FDD\u7559" : "\u65AD\u5F00\u8FDE\u63A5", className: iconActionClass, onClick: async () => {
275
+ setBusy(true);
276
+ try {
277
+ await client.connectors.disconnect(item.name);
278
+ await reload();
279
+ } catch (error) {
280
+ setFailure(await failureMessage(error));
281
+ } finally {
282
+ setBusy(false);
283
+ }
284
+ }, children: /* @__PURE__ */ jsx(Unplug, { size: 15, "aria-hidden": "true" }) }),
285
+ item.source === "personal" ? /* @__PURE__ */ jsxs(Fragment, { children: [
286
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, "aria-label": "\u7F16\u8F91", title: "\u7F16\u8F91\u8FDE\u63A5\u5668", className: iconActionClass, onClick: () => onEdit?.(item), children: /* @__PURE__ */ jsx(Pencil, { size: 15, "aria-hidden": "true" }) }),
287
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, "aria-label": "\u5220\u9664", title: "\u5220\u9664\u8FDE\u63A5\u5668", className: `${iconActionClass} text-[hsl(var(--destructive))] hover:border-[hsl(var(--destructive)/0.3)] hover:bg-[hsl(var(--destructive)/0.08)]`, onClick: () => setDeleting(item), children: /* @__PURE__ */ jsx(Trash2, { size: 15, "aria-hidden": "true" }) })
288
+ ] }) : null
289
+ ] }) : null
290
+ ] }) : null
291
+ ] }, item.name);
292
+ }),
293
+ deleting ? /* @__PURE__ */ jsxs("dialog", { ref: deleteDialog, onCancel: (event) => {
294
+ event.preventDefault();
295
+ if (!busy) setDeleting(null);
296
+ }, "aria-label": "\u5220\u9664\u8FDE\u63A5\u5668", className: "fixed inset-0 z-50 m-auto w-[min(420px,calc(100%_-_32px))] rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-5 text-[hsl(var(--popover-foreground))] shadow-xl", children: [
297
+ /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
298
+ "\u5220\u9664\u300C",
299
+ deleting.display_name || deleting.name,
300
+ "\u300D\u53CA\u5176\u8FDE\u63A5\u4FE1\u606F\uFF1F\u9700\u8981\u4F7F\u7528\u65F6\u53EF\u4EE5\u91CD\u65B0\u521B\u5EFA\u3002"
301
+ ] }),
302
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-end gap-3", children: [
303
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, className: actionClass, onClick: () => setDeleting(null), children: "\u53D6\u6D88" }),
304
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, className: `${actionClass} border-transparent bg-[hsl(var(--destructive))] text-white hover:bg-[hsl(var(--destructive)/0.9)]`, onClick: async () => {
305
+ setBusy(true);
306
+ try {
307
+ await client.connectors.delete(deleting.name);
308
+ setDeleting(null);
309
+ await reload();
310
+ } catch (error) {
311
+ setFailure(await failureMessage(error));
312
+ setDeleting(null);
313
+ } finally {
314
+ setBusy(false);
315
+ }
316
+ }, children: busy ? "\u6B63\u5728\u5220\u9664\u2026" : "\u786E\u8BA4\u5220\u9664" })
317
+ ] })
318
+ ] }) : null,
319
+ failure ? /* @__PURE__ */ jsxs("div", { role: "alert", className: "px-3 py-1 text-xs text-[hsl(var(--destructive))]", children: [
320
+ failure,
321
+ /* @__PURE__ */ jsx("button", { type: "button", className: `${actionClass} ml-2`, onClick: () => {
322
+ void reload().catch(() => setFailure("\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"));
323
+ }, children: "\u91CD\u8BD5" })
324
+ ] }) : null,
325
+ editing && ["device", "managed"].includes(editing.authorization?.type ?? "") ? /* @__PURE__ */ jsx(DeviceDialog, { client, connector: editing, onChanged: reload, onClose: () => {
326
+ setEditing(null);
327
+ void reload();
328
+ } }, editing.name) : editing?.authorization?.type === "browser" ? /* @__PURE__ */ jsx(BrowserConnectionDialog, { client, name: editing.name, label: editing.display_name || editing.name, onClose: () => {
329
+ setEditing(null);
330
+ void reload().catch(() => setFailure("\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"));
331
+ } }, editing.name) : editing ? /* @__PURE__ */ jsx(ConnectionDialog, { client, connector: editing, onClose: () => setEditing(null), onConnected: async () => {
332
+ const scope = lifetime.current;
333
+ await reload();
334
+ if (scope !== lifetime.current || scope?.signal.aborted) return;
335
+ if (onUse && editing.operations > 0 && !disabledReason) {
336
+ await onUse(editing.name, editing.display_name || editing.name, true);
337
+ if (sessionId) await reload();
338
+ }
339
+ } }, editing.name) : null
340
+ ] });
341
+ }
342
+
343
+ // src/components/ConnectorPanel.tsx
344
+ import { isLocalConnectorName as isLocalConnectorName2 } from "@blade-hq/agent-client/internal";
345
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
346
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
347
+ function PanelDivider() {
348
+ return /* @__PURE__ */ jsx2("div", { className: "my-1 border-[hsl(var(--border))] border-t" });
349
+ }
350
+ function PanelTitle({ children }) {
351
+ return /* @__PURE__ */ jsx2("div", { className: "px-3 pt-1 pb-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children });
352
+ }
353
+ function ConnectorPanel({
354
+ client,
355
+ sessionId,
356
+ pendingPlugins,
357
+ onPendingPluginsChange,
358
+ pendingDisabledReason,
359
+ onPluginsChanged,
360
+ onSelectedChange,
361
+ renderComputerSection,
362
+ renderPhoneSection,
363
+ renderExternalAccounts,
364
+ renderFooterActions,
365
+ className
366
+ }) {
367
+ const [query, setQuery] = useState2("");
368
+ const [selectedConnectors, setSelectedConnectors] = useState2([]);
369
+ const [pendingCatalog, setPendingCatalog] = useState2(null);
370
+ const [pendingLoading, setPendingLoading] = useState2(false);
371
+ const [pendingError, setPendingError] = useState2(false);
372
+ const activation = useSessionPluginActivation({
373
+ client,
374
+ sessionId: sessionId ?? "",
375
+ onChange: onPluginsChanged
376
+ });
377
+ const { reload, items: sessionItems } = activation;
378
+ useEffect2(() => {
379
+ if (sessionId) reload();
380
+ }, [reload, sessionId]);
381
+ const loadPendingCatalog = useCallback2(async () => {
382
+ setPendingLoading(true);
383
+ setPendingError(false);
384
+ try {
385
+ const { plugins } = await client.plugins.catalog();
386
+ setPendingCatalog(plugins);
387
+ } catch {
388
+ setPendingError(true);
389
+ } finally {
390
+ setPendingLoading(false);
391
+ }
392
+ }, [client]);
393
+ useEffect2(() => {
394
+ if (sessionId) return;
395
+ void loadPendingCatalog();
396
+ }, [loadPendingCatalog, sessionId]);
397
+ const selected = useMemo2(
398
+ () => new Set((pendingPlugins ?? []).map((item) => item.name)),
399
+ [pendingPlugins]
400
+ );
401
+ const items = useMemo2(() => {
402
+ if (sessionId) return sessionItems;
403
+ return catalogToConnectorItems(pendingCatalog ?? []).map((item) => ({
404
+ ...item,
405
+ active: selected.has(item.name)
406
+ }));
407
+ }, [pendingCatalog, selected, sessionId, sessionItems]);
408
+ const visibleItems = useMemo2(
409
+ () => sessionId ? filterConnectorItems(items, query) : filterConnectorItems(items, query).map((item) => ({ ...item, config: void 0 })),
410
+ [items, query, sessionId]
411
+ );
412
+ const togglePending = useCallback2((item, next) => {
413
+ const kept = (pendingPlugins ?? []).filter((entry) => entry.name !== item.name);
414
+ onPendingPluginsChange?.(next ? [...kept, selectionFromItem(item)] : kept);
415
+ }, [onPendingPluginsChange, pendingPlugins]);
416
+ const toggle = useCallback2((item, next) => {
417
+ if (sessionId) activation.toggle(item, next);
418
+ else togglePending(item, next);
419
+ }, [activation, sessionId, togglePending]);
420
+ const selectedItems = useMemo2(
421
+ () => [
422
+ ...items.filter((item) => item.active && !isLocalConnectorName2(item.name)),
423
+ ...selectedConnectors.map((item) => ({
424
+ name: item.name,
425
+ display_name: item.display_name,
426
+ icon: item.icon ?? null,
427
+ iconSource: "account",
428
+ installed: true,
429
+ active: true,
430
+ status: "valid",
431
+ projected: false,
432
+ connector: true
433
+ }))
434
+ ],
435
+ [items, selectedConnectors]
436
+ );
437
+ const onSelectedChangeRef = useRef2(onSelectedChange);
438
+ onSelectedChangeRef.current = onSelectedChange;
439
+ const latestSelected = useRef2(selectedItems);
440
+ latestSelected.current = selectedItems;
441
+ const reportSelected = useCallback2(() => {
442
+ onSelectedChangeRef.current?.(latestSelected.current);
443
+ }, []);
444
+ const selectedNames = selectedItems.map((item) => item.name).join("\0");
445
+ useEffect2(reportSelected, [reportSelected, selectedNames]);
446
+ const failed = sessionId ? activation.listError : pendingError;
447
+ return /* @__PURE__ */ jsxs2("div", { className, children: [
448
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-[hsl(var(--border))] border-b px-3 py-2", children: [
449
+ /* @__PURE__ */ jsx2(Search, { size: 12, className: "shrink-0 text-[hsl(var(--muted-foreground))]", "aria-hidden": "true" }),
450
+ /* @__PURE__ */ jsx2(
451
+ "input",
452
+ {
453
+ value: query,
454
+ onChange: (event) => setQuery(event.target.value),
455
+ placeholder: "\u641C\u7D22\u8FDE\u63A5\u5668",
456
+ "aria-label": "\u641C\u7D22\u8FDE\u63A5\u5668",
457
+ className: "min-w-0 flex-1 bg-transparent text-[11px] outline-none placeholder:text-[hsl(var(--muted-foreground))]"
458
+ }
459
+ )
460
+ ] }),
461
+ renderComputerSection ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
462
+ /* @__PURE__ */ jsx2(PanelTitle, { children: "\u7535\u8111" }),
463
+ renderComputerSection(query)
464
+ ] }) : null,
465
+ renderPhoneSection ? renderPhoneSection(query) : null,
466
+ /* @__PURE__ */ jsx2(PanelDivider, {}),
467
+ /* @__PURE__ */ jsx2(
468
+ AccountConnectors,
469
+ {
470
+ client,
471
+ query,
472
+ sessionId,
473
+ pending: selected,
474
+ onSelectedChange: setSelectedConnectors,
475
+ disabledReason: pendingDisabledReason,
476
+ onUse: async (name, label, enabled, icon) => {
477
+ if (sessionId) {
478
+ const result = await client.sessions.setSessionPluginActivation(sessionId, name, enabled);
479
+ onPluginsChanged?.(result.plugin);
480
+ } else {
481
+ const kept = (pendingPlugins ?? []).filter((item) => item.name !== name);
482
+ onPendingPluginsChange?.(enabled ? [...kept, { name, displayName: label, icon: icon ?? null, iconSource: "account" }] : kept);
483
+ }
484
+ }
485
+ }
486
+ ),
487
+ /* @__PURE__ */ jsx2(PanelDivider, {}),
488
+ /* @__PURE__ */ jsx2(PanelTitle, { children: "\u63D2\u4EF6" }),
489
+ !sessionId ? /* @__PURE__ */ jsx2("div", { className: "px-3 pb-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children: "\u5148\u9009\u4E2D\uFF0C\u53D1\u9001\u8FD9\u6761\u6D88\u606F\u65F6\u4F1A\u4E00\u5E76\u542F\u7528" }) : null,
490
+ (sessionId ? activation.loading : pendingLoading) && visibleItems.length === 0 ? /* @__PURE__ */ jsxs2("div", { className: "px-3 py-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
491
+ /* @__PURE__ */ jsx2(LoaderCircle, { size: 12, className: "mr-1 inline animate-spin" }),
492
+ "\u6B63\u5728\u83B7\u53D6\u63D2\u4EF6\u2026"
493
+ ] }) : null,
494
+ failed ? /* @__PURE__ */ jsx2(
495
+ "button",
496
+ {
497
+ type: "button",
498
+ onClick: () => sessionId ? reload() : void loadPendingCatalog(),
499
+ className: "px-3 py-1.5 text-left text-[11px] text-[hsl(var(--muted-foreground))] underline",
500
+ children: "\u63D2\u4EF6\u5217\u8868\u6682\u4E0D\u53EF\u7528\uFF0C\u70B9\u51FB\u91CD\u8BD5"
501
+ }
502
+ ) : null,
503
+ /* @__PURE__ */ jsx2(
504
+ PluginConnectorList,
505
+ {
506
+ client,
507
+ sessionId,
508
+ items: visibleItems.filter((item) => !isLocalConnectorName2(item.name)),
509
+ inFlight: activation.inFlight,
510
+ busy: sessionId ? activation.busy : pendingLoading,
511
+ mutationError: sessionId ? activation.mutationError : false,
512
+ onToggle: toggle,
513
+ onRetry: activation.retry,
514
+ onEditConfig: activation.editConfig,
515
+ configuring: sessionId ? activation.configuring : null,
516
+ onConfigSaved: activation.onConfigSaved,
517
+ onConfigClose: activation.onConfigClose,
518
+ disabledReason: sessionId ? null : pendingDisabledReason,
519
+ unavailableText: failed ? null : query.trim() ? "\u6CA1\u6709\u5339\u914D\u7684\u63D2\u4EF6" : null,
520
+ emptyText: sessionId ? "\u5C1A\u672A\u5B89\u88C5\u63D2\u4EF6" : "\u5C1A\u672A\u5B89\u88C5\u63D2\u4EF6\uFF0C\u53BB\u5E94\u7528\u5E02\u573A\u6DFB\u52A0\u4E00\u4E2A",
521
+ draft: !sessionId
522
+ }
523
+ ),
524
+ renderExternalAccounts ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
525
+ /* @__PURE__ */ jsx2(PanelDivider, {}),
526
+ /* @__PURE__ */ jsx2(PanelTitle, { children: "\u5916\u90E8\u8D26\u53F7" }),
527
+ renderExternalAccounts(query)
528
+ ] }) : null,
529
+ renderFooterActions ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
530
+ /* @__PURE__ */ jsx2(PanelDivider, {}),
531
+ renderFooterActions()
532
+ ] }) : null
533
+ ] });
534
+ }
535
+
536
+ // src/components/PluginTriggerStack.tsx
537
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
538
+ var AVATAR_SIZE = 20;
539
+ function hueOf(name) {
540
+ let hash = 0;
541
+ for (const char of name) hash = (hash * 31 + char.codePointAt(0)) % 1000003;
542
+ return hash % 360;
543
+ }
544
+ var AVATAR_PALETTE = [
545
+ "bg-violet-100 text-violet-800 dark:bg-violet-500/25 dark:text-violet-200",
546
+ "bg-sky-100 text-sky-800 dark:bg-sky-500/25 dark:text-sky-200",
547
+ "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/25 dark:text-emerald-200",
548
+ "bg-amber-100 text-amber-800 dark:bg-amber-500/25 dark:text-amber-200",
549
+ "bg-rose-100 text-rose-800 dark:bg-rose-500/25 dark:text-rose-200",
550
+ "bg-indigo-100 text-indigo-800 dark:bg-indigo-500/25 dark:text-indigo-200",
551
+ "bg-teal-100 text-teal-800 dark:bg-teal-500/25 dark:text-teal-200",
552
+ "bg-fuchsia-100 text-fuchsia-800 dark:bg-fuchsia-500/25 dark:text-fuchsia-200"
553
+ ];
554
+ function PluginTriggerStack({ client, sessionId, summary, className }) {
555
+ if (summary.total === 0) return null;
556
+ const ring = "ring-2 ring-[hsl(var(--background))]";
557
+ return /* @__PURE__ */ jsxs3("span", { className: `flex items-center -space-x-1 ${className ?? ""}`, children: [
558
+ summary.visible.map((item) => {
559
+ const label = item.displayName?.trim() || item.name;
560
+ const tone = AVATAR_PALETTE[hueOf(item.name) % AVATAR_PALETTE.length];
561
+ return item.icon ? /* @__PURE__ */ jsx3(
562
+ SessionPluginIcon,
563
+ {
564
+ client,
565
+ sessionId: item.iconSource === "account" ? null : sessionId,
566
+ plugin: item,
567
+ size: AVATAR_SIZE,
568
+ shape: "circle",
569
+ className: ring
570
+ },
571
+ item.name
572
+ ) : /* @__PURE__ */ jsx3(
573
+ "span",
574
+ {
575
+ title: label,
576
+ className: `flex shrink-0 items-center justify-center rounded-full font-semibold text-[11px] ${tone} ${ring}`,
577
+ style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
578
+ children: Array.from(label.trim())[0]?.toUpperCase() ?? "?"
579
+ },
580
+ item.name
581
+ );
582
+ }),
583
+ summary.overflow > 0 ? /* @__PURE__ */ jsxs3(
584
+ "span",
585
+ {
586
+ className: `flex shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] font-medium text-[hsl(var(--muted-foreground))] text-[10px] ${ring}`,
587
+ style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
588
+ children: [
589
+ "+",
590
+ summary.overflow
591
+ ]
592
+ }
593
+ ) : null
594
+ ] });
595
+ }
596
+
597
+ export {
598
+ selectionFromItem,
599
+ TRIGGER_ICON_LIMIT,
600
+ triggerSummary,
601
+ AccountConnectors,
602
+ ConnectorPanel,
603
+ PluginTriggerStack
604
+ };
605
+ //# sourceMappingURL=chunk-7MCGQH34.js.map