@blade-hq/agent-react 2612.0.0-beta.8 → 2612.0.0-beta.81

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 (177) hide show
  1. package/README.md +47 -0
  2. package/dist/SessionPluginConfigForm-7LJ5SUNY.js +9 -0
  3. package/dist/SessionPluginConfigForm-7LJ5SUNY.js.map +1 -0
  4. package/dist/chat/AgentLoopBlock.d.ts +0 -2
  5. package/dist/chat/AskUserQuestionBlock.d.ts +3 -20
  6. package/dist/chat/AssistantTurnBlock.d.ts +1 -9
  7. package/dist/chat/AttachmentPreviewDialog.d.ts +0 -1
  8. package/dist/chat/ChatLoadingIndicator.d.ts +7 -0
  9. package/dist/chat/ContextAttachmentPills.d.ts +4 -0
  10. package/dist/chat/CurrentPlanPanel.d.ts +0 -3
  11. package/dist/chat/FileDeliveryCards.d.ts +0 -4
  12. package/dist/chat/FinalArtifactCards.d.ts +0 -1
  13. package/dist/chat/ImageLightbox.d.ts +1 -1
  14. package/dist/chat/LiteMessageList.d.ts +5 -3
  15. package/dist/chat/MessageFileAttachmentList.d.ts +0 -5
  16. package/dist/chat/QuestionnaireQuestionBlock.d.ts +11 -0
  17. package/dist/chat/SessionReplayBar.d.ts +0 -1
  18. package/dist/chat/TextAttachmentPills.d.ts +0 -3
  19. package/dist/chat/TurnNavRail.d.ts +1 -7
  20. package/dist/chat/WorkflowRunBlock.d.ts +21 -4
  21. package/dist/chat/ai-elements/shimmer.d.ts +0 -4
  22. package/dist/chat/customization.d.ts +1 -1
  23. package/dist/chat/index.d.ts +3 -2
  24. package/dist/chat/markdown/ExternalAnchor.d.ts +2 -2
  25. package/dist/chat/markdown/MarkdownContent.d.ts +3 -0
  26. package/dist/chat/message-list-blocks.d.ts +0 -1
  27. package/dist/chat/runtime/actions.d.ts +2 -2
  28. package/dist/chat/runtime/background-task-dismissals.d.ts +0 -1
  29. package/dist/chat/runtime/composer-channels.d.ts +0 -3
  30. package/dist/chat/runtime/input-cache-reset.d.ts +0 -5
  31. package/dist/chat/runtime/input-services.d.ts +10 -0
  32. package/dist/chat/runtime/session-source.d.ts +0 -5
  33. package/dist/chat/runtime/use-chat-actions.d.ts +0 -4
  34. package/dist/chat/turn-locate-channel.d.ts +53 -0
  35. package/dist/{chat-OCLOVB3H.css → chat-IHPRU35X.css} +5 -18
  36. package/dist/chat.css +5 -18
  37. package/dist/chunk-66JXSDLB.js +13770 -0
  38. package/dist/chunk-66JXSDLB.js.map +1 -0
  39. package/dist/chunk-C3LBNHVM.js +9482 -0
  40. package/dist/chunk-C3LBNHVM.js.map +1 -0
  41. package/dist/chunk-F4MWGSKX.js +1308 -0
  42. package/dist/chunk-F4MWGSKX.js.map +1 -0
  43. package/dist/chunk-FBGCDXRK.js +607 -0
  44. package/dist/chunk-FBGCDXRK.js.map +1 -0
  45. package/dist/{chunk-67GHJQK5.js → chunk-FDB3J5QF.js} +3889 -26106
  46. package/dist/chunk-FDB3J5QF.js.map +1 -0
  47. package/dist/chunk-FH5HA3GW.js +2416 -0
  48. package/dist/chunk-FH5HA3GW.js.map +1 -0
  49. package/dist/chunk-KHJEIHMJ.js +973 -0
  50. package/dist/chunk-KHJEIHMJ.js.map +1 -0
  51. package/dist/chunk-MWILWSPG.js +9629 -0
  52. package/dist/chunk-MWILWSPG.js.map +1 -0
  53. package/dist/chunk-NRYLAO3X.js +3978 -0
  54. package/dist/chunk-NRYLAO3X.js.map +1 -0
  55. package/dist/{chunk-MERN5XEM.js → chunk-SK43YNRX.js} +4181 -16594
  56. package/dist/chunk-SK43YNRX.js.map +1 -0
  57. package/dist/components/AccountConnectorRules.d.ts +7 -0
  58. package/dist/components/AccountConnectors.d.ts +13 -0
  59. package/dist/components/BrowserConnectionDialog.d.ts +8 -0
  60. package/dist/components/ChatInput.d.ts +1 -15
  61. package/dist/components/ConfigConnection.d.ts +16 -0
  62. package/dist/components/ConnectorAuthorizationProgress.d.ts +6 -0
  63. package/dist/components/ConnectorConnection.d.ts +4 -0
  64. package/dist/components/ConnectorDetail.d.ts +46 -0
  65. package/dist/components/ConnectorPanel.d.ts +3 -1
  66. package/dist/components/ConnectorRulesPanel.d.ts +10 -0
  67. package/dist/components/ConnectorRuntimeDiagnostics.d.ts +5 -0
  68. package/dist/components/DeviceConnection.d.ts +17 -0
  69. package/dist/components/FeishuCapabilitySelection.d.ts +14 -0
  70. package/dist/components/FeishuPermissionStatus.d.ts +7 -0
  71. package/dist/components/LlmAdvancedSettings.d.ts +0 -1
  72. package/dist/components/ManagedConnection.d.ts +12 -0
  73. package/dist/components/McpAppFrame.d.ts +17 -0
  74. package/dist/components/PackEventNotice.d.ts +3 -0
  75. package/dist/components/PlanUpdateBlock.d.ts +0 -1
  76. package/dist/components/SessionPluginConfigForm.d.ts +4 -1
  77. package/dist/components/SessionPluginIcon.d.ts +1 -0
  78. package/dist/components/plugin-connector.d.ts +1 -0
  79. package/dist/connectors.d.ts +6 -0
  80. package/dist/connectors.js +19 -0
  81. package/dist/connectors.js.map +1 -0
  82. package/dist/embed/blade-chat-element.d.ts +0 -8
  83. package/dist/embed/entry.d.ts +13 -19
  84. package/dist/hooks/use-message-pin.d.ts +1 -1
  85. package/dist/hooks/use-turn-navigation.d.ts +19 -0
  86. package/dist/index.d.ts +6 -0
  87. package/dist/index.js +23 -3
  88. package/dist/internal.d.ts +7 -3
  89. package/dist/internal.js +59 -71
  90. package/dist/internal.js.map +1 -1
  91. package/dist/lib/message-shortcuts.d.ts +5 -0
  92. package/dist/questions.d.ts +7 -0
  93. package/dist/questions.js +910 -0
  94. package/dist/questions.js.map +1 -0
  95. package/dist/rich-input/ConnectButton.d.ts +7 -5
  96. package/dist/rich-input/FileCompletionMenu.d.ts +1 -2
  97. package/dist/rich-input/InputActionSubmenu.d.ts +10 -0
  98. package/dist/rich-input/SkillActionMenu.d.ts +10 -0
  99. package/dist/rich-input/SkillStatusBar.d.ts +0 -6
  100. package/dist/rich-input/extensions/skill-mention.d.ts +3 -20
  101. package/dist/rich-input/index.d.ts +3 -2
  102. package/dist/rich-input/lib/composer-content.d.ts +5 -1
  103. package/dist/rich-input/lib/plugin-suggestions.d.ts +5 -5
  104. package/dist/rich-input/lib/reference-candidates.d.ts +0 -1
  105. package/dist/rich-input/lib/skill-suggestions.d.ts +1 -1
  106. package/dist/rich-input/lib/user-home.d.ts +0 -17
  107. package/dist/rich-input/services.d.ts +1 -1
  108. package/dist/rich-input/voice/VoiceWaveform.d.ts +0 -3
  109. package/dist/rich-input.js +793 -1068
  110. package/dist/rich-input.js.map +1 -1
  111. package/dist/style.css +16 -55
  112. package/dist/style.full.css +23 -77
  113. package/dist/tool-details.d.ts +8 -0
  114. package/dist/tool-details.js +25 -0
  115. package/dist/tool-details.js.map +1 -0
  116. package/node_modules/@modelcontextprotocol/ext-apps/LICENSE +216 -0
  117. package/node_modules/@modelcontextprotocol/ext-apps/README.md +284 -0
  118. package/node_modules/@modelcontextprotocol/ext-apps/dist/docs/patterns.d.ts +9 -0
  119. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.d.ts +1348 -0
  120. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.examples.d.ts +9 -0
  121. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js +39 -0
  122. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.test.d.ts +1 -0
  123. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-with-deps.js +82 -0
  124. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.d.ts +1214 -0
  125. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.examples.d.ts +9 -0
  126. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.js +39 -0
  127. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/app.test.d.ts +1 -0
  128. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/constants.d.ts +65 -0
  129. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/events.d.ts +47 -0
  130. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/events.test.d.ts +1 -0
  131. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.d.ts +1047 -0
  132. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.json +6170 -0
  133. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/generated/schema.test.d.ts +41 -0
  134. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/interop-v1.test.d.ts +1 -0
  135. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/legacy-handlers.d.ts +66 -0
  136. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/legacy-handlers.test.d.ts +1 -0
  137. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.d.ts +126 -0
  138. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.examples.d.ts +9 -0
  139. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/message-transport.test.d.ts +1 -0
  140. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.d.ts +37 -0
  141. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.examples.d.ts +6 -0
  142. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js +39 -0
  143. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/react-with-deps.js +82 -0
  144. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useApp.d.ts +115 -0
  145. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useApp.examples.d.ts +6 -0
  146. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useAutoResize.d.ts +54 -0
  147. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useAutoResize.examples.d.ts +6 -0
  148. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useDocumentTheme.d.ts +44 -0
  149. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useDocumentTheme.examples.d.ts +6 -0
  150. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useHostStyles.d.ts +113 -0
  151. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/useHostStyles.examples.d.ts +6 -0
  152. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.d.ts +381 -0
  153. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.examples.d.ts +9 -0
  154. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.js +1 -0
  155. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/server/index.test.d.ts +1 -0
  156. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/spec.types.d.ts +698 -0
  157. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/standard-schema.d.ts +23 -0
  158. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/styles.d.ts +184 -0
  159. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/styles.examples.d.ts +9 -0
  160. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/types.d.ts +33 -0
  161. package/node_modules/@modelcontextprotocol/ext-apps/dist/src/wire-compat.test.d.ts +1 -0
  162. package/node_modules/@modelcontextprotocol/ext-apps/package.json +144 -0
  163. package/node_modules/@standard-schema/spec/LICENSE +21 -0
  164. package/node_modules/@standard-schema/spec/README.md +198 -0
  165. package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
  166. package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
  167. package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
  168. package/node_modules/@standard-schema/spec/dist/index.js +0 -0
  169. package/node_modules/@standard-schema/spec/package.json +52 -0
  170. package/package.json +19 -3
  171. package/public-api.md +60 -4
  172. package/dist/chunk-67GHJQK5.js.map +0 -1
  173. package/dist/chunk-DPDXGYGM.js +0 -258
  174. package/dist/chunk-DPDXGYGM.js.map +0 -1
  175. package/dist/chunk-MERN5XEM.js.map +0 -1
  176. package/dist/lib/agent-computer-command.d.ts +0 -32
  177. package/dist/rich-input/extensions/workflow-mention.d.ts +0 -10
@@ -3,7 +3,66 @@ import {
3
3
  PluginTriggerStack,
4
4
  selectionFromItem,
5
5
  triggerSummary
6
- } from "./chunk-DPDXGYGM.js";
6
+ } from "./chunk-FBGCDXRK.js";
7
+ import {
8
+ MODEL_REASONING_LEVELS_KEY,
9
+ PREFERRED_MODEL_KEY,
10
+ RichInputServicesProvider,
11
+ chatTone,
12
+ fetchClientQuery,
13
+ getInputHistoryGeneration,
14
+ getPluginSuggestionItems,
15
+ isQueueShortcut,
16
+ onInputCachesReset,
17
+ pluginRefsForSend,
18
+ queueShortcutLabel,
19
+ refreshClientQuery,
20
+ refreshClientSessionSkills,
21
+ sendToSession,
22
+ setClientQueryData,
23
+ useBackgroundTaskList,
24
+ useClientBackgroundTasks,
25
+ useClientContextStats,
26
+ useClientModelCatalog,
27
+ useClientModelPreferences,
28
+ useClientQuery,
29
+ useClientSessionModel,
30
+ useClientSessionSkills,
31
+ useClientSkillStats,
32
+ useComposerConnection,
33
+ useComposerConnectionInfo,
34
+ useContextStats,
35
+ useEffectEvent,
36
+ useModelCatalog,
37
+ useModelPreferences,
38
+ useRefreshWhenRunEnds,
39
+ useRichInputServices,
40
+ useSessionDataInvalidation,
41
+ useSessionSkills,
42
+ useSkillStats
43
+ } from "./chunk-F4MWGSKX.js";
44
+ import "./chunk-FH5HA3GW.js";
45
+ import {
46
+ cn,
47
+ notifyChat,
48
+ useBladeClient,
49
+ useChatEnvironment,
50
+ useChatRenderMode,
51
+ useChatSessionDetail,
52
+ useCurrentChatSessionId,
53
+ useSessionHandle,
54
+ useSessionSource
55
+ } from "./chunk-NRYLAO3X.js";
56
+ import {
57
+ Dialog,
58
+ DialogClose,
59
+ DialogContent,
60
+ DialogTitle,
61
+ cn as cn2,
62
+ dist_exports4 as dist_exports,
63
+ usePortalContainer
64
+ } from "./chunk-MWILWSPG.js";
65
+ import "./chunk-SK43YNRX.js";
7
66
  import {
8
67
  Archive,
9
68
  BookOpen,
@@ -11,10 +70,6 @@ import {
11
70
  Check,
12
71
  ChevronDown,
13
72
  ChevronRight,
14
- Dialog,
15
- DialogClose,
16
- DialogContent,
17
- DialogTitle,
18
73
  Download,
19
74
  EyeOff,
20
75
  File,
@@ -27,6 +82,7 @@ import {
27
82
  Import,
28
83
  Lightbulb,
29
84
  ListPlus,
85
+ ListTree,
30
86
  LoaderCircle,
31
87
  Mic,
32
88
  Music,
@@ -37,32 +93,14 @@ import {
37
93
  Rocket,
38
94
  RotateCcw,
39
95
  Scissors,
96
+ Search,
40
97
  Send,
41
98
  Share2,
42
99
  Sparkles,
43
100
  Square,
44
101
  Terminal,
45
- X,
46
- chatTone,
47
- cn,
48
- cn2,
49
- dist_exports2 as dist_exports,
50
- getInputHistoryGeneration,
51
- getPluginSuggestionItems,
52
- notifyChat,
53
- onInputCachesReset,
54
- pluginRefsForSend,
55
- sendToSession,
56
- useBladeClient,
57
- useChatEnvironment,
58
- useChatRenderMode,
59
- useChatSessionDetail,
60
- useCurrentChatSessionId,
61
- useEffectEvent,
62
- usePortalContainer,
63
- useSessionHandle,
64
- useSessionState
65
- } from "./chunk-MERN5XEM.js";
102
+ X
103
+ } from "./chunk-KHJEIHMJ.js";
66
104
  import {
67
105
  __commonJS,
68
106
  __require,
@@ -88,7 +126,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
88
126
  "The result of getSnapshot should be cached to avoid an infinite loop"
89
127
  ), didWarnUncachedGetSnapshot = true);
90
128
  }
91
- cachedValue = useState12({
129
+ cachedValue = useState13({
92
130
  inst: { value, getSnapshot }
93
131
  });
94
132
  var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
@@ -126,7 +164,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
126
164
  return getSnapshot();
127
165
  }
128
166
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
129
- var React2 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is, useState12 = React2.useState, useEffect10 = React2.useEffect, useLayoutEffect3 = React2.useLayoutEffect, useDebugValue3 = React2.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
167
+ var React2 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is, useState13 = React2.useState, useEffect10 = React2.useEffect, useLayoutEffect3 = React2.useLayoutEffect, useDebugValue3 = React2.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
130
168
  exports.useSyncExternalStore = void 0 !== React2.useSyncExternalStore ? React2.useSyncExternalStore : shim;
131
169
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
132
170
  })();
@@ -154,14 +192,14 @@ var require_with_selector_development = __commonJS({
154
192
  return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
155
193
  }
156
194
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
157
- var React2 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore5 = shim.useSyncExternalStore, useRef10 = React2.useRef, useEffect10 = React2.useEffect, useMemo9 = React2.useMemo, useDebugValue3 = React2.useDebugValue;
195
+ var React2 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore5 = shim.useSyncExternalStore, useRef8 = React2.useRef, useEffect10 = React2.useEffect, useMemo8 = React2.useMemo, useDebugValue3 = React2.useDebugValue;
158
196
  exports.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
159
- var instRef = useRef10(null);
197
+ var instRef = useRef8(null);
160
198
  if (null === instRef.current) {
161
199
  var inst = { hasValue: false, value: null };
162
200
  instRef.current = inst;
163
201
  } else inst = instRef.current;
164
- instRef = useMemo9(
202
+ instRef = useMemo8(
165
203
  function() {
166
204
  function memoizedSelector(nextSnapshot) {
167
205
  if (!hasMemo) {
@@ -225,7 +263,7 @@ var require_with_selector = __commonJS({
225
263
  });
226
264
 
227
265
  // src/rich-input/BackgroundTasksPill.tsx
228
- import { useMemo as useMemo2, useState } from "react";
266
+ import { useMemo, useState } from "react";
229
267
 
230
268
  // src/chat/runtime/background-task-dismissals.ts
231
269
  import { useSyncExternalStore } from "react";
@@ -249,7 +287,6 @@ var backgroundTaskDismissals = {
249
287
  state = { ...state, [sessionId]: [...existing, taskId] };
250
288
  emit();
251
289
  },
252
- /** 换身份:清空。 */
253
290
  reset() {
254
291
  state = {};
255
292
  emit();
@@ -263,331 +300,6 @@ function useDismissedBackgroundTasks(sessionId) {
263
300
  );
264
301
  }
265
302
 
266
- // src/rich-input/services.tsx
267
- import { useMemo, useRef as useRef2 } from "react";
268
-
269
- // src/chat/runtime/input-services.tsx
270
- import { createContext, useContext } from "react";
271
- import { jsx } from "react/jsx-runtime";
272
- function parseModelReasoningLevels(value) {
273
- if (!value) return {};
274
- try {
275
- const parsed = JSON.parse(value);
276
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
277
- return Object.fromEntries(
278
- Object.entries(parsed).filter(
279
- (entry) => Boolean(entry[0]) && typeof entry[1] === "string" && Boolean(entry[1])
280
- )
281
- );
282
- } catch {
283
- return {};
284
- }
285
- }
286
- var RichInputServicesContext = createContext({});
287
- function RichInputServicesProvider({ value, children }) {
288
- return /* @__PURE__ */ jsx(RichInputServicesContext.Provider, { value, children });
289
- }
290
- function useRichInputServices() {
291
- return useContext(RichInputServicesContext);
292
- }
293
-
294
- // src/rich-input/lib/session-data.ts
295
- import { useEffect as useEffect2, useRef } from "react";
296
-
297
- // src/rich-input/lib/client-query.ts
298
- import { useCallback, useEffect, useSyncExternalStore as useSyncExternalStore2 } from "react";
299
- var EMPTY = { data: void 0, error: null, isLoading: false, isFetching: false };
300
- var caches = /* @__PURE__ */ new WeakMap();
301
- function entryFor(client, key) {
302
- let cache = caches.get(client);
303
- if (!cache) {
304
- const created = /* @__PURE__ */ new Map();
305
- cache = created;
306
- caches.set(client, created);
307
- onInputCachesReset(client, () => {
308
- for (const [key2, entry2] of created) {
309
- entry2.request = null;
310
- entry2.fetchedAt = 0;
311
- update(entry2, EMPTY);
312
- const load = loadersFor(client).get(key2);
313
- if (load && entry2.listeners.size > 0) void fetchClientQuery(client, key2, load, { force: true }).catch(() => {
314
- });
315
- }
316
- });
317
- }
318
- let entry = cache.get(key);
319
- if (!entry) {
320
- entry = { snapshot: EMPTY, fetchedAt: 0, request: null, listeners: /* @__PURE__ */ new Set() };
321
- cache.set(key, entry);
322
- }
323
- return entry;
324
- }
325
- function update(entry, patch) {
326
- entry.snapshot = { ...entry.snapshot, ...patch };
327
- for (const listener of [...entry.listeners]) listener();
328
- }
329
- function fetchClientQuery(client, key, load, { staleMs = 3e4, force = false } = {}) {
330
- const entry = entryFor(client, key);
331
- if (entry.request) return entry.request;
332
- if (!force && entry.snapshot.data !== void 0 && Date.now() - entry.fetchedAt < staleMs) {
333
- return Promise.resolve(entry.snapshot.data);
334
- }
335
- const request = Promise.resolve().then(() => load(client));
336
- entry.request = request;
337
- update(entry, { isFetching: true, isLoading: entry.snapshot.data === void 0 });
338
- request.then(
339
- (data) => {
340
- if (entry.request !== request) return;
341
- entry.request = null;
342
- entry.fetchedAt = Date.now();
343
- update(entry, { data, error: null, isFetching: false, isLoading: false });
344
- },
345
- (error) => {
346
- if (entry.request !== request) return;
347
- entry.request = null;
348
- update(entry, { error, isFetching: false, isLoading: false });
349
- }
350
- );
351
- return request;
352
- }
353
- function setClientQueryData(client, key, updater) {
354
- const entry = entryFor(client, key);
355
- if (entry.snapshot.data === void 0) return;
356
- update(entry, { data: updater(entry.snapshot.data) });
357
- }
358
- function useClientQuery(key, load, { staleMs = 3e4 } = {}) {
359
- const client = useBladeClient();
360
- const subscribe = useCallback(
361
- (listener) => {
362
- if (!key) return () => {
363
- };
364
- const entry = entryFor(client, key);
365
- entry.listeners.add(listener);
366
- return () => {
367
- entry.listeners.delete(listener);
368
- };
369
- },
370
- [client, key]
371
- );
372
- const snapshot = useSyncExternalStore2(
373
- subscribe,
374
- () => key ? entryFor(client, key).snapshot : EMPTY,
375
- () => key ? entryFor(client, key).snapshot : EMPTY
376
- );
377
- if (key) loadersFor(client).set(key, load);
378
- useEffect(() => {
379
- if (!key) return;
380
- const registered = loadersFor(client).get(key);
381
- if (registered) void fetchClientQuery(client, key, registered, { staleMs }).catch(() => {
382
- });
383
- }, [client, key, staleMs]);
384
- const refetch = useCallback(async () => {
385
- if (!key) return void 0;
386
- const registered = loadersFor(client).get(key);
387
- if (!registered) return void 0;
388
- return fetchClientQuery(client, key, registered, { force: true }).catch(() => void 0);
389
- }, [client, key]);
390
- return { ...snapshot, refetch };
391
- }
392
- var loaderRegistry = /* @__PURE__ */ new WeakMap();
393
- function loadersFor(client) {
394
- let loaders = loaderRegistry.get(client);
395
- if (!loaders) {
396
- loaders = /* @__PURE__ */ new Map();
397
- loaderRegistry.set(client, loaders);
398
- }
399
- return loaders;
400
- }
401
- function refreshClientQuery(client, key) {
402
- const entry = caches.get(client)?.get(key);
403
- if (!entry) return;
404
- entry.fetchedAt = 0;
405
- const load = loadersFor(client).get(key);
406
- if (load && entry.listeners.size > 0) void fetchClientQuery(client, key, load, { force: true }).catch(() => {
407
- });
408
- }
409
-
410
- // src/rich-input/lib/session-data.ts
411
- var sessionPath = (sessionId, rest) => `/api/sessions/${encodeURIComponent(sessionId)}/${rest}`;
412
- function useRefreshWhenRunEnds(sessionId, keys3) {
413
- const client = useBladeClient();
414
- const streaming = useSessionState(sessionId, (state3) => state3.isStreaming);
415
- const wasStreaming = useRef(streaming);
416
- useEffect2(() => {
417
- if (wasStreaming.current && !streaming) {
418
- for (const key of keys3) refreshClientQuery(client, key);
419
- }
420
- wasStreaming.current = streaming;
421
- });
422
- }
423
- function useClientSessionSkills(sessionId) {
424
- const key = sessionId ? `session-skills:${sessionId}` : null;
425
- const query = useClientQuery(
426
- key,
427
- (client) => client.json("GET", sessionPath(sessionId ?? "", "skills"))
428
- );
429
- useRefreshWhenRunEnds(sessionId, key ? [key] : []);
430
- return { data: query.data, loading: query.isLoading, error: query.error };
431
- }
432
- function useClientSkillStats(sessionId) {
433
- const key = sessionId ? `skill-stats:${sessionId}` : null;
434
- const query = useClientQuery(key, (client) => client.json("GET", sessionPath(sessionId ?? "", "skill-stats")), {
435
- staleMs: 3e5
436
- });
437
- useRefreshWhenRunEnds(sessionId, key ? [key] : []);
438
- return { data: query.data, loading: query.isLoading, error: query.error };
439
- }
440
- function useClientContextStats(sessionId) {
441
- const key = sessionId ? `context-stats:${sessionId}` : null;
442
- const query = useClientQuery(
443
- key,
444
- (client) => client.json("GET", sessionPath(sessionId ?? "", "context-stats"))
445
- );
446
- useRefreshWhenRunEnds(sessionId, key ? [key] : []);
447
- return { data: query.data, loading: query.isLoading, error: query.error };
448
- }
449
- function useClientBackgroundTasks(sessionId) {
450
- const client = useBladeClient();
451
- const key = sessionId ? `background-tasks:${sessionId}` : null;
452
- const query = useClientQuery(key, (c) => c.sessions.listBackgroundTasks(sessionId ?? ""));
453
- const session = useSessionHandle(sessionId);
454
- useEffect2(() => {
455
- if (!session || !key) return;
456
- return session.on("backgroundTask", () => refreshClientQuery(client, key));
457
- }, [client, key, session]);
458
- return { data: query.data, loading: query.isLoading, error: query.error };
459
- }
460
- function refreshClientSessionSkills(client, sessionId) {
461
- refreshClientQuery(client, `session-skills:${sessionId}`);
462
- refreshClientQuery(client, `skill-stats:${sessionId}`);
463
- }
464
- function useClientSessionModel(sessionId) {
465
- const key = sessionId ? `session-detail:${sessionId}` : null;
466
- const query = useClientQuery(key, (client) => client.sessions.getSession(sessionId ?? ""));
467
- useRefreshWhenRunEnds(sessionId, key ? [key] : []);
468
- return query.data?.model ?? null;
469
- }
470
-
471
- // src/rich-input/model/model-data.ts
472
- var EMPTY_MODELS = [];
473
- var EMPTY_IDS = [];
474
- var CATALOG_KEY = "model-catalog";
475
- function useClientModelCatalog() {
476
- const { data, isLoading, isFetching, refetch } = useClientQuery(
477
- CATALOG_KEY,
478
- (client) => client.json("GET", "/api/config/models"),
479
- // 模型服务在设置里随时可改:打开选择器时总是重新拉一次(见 ModelSelector)
480
- { staleMs: 0 }
481
- );
482
- return {
483
- models: data?.models ?? EMPTY_MODELS,
484
- defaultModel: data?.default ?? "",
485
- thinkingAvailable: data?.thinkingAvailable ?? false,
486
- unavailableProviderIds: data?.unavailableProviderIds ?? EMPTY_IDS,
487
- unavailableModelIds: data?.unavailableModelIds ?? EMPTY_IDS,
488
- isLoading,
489
- isFetching,
490
- refresh: async () => {
491
- await refetch();
492
- }
493
- };
494
- }
495
- var PREFERRED_MODEL_KEY = "preferred_model";
496
- var MODEL_REASONING_LEVELS_KEY = "llm.model_thinking_preferences";
497
- var PREFERENCES_KEY = "model-preferences";
498
- function loadPreferences(client) {
499
- const query = new URLSearchParams();
500
- query.append("key", PREFERRED_MODEL_KEY);
501
- query.append("key", MODEL_REASONING_LEVELS_KEY);
502
- return client.json("GET", `/api/user/preferences?${query.toString()}`).then((response) => response.values ?? {});
503
- }
504
- async function writePreference(client, key, value) {
505
- const previous = await fetchClientQuery(client, PREFERENCES_KEY, loadPreferences, { staleMs: 6e4 }).catch(
506
- () => ({})
507
- );
508
- setClientQueryData(client, PREFERENCES_KEY, (current) => ({ ...current, [key]: value }));
509
- try {
510
- await client.json("PUT", `/api/user/preferences/${encodeURIComponent(key)}`, { value });
511
- } catch {
512
- setClientQueryData(client, PREFERENCES_KEY, (current) => ({ ...current, [key]: previous[key] ?? null }));
513
- }
514
- }
515
- var EMPTY_LEVELS = {};
516
- function useClientModelPreferences() {
517
- const client = useBladeClient();
518
- const { data } = useClientQuery(PREFERENCES_KEY, loadPreferences, { staleMs: 6e4 });
519
- const rawLevels = data?.[MODEL_REASONING_LEVELS_KEY] ?? null;
520
- const reasoningLevels = rawLevels ? parseModelReasoningLevels(rawLevels) : EMPTY_LEVELS;
521
- return {
522
- preferredModel: data?.[PREFERRED_MODEL_KEY] ?? null,
523
- setPreferredModel: (modelId) => void writePreference(client, PREFERRED_MODEL_KEY, modelId),
524
- reasoningLevels,
525
- setReasoningLevel: (modelId, level) => {
526
- if (!modelId) return;
527
- void writePreference(
528
- client,
529
- MODEL_REASONING_LEVELS_KEY,
530
- JSON.stringify({ ...reasoningLevels, [modelId]: level })
531
- );
532
- }
533
- };
534
- }
535
-
536
- // src/rich-input/services.tsx
537
- function useModelCatalog() {
538
- const use = useRichInputServices().useModelCatalog ?? useClientModelCatalog;
539
- return use();
540
- }
541
- function useModelPreferences() {
542
- const use = useRichInputServices().useModelPreferences ?? useClientModelPreferences;
543
- return use();
544
- }
545
- function useSessionConnection(sessionId) {
546
- const connection = useSessionState(sessionId, (state3) => state3.connection);
547
- const status = sessionId ? connection : "connected";
548
- const everConnected = useRef2(false);
549
- if (status === "connected") everConnected.current = true;
550
- return { status, reconnectAttempt: 0, hasEverConnected: everConnected.current };
551
- }
552
- function useComposerConnectionInfo(sessionId) {
553
- const use = useRichInputServices().useConnection ?? useSessionConnection;
554
- return use(sessionId);
555
- }
556
- function useComposerConnection(sessionId) {
557
- return useComposerConnectionInfo(sessionId).status;
558
- }
559
- function useSessionSkills(sessionId) {
560
- const use = useRichInputServices().useSessionSkills ?? useClientSessionSkills;
561
- return use(sessionId);
562
- }
563
- function useSkillStats(sessionId) {
564
- const use = useRichInputServices().useSkillStats ?? useClientSkillStats;
565
- return use(sessionId);
566
- }
567
- function useContextStats(sessionId) {
568
- const use = useRichInputServices().useContextStats ?? useClientContextStats;
569
- return use(sessionId);
570
- }
571
- function useBackgroundTaskList(sessionId) {
572
- const use = useRichInputServices().useBackgroundTasks ?? useClientBackgroundTasks;
573
- return use(sessionId);
574
- }
575
- function useClientSessionDataInvalidation() {
576
- const client = useBladeClient();
577
- return useMemo(
578
- () => ({
579
- filesUploaded: (_sessionId) => {
580
- },
581
- pluginsChanged: (sessionId) => refreshClientSessionSkills(client, sessionId)
582
- }),
583
- [client]
584
- );
585
- }
586
- function useSessionDataInvalidation() {
587
- const use = useRichInputServices().useSessionDataInvalidation ?? useClientSessionDataInvalidation;
588
- return use();
589
- }
590
-
591
303
  // src/rich-input/lib/background-tasks-view.ts
592
304
  var LIVE_STATUSES = /* @__PURE__ */ new Set(["starting", "running", "cancelling"]);
593
305
  var ATTENTION_STATUSES = /* @__PURE__ */ new Set(["failed", "lost"]);
@@ -599,7 +311,6 @@ var STATUS_LABELS = {
599
311
  succeeded: "\u5DF2\u5B8C\u6210",
600
312
  cancelled: "\u5DF2\u505C\u6B62",
601
313
  failed: "\u5931\u8D25",
602
- // 不是失败:平台只是不再能追踪这个进程,它可能还在跑。
603
314
  lost: "\u72B6\u6001\u672A\u77E5"
604
315
  };
605
316
  function statusLabel(status) {
@@ -648,7 +359,7 @@ function formatStartedAt(value, now = /* @__PURE__ */ new Date()) {
648
359
  }
649
360
 
650
361
  // src/rich-input/BackgroundTasksPill.tsx
651
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
362
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
652
363
  var NO_TASKS = [];
653
364
  function TaskCard({
654
365
  task,
@@ -658,8 +369,8 @@ function TaskCard({
658
369
  }) {
659
370
  return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-[hsl(var(--border))] p-2", children: [
660
371
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
661
- /* @__PURE__ */ jsx2("div", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: task.description || task.command }),
662
- /* @__PURE__ */ jsx2(
372
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: task.description || task.command }),
373
+ /* @__PURE__ */ jsx(
663
374
  "span",
664
375
  {
665
376
  className: cn(
@@ -670,10 +381,10 @@ function TaskCard({
670
381
  }
671
382
  )
672
383
  ] }),
673
- task.status === "lost" ? /* @__PURE__ */ jsx2("div", { className: "mt-1 text-[11px] text-[hsl(var(--swf-warning))]", children: "\u5E73\u53F0\u91CD\u542F\u540E\u8DDF\u4E22\u4E86\uFF0C\u7A0B\u5E8F\u53EF\u80FD\u4ECD\u5728\u8FD0\u884C" }) : null,
384
+ task.status === "lost" ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-[11px] text-[hsl(var(--swf-warning))]", children: "\u5E73\u53F0\u91CD\u542F\u540E\u8DDF\u4E22\u4E86\uFF0C\u7A0B\u5E8F\u53EF\u80FD\u4ECD\u5728\u8FD0\u884C" }) : null,
674
385
  /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-[10px] text-[hsl(var(--muted-foreground))]/60", children: [
675
- /* @__PURE__ */ jsx2("span", { children: formatStartedAt(task.started_at) }),
676
- /* @__PURE__ */ jsx2("span", { className: "truncate font-mono", children: task.id })
386
+ /* @__PURE__ */ jsx("span", { children: formatStartedAt(task.started_at) }),
387
+ /* @__PURE__ */ jsx("span", { className: "truncate font-mono", children: task.id })
677
388
  ] }),
678
389
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-1.5", children: [
679
390
  /* @__PURE__ */ jsxs(
@@ -683,7 +394,7 @@ function TaskCard({
683
394
  onClick: onOpenLog,
684
395
  className: "inline-flex h-6 items-center gap-1 rounded-md border border-[hsl(var(--border))] px-2 text-[11px] hover:bg-[hsl(var(--accent))]",
685
396
  children: [
686
- /* @__PURE__ */ jsx2(FileText, { size: 12 }),
397
+ /* @__PURE__ */ jsx(FileText, { size: 12 }),
687
398
  "\u65E5\u5FD7"
688
399
  ]
689
400
  }
@@ -695,7 +406,7 @@ function TaskCard({
695
406
  onClick: onStop,
696
407
  className: "inline-flex h-6 items-center gap-1 rounded-[6px] border border-[hsl(var(--swf-danger)/0.35)] px-2 text-[11px] text-[hsl(var(--swf-danger))] hover:bg-[hsl(var(--swf-danger-soft))]",
697
408
  children: [
698
- /* @__PURE__ */ jsx2(Square, { size: 10 }),
409
+ /* @__PURE__ */ jsx(Square, { size: 10 }),
699
410
  "\u505C\u6B62"
700
411
  ]
701
412
  }
@@ -707,7 +418,7 @@ function TaskCard({
707
418
  onClick: onDismiss,
708
419
  className: "inline-flex h-6 items-center gap-1 rounded-md border border-[hsl(var(--border))] px-2 text-[11px] hover:bg-[hsl(var(--accent))]",
709
420
  children: [
710
- /* @__PURE__ */ jsx2(EyeOff, { size: 12 }),
421
+ /* @__PURE__ */ jsx(EyeOff, { size: 12 }),
711
422
  "\u9690\u85CF"
712
423
  ]
713
424
  }
@@ -724,7 +435,7 @@ function BackgroundTasksPill({ sessionId }) {
724
435
  const [historyOverride, setHistoryOverride] = useState(null);
725
436
  const [logTask, setLogTask] = useState(null);
726
437
  const [logDialogOpen, setLogDialogOpen] = useState(false);
727
- const { activeTasks, historyTasks, runningCount, attentionCount } = useMemo2(
438
+ const { activeTasks, historyTasks, runningCount, attentionCount } = useMemo(
728
439
  () => splitTasks(tasks, dismissed),
729
440
  [tasks, dismissed]
730
441
  );
@@ -758,7 +469,6 @@ function BackgroundTasksPill({ sessionId }) {
758
469
  title,
759
470
  output: "",
760
471
  loading: false,
761
- // 跟丢或过期的任务,控制目录可能已经被回收,报错串对用户没有意义。
762
472
  error: "\u65E5\u5FD7\u5DF2\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u53EF\u80FD\u5DF2\u88AB\u6E05\u7406"
763
473
  });
764
474
  }
@@ -771,7 +481,7 @@ function BackgroundTasksPill({ sessionId }) {
771
481
  closePanel();
772
482
  };
773
483
  return /* @__PURE__ */ jsxs(Fragment, { children: [
774
- /* @__PURE__ */ jsx2(
484
+ /* @__PURE__ */ jsx(
775
485
  Dialog,
776
486
  {
777
487
  open: logDialogOpen,
@@ -786,10 +496,10 @@ function BackgroundTasksPill({ sessionId }) {
786
496
  children: [
787
497
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-[hsl(var(--border))] px-4 py-3", children: [
788
498
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
789
- /* @__PURE__ */ jsx2(DialogTitle, { className: "truncate text-sm font-medium text-[hsl(var(--foreground))]", children: logTask?.title }),
790
- /* @__PURE__ */ jsx2("div", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: "\u540E\u53F0\u4EFB\u52A1\u65E5\u5FD7" })
499
+ /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm font-medium text-[hsl(var(--foreground))]", children: logTask?.title }),
500
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: "\u540E\u53F0\u4EFB\u52A1\u65E5\u5FD7" })
791
501
  ] }),
792
- /* @__PURE__ */ jsx2(
502
+ /* @__PURE__ */ jsx(
793
503
  "button",
794
504
  {
795
505
  type: "button",
@@ -799,7 +509,7 @@ function BackgroundTasksPill({ sessionId }) {
799
509
  }
800
510
  )
801
511
  ] }),
802
- /* @__PURE__ */ jsx2("pre", { className: "min-h-64 flex-1 overflow-auto whitespace-pre-wrap p-4 font-mono text-xs leading-5 text-[hsl(var(--foreground))]", children: logTask?.loading ? "\u52A0\u8F7D\u4E2D..." : logTask?.error || logTask?.output })
512
+ /* @__PURE__ */ jsx("pre", { className: "min-h-64 flex-1 overflow-auto whitespace-pre-wrap p-4 font-mono text-xs leading-5 text-[hsl(var(--foreground))]", children: logTask?.loading ? "\u52A0\u8F7D\u4E2D..." : logTask?.error || logTask?.output })
803
513
  ]
804
514
  }
805
515
  )
@@ -821,8 +531,8 @@ function BackgroundTasksPill({ sessionId }) {
821
531
  title: summary,
822
532
  className: "relative flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
823
533
  children: [
824
- /* @__PURE__ */ jsx2(Terminal, { size: 16 }),
825
- runningCount > 0 ? /* @__PURE__ */ jsx2("span", { className: "absolute right-1 top-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-[hsl(var(--muted))] px-1 text-[9px] font-medium leading-none text-[hsl(var(--muted-foreground))]", children: runningCount }) : attentionCount > 0 ? /* @__PURE__ */ jsx2(
534
+ /* @__PURE__ */ jsx(Terminal, { size: 16 }),
535
+ runningCount > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute right-1 top-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-[hsl(var(--muted))] px-1 text-[9px] font-medium leading-none text-[hsl(var(--muted-foreground))]", children: runningCount }) : attentionCount > 0 ? /* @__PURE__ */ jsx(
826
536
  "span",
827
537
  {
828
538
  "data-attention-dot": "true",
@@ -832,64 +542,59 @@ function BackgroundTasksPill({ sessionId }) {
832
542
  ]
833
543
  }
834
544
  ),
835
- open ? (
836
- // before 那层透明桥接盖住浮层和按钮之间 mb-2 的空隙:没有它,鼠标从按钮
837
- // 移向浮层会先穿过一段"两者都不在"的空白,onMouseLeave 立刻收起浮层,
838
- // 里面的日志/停止按钮根本点不到。
839
- /* @__PURE__ */ jsx2("div", { className: "absolute bottom-full left-0 z-40 mb-2 w-[min(24rem,calc(100vw-2rem))] rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-2 text-xs text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)] before:absolute before:inset-x-0 before:top-full before:h-2 before:content-['']", children: /* @__PURE__ */ jsxs("div", { className: "max-h-72 space-y-2 overflow-y-auto", children: [
840
- activeTasks.map((task) => /* @__PURE__ */ jsx2(
841
- TaskCard,
842
- {
843
- task,
844
- onOpenLog: () => void openTaskLog(task),
845
- onStop: () => requestStopTask(task),
846
- onDismiss: ATTENTION_STATUSES.has(task.status) ? () => hideTask(task.id) : null
847
- },
848
- task.id
849
- )),
850
- historyTasks.length > 0 ? /* @__PURE__ */ jsxs(
851
- "div",
852
- {
853
- className: cn(
854
- activeTasks.length > 0 && "border-t border-[hsl(var(--border))] pt-2"
545
+ open ? /* @__PURE__ */ jsx("div", { className: "absolute bottom-full left-0 z-40 mb-2 w-[min(24rem,calc(100vw-2rem))] rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-2 text-xs text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)] before:absolute before:inset-x-0 before:top-full before:h-2 before:content-['']", children: /* @__PURE__ */ jsxs("div", { className: "max-h-72 space-y-2 overflow-y-auto", children: [
546
+ activeTasks.map((task) => /* @__PURE__ */ jsx(
547
+ TaskCard,
548
+ {
549
+ task,
550
+ onOpenLog: () => void openTaskLog(task),
551
+ onStop: () => requestStopTask(task),
552
+ onDismiss: ATTENTION_STATUSES.has(task.status) ? () => hideTask(task.id) : null
553
+ },
554
+ task.id
555
+ )),
556
+ historyTasks.length > 0 ? /* @__PURE__ */ jsxs(
557
+ "div",
558
+ {
559
+ className: cn(
560
+ activeTasks.length > 0 && "border-t border-[hsl(var(--border))] pt-2"
561
+ ),
562
+ children: [
563
+ /* @__PURE__ */ jsxs(
564
+ "button",
565
+ {
566
+ type: "button",
567
+ onClick: () => setHistoryOverride(!historyOpen),
568
+ "aria-expanded": historyOpen,
569
+ className: "flex w-full items-center gap-1 px-1 py-1 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
570
+ children: [
571
+ /* @__PURE__ */ jsx(
572
+ ChevronDown,
573
+ {
574
+ size: 12,
575
+ className: cn("transition-transform", historyOpen ? "" : "-rotate-90")
576
+ }
577
+ ),
578
+ "\u5386\u53F2\u540E\u53F0\u4EFB\u52A1\uFF08",
579
+ historyTasks.length,
580
+ "\uFF09"
581
+ ]
582
+ }
855
583
  ),
856
- children: [
857
- /* @__PURE__ */ jsxs(
858
- "button",
859
- {
860
- type: "button",
861
- onClick: () => setHistoryOverride(!historyOpen),
862
- "aria-expanded": historyOpen,
863
- className: "flex w-full items-center gap-1 px-1 py-1 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
864
- children: [
865
- /* @__PURE__ */ jsx2(
866
- ChevronDown,
867
- {
868
- size: 12,
869
- className: cn("transition-transform", historyOpen ? "" : "-rotate-90")
870
- }
871
- ),
872
- "\u5386\u53F2\u540E\u53F0\u4EFB\u52A1\uFF08",
873
- historyTasks.length,
874
- "\uFF09"
875
- ]
876
- }
877
- ),
878
- historyOpen ? /* @__PURE__ */ jsx2("div", { className: "mt-2 space-y-2", children: historyTasks.map((task) => /* @__PURE__ */ jsx2(
879
- TaskCard,
880
- {
881
- task,
882
- onOpenLog: () => void openTaskLog(task),
883
- onStop: () => requestStopTask(task),
884
- onDismiss: null
885
- },
886
- task.id
887
- )) }) : null
888
- ]
889
- }
890
- ) : null
891
- ] }) })
892
- ) : null
584
+ historyOpen ? /* @__PURE__ */ jsx("div", { className: "mt-2 space-y-2", children: historyTasks.map((task) => /* @__PURE__ */ jsx(
585
+ TaskCard,
586
+ {
587
+ task,
588
+ onOpenLog: () => void openTaskLog(task),
589
+ onStop: () => requestStopTask(task),
590
+ onDismiss: null
591
+ },
592
+ task.id
593
+ )) }) : null
594
+ ]
595
+ }
596
+ ) : null
597
+ ] }) }) : null
893
598
  ]
894
599
  }
895
600
  )
@@ -12254,7 +11959,7 @@ function resolveSelection(view, doc3, parsedSel) {
12254
11959
  }
12255
11960
  function isMarkChange(cur, prev) {
12256
11961
  let curMarks = cur.firstChild.marks, prevMarks = prev.firstChild.marks;
12257
- let added = curMarks, removed = prevMarks, type, mark, update2;
11962
+ let added = curMarks, removed = prevMarks, type, mark, update;
12258
11963
  for (let i = 0; i < prevMarks.length; i++)
12259
11964
  added = prevMarks[i].removeFromSet(added);
12260
11965
  for (let i = 0; i < curMarks.length; i++)
@@ -12262,17 +11967,17 @@ function isMarkChange(cur, prev) {
12262
11967
  if (added.length == 1 && removed.length == 0) {
12263
11968
  mark = added[0];
12264
11969
  type = "add";
12265
- update2 = (node) => node.mark(mark.addToSet(node.marks));
11970
+ update = (node) => node.mark(mark.addToSet(node.marks));
12266
11971
  } else if (added.length == 0 && removed.length == 1) {
12267
11972
  mark = removed[0];
12268
11973
  type = "remove";
12269
- update2 = (node) => node.mark(mark.removeFromSet(node.marks));
11974
+ update = (node) => node.mark(mark.removeFromSet(node.marks));
12270
11975
  } else {
12271
11976
  return null;
12272
11977
  }
12273
11978
  let updated = [];
12274
11979
  for (let i = 0; i < prev.childCount; i++)
12275
- updated.push(update2(prev.child(i)));
11980
+ updated.push(update(prev.child(i)));
12276
11981
  if (Fragment2.from(updated).eq(cur))
12277
11982
  return { mark, type };
12278
11983
  }
@@ -18948,7 +18653,7 @@ var PluginMention = index_default.extend({
18948
18653
  });
18949
18654
 
18950
18655
  // src/rich-input/lib/composer-content.ts
18951
- import { normalizePluginRefs, normalizeTopicAssetRefs } from "@blade-hq/agent-client";
18656
+ import { normalizePluginRefs, normalizeMessageRefs, normalizeTopicAssetRefs } from "@blade-hq/agent-client";
18952
18657
  function serializeEditorContent(node) {
18953
18658
  if (!node) return "";
18954
18659
  if (node.type === "text") {
@@ -18963,11 +18668,7 @@ function serializeEditorContent(node) {
18963
18668
  }
18964
18669
  if (node.type === "skillMention") {
18965
18670
  const skillId = typeof node.attrs?.skillId === "string" ? node.attrs.skillId : "";
18966
- return skillId ? `<skill>${skillId}</skill>` : "";
18967
- }
18968
- if (node.type === "workflowMention") {
18969
- const name = typeof node.attrs?.name === "string" ? node.attrs.name : "";
18970
- return name ? `\u8FD0\u884C\u5DE5\u4F5C\u6D41 ${name}` : "";
18671
+ return skillId ? `@${node.attrs?.displayName || skillId}` : "";
18971
18672
  }
18972
18673
  if (node.type === "pluginMention") return `@${node.attrs?.label ?? ""}`;
18973
18674
  if (node.type === "topicAssetMention") {
@@ -18987,7 +18688,7 @@ function scanLeadingSkillMention(node, seenContent) {
18987
18688
  if (node.type === "text") {
18988
18689
  return { skill: null, seenContent: seenContent || /\S/.test(node.text ?? "") };
18989
18690
  }
18990
- if (node.type === "hardBreak" || node.type === "fileMention" || node.type === "workflowMention") {
18691
+ if (node.type === "hardBreak" || node.type === "fileMention") {
18991
18692
  return { skill: null, seenContent: true };
18992
18693
  }
18993
18694
  if (node.type === "pluginMention") return { skill: null, seenContent };
@@ -19069,6 +18770,27 @@ function collectPluginMentions(node) {
19069
18770
  function buildEditorDocument(text) {
19070
18771
  return { type: "doc", content: text.split("\n").map((line) => ({ type: "paragraph", content: line ? [{ type: "text", text: line }] : [] })) };
19071
18772
  }
18773
+ function collectMessageMentions(node) {
18774
+ const refs = [];
18775
+ const visit = (current) => {
18776
+ if (!current) return;
18777
+ if (current.type === "pluginMention") refs.push(current.attrs);
18778
+ if (current.type === "skillMention") refs.push({
18779
+ provider: "skill",
18780
+ id: current.attrs?.skillId,
18781
+ label: current.attrs?.displayName || current.attrs?.skillId
18782
+ });
18783
+ current.content?.forEach(visit);
18784
+ };
18785
+ visit(node);
18786
+ return normalizeMessageRefs(refs);
18787
+ }
18788
+ function buildPluginSelectionDocument(refs) {
18789
+ return { type: "doc", content: [{ type: "paragraph", content: normalizePluginRefs(refs).flatMap((ref) => [
18790
+ { type: "pluginMention", attrs: { ...ref } },
18791
+ { type: "text", text: " " }
18792
+ ]) }] };
18793
+ }
19072
18794
 
19073
18795
  // src/rich-input/extensions/topic-asset-mention.ts
19074
18796
  function isTopicAssetSuggestionItem(value) {
@@ -19092,7 +18814,7 @@ var TopicAssetMention = index_default.extend({
19092
18814
  class: "file-mention-pill topic-asset-mention-pill",
19093
18815
  "data-topic-id": node.attrs.topic_id,
19094
18816
  "data-path": node.attrs.path,
19095
- title: `\u4E3B\u9898\u8D44\u4EA7\uFF1A${node.attrs.path}`
18817
+ title: `\u5DE5\u4F5C\u7A7A\u95F4\u8D44\u4EA7\uFF1A${node.attrs.path}`
19096
18818
  }, `@${node.attrs.path}`]
19097
18819
  };
19098
18820
  },
@@ -19109,7 +18831,7 @@ var TopicAssetMention = index_default.extend({
19109
18831
 
19110
18832
  // src/chat/runtime/composer-channels.ts
19111
18833
  import { normalizeTopicAssetRefs as normalizeTopicAssetRefs2 } from "@blade-hq/agent-client";
19112
- import { useSyncExternalStore as useSyncExternalStore3 } from "react";
18834
+ import { useSyncExternalStore as useSyncExternalStore2 } from "react";
19113
18835
  function buildSignalId() {
19114
18836
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
19115
18837
  return crypto.randomUUID();
@@ -19131,8 +18853,8 @@ var state2 = {
19131
18853
  rewindDrafts: {}
19132
18854
  };
19133
18855
  var listeners2 = /* @__PURE__ */ new Set();
19134
- function setState(update2) {
19135
- const next = update2(state2);
18856
+ function setState(update) {
18857
+ const next = update(state2);
19136
18858
  if (next === state2) return;
19137
18859
  state2 = next;
19138
18860
  for (const listener of [...listeners2]) listener();
@@ -19217,13 +18939,11 @@ var composerChannels = {
19217
18939
  clearModelDraft(sessionId) {
19218
18940
  setState((current) => ({ ...current, modelDrafts: withoutKey(current.modelDrafts, sessionId) }));
19219
18941
  },
19220
- /** 回退到某一步后,把那一步的用户原话放回输入框(null 清除)。 */
19221
18942
  setRewindDraft(sessionId, text) {
19222
18943
  setState(
19223
18944
  (current) => text === null ? { ...current, rewindDrafts: withoutKey(current.rewindDrafts, sessionId) } : { ...current, rewindDrafts: { ...current.rewindDrafts, [sessionId]: text } }
19224
18945
  );
19225
18946
  },
19226
- /** 会话被关闭 / 删除:清掉它还没被取走的信号。 */
19227
18947
  clearSession(sessionId) {
19228
18948
  setState((current) => ({
19229
18949
  ...current,
@@ -19233,13 +18953,12 @@ var composerChannels = {
19233
18953
  sendRequests: withoutKey(current.sendRequests, sessionId)
19234
18954
  }));
19235
18955
  },
19236
- /** 换身份:清空全部通道。 */
19237
18956
  reset() {
19238
18957
  setState(() => ({ topicAssetReferences: {}, pendingContexts: {}, draftAppends: {}, sendRequests: {}, modelDrafts: {}, rewindDrafts: {} }));
19239
18958
  }
19240
18959
  };
19241
18960
  function useComposerChannels(selector) {
19242
- return useSyncExternalStore3(
18961
+ return useSyncExternalStore2(
19243
18962
  composerChannels.subscribe,
19244
18963
  () => selector(state2),
19245
18964
  () => selector(state2)
@@ -19253,7 +18972,7 @@ async function getTopicAssetSuggestionItems(client, topicId, query) {
19253
18972
  const result = await client.chatGroups.listAssets(topicId);
19254
18973
  return result.items.filter((asset) => !asset.is_dir && asset.path.toLowerCase().includes(query.toLowerCase())).map((asset) => ({ kind: "topicAsset", topic_id: topicId, path: asset.path, name: asset.path }));
19255
18974
  } catch {
19256
- return [{ kind: "topicAssetError", message: "\u4E3B\u9898\u8D44\u4EA7\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165 @ \u91CD\u8BD5" }];
18975
+ return [{ kind: "topicAssetError", message: "\u5DE5\u4F5C\u7A7A\u95F4\u8D44\u4EA7\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165 @ \u91CD\u8BD5" }];
19257
18976
  }
19258
18977
  }
19259
18978
  function queueTopicAssetReference(sessionId, ref) {
@@ -19261,22 +18980,9 @@ function queueTopicAssetReference(sessionId, ref) {
19261
18980
  }
19262
18981
 
19263
18982
  // src/rich-input/use-dismiss-skill-suggestions-on-mode-change.ts
19264
- import { useEffect as useEffect3, useRef as useRef3 } from "react";
18983
+ import { useEffect, useRef } from "react";
19265
18984
 
19266
18985
  // src/rich-input/extensions/skill-mention.ts
19267
- function workflowParamsTail(item) {
19268
- const params = (item.inputs ?? []).filter((p) => p.name);
19269
- if (params.length === 0) return " ";
19270
- const filled = params.map((p) => {
19271
- const hasDefault = p.default !== void 0 && p.default !== null;
19272
- const value = hasDefault ? typeof p.default === "string" ? p.default : JSON.stringify(p.default) : `<${p.description || "\u586B\u503C"}>`;
19273
- return `${p.name}=${value}`;
19274
- }).join(" ");
19275
- return ` ${filled} `;
19276
- }
19277
- function workflowRunText(item) {
19278
- return `\u8FD0\u884C\u5DE5\u4F5C\u6D41 ${item.name}${workflowParamsTail(item)}`.trimEnd();
19279
- }
19280
18986
  var skillMentionSuggestionKey = new PluginKey("skillMentionSuggestion");
19281
18987
  function getSkillMentionName(attrs) {
19282
18988
  return attrs.displayName || attrs.skillId || "";
@@ -19358,8 +19064,8 @@ var SkillMention = index_default.extend({
19358
19064
  // src/rich-input/use-dismiss-skill-suggestions-on-mode-change.ts
19359
19065
  function useDismissSkillSuggestionsOnModeChange(editor) {
19360
19066
  const renderMode = useChatRenderMode();
19361
- const previousRef = useRef3(renderMode);
19362
- useEffect3(() => {
19067
+ const previousRef = useRef(renderMode);
19068
+ useEffect(() => {
19363
19069
  if (previousRef.current === renderMode) return;
19364
19070
  previousRef.current = renderMode;
19365
19071
  if (editor && !editor.isDestroyed && skillMentionSuggestionKey.getState(editor.state)?.active) {
@@ -19370,12 +19076,12 @@ function useDismissSkillSuggestionsOnModeChange(editor) {
19370
19076
 
19371
19077
  // ../../node_modules/.pnpm/@tiptap+react@3.20.4_@floating-ui+dom@1.7.6_@tiptap+core@3.20.4_@tiptap+pm@3.20.4__@tip_1ce9f35538141630e675758ebf46eb2f/node_modules/@tiptap/react/dist/index.js
19372
19078
  var import_shim = __toESM(require_shim(), 1);
19373
- import { createContext as createContext2, useContext as useContext2, useMemo as useMemo3 } from "react";
19079
+ import { createContext, useContext, useMemo as useMemo2 } from "react";
19374
19080
  import React, { forwardRef } from "react";
19375
19081
  import ReactDOM from "react-dom";
19376
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
19082
+ import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
19377
19083
  var import_shim2 = __toESM(require_shim(), 1);
19378
- import { useDebugValue as useDebugValue2, useEffect as useEffect22, useRef as useRef4, useState as useState2 } from "react";
19084
+ import { useDebugValue as useDebugValue2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
19379
19085
 
19380
19086
  // ../../node_modules/.pnpm/fast-equals@5.4.0/node_modules/fast-equals/dist/es/index.mjs
19381
19087
  var { getOwnPropertyNames, getOwnPropertySymbols } = Object;
@@ -19817,10 +19523,10 @@ function createCustomEqual(options = {}) {
19817
19523
 
19818
19524
  // ../../node_modules/.pnpm/@tiptap+react@3.20.4_@floating-ui+dom@1.7.6_@tiptap+core@3.20.4_@tiptap+pm@3.20.4__@tip_1ce9f35538141630e675758ebf46eb2f/node_modules/@tiptap/react/dist/index.js
19819
19525
  var import_with_selector = __toESM(require_with_selector(), 1);
19820
- import { useDebugValue, useEffect as useEffect4, useLayoutEffect, useState as useState3 } from "react";
19526
+ import { useDebugValue, useEffect as useEffect3, useLayoutEffect, useState as useState3 } from "react";
19821
19527
  import { jsx as jsx22, jsxs as jsxs22 } from "react/jsx-runtime";
19822
- import { createContext as createContext22, createElement, useContext as useContext22 } from "react";
19823
- import { jsx as jsx32 } from "react/jsx-runtime";
19528
+ import { createContext as createContext2, createElement, useContext as useContext2 } from "react";
19529
+ import { jsx as jsx3 } from "react/jsx-runtime";
19824
19530
  import React3 from "react";
19825
19531
  import { jsx as jsx4 } from "react/jsx-runtime";
19826
19532
  import React4 from "react";
@@ -19850,7 +19556,7 @@ var Portals = ({ contentComponent }) => {
19850
19556
  contentComponent.getSnapshot,
19851
19557
  contentComponent.getServerSnapshot
19852
19558
  );
19853
- return /* @__PURE__ */ jsx3(Fragment3, { children: Object.values(renderers) });
19559
+ return /* @__PURE__ */ jsx2(Fragment3, { children: Object.values(renderers) });
19854
19560
  };
19855
19561
  function getInstance() {
19856
19562
  const subscribers = /* @__PURE__ */ new Set();
@@ -19971,8 +19677,8 @@ var PureEditorContent = class extends React.Component {
19971
19677
  render() {
19972
19678
  const { editor, innerRef, ...rest } = this.props;
19973
19679
  return /* @__PURE__ */ jsxs2(Fragment3, { children: [
19974
- /* @__PURE__ */ jsx3("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
19975
- (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ jsx3(Portals, { contentComponent: editor.contentComponent })
19680
+ /* @__PURE__ */ jsx2("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
19681
+ (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ jsx2(Portals, { contentComponent: editor.contentComponent })
19976
19682
  ] });
19977
19683
  }
19978
19684
  };
@@ -19989,7 +19695,7 @@ var EditorContentWithKey = forwardRef(
19989
19695
  }
19990
19696
  );
19991
19697
  var EditorContent = React.memo(EditorContentWithKey);
19992
- var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect4;
19698
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect3;
19993
19699
  var EditorStateManager = class {
19994
19700
  constructor(initialEditor) {
19995
19701
  this.transactionNumber = 0;
@@ -20297,7 +20003,7 @@ var EditorInstanceManager = class _EditorInstanceManager {
20297
20003
  }
20298
20004
  };
20299
20005
  function useEditor(options = {}, deps = []) {
20300
- const mostRecentOptions = useRef4(options);
20006
+ const mostRecentOptions = useRef2(options);
20301
20007
  mostRecentOptions.current = options;
20302
20008
  const [instanceManager] = useState2(() => new EditorInstanceManager(mostRecentOptions));
20303
20009
  const editor = (0, import_shim2.useSyncExternalStore)(
@@ -20306,7 +20012,7 @@ function useEditor(options = {}, deps = []) {
20306
20012
  instanceManager.getServerSnapshot
20307
20013
  );
20308
20014
  useDebugValue2(editor);
20309
- useEffect22(instanceManager.onRender(deps));
20015
+ useEffect2(instanceManager.onRender(deps));
20310
20016
  useEditorState({
20311
20017
  editor,
20312
20018
  selector: ({ transactionNumber }) => {
@@ -20321,18 +20027,18 @@ function useEditor(options = {}, deps = []) {
20321
20027
  });
20322
20028
  return editor;
20323
20029
  }
20324
- var EditorContext = createContext2({
20030
+ var EditorContext = createContext({
20325
20031
  editor: null
20326
20032
  });
20327
20033
  var EditorConsumer = EditorContext.Consumer;
20328
- var ReactNodeViewContext = createContext22({
20034
+ var ReactNodeViewContext = createContext2({
20329
20035
  onDragStart: () => {
20330
20036
  },
20331
20037
  nodeViewContentChildren: void 0,
20332
20038
  nodeViewContentRef: () => {
20333
20039
  }
20334
20040
  });
20335
- var useReactNodeView = () => useContext22(ReactNodeViewContext);
20041
+ var useReactNodeView = () => useContext2(ReactNodeViewContext);
20336
20042
  var NodeViewWrapper = React3.forwardRef((props, ref) => {
20337
20043
  const { onDragStart } = useReactNodeView();
20338
20044
  const Tag = props.as || "div";
@@ -25395,8 +25101,8 @@ var index_default2 = StarterKit;
25395
25101
 
25396
25102
  // src/rich-input/ChatInput.tsx
25397
25103
  import {
25398
- useEffect as useEffect9,
25399
- useRef as useRef9,
25104
+ useEffect as useEffect8,
25105
+ useRef as useRef7,
25400
25106
  useState as useState11
25401
25107
  } from "react";
25402
25108
  import { createRoot } from "react-dom/client";
@@ -25411,7 +25117,7 @@ function skillDisplayName(skill) {
25411
25117
  }
25412
25118
 
25413
25119
  // src/rich-input/voice/use-tiptap-voice-input.ts
25414
- import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef5 } from "react";
25120
+ import { useCallback, useEffect as useEffect4, useRef as useRef3 } from "react";
25415
25121
  var IDLE_VOICE = {
25416
25122
  status: "idle",
25417
25123
  error: null,
@@ -25427,8 +25133,8 @@ function useNoVoiceInput() {
25427
25133
  function useTiptapVoiceInput(options) {
25428
25134
  const { editorRef, workletUrl, onError } = options;
25429
25135
  const useVoiceInput2 = options.useVoiceInput ?? useNoVoiceInput;
25430
- const partialRangeRef = useRef5(null);
25431
- const lastPartialLenRef = useRef5(0);
25136
+ const partialRangeRef = useRef3(null);
25137
+ const lastPartialLenRef = useRef3(0);
25432
25138
  const handlePartial = useEffectEvent((text) => {
25433
25139
  const ed = editorRef.current;
25434
25140
  if (!ed) return;
@@ -25478,18 +25184,18 @@ function useTiptapVoiceInput(options) {
25478
25184
  onError: handleError
25479
25185
  });
25480
25186
  const isRecording = voice.status === "recording";
25481
- useEffect5(() => {
25187
+ useEffect4(() => {
25482
25188
  const ed = editorRef.current;
25483
25189
  if (!ed) return;
25484
25190
  ed.setEditable(!isRecording);
25485
25191
  }, [isRecording, editorRef]);
25486
- useEffect5(() => {
25192
+ useEffect4(() => {
25487
25193
  if (voice.status === "idle" || voice.status === "error") {
25488
25194
  partialRangeRef.current = null;
25489
25195
  lastPartialLenRef.current = 0;
25490
25196
  }
25491
25197
  }, [voice.status]);
25492
- const toggle = useCallback2(() => {
25198
+ const toggle = useCallback(() => {
25493
25199
  if (voice.status === "recording" || voice.status === "starting") {
25494
25200
  void voice.stop();
25495
25201
  } else {
@@ -25546,7 +25252,7 @@ function VoiceWaveform({ level, color = "currentColor", size = 16 }) {
25546
25252
  }
25547
25253
 
25548
25254
  // src/rich-input/model/resolve-model.ts
25549
- import { useMemo as useMemo4 } from "react";
25255
+ import { useMemo as useMemo3 } from "react";
25550
25256
  var MODEL_LOADING_SEND_HINT = "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u914D\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001";
25551
25257
  function gateSendWhileModelLoading(isModelLoading, hasContent) {
25552
25258
  if (!isModelLoading) return { blocked: false };
@@ -25615,7 +25321,7 @@ function resolveModelChoice({
25615
25321
  function useResolvedModel(activeSessionModel) {
25616
25322
  const { models, defaultModel, thinkingAvailable, isLoading, unavailableProviderIds, unavailableModelIds } = useModelCatalog();
25617
25323
  const { preferredModel } = useModelPreferences();
25618
- const resolved = useMemo4(() => {
25324
+ const resolved = useMemo3(() => {
25619
25325
  return resolveModelChoice({
25620
25326
  activeSessionModel,
25621
25327
  preferredModel,
@@ -25635,9 +25341,6 @@ function useResolvedModel(activeSessionModel) {
25635
25341
  reasoningLevels: selectedModel?.reasoningLevels ?? [],
25636
25342
  defaultReasoningLevel: selectedModel?.defaultReasoningLevel ?? "",
25637
25343
  modelAvailabilityMessage,
25638
- // Undefined means the catalog is still loading or the model does not
25639
- // publish this optional capability. In either case keep existing upload
25640
- // behavior until the server has explicitly said images are unsupported.
25641
25344
  supportsImage: selectedModel?.supportsImage ?? selectedModel?.inputModalities?.includes("image")
25642
25345
  };
25643
25346
  }
@@ -25652,17 +25355,21 @@ function useReasoningLevelPreference(modelId) {
25652
25355
  }
25653
25356
 
25654
25357
  // src/rich-input/model/use-composer-model.ts
25655
- import { useEffect as useEffect6, useRef as useRef6, useState as useState4 } from "react";
25358
+ import { useEffect as useEffect5, useRef as useRef4, useState as useState4 } from "react";
25656
25359
  function useInjectedSessionModel(sessionId) {
25657
25360
  return useChatSessionDetail(sessionId)?.model ?? null;
25658
25361
  }
25659
25362
  function useComposerModel(activeSessionId) {
25660
25363
  const [newSessionModelSelection, setNewSessionModelSelection] = useState4(null);
25661
- const newSessionModelSelectionRef = useRef6(null);
25364
+ const newSessionModelSelectionRef = useRef4(null);
25662
25365
  const { setPreferredModel } = useModelPreferences();
25663
25366
  const { models: modelCatalog } = useModelCatalog();
25664
25367
  const useSessionModel = useChatEnvironment().useSessionDetail ? useInjectedSessionModel : useClientSessionModel;
25665
25368
  const activeSessionModel = useSessionModel(activeSessionId);
25369
+ const session = useSessionHandle(activeSessionId);
25370
+ const source = useSessionSource();
25371
+ const [selectingSession, setSelectingSession] = useState4(null);
25372
+ const selectingRef = useRef4(null);
25666
25373
  const sharedModelDraft = useComposerChannels(
25667
25374
  (state3) => activeSessionId ? state3.modelDrafts[activeSessionId] : void 0
25668
25375
  );
@@ -25677,18 +25384,18 @@ function useComposerModel(activeSessionId) {
25677
25384
  isLoading
25678
25385
  } = useResolvedModel(resolveComposerModel(activeSessionId, activeSessionModel, explicitModelSelection));
25679
25386
  const { reasoningLevelPreference, setReasoningLevelPreference } = useReasoningLevelPreference(selectedModel);
25680
- useEffect6(() => {
25387
+ useEffect5(() => {
25681
25388
  if (!activeSessionId || !newSessionModelSelectionRef.current) return;
25682
25389
  newSessionModelSelectionRef.current = null;
25683
25390
  setNewSessionModelSelection(null);
25684
25391
  }, [activeSessionId]);
25685
- useEffect6(() => {
25392
+ useEffect5(() => {
25686
25393
  if (!activeSessionId || !sharedModelDraft || isLoading || modelCatalog.length === 0) return;
25687
25394
  if (!modelCatalog.some((model) => model.id === sharedModelDraft)) {
25688
25395
  composerChannels.clearModelDraft(activeSessionId);
25689
25396
  }
25690
25397
  }, [activeSessionId, sharedModelDraft, isLoading, modelCatalog]);
25691
- useEffect6(() => {
25398
+ useEffect5(() => {
25692
25399
  if (!activeSessionId || sharedModelDraft !== activeSessionModel) return;
25693
25400
  composerChannels.clearModelDraft(activeSessionId);
25694
25401
  }, [activeSessionId, activeSessionModel, sharedModelDraft]);
@@ -25696,7 +25403,7 @@ function useComposerModel(activeSessionId) {
25696
25403
  return {
25697
25404
  selectedModel,
25698
25405
  hasAvailableModel,
25699
- isLoading,
25406
+ isLoading: isLoading || !!activeSessionId && (selectingSession === activeSessionId || !session),
25700
25407
  availabilityMessage: modelAvailabilityMessage,
25701
25408
  thinkingAvailable,
25702
25409
  reasoningLevels,
@@ -25704,7 +25411,22 @@ function useComposerModel(activeSessionId) {
25704
25411
  setReasoningLevel: setReasoningLevelPreference,
25705
25412
  selectModel(model) {
25706
25413
  if (activeSessionId) {
25414
+ if (selectingRef.current === activeSessionId) return;
25415
+ selectingRef.current = activeSessionId;
25416
+ setSelectingSession(activeSessionId);
25707
25417
  composerChannels.setModelDraft(activeSessionId, model);
25418
+ const select = (ready) => ready.selectModel(model);
25419
+ const pending = source.whenReady ? source.whenReady(activeSessionId, select) : session ? select(session) : Promise.resolve(false);
25420
+ void pending.catch(() => false).then((ok) => {
25421
+ if (!ok && composerChannels.getState().modelDrafts[activeSessionId] === model) {
25422
+ composerChannels.clearModelDraft(activeSessionId);
25423
+ }
25424
+ }).finally(() => {
25425
+ if (selectingRef.current === activeSessionId) {
25426
+ selectingRef.current = null;
25427
+ setSelectingSession(null);
25428
+ }
25429
+ });
25708
25430
  } else {
25709
25431
  const selection = { sessionId: activeSessionId, model };
25710
25432
  newSessionModelSelectionRef.current = selection;
@@ -25768,7 +25490,7 @@ function PopoverContent({
25768
25490
  }
25769
25491
 
25770
25492
  // src/rich-input/ModelSelector.tsx
25771
- import { useMemo as useMemo5, useState as useState5 } from "react";
25493
+ import { useMemo as useMemo4, useState as useState5 } from "react";
25772
25494
  import { jsx as jsx12, jsxs as jsxs3 } from "react/jsx-runtime";
25773
25495
  var inputModalityLabels = {
25774
25496
  text: "\u6587\u672C",
@@ -25810,7 +25532,7 @@ function ModelSelector({
25810
25532
  }
25811
25533
  void refresh();
25812
25534
  }
25813
- const filteredModels = useMemo5(() => {
25535
+ const filteredModels = useMemo4(() => {
25814
25536
  const normalized = query.trim().toLowerCase();
25815
25537
  if (!normalized) return models;
25816
25538
  return models.filter(
@@ -25837,10 +25559,7 @@ function ModelSelector({
25837
25559
  className: `flex min-w-0 items-center gap-1 rounded-lg py-[5px] text-muted-foreground ${compact ? "ml-auto px-1.5" : "px-2.5"}`,
25838
25560
  title: selectorTitle,
25839
25561
  children: [
25840
- isLoading ? /* @__PURE__ */ jsx12(LoaderCircle, { size: 14, className: "animate-spin", "aria-hidden": "true" }) : compact ? null : (
25841
- // compact 用于「+」菜单的「模型」行,行首已有图标,触发器内不再重复。
25842
- /* @__PURE__ */ jsx12(Sparkles, { size: 14, "aria-hidden": "true" })
25843
- ),
25562
+ isLoading ? /* @__PURE__ */ jsx12(LoaderCircle, { size: 14, className: "animate-spin", "aria-hidden": "true" }) : compact ? null : /* @__PURE__ */ jsx12(Sparkles, { size: 14, "aria-hidden": "true" }),
25844
25563
  /* @__PURE__ */ jsx12(
25845
25564
  "span",
25846
25565
  {
@@ -25946,7 +25665,7 @@ function ModelSelector({
25946
25665
  }
25947
25666
 
25948
25667
  // src/rich-input/SkillStatusBar.tsx
25949
- import { useMemo as useMemo6 } from "react";
25668
+ import { useMemo as useMemo5 } from "react";
25950
25669
 
25951
25670
  // src/chat/lib/skill-visibility.ts
25952
25671
  function visibleSkills(skills, mode) {
@@ -26124,7 +25843,7 @@ function SkillStatusBar({
26124
25843
  const { status: connectionStatus, reconnectAttempt, hasEverConnected } = useComposerConnectionInfo(sessionId);
26125
25844
  const statsReady = !loading && !error;
26126
25845
  const skillStoreConnected = statsReady && skillStats.remote_connected;
26127
- const connectionMeta = useMemo6(
25846
+ const connectionMeta = useMemo5(
26128
25847
  () => getConnectionMeta(
26129
25848
  connectionStatus,
26130
25849
  reconnectAttempt,
@@ -26144,7 +25863,8 @@ function SkillStatusBar({
26144
25863
  text: skillStoreConnected ? `\u5DF2\u5B89\u88C5 ${skillStats.installed_skill_count} \u4E2A\u6280\u80FD` : "\u5C1A\u672A\u767B\u5F55\u6280\u80FD\u5546\u5E97"
26145
25864
  }
26146
25865
  ].filter((item) => item.key !== "total" || skillStats.remote_configured);
26147
- const tokenSummary = useMemo6(() => {
25866
+ const tokenSummary = useMemo5(() => {
25867
+ if (mode !== "developer") return null;
26148
25868
  if (contextStatsLoading || contextStatsError || !contextStats) {
26149
25869
  return {
26150
25870
  detail: /* @__PURE__ */ jsx14("div", { className: "pt-1 text-[hsl(var(--muted-foreground))]", children: "\u4E0A\u4E0B\u6587\u7EDF\u8BA1\u4E0D\u53EF\u7528" }),
@@ -26170,7 +25890,7 @@ function SkillStatusBar({
26170
25890
  label: contextStats.context_window > 0 ? `${formatTokensK(contextStats.tokens_used)} / ${formatTokensK(contextStats.context_window)} \u4F1A\u8BDD\u6D88\u606F\u4F30\u7B97` : `${formatTokensK(contextStats.tokens_used)} \u4F1A\u8BDD\u6D88\u606F\u4F30\u7B97`,
26171
25891
  warn: tokenPressure.level === "critical"
26172
25892
  };
26173
- }, [contextStats, contextStatsError, contextStatsLoading, tokenPressure.level]);
25893
+ }, [mode, contextStats, contextStatsError, contextStatsLoading, tokenPressure.level]);
26174
25894
  const containerClass = vertical ? "text-[11px] text-[hsl(var(--muted-foreground))]" : "bg-[hsl(var(--background))] px-5 pt-2";
26175
25895
  const innerClass = vertical ? "" : "mx-auto max-w-3xl";
26176
25896
  const listClass = vertical ? "flex flex-col items-stretch gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]" : "flex flex-wrap items-center gap-2 text-[10px] text-[hsl(var(--muted-foreground))]";
@@ -26213,20 +25933,16 @@ function SkillStatusBar({
26213
25933
  /* @__PURE__ */ jsx14("span", { className: "mt-1.5 inline-block h-2 w-2 shrink-0 rounded-full border border-[hsl(var(--swf-success))] bg-transparent" }),
26214
25934
  /* @__PURE__ */ jsx14("span", { className: "break-words", children: skillDisplayName(skill) })
26215
25935
  ] }, skill.skill_id)) }) : null }) : null
26216
- ] }) : (
26217
- // 「已安装」是可点的导航:用户看到数字会想去看是哪些技能。
26218
- // 改的是「已加载」那一行就会变成另一个功能,所以只动这一条。
26219
- onOpenSkills ? /* @__PURE__ */ jsx14(
26220
- "button",
26221
- {
26222
- type: "button",
26223
- onClick: onOpenSkills,
26224
- title: "\u67E5\u770B\u5DF2\u5B89\u88C5\u7684\u6280\u80FD",
26225
- className: "cursor-pointer font-mono underline decoration-dotted underline-offset-2 transition-colors hover:text-[hsl(var(--foreground))]",
26226
- children: item.text
26227
- }
26228
- ) : /* @__PURE__ */ jsx14("span", { className: "font-mono", children: item.text })
26229
- )
25936
+ ] }) : onOpenSkills ? /* @__PURE__ */ jsx14(
25937
+ "button",
25938
+ {
25939
+ type: "button",
25940
+ onClick: onOpenSkills,
25941
+ title: "\u67E5\u770B\u5DF2\u5B89\u88C5\u7684\u6280\u80FD",
25942
+ className: "cursor-pointer font-mono underline decoration-dotted underline-offset-2 transition-colors hover:text-[hsl(var(--foreground))]",
25943
+ children: item.text
25944
+ }
25945
+ ) : /* @__PURE__ */ jsx14("span", { className: "font-mono", children: item.text })
26230
25946
  ]
26231
25947
  },
26232
25948
  item.key
@@ -26234,11 +25950,72 @@ function SkillStatusBar({
26234
25950
  ] }) }) });
26235
25951
  }
26236
25952
 
25953
+ // src/rich-input/InputActionSubmenu.tsx
25954
+ import { useSyncExternalStore as useSyncExternalStore4 } from "react";
25955
+ import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
25956
+ var narrowQuery = "(max-width: 639px)";
25957
+ function subscribeToViewport(onChange) {
25958
+ const media = window.matchMedia(narrowQuery);
25959
+ media.addEventListener("change", onChange);
25960
+ return () => media.removeEventListener("change", onChange);
25961
+ }
25962
+ var isNarrowViewport = () => window.matchMedia(narrowQuery).matches;
25963
+ function InputActionSubmenu({ label, icon, open, onOpenChange, children, disabled = false }) {
25964
+ const narrow = useSyncExternalStore4(subscribeToViewport, isNarrowViewport, () => false);
25965
+ return /* @__PURE__ */ jsxs6(dist_exports.Root, { open, onOpenChange, children: [
25966
+ /* @__PURE__ */ jsx15(dist_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
25967
+ "button",
25968
+ {
25969
+ type: "button",
25970
+ disabled,
25971
+ onClick: (event) => {
25972
+ event.preventDefault();
25973
+ onOpenChange(true);
25974
+ },
25975
+ onPointerEnter: (event) => {
25976
+ if (event.pointerType === "mouse" && !disabled) onOpenChange(true);
25977
+ },
25978
+ onKeyDown: (event) => {
25979
+ if (event.key === "ArrowRight") {
25980
+ event.preventDefault();
25981
+ onOpenChange(true);
25982
+ }
25983
+ },
25984
+ className: "flex w-full items-center gap-2 rounded-lg px-3 py-2.5 text-left text-sm text-[hsl(var(--popover-foreground))] outline-none hover:bg-[hsl(var(--accent))] focus-visible:bg-[hsl(var(--accent))] disabled:opacity-50 data-[state=open]:bg-[hsl(var(--accent))]",
25985
+ children: [
25986
+ icon,
25987
+ /* @__PURE__ */ jsx15("span", { children: label }),
25988
+ /* @__PURE__ */ jsx15(ChevronRight, { size: 14, className: "ml-auto", "aria-hidden": "true" })
25989
+ ]
25990
+ }
25991
+ ) }),
25992
+ /* @__PURE__ */ jsx15(dist_exports.Portal, { children: /* @__PURE__ */ jsx15(
25993
+ dist_exports.Content,
25994
+ {
25995
+ side: narrow ? "bottom" : "right",
25996
+ align: "start",
25997
+ sideOffset: 8,
25998
+ collisionPadding: 12,
25999
+ "aria-label": label,
26000
+ onEscapeKeyDown: (event) => event.stopPropagation(),
26001
+ onKeyDown: (event) => {
26002
+ if (event.key === "ArrowLeft" && !(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement)) {
26003
+ event.preventDefault();
26004
+ onOpenChange(false);
26005
+ }
26006
+ },
26007
+ className: "z-50 max-h-[min(70vh,var(--radix-popover-content-available-height))] w-[min(320px,calc(100vw-2rem))] overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-1 text-xs text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)] outline-none",
26008
+ children
26009
+ }
26010
+ ) })
26011
+ ] });
26012
+ }
26013
+
26237
26014
  // src/rich-input/ConnectButton.tsx
26238
26015
  import { useState as useState6 } from "react";
26239
26016
 
26240
26017
  // src/rich-input/lib/skill-suggestions.ts
26241
- var sessionPath2 = (sessionId, rest) => `/api/sessions/${encodeURIComponent(sessionId)}/${rest}`;
26018
+ var sessionPath = (sessionId, rest) => `/api/sessions/${encodeURIComponent(sessionId)}/${rest}`;
26242
26019
  function toItem(skill) {
26243
26020
  return {
26244
26021
  type: "skill",
@@ -26246,9 +26023,8 @@ function toItem(skill) {
26246
26023
  displayName: skill.display_name,
26247
26024
  description: skill.description,
26248
26025
  local: skill.local,
26249
- // 本地技能天然可用。搜索结果带后端算好的安装状态,列表接口没有这个字段
26250
- // 时按 local 推断。
26251
- installed: "installed" in skill ? skill.installed : skill.local
26026
+ installed: "installed" in skill ? skill.installed : skill.local,
26027
+ hasFlow: skill.has_flow === true
26252
26028
  };
26253
26029
  }
26254
26030
  var CACHE_TTL_MS = 15e3;
@@ -26256,19 +26032,12 @@ var cachesByClient = /* @__PURE__ */ new WeakMap();
26256
26032
  function cachesFor(client) {
26257
26033
  const existing = cachesByClient.get(client);
26258
26034
  if (existing) return existing;
26259
- const caches2 = {
26260
- requests: /* @__PURE__ */ new Map(),
26261
- workflows: /* @__PURE__ */ new Map(),
26262
- workflowsRefreshedAt: /* @__PURE__ */ new Map(),
26263
- workflowsAbort: null,
26264
- searchSeq: 0
26265
- };
26266
- cachesByClient.set(client, caches2);
26035
+ const caches = { requests: /* @__PURE__ */ new Map(), searchSeq: 0 };
26036
+ cachesByClient.set(client, caches);
26267
26037
  onInputCachesReset(client, () => {
26268
- caches2.workflowsAbort?.abort();
26269
- if (cachesByClient.get(client) === caches2) cachesByClient.delete(client);
26038
+ if (cachesByClient.get(client) === caches) cachesByClient.delete(client);
26270
26039
  });
26271
- return caches2;
26040
+ return caches;
26272
26041
  }
26273
26042
  function cached(client, key, load) {
26274
26043
  const { requests } = cachesFor(client);
@@ -26282,9 +26051,7 @@ function cached(client, key, load) {
26282
26051
  return request;
26283
26052
  }
26284
26053
  function invalidateSlashSuggestions(client, sessionId) {
26285
- const caches2 = cachesFor(client);
26286
- caches2.requests.delete(`session-skills:${sessionId ?? ""}`);
26287
- caches2.workflows.delete(sessionId ?? "__home__");
26054
+ cachesFor(client).requests.delete(`session-skills:${sessionId ?? ""}`);
26288
26055
  }
26289
26056
  async function loadSessionSkills({ client, sessionId, renderMode }) {
26290
26057
  if (!sessionId) return [];
@@ -26292,79 +26059,50 @@ async function loadSessionSkills({ client, sessionId, renderMode }) {
26292
26059
  const skills = await cached(
26293
26060
  client,
26294
26061
  `session-skills:${sessionId}`,
26295
- () => client.json("GET", sessionPath2(sessionId, "skills"))
26062
+ () => client.json("GET", sessionPath(sessionId, "skills"))
26296
26063
  );
26297
26064
  return visibleSkills(skills, renderMode);
26298
26065
  } catch {
26299
26066
  return [];
26300
26067
  }
26301
26068
  }
26069
+ var HUB_WAIT_MS = 600;
26302
26070
  var DEFAULT_SUGGESTION_LIMIT = 50;
26303
26071
  async function getDefaultSuggestions(options) {
26304
26072
  if (options.sessionId) {
26305
26073
  return (await loadSessionSkills(options)).map(toItem);
26306
26074
  }
26075
+ const { client, renderMode } = options;
26076
+ const installedRequest = cached(
26077
+ client,
26078
+ "installed-skills",
26079
+ () => client.json("GET", "/api/skills/installed").catch(() => [])
26080
+ );
26307
26081
  try {
26308
- const skills = await cached(options.client, "skills", () => options.client.json("GET", "/api/skills"));
26309
- return visibleSkills(skills, options.renderMode).slice(0, DEFAULT_SUGGESTION_LIMIT).map(toItem);
26082
+ const local = await cached(client, "skills", () => client.json("GET", "/api/skills"));
26083
+ const installed = await Promise.race([
26084
+ installedRequest,
26085
+ new Promise((resolve) => setTimeout(() => resolve([]), HUB_WAIT_MS))
26086
+ ]);
26087
+ const seen = new Set(local.map((skill) => skill.skill_id));
26088
+ const hub = (Array.isArray(installed) ? installed : []).filter((skill) => skill.id && !seen.has(skill.id)).map((skill) => ({
26089
+ skill_id: skill.id,
26090
+ display_name: skill.display_name ?? "",
26091
+ description: skill.description ?? "",
26092
+ local: false,
26093
+ installed: true,
26094
+ has_flow: skill.has_flow
26095
+ }));
26096
+ return [
26097
+ ...visibleSkills(local, renderMode).slice(0, DEFAULT_SUGGESTION_LIMIT),
26098
+ ...visibleSkills(hub, renderMode).slice(0, DEFAULT_SUGGESTION_LIMIT)
26099
+ ].map(toItem);
26310
26100
  } catch {
26311
26101
  return [];
26312
26102
  }
26313
26103
  }
26314
- async function loadWorkflows(client, sessionId) {
26315
- const caches2 = cachesFor(client);
26316
- caches2.workflowsAbort?.abort();
26317
- const ac = new AbortController();
26318
- caches2.workflowsAbort = ac;
26319
- let timedOut = false;
26320
- const timer = setTimeout(() => {
26321
- timedOut = true;
26322
- ac.abort();
26323
- }, 1500);
26324
- try {
26325
- const res = await client.jsonFromInit(
26326
- sessionId ? sessionPath2(sessionId, "workflows") : "/api/workflows",
26327
- { signal: ac.signal }
26328
- );
26329
- const items = res.workflows.map((w) => ({
26330
- type: "workflow",
26331
- name: w.name,
26332
- displayName: w.display_name || w.name,
26333
- description: w.description || "",
26334
- inputs: w.inputs ?? []
26335
- }));
26336
- caches2.workflows.set(sessionId ?? "__home__", items);
26337
- caches2.workflowsRefreshedAt.set(sessionId ?? "__home__", Date.now());
26338
- return items;
26339
- } catch (err) {
26340
- if (timedOut || err?.name !== "AbortError") {
26341
- caches2.workflows.set(sessionId ?? "__home__", []);
26342
- }
26343
- return caches2.workflows.get(sessionId ?? "__home__") ?? [];
26344
- } finally {
26345
- clearTimeout(timer);
26346
- if (caches2.workflowsAbort === ac) caches2.workflowsAbort = null;
26347
- }
26348
- }
26349
26104
  async function getSlashSuggestions(query, options) {
26350
- const q = query.trim().toLowerCase();
26351
- const cacheKey = options.sessionId ?? "__home__";
26352
- const caches2 = cachesFor(options.client);
26353
- const cachedWorkflows = caches2.workflows.get(cacheKey);
26354
- let workflowsP;
26355
- if (cachedWorkflows) {
26356
- if (Date.now() - (caches2.workflowsRefreshedAt.get(cacheKey) ?? 0) >= CACHE_TTL_MS) {
26357
- void loadWorkflows(options.client, options.sessionId);
26358
- }
26359
- workflowsP = Promise.resolve(cachedWorkflows);
26360
- } else {
26361
- workflowsP = loadWorkflows(options.client, options.sessionId);
26362
- }
26363
- const [workflows, skills] = await Promise.all([workflowsP, getSkillSuggestions(query, options)]);
26364
- const matched = workflows.filter(
26365
- (w) => !q || w.name.toLowerCase().includes(q) || w.displayName.toLowerCase().includes(q) || w.description.toLowerCase().includes(q)
26366
- );
26367
- return [...matched, ...skills];
26105
+ return getSkillSuggestions(query, options);
26368
26106
  }
26369
26107
  var SEARCH_DEBOUNCE_MS = 150;
26370
26108
  async function getSkillSuggestions(query, options) {
@@ -26372,14 +26110,14 @@ async function getSkillSuggestions(query, options) {
26372
26110
  if (!trimmed) {
26373
26111
  return getDefaultSuggestions(options);
26374
26112
  }
26375
- const caches2 = cachesFor(options.client);
26376
- const seq = ++caches2.searchSeq;
26113
+ const caches = cachesFor(options.client);
26114
+ const seq = ++caches.searchSeq;
26377
26115
  const q = trimmed.toLowerCase();
26378
26116
  const sessionMatches = (await loadSessionSkills(options)).filter(
26379
26117
  (skill) => skill.skill_id.toLowerCase().includes(q) || skill.description.toLowerCase().includes(q)
26380
26118
  ).map(toItem);
26381
26119
  await new Promise((resolve) => setTimeout(resolve, SEARCH_DEBOUNCE_MS));
26382
- if (seq !== caches2.searchSeq) return sessionMatches;
26120
+ if (seq !== caches.searchSeq) return sessionMatches;
26383
26121
  try {
26384
26122
  const seen = new Set(sessionMatches.map((item) => item.skillId));
26385
26123
  const { client, renderMode } = options;
@@ -26396,7 +26134,7 @@ async function getSkillSuggestions(query, options) {
26396
26134
  }
26397
26135
 
26398
26136
  // src/rich-input/ConnectButton.tsx
26399
- import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
26137
+ import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
26400
26138
  function ConnectButton({
26401
26139
  sessionId,
26402
26140
  open,
@@ -26404,12 +26142,15 @@ function ConnectButton({
26404
26142
  pendingPlugins,
26405
26143
  onPendingPluginsChange,
26406
26144
  pendingPluginsDisabledReason,
26407
- pendingComputers,
26408
- onPendingComputersChange,
26409
- onPluginsChanged
26145
+ excludedComputers,
26146
+ onExcludedComputersChange,
26147
+ pendingPhones,
26148
+ onPendingPhonesChange,
26149
+ onPluginsChanged,
26150
+ variant = "icon"
26410
26151
  }) {
26411
26152
  const client = useBladeClient();
26412
- const { ConnectorComputerSection, ConnectorAccountsSection } = useRichInputServices();
26153
+ const { ConnectorComputerSection, ConnectorPhoneSection, ConnectorAccountsSection } = useRichInputServices();
26413
26154
  const invalidation = useSessionDataInvalidation();
26414
26155
  const [uncontrolledOpen, setUncontrolledOpen] = useState6(false);
26415
26156
  const isOpen = open ?? uncontrolledOpen;
@@ -26422,60 +26163,83 @@ function ConnectButton({
26422
26163
  const summary = triggerSummary(triggerItems);
26423
26164
  const triggerCls = summary.total === 0 ? "w-9 p-0 text-[hsl(var(--muted-foreground))]" : summary.total === 1 ? "w-9 p-0" : "px-1";
26424
26165
  const selectedLabels = sessionId === null ? (pendingPlugins ?? []).map((item) => item.displayName?.trim() || item.name) : selectedItems.map((item) => item.display_name?.trim() || item.name);
26425
- return /* @__PURE__ */ jsxs6(dist_exports.Root, { open: isOpen, onOpenChange: setOpen, children: [
26426
- /* @__PURE__ */ jsx15(dist_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx15(
26166
+ const panel = /* @__PURE__ */ jsx16(
26167
+ ConnectorPanel,
26168
+ {
26169
+ client,
26170
+ sessionId,
26171
+ pendingPlugins,
26172
+ onPendingPluginsChange,
26173
+ pendingDisabledReason: pendingPluginsDisabledReason,
26174
+ onPluginsChanged: () => {
26175
+ if (sessionId) {
26176
+ invalidateSlashSuggestions(client, sessionId);
26177
+ invalidation.pluginsChanged(sessionId);
26178
+ }
26179
+ onPluginsChanged?.();
26180
+ },
26181
+ onSelectedChange: setSelectedItems,
26182
+ renderComputerSection: ConnectorComputerSection ? (query) => /* @__PURE__ */ jsx16(
26183
+ ConnectorComputerSection,
26184
+ {
26185
+ sessionId,
26186
+ query,
26187
+ excludedSelection: excludedComputers,
26188
+ onExcludedSelectionChange: onExcludedComputersChange,
26189
+ closePanel: () => setOpen(false)
26190
+ }
26191
+ ) : void 0,
26192
+ renderPhoneSection: ConnectorPhoneSection ? (query) => /* @__PURE__ */ jsx16(
26193
+ ConnectorPhoneSection,
26194
+ {
26195
+ sessionId,
26196
+ query,
26197
+ pendingSelection: pendingPhones,
26198
+ onPendingSelectionChange: onPendingPhonesChange,
26199
+ closePanel: () => setOpen(false)
26200
+ }
26201
+ ) : void 0,
26202
+ renderExternalAccounts: ConnectorAccountsSection ? (query) => /* @__PURE__ */ jsx16(ConnectorAccountsSection, { query, closePanel: () => setOpen(false) }) : void 0
26203
+ }
26204
+ );
26205
+ if (variant === "submenu") {
26206
+ return /* @__PURE__ */ jsx16(
26207
+ InputActionSubmenu,
26208
+ {
26209
+ label: summary.total ? `\u8FDE\u63A5\u5668 \xB7 \u5DF2\u9009 ${summary.total}` : "\u8FDE\u63A5\u5668",
26210
+ icon: /* @__PURE__ */ jsx16(Plug, { size: 16, "aria-hidden": "true" }),
26211
+ open: isOpen,
26212
+ onOpenChange: setOpen,
26213
+ children: panel
26214
+ }
26215
+ );
26216
+ }
26217
+ return /* @__PURE__ */ jsxs7(dist_exports.Root, { open: isOpen, onOpenChange: setOpen, children: [
26218
+ /* @__PURE__ */ jsx16(dist_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx16(
26427
26219
  "button",
26428
26220
  {
26429
26221
  type: "button",
26430
26222
  "aria-label": summary.total > 0 ? `\u8FDE\u63A5\u5668\uFF1A\u5DF2\u9009 ${summary.total} \u4E2A\u63D2\u4EF6` : "\u8FDE\u63A5\u5668",
26431
26223
  title: selectedLabels.length > 0 ? `\u8FDE\u63A5\u5668\uFF1A${selectedLabels.join("\u3001")}` : "\u8FDE\u63A5\u5668",
26432
26224
  className: `flex h-9 shrink-0 cursor-pointer items-center justify-center rounded-full border border-[hsl(var(--border))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))] ${triggerCls}`,
26433
- children: summary.total === 0 ? /* @__PURE__ */ jsx15(Plug, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsx15(PluginTriggerStack, { client, sessionId, summary })
26225
+ children: summary.total === 0 ? /* @__PURE__ */ jsx16(Plug, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsx16(PluginTriggerStack, { client, sessionId, summary })
26434
26226
  }
26435
26227
  ) }),
26436
- /* @__PURE__ */ jsx15(dist_exports.Portal, { children: /* @__PURE__ */ jsx15(
26228
+ /* @__PURE__ */ jsx16(dist_exports.Portal, { children: /* @__PURE__ */ jsx16(
26437
26229
  dist_exports.Content,
26438
26230
  {
26439
26231
  side: "top",
26440
26232
  align: "start",
26441
26233
  sideOffset: 8,
26442
26234
  className: "z-50 w-[min(320px,calc(100vw-2rem))] origin-(--radix-popover-content-transform-origin) overflow-hidden rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] text-[11px] text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)] outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
26443
- children: /* @__PURE__ */ jsx15("div", { className: "max-h-[min(70vh,32rem)] overflow-y-auto", children: /* @__PURE__ */ jsx15(
26444
- ConnectorPanel,
26445
- {
26446
- client,
26447
- sessionId,
26448
- pendingPlugins,
26449
- onPendingPluginsChange,
26450
- pendingDisabledReason: pendingPluginsDisabledReason,
26451
- onPluginsChanged: () => {
26452
- if (sessionId) {
26453
- invalidateSlashSuggestions(client, sessionId);
26454
- invalidation.pluginsChanged(sessionId);
26455
- }
26456
- onPluginsChanged?.();
26457
- },
26458
- onSelectedChange: setSelectedItems,
26459
- renderComputerSection: ConnectorComputerSection ? (query) => /* @__PURE__ */ jsx15(
26460
- ConnectorComputerSection,
26461
- {
26462
- sessionId,
26463
- query,
26464
- pendingSelection: pendingComputers,
26465
- onPendingSelectionChange: onPendingComputersChange,
26466
- closePanel: () => setOpen(false)
26467
- }
26468
- ) : void 0,
26469
- renderExternalAccounts: ConnectorAccountsSection ? (query) => /* @__PURE__ */ jsx15(ConnectorAccountsSection, { query, closePanel: () => setOpen(false) }) : void 0
26470
- }
26471
- ) })
26235
+ children: /* @__PURE__ */ jsx16("div", { className: "max-h-[min(70vh,32rem)] overflow-y-auto", children: panel })
26472
26236
  }
26473
26237
  ) })
26474
26238
  ] });
26475
26239
  }
26476
26240
 
26477
26241
  // src/rich-input/voice/use-voice-input.ts
26478
- import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef7, useState as useState7 } from "react";
26242
+ import { useCallback as useCallback2, useEffect as useEffect6, useRef as useRef5, useState as useState7 } from "react";
26479
26243
 
26480
26244
  // src/rich-input/voice/voice-input-support.ts
26481
26245
  function isIpHost(hostname) {
@@ -26523,25 +26287,25 @@ function matchesRequest(data, requestId) {
26523
26287
  }
26524
26288
  function useVoiceInput(options) {
26525
26289
  const client = useBladeClient();
26526
- const clientRef = useRef7(client);
26290
+ const clientRef = useRef5(client);
26527
26291
  clientRef.current = client;
26528
- const getSocket = useCallback3(() => clientRef.current.socket(), []);
26292
+ const getSocket = useCallback2(() => clientRef.current.socket(), []);
26529
26293
  const [status, setStatus] = useState7("idle");
26530
26294
  const [error, setError] = useState7(null);
26531
26295
  const [level, setLevel] = useState7(0);
26532
- const sessionRef = useRef7(null);
26533
- const stoppingRef = useRef7(false);
26534
- const startAbortRef = useRef7(null);
26535
- const optionsRef = useRef7(options);
26296
+ const sessionRef = useRef5(null);
26297
+ const stoppingRef = useRef5(false);
26298
+ const startAbortRef = useRef5(null);
26299
+ const optionsRef = useRef5(options);
26536
26300
  optionsRef.current = options;
26537
- const reportError = useCallback3((err) => {
26301
+ const reportError = useCallback2((err) => {
26538
26302
  const payload = typeof err === "string" ? { title: err } : err;
26539
26303
  setError(payload.title);
26540
26304
  setStatus("error");
26541
26305
  setLevel(0);
26542
26306
  optionsRef.current.onError?.(payload);
26543
26307
  }, []);
26544
- const disposeSession = useCallback3((s) => {
26308
+ const disposeSession = useCallback2((s) => {
26545
26309
  if (s.disposed) return;
26546
26310
  s.disposed = true;
26547
26311
  const socket = getSocket();
@@ -26566,7 +26330,7 @@ function useVoiceInput(options) {
26566
26330
  } catch {
26567
26331
  }
26568
26332
  }, [getSocket]);
26569
- const stop = useCallback3(async () => {
26333
+ const stop = useCallback2(async () => {
26570
26334
  startAbortRef.current?.abort();
26571
26335
  const s = sessionRef.current;
26572
26336
  if (!s || stoppingRef.current) {
@@ -26613,7 +26377,7 @@ function useVoiceInput(options) {
26613
26377
  setLevel(0);
26614
26378
  setStatus((prev) => prev === "error" ? "error" : "idle");
26615
26379
  }, [disposeSession, getSocket]);
26616
- const start = useCallback3(async () => {
26380
+ const start = useCallback2(async () => {
26617
26381
  if (sessionRef.current || startAbortRef.current && !startAbortRef.current.signal.aborted || stoppingRef.current) {
26618
26382
  return;
26619
26383
  }
@@ -26787,7 +26551,7 @@ function useVoiceInput(options) {
26787
26551
  if (startAbortRef.current === abort) startAbortRef.current = null;
26788
26552
  }
26789
26553
  }, [reportError, disposeSession, getSocket]);
26790
- useEffect7(() => {
26554
+ useEffect6(() => {
26791
26555
  return () => {
26792
26556
  startAbortRef.current?.abort();
26793
26557
  const s = sessionRef.current;
@@ -26805,7 +26569,7 @@ function useVoiceInput(options) {
26805
26569
  }
26806
26570
 
26807
26571
  // src/rich-input/use-reference-candidates.ts
26808
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
26572
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef6 } from "react";
26809
26573
 
26810
26574
  // src/rich-input/lib/reference-candidates.ts
26811
26575
  function createReferenceCandidateController(getScope, sources, timeoutMs = 300) {
@@ -26880,7 +26644,6 @@ function createReferenceCandidateController(getScope, sources, timeoutMs = 300)
26880
26644
  }
26881
26645
  return result;
26882
26646
  },
26883
- /** Bind by result identity, never by label/query: closing and reopening @ is a new request. */
26884
26647
  observe(items, listener) {
26885
26648
  const request = requests.get(items);
26886
26649
  if (!request || !isCurrent(request)) {
@@ -26904,7 +26667,7 @@ function useReferenceCandidates(getScope, sources) {
26904
26667
  const plugins = useEffectEvent((query) => sources.plugins?.(query) ?? Promise.resolve([]));
26905
26668
  const topics = useEffectEvent(sources.topics);
26906
26669
  const files = useEffectEvent(sources.files);
26907
- const ref = useRef8(null);
26670
+ const ref = useRef6(null);
26908
26671
  if (!ref.current) ref.current = createReferenceCandidateController(readScope, { plugins, topics, files });
26909
26672
  const controller = ref.current;
26910
26673
  const [client, identity, session, topic] = getScope();
@@ -26914,7 +26677,7 @@ function useReferenceCandidates(getScope, sources) {
26914
26677
  }
26915
26678
 
26916
26679
  // src/rich-input/use-input-history.ts
26917
- import { useCallback as useCallback4, useEffect as useEffect8, useMemo as useMemo7, useState as useState8 } from "react";
26680
+ import { useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo6, useState as useState8 } from "react";
26918
26681
 
26919
26682
  // src/rich-input/lib/input-history-document.ts
26920
26683
  import { normalizeTopicAssetRefs as normalizeTopicAssetRefs3 } from "@blade-hq/agent-client";
@@ -26923,8 +26686,7 @@ function copyEditorDocument(value) {
26923
26686
  pluginMention: { provider: "string", plugin: "string", server: "string", id: "string", label: "string" },
26924
26687
  fileMention: { path: "string", name: "string" },
26925
26688
  topicAssetMention: { topic_id: "string", path: "string" },
26926
- skillMention: { skillId: "string", displayName: "string", description: "string", local: "boolean", installed: "boolean" },
26927
- workflowMention: { name: "string" }
26689
+ skillMention: { skillId: "string", displayName: "string", description: "string", local: "boolean", installed: "boolean" }
26928
26690
  };
26929
26691
  const copy2 = (input, parent) => {
26930
26692
  if (!input || typeof input !== "object" || Array.isArray(input)) return null;
@@ -27005,17 +26767,17 @@ function readEntries(storageKey) {
27005
26767
  }
27006
26768
  function useInputHistory(sessionId, client) {
27007
26769
  const [generation, setGeneration] = useState8(getInputHistoryGeneration);
27008
- const storageKey = useMemo7(() => getStorageKey(sessionId), [sessionId]);
26770
+ const storageKey = useMemo6(() => getStorageKey(sessionId), [sessionId]);
27009
26771
  const [entries, setEntries] = useState8([]);
27010
26772
  const [cursor, setCursor] = useState8(null);
27011
26773
  const [draft, setDraft] = useState8(emptyEntry);
27012
- useEffect8(() => {
26774
+ useEffect7(() => {
27013
26775
  setGeneration(getInputHistoryGeneration());
27014
26776
  setEntries(readEntries(storageKey));
27015
26777
  setCursor(null);
27016
26778
  setDraft(emptyEntry());
27017
26779
  }, [storageKey, client]);
27018
- useEffect8(() => {
26780
+ useEffect7(() => {
27019
26781
  if (!client) return;
27020
26782
  return onInputCachesReset(client, () => {
27021
26783
  setGeneration(getInputHistoryGeneration());
@@ -27024,7 +26786,7 @@ function useInputHistory(sessionId, client) {
27024
26786
  setDraft(emptyEntry());
27025
26787
  });
27026
26788
  }, [client]);
27027
- const persistEntries = useCallback4(
26789
+ const persistEntries = useCallback3(
27028
26790
  (nextEntries) => {
27029
26791
  if (generation !== getInputHistoryGeneration() || typeof window === "undefined" || !storageKey) {
27030
26792
  return;
@@ -27036,7 +26798,7 @@ function useInputHistory(sessionId, client) {
27036
26798
  },
27037
26799
  [storageKey, generation]
27038
26800
  );
27039
- const addEntry = useCallback4(
26801
+ const addEntry = useCallback3(
27040
26802
  (value) => {
27041
26803
  if (generation !== getInputHistoryGeneration()) return;
27042
26804
  const document2 = copyEditorDocument(value);
@@ -27052,7 +26814,7 @@ function useInputHistory(sessionId, client) {
27052
26814
  },
27053
26815
  [persistEntries, generation]
27054
26816
  );
27055
- const navigateUp = useCallback4(
26817
+ const navigateUp = useCallback3(
27056
26818
  (currentDraft = emptyEntry().document) => {
27057
26819
  if (generation !== getInputHistoryGeneration() || entries.length === 0) {
27058
26820
  return null;
@@ -27066,7 +26828,7 @@ function useInputHistory(sessionId, client) {
27066
26828
  },
27067
26829
  [cursor, entries, generation]
27068
26830
  );
27069
- const navigateDown = useCallback4(() => {
26831
+ const navigateDown = useCallback3(() => {
27070
26832
  if (generation !== getInputHistoryGeneration() || cursor == null) {
27071
26833
  return null;
27072
26834
  }
@@ -27089,7 +26851,7 @@ function useInputHistory(sessionId, client) {
27089
26851
  }
27090
26852
 
27091
26853
  // src/rich-input/lib/attachment-upload.ts
27092
- var ATTACHMENT_SIZE_LIMIT_BYTES = 1e3 * 1024 * 1024;
26854
+ var ATTACHMENT_SIZE_LIMIT_BYTES = 1024 * 1024 * 1024;
27093
26855
  function formatFileSize(size) {
27094
26856
  if (size < 1024) {
27095
26857
  return `${size} B`;
@@ -27097,7 +26859,10 @@ function formatFileSize(size) {
27097
26859
  if (size < 1024 * 1024) {
27098
26860
  return `${(size / 1024).toFixed(size >= 100 * 1024 ? 0 : 1)} KB`;
27099
26861
  }
27100
- return `${(size / (1024 * 1024)).toFixed(size >= 10 * 1024 * 1024 ? 0 : 1)} MB`;
26862
+ if (size < 1024 * 1024 * 1024) {
26863
+ return `${(size / (1024 * 1024)).toFixed(size >= 10 * 1024 * 1024 ? 0 : 1)} MB`;
26864
+ }
26865
+ return `${(size / (1024 * 1024 * 1024)).toFixed(1)} GB`;
27101
26866
  }
27102
26867
  function splitFilesBySize(files, limitBytes = ATTACHMENT_SIZE_LIMIT_BYTES) {
27103
26868
  const accepted = [];
@@ -27117,8 +26882,7 @@ function splitFilesBySize(files, limitBytes = ATTACHMENT_SIZE_LIMIT_BYTES) {
27117
26882
 
27118
26883
  // src/rich-input/ChatInput.tsx
27119
26884
  import {
27120
- buildMessageContent,
27121
- transformSlashCommand
26885
+ buildMessageContent
27122
26886
  } from "@blade-hq/agent-client/internal";
27123
26887
 
27124
26888
  // src/rich-input/lib/upload-results.ts
@@ -27149,47 +26913,20 @@ function getUnsupportedImageFiles(files, supportsImage) {
27149
26913
  }
27150
26914
 
27151
26915
  // src/rich-input/FileCompletionMenu.tsx
27152
- import { forwardRef as forwardRef2, useCallback as useCallback5, useImperativeHandle, useMemo as useMemo8, useState as useState9 } from "react";
26916
+ import { forwardRef as forwardRef2, useCallback as useCallback4, useImperativeHandle, useMemo as useMemo7, useState as useState9 } from "react";
27153
26917
 
27154
26918
  // src/rich-input/lib/user-home.ts
27155
- var SANDBOX_HOME_ROOT = "/root";
27156
- var SANDBOX_RUNTIME = { homePath: SANDBOX_HOME_ROOT, separator: "/" };
27157
26919
  var CACHE_TTL_MS2 = 15e3;
27158
26920
  var cachesByClient2 = /* @__PURE__ */ new WeakMap();
27159
- var lastResolvedRuntime = SANDBOX_RUNTIME;
27160
26921
  function cachesFor2(client) {
27161
26922
  const existing = cachesByClient2.get(client);
27162
26923
  if (existing) return existing;
27163
- const caches2 = { runtime: null, dirs: /* @__PURE__ */ new Map() };
27164
- cachesByClient2.set(client, caches2);
26924
+ const caches = { dirs: /* @__PURE__ */ new Map() };
26925
+ cachesByClient2.set(client, caches);
27165
26926
  onInputCachesReset(client, () => {
27166
- if (cachesByClient2.get(client) === caches2) cachesByClient2.delete(client);
27167
- lastResolvedRuntime = SANDBOX_RUNTIME;
26927
+ if (cachesByClient2.get(client) === caches) cachesByClient2.delete(client);
27168
26928
  });
27169
- return caches2;
27170
- }
27171
- function getUserHomeRuntime(client) {
27172
- const caches2 = cachesFor2(client);
27173
- if (caches2.runtime && Date.now() - caches2.runtime.at < CACHE_TTL_MS2) {
27174
- return caches2.runtime.request;
27175
- }
27176
- const request = client.json("GET", "/api/agent-board/workspace-runtime").then((runtime) => {
27177
- const homePath = (runtime.home_path ?? "").trim() || SANDBOX_HOME_ROOT;
27178
- const resolved = {
27179
- homePath,
27180
- separator: (runtime.os ?? "").toLowerCase().startsWith("windows") ? "\\" : "/"
27181
- };
27182
- lastResolvedRuntime = resolved;
27183
- return resolved;
27184
- }).catch(() => {
27185
- if (caches2.runtime?.request === request) caches2.runtime = null;
27186
- return SANDBOX_RUNTIME;
27187
- });
27188
- caches2.runtime = { at: Date.now(), request };
27189
- return request;
27190
- }
27191
- function getLastUserHomeRuntime() {
27192
- return lastResolvedRuntime;
26929
+ return caches;
27193
26930
  }
27194
26931
  function listUserHomeDir(client, dirPath) {
27195
26932
  const { dirs } = cachesFor2(client);
@@ -27204,7 +26941,7 @@ function listUserHomeDir(client, dirPath) {
27204
26941
  }
27205
26942
 
27206
26943
  // src/rich-input/FileCompletionMenu.tsx
27207
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
26944
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
27208
26945
  var ROOT_DIR = ".";
27209
26946
  function installSuggestionOutsideDismiss(container, onDismiss) {
27210
26947
  const onPointerDown = (event) => {
@@ -27301,7 +27038,9 @@ async function getFileSuggestionItems(client, sessionId, query) {
27301
27038
  const entries = await listDirectory(client, sessionId, dirPath);
27302
27039
  return filterEntries(entries, filterQuery);
27303
27040
  }
27304
- function parseUserHomeQuery(query, { homePath, separator }) {
27041
+ function parseUserHomeQuery(query) {
27042
+ const homePath = "/root";
27043
+ const separator = "/";
27305
27044
  if (!query.startsWith(homePath)) {
27306
27045
  return { dirPath: homePath, filterQuery: query };
27307
27046
  }
@@ -27315,8 +27054,7 @@ function parseUserHomeQuery(query, { homePath, separator }) {
27315
27054
  };
27316
27055
  }
27317
27056
  async function getUserHomeSuggestionItems(client, query) {
27318
- const runtime = await getUserHomeRuntime(client);
27319
- const { dirPath, filterQuery } = parseUserHomeQuery(query, runtime);
27057
+ const { dirPath, filterQuery } = parseUserHomeQuery(query);
27320
27058
  let entries;
27321
27059
  try {
27322
27060
  entries = (await listUserHomeDir(client, dirPath)).map((entry) => ({
@@ -27331,11 +27069,11 @@ async function getUserHomeSuggestionItems(client, query) {
27331
27069
  var FileCompletionMenu = forwardRef2(
27332
27070
  function FileCompletionMenu2({ command: command2, editor, items, onExit, query, range, scope = "session", sessionId: sessionIdProp }, ref) {
27333
27071
  const sessionId = sessionIdProp ?? null;
27334
- const { dirPath, filterQuery } = useMemo8(
27072
+ const { dirPath, filterQuery } = useMemo7(
27335
27073
  () => scope === "userHome" ? { dirPath: query, filterQuery: "" } : parseSuggestionQuery(query),
27336
27074
  [query, scope]
27337
27075
  );
27338
- const { pluginItems, pluginError, fileItems, topicItems, topicError } = useMemo8(() => {
27076
+ const { pluginItems, pluginError, fileItems, topicItems, topicError } = useMemo7(() => {
27339
27077
  let pluginError2;
27340
27078
  const pluginItems2 = [];
27341
27079
  const files = [];
@@ -27350,7 +27088,7 @@ var FileCompletionMenu = forwardRef2(
27350
27088
  }
27351
27089
  return { pluginItems: pluginItems2, pluginError: pluginError2, fileItems: files, topicItems: topicItems2, topicError: topicError2 };
27352
27090
  }, [items]);
27353
- return /* @__PURE__ */ jsx16(
27091
+ return /* @__PURE__ */ jsx17(
27354
27092
  FileCompletionMenuContent,
27355
27093
  {
27356
27094
  ref,
@@ -27373,21 +27111,20 @@ var FileCompletionMenu = forwardRef2(
27373
27111
  );
27374
27112
  var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2({ command: command2, editor, filterQuery, items, pluginItems, pluginError, topicItems, topicError, onExit, range, scope, sessionId }, ref) {
27375
27113
  const [rawSelectedIndex, setRawSelectedIndex] = useState9(0);
27376
- const filteredEntries = useMemo8(() => filterEntries(items, filterQuery), [filterQuery, items]);
27377
- const navigableItems = useMemo8(
27114
+ const filteredEntries = useMemo7(() => filterEntries(items, filterQuery), [filterQuery, items]);
27115
+ const navigableItems = useMemo7(
27378
27116
  () => [...pluginItems, ...topicItems, ...filteredEntries],
27379
27117
  [filteredEntries, pluginItems, topicItems]
27380
27118
  );
27381
27119
  const selectedIndex = navigableItems.length === 0 ? 0 : Math.min(rawSelectedIndex, navigableItems.length - 1);
27382
- const handleSelect = useCallback5(
27120
+ const handleSelect = useCallback4(
27383
27121
  (entry) => {
27384
27122
  if (isPluginSuggestionItem(entry) || isTopicAssetSuggestionItem(entry)) {
27385
27123
  command2(entry);
27386
27124
  return;
27387
27125
  }
27388
27126
  if (entry.is_dir) {
27389
- const separator = scope === "userHome" ? getLastUserHomeRuntime().separator : "/";
27390
- const nextValue = entry.path === ROOT_DIR ? "@" : `@${entry.path}${separator}`;
27127
+ const nextValue = entry.path === ROOT_DIR ? "@" : `@${entry.path}/`;
27391
27128
  editor.chain().focus().insertContentAt(range, nextValue).run();
27392
27129
  return;
27393
27130
  }
@@ -27397,7 +27134,7 @@ var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2(
27397
27134
  path: entry.path
27398
27135
  });
27399
27136
  },
27400
- [command2, editor, range, scope]
27137
+ [command2, editor, range]
27401
27138
  );
27402
27139
  useImperativeHandle(
27403
27140
  ref,
@@ -27445,9 +27182,9 @@ var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2(
27445
27182
  };
27446
27183
  const showGroupLabels = pluginItems.length > 0 || topicItems.length > 0 || Boolean(topicError);
27447
27184
  const fileEmptyLabel = scope === "session" && !sessionId ? "\u6682\u65E0\u4F1A\u8BDD" : filteredEntries.length === 0 ? "\u6CA1\u6709\u6587\u4EF6" : null;
27448
- return /* @__PURE__ */ jsxs7("div", { className: "max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]", children: [
27449
- pluginError ? /* @__PURE__ */ jsx16("output", { className: "block px-3 py-2 text-xs text-muted-foreground", children: pluginError }) : null,
27450
- pluginItems.map((item, index) => /* @__PURE__ */ jsxs7(
27185
+ return /* @__PURE__ */ jsxs8("div", { className: "max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]", children: [
27186
+ pluginError ? /* @__PURE__ */ jsx17("output", { className: "block px-3 py-2 text-xs text-muted-foreground", children: pluginError }) : null,
27187
+ pluginItems.map((item, index) => /* @__PURE__ */ jsxs8(
27451
27188
  "button",
27452
27189
  {
27453
27190
  ref: selectedRef(index),
@@ -27458,31 +27195,31 @@ var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2(
27458
27195
  handleSelect(item);
27459
27196
  },
27460
27197
  children: [
27461
- item.icon ? /* @__PURE__ */ jsx16("img", { src: item.icon, alt: "", width: 16, height: 16, className: "shrink-0" }) : /* @__PURE__ */ jsx16(BookOpen, { size: 14 }),
27462
- /* @__PURE__ */ jsx16("span", { className: "truncate", children: item.label }),
27463
- /* @__PURE__ */ jsx16("span", { className: "ml-auto truncate text-xs text-muted-foreground", children: item.display_name })
27198
+ item.icon ? /* @__PURE__ */ jsx17("img", { src: item.icon, alt: "", width: 16, height: 16, className: "shrink-0" }) : /* @__PURE__ */ jsx17(BookOpen, { size: 14 }),
27199
+ /* @__PURE__ */ jsx17("span", { className: "truncate", children: item.label }),
27200
+ /* @__PURE__ */ jsx17("span", { className: "ml-auto truncate text-xs text-muted-foreground", children: item.display_name })
27464
27201
  ]
27465
27202
  },
27466
27203
  `${item.plugin}:${item.server}:${item.id}`
27467
27204
  )),
27468
- topicItems.length > 0 || topicError ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
27469
- /* @__PURE__ */ jsx16("div", { className: "px-3 pt-1 pb-0.5 text-xs font-medium text-muted-foreground", children: "\u4E3B\u9898\u8D44\u4EA7" }),
27470
- topicError ? /* @__PURE__ */ jsx16("output", { className: "block px-3 py-2 text-xs text-muted-foreground", children: topicError }) : null,
27205
+ topicItems.length > 0 || topicError ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
27206
+ /* @__PURE__ */ jsx17("div", { className: "px-3 pt-1 pb-0.5 text-xs font-medium text-muted-foreground", children: "\u5DE5\u4F5C\u7A7A\u95F4\u8D44\u4EA7" }),
27207
+ topicError ? /* @__PURE__ */ jsx17("output", { className: "block px-3 py-2 text-xs text-muted-foreground", children: topicError }) : null,
27471
27208
  topicItems.map((item, topicIndex) => {
27472
27209
  const index = pluginItems.length + topicIndex;
27473
- return /* @__PURE__ */ jsxs7("button", { ref: selectedRef(index), type: "button", title: item.path, className: rowClassName(index), onMouseDown: (event) => {
27210
+ return /* @__PURE__ */ jsxs8("button", { ref: selectedRef(index), type: "button", title: item.path, className: rowClassName(index), onMouseDown: (event) => {
27474
27211
  event.preventDefault();
27475
27212
  handleSelect(item);
27476
27213
  }, children: [
27477
- /* @__PURE__ */ jsx16(File, { size: 14, className: "shrink-0 text-muted-foreground" }),
27478
- /* @__PURE__ */ jsx16("span", { className: "truncate", children: item.path })
27214
+ /* @__PURE__ */ jsx17(File, { size: 14, className: "shrink-0 text-muted-foreground" }),
27215
+ /* @__PURE__ */ jsx17("span", { className: "truncate", children: item.path })
27479
27216
  ] }, `${item.topic_id}:${item.path}`);
27480
27217
  })
27481
27218
  ] }) : null,
27482
- showGroupLabels ? /* @__PURE__ */ jsx16("div", { className: "px-3 pt-1 pb-0.5 text-[10px] font-medium uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u6587\u4EF6" }) : null,
27483
- fileEmptyLabel ? /* @__PURE__ */ jsx16("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: fileEmptyLabel }) : filteredEntries.map((entry, fileIndex) => {
27219
+ showGroupLabels ? /* @__PURE__ */ jsx17("div", { className: "px-3 pt-1 pb-0.5 text-[10px] font-medium uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u6587\u4EF6" }) : null,
27220
+ fileEmptyLabel ? /* @__PURE__ */ jsx17("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: fileEmptyLabel }) : filteredEntries.map((entry, fileIndex) => {
27484
27221
  const index = pluginItems.length + topicItems.length + fileIndex;
27485
- return /* @__PURE__ */ jsxs7(
27222
+ return /* @__PURE__ */ jsxs8(
27486
27223
  "button",
27487
27224
  {
27488
27225
  ref: selectedRef(index),
@@ -27493,9 +27230,9 @@ var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2(
27493
27230
  },
27494
27231
  className: rowClassName(index),
27495
27232
  children: [
27496
- entry.is_dir ? /* @__PURE__ */ jsx16(Folder, { size: 14, className: "shrink-0 text-[hsl(var(--primary))]" }) : /* @__PURE__ */ jsx16(File, { size: 14, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
27497
- /* @__PURE__ */ jsx16("span", { className: "truncate", children: entry.name }),
27498
- entry.is_dir && /* @__PURE__ */ jsx16(ChevronRight, { size: 12, className: "ml-auto shrink-0 opacity-40" })
27233
+ entry.is_dir ? /* @__PURE__ */ jsx17(Folder, { size: 14, className: "shrink-0 text-[hsl(var(--primary))]" }) : /* @__PURE__ */ jsx17(File, { size: 14, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
27234
+ /* @__PURE__ */ jsx17("span", { className: "truncate", children: entry.name }),
27235
+ entry.is_dir && /* @__PURE__ */ jsx17(ChevronRight, { size: 12, className: "ml-auto shrink-0 opacity-40" })
27499
27236
  ]
27500
27237
  },
27501
27238
  entry.path
@@ -27505,13 +27242,13 @@ var FileCompletionMenuContent = forwardRef2(function FileCompletionMenuContent2(
27505
27242
  });
27506
27243
 
27507
27244
  // src/rich-input/SkillCompletionMenu.tsx
27508
- import { forwardRef as forwardRef3, useCallback as useCallback6, useImperativeHandle as useImperativeHandle2, useState as useState10 } from "react";
27509
- import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
27245
+ import { forwardRef as forwardRef3, useCallback as useCallback5, useImperativeHandle as useImperativeHandle2, useState as useState10 } from "react";
27246
+ import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
27510
27247
  var SkillCompletionMenu = forwardRef3(
27511
27248
  function SkillCompletionMenu2({ command: command2, items }, ref) {
27512
27249
  const [rawSelectedIndex, setRawSelectedIndex] = useState10(0);
27513
27250
  const selectedIndex = items.length === 0 ? 0 : Math.min(rawSelectedIndex, items.length - 1);
27514
- const handleSelect = useCallback6(
27251
+ const handleSelect = useCallback5(
27515
27252
  (item) => {
27516
27253
  command2(item);
27517
27254
  },
@@ -27552,12 +27289,11 @@ var SkillCompletionMenu = forwardRef3(
27552
27289
  [handleSelect, items, selectedIndex]
27553
27290
  );
27554
27291
  const commandItems = items.filter((item) => item.type === "command");
27555
- const workflowItems = items.filter((item) => item.type === "workflow");
27556
27292
  const skillItems = items.filter((item) => item.type === "skill");
27557
- return /* @__PURE__ */ jsx17("div", { className: "max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]", children: items.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6CA1\u6709\u5339\u914D\u7684\u547D\u4EE4\u6216\u6280\u80FD" }) : /* @__PURE__ */ jsxs8("div", { children: [
27558
- commandItems.length > 0 ? /* @__PURE__ */ jsxs8("div", { className: "px-2 pb-1 pt-1", children: [
27559
- /* @__PURE__ */ jsx17("div", { className: "px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]", children: "\u547D\u4EE4" }),
27560
- commandItems.map((item, index) => /* @__PURE__ */ jsxs8(
27293
+ return /* @__PURE__ */ jsx18("div", { className: "max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]", children: items.length === 0 ? /* @__PURE__ */ jsx18("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6CA1\u6709\u5339\u914D\u7684\u547D\u4EE4\u6216\u6280\u80FD" }) : /* @__PURE__ */ jsxs9("div", { children: [
27294
+ commandItems.length > 0 ? /* @__PURE__ */ jsxs9("div", { className: "px-2 pb-1 pt-1", children: [
27295
+ /* @__PURE__ */ jsx18("div", { className: "px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]", children: "\u547D\u4EE4" }),
27296
+ commandItems.map((item, index) => /* @__PURE__ */ jsxs9(
27561
27297
  "button",
27562
27298
  {
27563
27299
  ref: (element) => {
@@ -27572,51 +27308,21 @@ var SkillCompletionMenu = forwardRef3(
27572
27308
  },
27573
27309
  className: `flex w-full items-start gap-2 rounded-lg px-2 py-1.5 text-left transition-colors ${index === selectedIndex ? "bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]" : "text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]"}`,
27574
27310
  children: [
27575
- /* @__PURE__ */ jsx17("span", { className: "pt-0.5 text-sm", children: "\u21BB" }),
27576
- /* @__PURE__ */ jsxs8("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
27577
- /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium", children: item.label }),
27578
- /* @__PURE__ */ jsx17("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: item.description })
27311
+ /* @__PURE__ */ jsx18("span", { className: "pt-0.5 text-sm", children: "\u21BB" }),
27312
+ /* @__PURE__ */ jsxs9("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
27313
+ /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium", children: item.label }),
27314
+ /* @__PURE__ */ jsx18("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: item.description })
27579
27315
  ] })
27580
27316
  ]
27581
27317
  },
27582
27318
  item.id
27583
27319
  ))
27584
27320
  ] }) : null,
27585
- workflowItems.length > 0 ? /* @__PURE__ */ jsxs8("div", { className: "px-2 pb-1 pt-1", children: [
27586
- /* @__PURE__ */ jsx17("div", { className: "px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u4F5C\u6D41" }),
27587
- workflowItems.map((item, wfIndex) => {
27588
- const index = commandItems.length + wfIndex;
27589
- return /* @__PURE__ */ jsxs8(
27590
- "button",
27591
- {
27592
- ref: (element) => {
27593
- if (element && index === selectedIndex) {
27594
- element.scrollIntoView({ block: "nearest" });
27595
- }
27596
- },
27597
- type: "button",
27598
- onMouseDown: (event) => {
27599
- event.preventDefault();
27600
- handleSelect(item);
27601
- },
27602
- className: `flex w-full items-start gap-2 rounded-lg px-2 py-1.5 text-left transition-colors ${index === selectedIndex ? "bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]" : "text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]"}`,
27603
- children: [
27604
- /* @__PURE__ */ jsx17("span", { className: "pt-0.5 text-sm", children: "\u2699" }),
27605
- /* @__PURE__ */ jsxs8("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
27606
- /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium", children: item.displayName }),
27607
- /* @__PURE__ */ jsx17("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: item.description || "\u8FD0\u884C\u8FD9\u4E2A\u5DE5\u4F5C\u6D41" })
27608
- ] })
27609
- ]
27610
- },
27611
- `wf:${item.name}`
27612
- );
27613
- })
27614
- ] }) : null,
27615
- skillItems.length > 0 ? /* @__PURE__ */ jsxs8("div", { className: "px-2 pb-1 pt-1", children: [
27616
- /* @__PURE__ */ jsx17("div", { className: "px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]", children: "\u6280\u80FD" }),
27321
+ skillItems.length > 0 ? /* @__PURE__ */ jsxs9("div", { className: "px-2 pb-1 pt-1", children: [
27322
+ /* @__PURE__ */ jsx18("div", { className: "px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]", children: "\u6280\u80FD" }),
27617
27323
  skillItems.map((item, skillIndex) => {
27618
- const index = commandItems.length + workflowItems.length + skillIndex;
27619
- return /* @__PURE__ */ jsxs8(
27324
+ const index = commandItems.length + skillIndex;
27325
+ return /* @__PURE__ */ jsxs9(
27620
27326
  "button",
27621
27327
  {
27622
27328
  ref: (element) => {
@@ -27631,11 +27337,19 @@ var SkillCompletionMenu = forwardRef3(
27631
27337
  },
27632
27338
  className: `flex w-full flex-col gap-0.5 rounded-lg px-2 py-1.5 text-left transition-colors ${index === selectedIndex ? "bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]" : "text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]"}`,
27633
27339
  children: [
27634
- /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-1.5", children: [
27635
- /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium", children: skillDisplayName(item) }),
27636
- item.installed === false ? /* @__PURE__ */ jsx17("span", { className: "shrink-0 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]", children: "\u672A\u5B89\u88C5" }) : null
27340
+ /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-1.5", children: [
27341
+ /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium", children: skillDisplayName(item) }),
27342
+ item.hasFlow ? /* @__PURE__ */ jsx18(
27343
+ "span",
27344
+ {
27345
+ title: "\u8FD9\u4E2A\u6280\u80FD\u6309\u56FA\u5B9A\u6D41\u7A0B\u6267\u884C:\u6B65\u9AA4\u4E8B\u5148\u7F16\u6392\u597D,\u8FD0\u884C\u4E2D\u4E0D\u4F1A\u5373\u5174\u53D1\u6325,\u4E5F\u4E0D\u4F1A\u4E2D\u9014\u95EE\u4F60",
27346
+ className: "shrink-0 rounded-full bg-violet-500/10 px-1.5 py-px text-[10px] font-medium text-violet-600",
27347
+ children: "\u26A1 \u56FA\u5B9A\u6D41\u7A0B"
27348
+ }
27349
+ ) : null,
27350
+ item.installed === false ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]", children: "\u672A\u5B89\u88C5" }) : null
27637
27351
  ] }),
27638
- /* @__PURE__ */ jsx17("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: item.description })
27352
+ /* @__PURE__ */ jsx18("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: item.description })
27639
27353
  ]
27640
27354
  },
27641
27355
  item.skillId
@@ -27647,7 +27361,7 @@ var SkillCompletionMenu = forwardRef3(
27647
27361
  );
27648
27362
 
27649
27363
  // src/rich-input/FileSizeLimitDialog.tsx
27650
- import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
27364
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
27651
27365
  function FileSizeLimitDialog({
27652
27366
  open,
27653
27367
  onOpenChange,
@@ -27658,37 +27372,37 @@ function FileSizeLimitDialog({
27658
27372
  return null;
27659
27373
  }
27660
27374
  const limitText = formatFileSize(limitBytes);
27661
- return /* @__PURE__ */ jsx18(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(DialogContent, { showCloseButton: false, className: "w-full max-w-lg gap-0 p-0", children: [
27662
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-3", children: [
27663
- /* @__PURE__ */ jsxs9("div", { children: [
27664
- /* @__PURE__ */ jsx18(DialogTitle, { className: "text-sm font-semibold text-[hsl(var(--foreground))]", children: "\u9644\u4EF6\u8D85\u8FC7\u5927\u5C0F\u9650\u5236" }),
27665
- /* @__PURE__ */ jsxs9("p", { className: "mt-1 text-xs text-[hsl(var(--muted-foreground))]", children: [
27375
+ return /* @__PURE__ */ jsx19(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs10(DialogContent, { showCloseButton: false, className: "w-full max-w-lg gap-0 p-0", children: [
27376
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-3", children: [
27377
+ /* @__PURE__ */ jsxs10("div", { children: [
27378
+ /* @__PURE__ */ jsx19(DialogTitle, { className: "text-sm font-semibold text-[hsl(var(--foreground))]", children: "\u9644\u4EF6\u8D85\u8FC7\u5927\u5C0F\u9650\u5236" }),
27379
+ /* @__PURE__ */ jsxs10("p", { className: "mt-1 text-xs text-[hsl(var(--muted-foreground))]", children: [
27666
27380
  "\u5355\u4E2A\u9644\u4EF6\u6700\u5927\u652F\u6301 ",
27667
27381
  limitText,
27668
27382
  "\u3002\u4EE5\u4E0B\u6587\u4EF6\u672A\u52A0\u5165\u9644\u4EF6\u5217\u8868\u3002"
27669
27383
  ] })
27670
27384
  ] }),
27671
- /* @__PURE__ */ jsx18(
27385
+ /* @__PURE__ */ jsx19(
27672
27386
  DialogClose,
27673
27387
  {
27674
27388
  title: "\u5173\u95ED",
27675
27389
  className: "flex h-7 w-7 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
27676
- children: /* @__PURE__ */ jsx18(X, { size: 14 })
27390
+ children: /* @__PURE__ */ jsx19(X, { size: 14 })
27677
27391
  }
27678
27392
  )
27679
27393
  ] }),
27680
- /* @__PURE__ */ jsx18("div", { className: "max-h-[min(50vh,24rem)] overflow-auto px-4 py-3", children: /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-2", children: files.map((file) => /* @__PURE__ */ jsxs9(
27394
+ /* @__PURE__ */ jsx19("div", { className: "max-h-[min(50vh,24rem)] overflow-auto px-4 py-3", children: /* @__PURE__ */ jsx19("div", { className: "flex flex-col gap-2", children: files.map((file) => /* @__PURE__ */ jsxs10(
27681
27395
  "div",
27682
27396
  {
27683
27397
  className: "flex items-center justify-between gap-3 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-3 py-2",
27684
27398
  children: [
27685
- /* @__PURE__ */ jsx18("span", { className: "min-w-0 truncate text-sm text-[hsl(var(--foreground))]", children: file.name }),
27686
- /* @__PURE__ */ jsx18("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: formatFileSize(file.size) })
27399
+ /* @__PURE__ */ jsx19("span", { className: "min-w-0 truncate text-sm text-[hsl(var(--foreground))]", children: file.name }),
27400
+ /* @__PURE__ */ jsx19("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: formatFileSize(file.size) })
27687
27401
  ]
27688
27402
  },
27689
27403
  `${file.name}:${file.size}`
27690
27404
  )) }) }),
27691
- /* @__PURE__ */ jsx18("div", { className: "flex justify-end border-t border-[hsl(var(--border))] px-4 py-3", children: /* @__PURE__ */ jsx18(
27405
+ /* @__PURE__ */ jsx19("div", { className: "flex justify-end border-t border-[hsl(var(--border))] px-4 py-3", children: /* @__PURE__ */ jsx19(
27692
27406
  "button",
27693
27407
  {
27694
27408
  type: "button",
@@ -27751,41 +27465,6 @@ var FileMention = index_default.extend({
27751
27465
  }
27752
27466
  });
27753
27467
 
27754
- // src/rich-input/extensions/workflow-mention.ts
27755
- var WorkflowMention = Node3.create({
27756
- name: "workflowMention",
27757
- group: "inline",
27758
- inline: true,
27759
- atom: true,
27760
- selectable: false,
27761
- addAttributes() {
27762
- return {
27763
- name: {
27764
- default: "",
27765
- parseHTML: (element) => element.getAttribute("data-workflow") || "",
27766
- renderHTML: (attributes) => ({ "data-workflow": attributes.name })
27767
- }
27768
- };
27769
- },
27770
- parseHTML() {
27771
- return [{ tag: "span[data-workflow]" }];
27772
- },
27773
- renderHTML({ node, HTMLAttributes }) {
27774
- return [
27775
- "span",
27776
- mergeAttributes(HTMLAttributes, {
27777
- // 复用技能胶囊的现成样式(两个输入框的容器 class 都已带它的规则)
27778
- class: "skill-mention-pill",
27779
- "data-workflow": node.attrs.name
27780
- }),
27781
- `\u8FD0\u884C\u5DE5\u4F5C\u6D41 ${node.attrs.name}`
27782
- ];
27783
- },
27784
- renderText({ node }) {
27785
- return `\u8FD0\u884C\u5DE5\u4F5C\u6D41 ${node.attrs.name}`;
27786
- }
27787
- });
27788
-
27789
27468
  // src/rich-input/lib/reasoning-levels.ts
27790
27469
  var REASONING_LEVEL_LABELS = {
27791
27470
  off: "\u5173",
@@ -27801,7 +27480,7 @@ function reasoningLevelLabel(level) {
27801
27480
  }
27802
27481
 
27803
27482
  // src/rich-input/ReasoningModeSelect.tsx
27804
- import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
27483
+ import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
27805
27484
  function ReasoningModeSelect({
27806
27485
  level,
27807
27486
  levels,
@@ -27809,11 +27488,11 @@ function ReasoningModeSelect({
27809
27488
  disabledReason,
27810
27489
  onChange
27811
27490
  }) {
27812
- return /* @__PURE__ */ jsxs10("label", { className: "flex w-full flex-col gap-1 px-3 py-2", children: [
27813
- /* @__PURE__ */ jsxs10("span", { className: "flex w-full items-center gap-2", children: [
27814
- /* @__PURE__ */ jsx19(Brain, { size: 14, className: `shrink-0 ${chatTone("reasoning").text}`, "aria-hidden": "true" }),
27815
- /* @__PURE__ */ jsx19("span", { className: "shrink-0", children: "\u601D\u8003\u6A21\u5F0F" }),
27816
- /* @__PURE__ */ jsx19(
27491
+ return /* @__PURE__ */ jsxs11("label", { className: "flex w-full flex-col gap-1 px-3 py-2", children: [
27492
+ /* @__PURE__ */ jsxs11("span", { className: "flex w-full items-center gap-2", children: [
27493
+ /* @__PURE__ */ jsx20(Brain, { size: 14, className: `shrink-0 ${chatTone("reasoning").text}`, "aria-hidden": "true" }),
27494
+ /* @__PURE__ */ jsx20("span", { className: "shrink-0", children: "\u601D\u8003\u6A21\u5F0F" }),
27495
+ /* @__PURE__ */ jsx20(
27817
27496
  "select",
27818
27497
  {
27819
27498
  value: level,
@@ -27822,18 +27501,18 @@ function ReasoningModeSelect({
27822
27501
  "aria-label": "\u601D\u8003\u6A21\u5F0F",
27823
27502
  title: "\u9009\u62E9\u601D\u8003\u6863\u4F4D\u3002\u6863\u4F4D\u8D8A\u9AD8\uFF0C\u6A21\u578B\u601D\u8003\u8D8A\u6DF1\u5165\uFF0C\u4F46\u54CD\u5E94\u53EF\u80FD\u66F4\u6162",
27824
27503
  className: "ml-auto h-6 min-w-20 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-1.5 disabled:cursor-not-allowed disabled:opacity-50",
27825
- children: levels.map((item) => /* @__PURE__ */ jsx19("option", { value: item, children: reasoningLevelLabel(item) }, item))
27504
+ children: levels.map((item) => /* @__PURE__ */ jsx20("option", { value: item, children: reasoningLevelLabel(item) }, item))
27826
27505
  }
27827
27506
  )
27828
27507
  ] }),
27829
- disabled && disabledReason ? /* @__PURE__ */ jsx19("span", { className: "pl-[22px] text-xs text-[hsl(var(--muted-foreground))]", children: disabledReason }) : null
27508
+ disabled && disabledReason ? /* @__PURE__ */ jsx20("span", { className: "pl-[22px] text-xs text-[hsl(var(--muted-foreground))]", children: disabledReason }) : null
27830
27509
  ] });
27831
27510
  }
27832
27511
 
27833
27512
  // src/rich-input/PlanningToggle.tsx
27834
- import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
27513
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
27835
27514
  function PlanningToggle({ enabled, onChange, disabled }) {
27836
- return /* @__PURE__ */ jsxs11(
27515
+ return /* @__PURE__ */ jsxs12(
27837
27516
  "button",
27838
27517
  {
27839
27518
  type: "button",
@@ -27845,18 +27524,18 @@ function PlanningToggle({ enabled, onChange, disabled }) {
27845
27524
  disabled,
27846
27525
  className: "flex w-full items-center justify-between gap-3 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))] disabled:cursor-not-allowed disabled:opacity-50",
27847
27526
  children: [
27848
- /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2", children: [
27849
- /* @__PURE__ */ jsx20(Lightbulb, { size: 14, className: "text-[#F97316]", "aria-hidden": "true" }),
27527
+ /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-2", children: [
27528
+ /* @__PURE__ */ jsx21(Lightbulb, { size: 14, className: "text-[#F97316]", "aria-hidden": "true" }),
27850
27529
  "\u89C4\u5212\u6A21\u5F0F"
27851
27530
  ] }),
27852
- /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2", children: [
27853
- /* @__PURE__ */ jsx20("span", { className: "text-[hsl(var(--muted-foreground))]", children: enabled ? "\u5F00" : "\u5173" }),
27854
- /* @__PURE__ */ jsx20(
27531
+ /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-2", children: [
27532
+ /* @__PURE__ */ jsx21("span", { className: "text-[hsl(var(--muted-foreground))]", children: enabled ? "\u5F00" : "\u5173" }),
27533
+ /* @__PURE__ */ jsx21(
27855
27534
  "span",
27856
27535
  {
27857
27536
  className: `flex h-4 w-7 items-center rounded-full p-0.5 transition-colors ${enabled ? "justify-end bg-[hsl(var(--primary))]" : "justify-start bg-[hsl(var(--muted))]"}`,
27858
27537
  "aria-hidden": "true",
27859
- children: /* @__PURE__ */ jsx20("span", { className: "h-3 w-3 rounded-full bg-[hsl(var(--background))]" })
27538
+ children: /* @__PURE__ */ jsx21("span", { className: "h-3 w-3 rounded-full bg-[hsl(var(--background))]" })
27860
27539
  }
27861
27540
  )
27862
27541
  ] })
@@ -27877,12 +27556,12 @@ function shouldHandleHistoryKey(event, menuOpen) {
27877
27556
  }
27878
27557
 
27879
27558
  // src/rich-input/ComposerAttachmentViewport.tsx
27880
- import { jsx as jsx21 } from "react/jsx-runtime";
27559
+ import { jsx as jsx23 } from "react/jsx-runtime";
27881
27560
  function ComposerAttachmentViewport({
27882
27561
  className,
27883
27562
  ...props
27884
27563
  }) {
27885
- return /* @__PURE__ */ jsx21(
27564
+ return /* @__PURE__ */ jsx23(
27886
27565
  "div",
27887
27566
  {
27888
27567
  className: cn("min-h-0 max-h-40 overflow-y-auto overscroll-contain", className),
@@ -27892,7 +27571,7 @@ function ComposerAttachmentViewport({
27892
27571
  }
27893
27572
 
27894
27573
  // src/rich-input/ChatInput.tsx
27895
- import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
27574
+ import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
27896
27575
  var RECENT_SESSION_LIMIT = 50;
27897
27576
  var DOUBLE_ESCAPE_MS = 450;
27898
27577
  function getEditorText(editor) {
@@ -28063,31 +27742,31 @@ function ComposerFilePill({
28063
27742
  const isFailed = isFile && attachment.status === "failed";
28064
27743
  const isUploading = isFile && attachment.status === "uploading";
28065
27744
  const uploadPercent = isUploading && typeof attachment.uploadProgress === "number" ? Math.max(0, Math.min(100, Math.round(attachment.uploadProgress * 100))) : null;
28066
- return /* @__PURE__ */ jsxs12(
27745
+ return /* @__PURE__ */ jsxs13(
28067
27746
  "div",
28068
27747
  {
28069
27748
  className: `relative flex shrink-0 items-center gap-1.5 overflow-hidden rounded-full border px-2.5 py-1 text-[11px] ${isFailed ? "border-[hsl(var(--swf-danger)/0.3)] bg-[hsl(var(--swf-danger-soft))] text-[hsl(var(--swf-danger))]" : "border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]"}`,
28070
27749
  children: [
28071
- uploadPercent !== null ? /* @__PURE__ */ jsx23(
27750
+ uploadPercent !== null ? /* @__PURE__ */ jsx24(
28072
27751
  "span",
28073
27752
  {
28074
27753
  className: "absolute inset-y-0 left-0 bg-[hsl(var(--primary))]/10 transition-[width]",
28075
27754
  style: { width: `${uploadPercent}%` }
28076
27755
  }
28077
27756
  ) : null,
28078
- isUploading ? /* @__PURE__ */ jsx23(
27757
+ isUploading ? /* @__PURE__ */ jsx24(
28079
27758
  LoaderCircle,
28080
27759
  {
28081
27760
  size: 12,
28082
27761
  className: "relative z-10 shrink-0 animate-spin text-[hsl(var(--muted-foreground))]"
28083
27762
  }
28084
- ) : /* @__PURE__ */ jsx23(Icon, { size: 12, className: "relative z-10 shrink-0 text-[hsl(var(--muted-foreground))]" }),
28085
- /* @__PURE__ */ jsx23("span", { className: "relative z-10 max-w-32 truncate", children: attachment.name }),
28086
- uploadPercent !== null ? /* @__PURE__ */ jsxs12("span", { className: "relative z-10 font-mono text-[10px] tabular-nums text-[hsl(var(--muted-foreground))]", children: [
27763
+ ) : /* @__PURE__ */ jsx24(Icon, { size: 12, className: "relative z-10 shrink-0 text-[hsl(var(--muted-foreground))]" }),
27764
+ /* @__PURE__ */ jsx24("span", { className: "relative z-10 max-w-32 truncate", children: attachment.name }),
27765
+ uploadPercent !== null ? /* @__PURE__ */ jsxs13("span", { className: "relative z-10 font-mono text-[10px] tabular-nums text-[hsl(var(--muted-foreground))]", children: [
28087
27766
  uploadPercent,
28088
27767
  "%"
28089
27768
  ] }) : null,
28090
- /* @__PURE__ */ jsx23(
27769
+ /* @__PURE__ */ jsx24(
28091
27770
  "button",
28092
27771
  {
28093
27772
  type: "button",
@@ -28095,7 +27774,7 @@ function ComposerFilePill({
28095
27774
  "aria-label": `\u79FB\u9664 ${attachment.name}`,
28096
27775
  title: "\u79FB\u9664",
28097
27776
  className: "relative z-10 ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-[hsl(var(--swf-danger))]",
28098
- children: /* @__PURE__ */ jsx23(X, { size: 10 })
27777
+ children: /* @__PURE__ */ jsx24(X, { size: 10 })
28099
27778
  }
28100
27779
  )
28101
27780
  ]
@@ -28218,7 +27897,7 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28218
27897
  setImportingId(null);
28219
27898
  }
28220
27899
  };
28221
- return /* @__PURE__ */ jsx23(
27900
+ return /* @__PURE__ */ jsx24(
28222
27901
  "div",
28223
27902
  {
28224
27903
  className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/55 p-4",
@@ -28226,44 +27905,44 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28226
27905
  onKeyDown: (e) => {
28227
27906
  if (e.key === "Escape") onClose();
28228
27907
  },
28229
- children: /* @__PURE__ */ jsxs12(
27908
+ children: /* @__PURE__ */ jsxs13(
28230
27909
  "div",
28231
27910
  {
28232
27911
  className: "w-full max-w-lg flex flex-col rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-[var(--swf-shadow-overlay)]",
28233
27912
  onClick: (e) => e.stopPropagation(),
28234
27913
  onKeyDown: (e) => e.stopPropagation(),
28235
27914
  children: [
28236
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-5 py-3", children: [
28237
- /* @__PURE__ */ jsx23("h4", { className: "text-sm font-semibold text-[hsl(var(--foreground))]", children: "\u6DFB\u52A0\u4E0A\u4E0B\u6587" }),
28238
- /* @__PURE__ */ jsx23(
27915
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-5 py-3", children: [
27916
+ /* @__PURE__ */ jsx24("h4", { className: "text-sm font-semibold text-[hsl(var(--foreground))]", children: "\u6DFB\u52A0\u4E0A\u4E0B\u6587" }),
27917
+ /* @__PURE__ */ jsx24(
28239
27918
  "button",
28240
27919
  {
28241
27920
  type: "button",
28242
27921
  onClick: onClose,
28243
27922
  className: "rounded-md p-1 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
28244
- children: /* @__PURE__ */ jsx23(X, { size: 14 })
27923
+ children: /* @__PURE__ */ jsx24(X, { size: 14 })
28245
27924
  }
28246
27925
  )
28247
27926
  ] }),
28248
- /* @__PURE__ */ jsxs12("div", { className: "px-5 py-4 space-y-3", children: [
28249
- /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
28250
- /* @__PURE__ */ jsxs12(
27927
+ /* @__PURE__ */ jsxs13("div", { className: "px-5 py-4 space-y-3", children: [
27928
+ /* @__PURE__ */ jsxs13("div", { className: "relative", children: [
27929
+ /* @__PURE__ */ jsxs13(
28251
27930
  "button",
28252
27931
  {
28253
27932
  type: "button",
28254
27933
  onClick: handleLoadSessions,
28255
27934
  className: "inline-flex items-center gap-1.5 rounded-md border border-[hsl(var(--border))] px-2.5 py-1.5 text-xs text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
28256
27935
  children: [
28257
- /* @__PURE__ */ jsx23(Import, { size: 12 }),
27936
+ /* @__PURE__ */ jsx24(Import, { size: 12 }),
28258
27937
  "\u4ECE\u5176\u4ED6\u4F1A\u8BDD\u5BFC\u5165",
28259
- /* @__PURE__ */ jsx23(ChevronDown, { size: 10, className: `transition-transform ${showSessionPicker ? "rotate-180" : ""}` })
27938
+ /* @__PURE__ */ jsx24(ChevronDown, { size: 10, className: `transition-transform ${showSessionPicker ? "rotate-180" : ""}` })
28260
27939
  ]
28261
27940
  }
28262
27941
  ),
28263
- showSessionPicker && /* @__PURE__ */ jsx23("div", { className: "absolute left-0 top-full z-10 mt-1 max-h-48 w-full overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-[var(--swf-shadow-overlay)]", children: loadingSessions ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]", children: [
28264
- /* @__PURE__ */ jsx23(LoaderCircle, { size: 12, className: "animate-spin" }),
27942
+ showSessionPicker && /* @__PURE__ */ jsx24("div", { className: "absolute left-0 top-full z-10 mt-1 max-h-48 w-full overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-[var(--swf-shadow-overlay)]", children: loadingSessions ? /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]", children: [
27943
+ /* @__PURE__ */ jsx24(LoaderCircle, { size: 12, className: "animate-spin" }),
28265
27944
  "\u52A0\u8F7D\u4F1A\u8BDD\u5217\u8868\u2026"
28266
- ] }) : sessions.length === 0 ? /* @__PURE__ */ jsx23("div", { className: "px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6682\u65E0\u5176\u4ED6\u4F1A\u8BDD" }) : sessions.map((s) => /* @__PURE__ */ jsxs12(
27945
+ ] }) : sessions.length === 0 ? /* @__PURE__ */ jsx24("div", { className: "px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6682\u65E0\u5176\u4ED6\u4F1A\u8BDD" }) : sessions.map((s) => /* @__PURE__ */ jsxs13(
28267
27946
  "button",
28268
27947
  {
28269
27948
  type: "button",
@@ -28271,16 +27950,16 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28271
27950
  onClick: () => handleImportSession(s.id),
28272
27951
  className: "flex w-full items-center gap-2 px-3 py-2 text-left text-xs text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))] disabled:opacity-50",
28273
27952
  children: [
28274
- importingId === s.id && /* @__PURE__ */ jsx23(LoaderCircle, { size: 10, className: "shrink-0 animate-spin" }),
28275
- /* @__PURE__ */ jsx23("span", { className: "truncate", children: s.intent })
27953
+ importingId === s.id && /* @__PURE__ */ jsx24(LoaderCircle, { size: 10, className: "shrink-0 animate-spin" }),
27954
+ /* @__PURE__ */ jsx24("span", { className: "truncate", children: s.intent })
28276
27955
  ]
28277
27956
  },
28278
27957
  s.id
28279
27958
  )) })
28280
27959
  ] }),
28281
- /* @__PURE__ */ jsxs12("div", { children: [
28282
- /* @__PURE__ */ jsx23("label", { htmlFor: "ctx-label", className: "block text-xs font-medium text-[hsl(var(--foreground))] mb-1", children: "\u6807\u7B7E" }),
28283
- /* @__PURE__ */ jsx23(
27960
+ /* @__PURE__ */ jsxs13("div", { children: [
27961
+ /* @__PURE__ */ jsx24("label", { htmlFor: "ctx-label", className: "block text-xs font-medium text-[hsl(var(--foreground))] mb-1", children: "\u6807\u7B7E" }),
27962
+ /* @__PURE__ */ jsx24(
28284
27963
  "input",
28285
27964
  {
28286
27965
  id: "ctx-label",
@@ -28291,13 +27970,13 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28291
27970
  }
28292
27971
  )
28293
27972
  ] }),
28294
- /* @__PURE__ */ jsxs12("div", { children: [
28295
- /* @__PURE__ */ jsx23("label", { htmlFor: "ctx-content", className: "block text-xs font-medium text-[hsl(var(--foreground))] mb-1", children: "\u5185\u5BB9" }),
28296
- isImportProcessing && /* @__PURE__ */ jsxs12("div", { className: "mb-1.5 flex items-center gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
28297
- /* @__PURE__ */ jsx23(LoaderCircle, { size: 12, className: "animate-spin" }),
27973
+ /* @__PURE__ */ jsxs13("div", { children: [
27974
+ /* @__PURE__ */ jsx24("label", { htmlFor: "ctx-content", className: "block text-xs font-medium text-[hsl(var(--foreground))] mb-1", children: "\u5185\u5BB9" }),
27975
+ isImportProcessing && /* @__PURE__ */ jsxs13("div", { className: "mb-1.5 flex items-center gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
27976
+ /* @__PURE__ */ jsx24(LoaderCircle, { size: 12, className: "animate-spin" }),
28298
27977
  "\u6B63\u5728\u5904\u7406\u5BFC\u5165\u5185\u5BB9\u5E76\u5199\u5165 workspace/context\uFF0C\u5B8C\u6210\u540E\u53EF\u70B9\u51FB\u201C\u786E\u5B9A\u201D"
28299
27978
  ] }),
28300
- /* @__PURE__ */ jsx23(
27979
+ /* @__PURE__ */ jsx24(
28301
27980
  "textarea",
28302
27981
  {
28303
27982
  id: "ctx-content",
@@ -28310,8 +27989,8 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28310
27989
  )
28311
27990
  ] })
28312
27991
  ] }),
28313
- /* @__PURE__ */ jsxs12("div", { className: "flex justify-end gap-2 border-t border-[hsl(var(--border))] px-5 py-3", children: [
28314
- /* @__PURE__ */ jsx23(
27992
+ /* @__PURE__ */ jsxs13("div", { className: "flex justify-end gap-2 border-t border-[hsl(var(--border))] px-5 py-3", children: [
27993
+ /* @__PURE__ */ jsx24(
28315
27994
  "button",
28316
27995
  {
28317
27996
  type: "button",
@@ -28320,7 +27999,7 @@ ${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`
28320
27999
  children: "\u53D6\u6D88"
28321
28000
  }
28322
28001
  ),
28323
- /* @__PURE__ */ jsx23(
28002
+ /* @__PURE__ */ jsx24(
28324
28003
  "button",
28325
28004
  {
28326
28005
  type: "button",
@@ -28351,19 +28030,19 @@ function ComposerContextPill({
28351
28030
  }) {
28352
28031
  const [showDetail, setShowDetail] = useState11(false);
28353
28032
  const tokenK = formatTokenK(content);
28354
- return /* @__PURE__ */ jsxs12(Fragment5, { children: [
28355
- /* @__PURE__ */ jsxs12("div", { className: "flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-2.5 py-1 text-[11px] text-[hsl(var(--foreground))]", children: [
28356
- imageUrl ? /* @__PURE__ */ jsx23(
28033
+ return /* @__PURE__ */ jsxs13(Fragment5, { children: [
28034
+ /* @__PURE__ */ jsxs13("div", { className: "flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-2.5 py-1 text-[11px] text-[hsl(var(--foreground))]", children: [
28035
+ imageUrl ? /* @__PURE__ */ jsx24(
28357
28036
  "button",
28358
28037
  {
28359
28038
  type: "button",
28360
28039
  onClick: () => setShowDetail(true),
28361
28040
  className: "h-6 w-6 overflow-hidden rounded-md border border-[hsl(var(--border))] bg-white",
28362
28041
  title: "\u67E5\u770B\u9009\u4E2D\u533A\u57DF\u622A\u56FE",
28363
- children: /* @__PURE__ */ jsx23("img", { src: imageUrl, alt: "\u9009\u4E2D\u533A\u57DF\u622A\u56FE", className: "h-full w-full object-cover" })
28042
+ children: /* @__PURE__ */ jsx24("img", { src: imageUrl, alt: "\u9009\u4E2D\u533A\u57DF\u622A\u56FE", className: "h-full w-full object-cover" })
28364
28043
  }
28365
28044
  ) : null,
28366
- /* @__PURE__ */ jsx23(
28045
+ /* @__PURE__ */ jsx24(
28367
28046
  "button",
28368
28047
  {
28369
28048
  type: "button",
@@ -28373,7 +28052,7 @@ function ComposerContextPill({
28373
28052
  children: label
28374
28053
  }
28375
28054
  ),
28376
- /* @__PURE__ */ jsx23(
28055
+ /* @__PURE__ */ jsx24(
28377
28056
  "span",
28378
28057
  {
28379
28058
  className: "shrink-0 rounded bg-[hsl(var(--background))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]",
@@ -28381,7 +28060,7 @@ function ComposerContextPill({
28381
28060
  children: tokenK
28382
28061
  }
28383
28062
  ),
28384
- /* @__PURE__ */ jsx23(
28063
+ /* @__PURE__ */ jsx24(
28385
28064
  "button",
28386
28065
  {
28387
28066
  type: "button",
@@ -28389,11 +28068,11 @@ function ComposerContextPill({
28389
28068
  "aria-label": `\u79FB\u9664\u4E0A\u4E0B\u6587 ${label}`,
28390
28069
  title: "\u79FB\u9664",
28391
28070
  className: "ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-[hsl(var(--swf-danger))]",
28392
- children: /* @__PURE__ */ jsx23(X, { size: 10 })
28071
+ children: /* @__PURE__ */ jsx24(X, { size: 10 })
28393
28072
  }
28394
28073
  )
28395
28074
  ] }),
28396
- showDetail && /* @__PURE__ */ jsx23(
28075
+ showDetail && /* @__PURE__ */ jsx24(
28397
28076
  "div",
28398
28077
  {
28399
28078
  className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/55 p-6",
@@ -28401,31 +28080,31 @@ function ComposerContextPill({
28401
28080
  onKeyDown: (e) => {
28402
28081
  if (e.key === "Escape") setShowDetail(false);
28403
28082
  },
28404
- children: /* @__PURE__ */ jsxs12(
28083
+ children: /* @__PURE__ */ jsxs13(
28405
28084
  "div",
28406
28085
  {
28407
28086
  className: "w-full max-w-4xl max-h-[85vh] flex flex-col rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-[var(--swf-shadow-overlay)]",
28408
28087
  onClick: (e) => e.stopPropagation(),
28409
28088
  onKeyDown: (e) => e.stopPropagation(),
28410
28089
  children: [
28411
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-6 py-3", children: [
28412
- /* @__PURE__ */ jsxs12("div", { className: "min-w-0", children: [
28413
- /* @__PURE__ */ jsx23("h4", { className: "truncate text-xs font-semibold text-[hsl(var(--foreground))]", children: label }),
28414
- imageUrl ? /* @__PURE__ */ jsx23("p", { className: "mt-0.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u9644\u52A0\u9009\u4E2D\u533A\u57DF\u622A\u56FE\uFF0C\u975E\u591A\u6A21\u6001\u6A21\u578B\u4F1A\u81EA\u52A8\u5FFD\u7565\u56FE\u7247\u3002" }) : null
28090
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-6 py-3", children: [
28091
+ /* @__PURE__ */ jsxs13("div", { className: "min-w-0", children: [
28092
+ /* @__PURE__ */ jsx24("h4", { className: "truncate text-xs font-semibold text-[hsl(var(--foreground))]", children: label }),
28093
+ imageUrl ? /* @__PURE__ */ jsx24("p", { className: "mt-0.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u9644\u52A0\u9009\u4E2D\u533A\u57DF\u622A\u56FE\uFF0C\u975E\u591A\u6A21\u6001\u6A21\u578B\u4F1A\u81EA\u52A8\u5FFD\u7565\u56FE\u7247\u3002" }) : null
28415
28094
  ] }),
28416
- /* @__PURE__ */ jsx23(
28095
+ /* @__PURE__ */ jsx24(
28417
28096
  "button",
28418
28097
  {
28419
28098
  type: "button",
28420
28099
  onClick: () => setShowDetail(false),
28421
28100
  className: "rounded-md p-1 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
28422
- children: /* @__PURE__ */ jsx23(X, { size: 14 })
28101
+ children: /* @__PURE__ */ jsx24(X, { size: 14 })
28423
28102
  }
28424
28103
  )
28425
28104
  ] }),
28426
- /* @__PURE__ */ jsxs12("div", { className: "min-h-0 flex-1 overflow-y-auto px-6 py-4", children: [
28427
- imageUrl ? /* @__PURE__ */ jsx23("div", { className: "mb-4 rounded-xl border border-[hsl(var(--border))] bg-white p-2", children: /* @__PURE__ */ jsx23("img", { src: imageUrl, alt: "\u9009\u4E2D\u533A\u57DF\u622A\u56FE", className: "max-h-72 max-w-full rounded-lg object-contain" }) }) : null,
28428
- /* @__PURE__ */ jsx23("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] leading-[1.6] text-[hsl(var(--foreground)/0.85)]", children: content })
28105
+ /* @__PURE__ */ jsxs13("div", { className: "min-h-0 flex-1 overflow-y-auto px-6 py-4", children: [
28106
+ imageUrl ? /* @__PURE__ */ jsx24("div", { className: "mb-4 rounded-xl border border-[hsl(var(--border))] bg-white p-2", children: /* @__PURE__ */ jsx24("img", { src: imageUrl, alt: "\u9009\u4E2D\u533A\u57DF\u622A\u56FE", className: "max-h-72 max-w-full rounded-lg object-contain" }) }) : null,
28107
+ /* @__PURE__ */ jsx24("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] leading-[1.6] text-[hsl(var(--foreground)/0.85)]", children: content })
28429
28108
  ] })
28430
28109
  ]
28431
28110
  }
@@ -28498,6 +28177,7 @@ function ChatInput({
28498
28177
  lite = false,
28499
28178
  canCreateBoardTask = false
28500
28179
  }) {
28180
+ const developer = useChatRenderMode() === "developer";
28501
28181
  const isBusy = isStreaming || isCompacting;
28502
28182
  const resolvedInputLabel = inputLabel?.trim() || "\u8F93\u5165\u6D88\u606F";
28503
28183
  const initialInput = externalDraft?.value ?? initialDraft ?? "";
@@ -28507,10 +28187,11 @@ function ChatInput({
28507
28187
  externalDraft?.setValue(value);
28508
28188
  });
28509
28189
  const externalDraftValue = externalDraft?.value;
28510
- const inputRef = useRef9(input);
28190
+ const inputRef = useRef7(input);
28511
28191
  inputRef.current = input;
28512
- const appliedInitialDraftKeyRef = useRef9(null);
28513
- useEffect9(() => {
28192
+ const appliedInitialDraftKeyRef = useRef7(null);
28193
+ const appliedInitialDraftRef = useRef7(null);
28194
+ useEffect8(() => {
28514
28195
  if (externalDraftValue == null) return;
28515
28196
  if (inputRef.current === externalDraftValue) return;
28516
28197
  if (editorRef.current) {
@@ -28518,16 +28199,18 @@ function ChatInput({
28518
28199
  }
28519
28200
  setInputInternal(externalDraftValue);
28520
28201
  }, [externalDraftValue]);
28521
- useEffect9(() => {
28202
+ useEffect8(() => {
28522
28203
  const key = initialDraftKey ?? initialDraft ?? "";
28523
28204
  if (!initialDraft || !key || appliedInitialDraftKeyRef.current === key) return;
28524
- if (inputRef.current.trim()) {
28205
+ if (inputRef.current === initialDraft) appliedInitialDraftRef.current = initialDraft;
28206
+ if (inputRef.current.trim() && inputRef.current !== appliedInitialDraftRef.current) {
28525
28207
  appliedInitialDraftKeyRef.current = key;
28526
28208
  return;
28527
28209
  }
28528
28210
  replaceEditorText(editorRef.current, initialDraft);
28529
28211
  setInput(initialDraft);
28530
28212
  appliedInitialDraftKeyRef.current = key;
28213
+ appliedInitialDraftRef.current = initialDraft;
28531
28214
  }, [initialDraft, initialDraftKey, setInput]);
28532
28215
  const [composerAttachments, setComposerAttachmentsInternal] = useState11(
28533
28216
  externalAttachments?.value ?? []
@@ -28542,9 +28225,9 @@ function ChatInput({
28542
28225
  }
28543
28226
  );
28544
28227
  const externalAttachmentsValue = externalAttachments?.value;
28545
- const composerAttachmentsRef = useRef9(composerAttachments);
28228
+ const composerAttachmentsRef = useRef7(composerAttachments);
28546
28229
  composerAttachmentsRef.current = composerAttachments;
28547
- useEffect9(() => {
28230
+ useEffect8(() => {
28548
28231
  if (externalAttachmentsValue == null) return;
28549
28232
  if (composerAttachmentsRef.current === externalAttachmentsValue) return;
28550
28233
  setComposerAttachmentsInternal(externalAttachmentsValue);
@@ -28558,16 +28241,16 @@ function ChatInput({
28558
28241
  const invalidation = useSessionDataInvalidation();
28559
28242
  const SkillStatusBarComponent = SkillStatusBarOverride ?? SkillStatusBar;
28560
28243
  const [actionMenuOpen, setActionMenuOpen] = useState11(false);
28561
- const actionMenuOpenRef = useRef9(false);
28562
- useEffect9(() => {
28244
+ const actionMenuOpenRef = useRef7(false);
28245
+ useEffect8(() => {
28563
28246
  actionMenuOpenRef.current = actionMenuOpen;
28564
28247
  }, [actionMenuOpen]);
28565
28248
  const [connectMenuOpen, setConnectMenuOpen] = useState11(false);
28566
- const fileInputRef = useRef9(null);
28567
- const folderInputRef = useRef9(null);
28568
- const editorRef = useRef9(null);
28569
- const lastEscapeAtRef = useRef9(0);
28570
- const localImageUrlsRef = useRef9(/* @__PURE__ */ new Map());
28249
+ const fileInputRef = useRef7(null);
28250
+ const folderInputRef = useRef7(null);
28251
+ const editorRef = useRef7(null);
28252
+ const lastEscapeAtRef = useRef7(0);
28253
+ const localImageUrlsRef = useRef7(/* @__PURE__ */ new Map());
28571
28254
  const currentChatSessionId = useCurrentChatSessionId();
28572
28255
  const activeSessionId = sessionIdProp ?? currentChatSessionId;
28573
28256
  const currentSession = useChatSessionDetail(activeSessionId);
@@ -28600,9 +28283,9 @@ function ChatInput({
28600
28283
  if (!activeSessionId) return [];
28601
28284
  try {
28602
28285
  const detail = await client.sessions.getSession(activeSessionId);
28603
- return detail.runtime_type === "sandbox" ? getTopicAssetSuggestionItems(client, detail.chat_group_id, query) : [];
28286
+ return getTopicAssetSuggestionItems(client, detail.chat_group_id, query);
28604
28287
  } catch {
28605
- return [{ kind: "topicAssetError", message: "\u4E3B\u9898\u8D44\u4EA7\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165 @ \u91CD\u8BD5" }];
28288
+ return [{ kind: "topicAssetError", message: "\u5DE5\u4F5C\u7A7A\u95F4\u8D44\u4EA7\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165 @ \u91CD\u8BD5" }];
28606
28289
  }
28607
28290
  });
28608
28291
  const getSessionId = useEffectEvent(() => activeSessionId);
@@ -28655,7 +28338,7 @@ function ChatInput({
28655
28338
  }
28656
28339
  };
28657
28340
  const stableAppendFiles = useEffectEvent((files) => appendFiles(files));
28658
- const stableHandleSubmit = useEffectEvent(() => handleSubmit());
28341
+ const stableHandleSubmit = useEffectEvent((queueWhenRunning = false) => handleSubmit(queueWhenRunning));
28659
28342
  const getEditorState = useEffectEvent(() => ({
28660
28343
  input,
28661
28344
  connectionStatus,
@@ -28686,7 +28369,6 @@ function ChatInput({
28686
28369
  gapcursor: false,
28687
28370
  heading: false,
28688
28371
  horizontalRule: false,
28689
- // 输入框是纯文本输入区,关掉自动识别链接,避免点击输入的网址直接跳转
28690
28372
  link: false,
28691
28373
  orderedList: false
28692
28374
  }),
@@ -28720,7 +28402,7 @@ function ChatInput({
28720
28402
  if (!container || !root) return;
28721
28403
  updateSuggestionPosition(container, props.clientRect);
28722
28404
  root.render(
28723
- /* @__PURE__ */ jsx23(
28405
+ /* @__PURE__ */ jsx24(
28724
28406
  FileCompletionMenu,
28725
28407
  {
28726
28408
  ref: (instance) => {
@@ -28774,7 +28456,6 @@ function ChatInput({
28774
28456
  }
28775
28457
  }
28776
28458
  }),
28777
- WorkflowMention,
28778
28459
  PluginMention,
28779
28460
  TopicAssetMention,
28780
28461
  SkillMention.configure({
@@ -28789,13 +28470,6 @@ function ChatInput({
28789
28470
  void handleSlashCommand(item.id);
28790
28471
  return;
28791
28472
  }
28792
- if (item.type === "workflow") {
28793
- suggestionEditor.chain().focus().insertContentAt(range, [
28794
- { type: "workflowMention", attrs: { name: item.name } },
28795
- { type: "text", text: workflowParamsTail(item) }
28796
- ]).run();
28797
- return;
28798
- }
28799
28473
  suggestionEditor.chain().focus().insertContentAt(range, [
28800
28474
  {
28801
28475
  type: "skillMention",
@@ -28821,7 +28495,7 @@ function ChatInput({
28821
28495
  if (!container || !root) return;
28822
28496
  updateSuggestionPosition(container, props.clientRect);
28823
28497
  root.render(
28824
- /* @__PURE__ */ jsx23(
28498
+ /* @__PURE__ */ jsx24(
28825
28499
  SkillCompletionMenu,
28826
28500
  {
28827
28501
  ref: (instance) => {
@@ -28939,7 +28613,7 @@ function ChatInput({
28939
28613
  if (state3.connectionStatus !== "connected") {
28940
28614
  return true;
28941
28615
  }
28942
- void state3.handleSubmit();
28616
+ void state3.handleSubmit(isQueueShortcut(event));
28943
28617
  return true;
28944
28618
  }
28945
28619
  return false;
@@ -28956,13 +28630,13 @@ function ChatInput({
28956
28630
  }
28957
28631
  });
28958
28632
  useDismissSkillSuggestionsOnModeChange(editor);
28959
- useEffect9(() => {
28633
+ useEffect8(() => {
28960
28634
  const dom = editor?.view.dom;
28961
28635
  if (!dom) return;
28962
28636
  dom.setAttribute("aria-label", resolvedInputLabel);
28963
28637
  dom.setAttribute("data-blade-input-label", resolvedInputLabel);
28964
28638
  }, [editor, resolvedInputLabel]);
28965
- useEffect9(() => {
28639
+ useEffect8(() => {
28966
28640
  if (!editor || !activeSessionId || rewindDraft == null) {
28967
28641
  return;
28968
28642
  }
@@ -28973,9 +28647,9 @@ function ChatInput({
28973
28647
  editor.commands.focus("end");
28974
28648
  composerChannels.setRewindDraft(activeSessionId, null);
28975
28649
  }, [activeSessionId, editor, rewindDraft]);
28976
- const submittingRef = useRef9(false);
28650
+ const submittingRef = useRef7(false);
28977
28651
  const [isSubmitting, setIsSubmitting] = useState11(false);
28978
- useEffect9(() => {
28652
+ useEffect8(() => {
28979
28653
  let changed = false;
28980
28654
  const nextLocalIds = /* @__PURE__ */ new Set();
28981
28655
  for (const attachment of composerAttachments) {
@@ -29000,7 +28674,7 @@ function ChatInput({
29000
28674
  setLocalImageUrls(Object.fromEntries(localImageUrlsRef.current));
29001
28675
  }
29002
28676
  }, [composerAttachments]);
29003
- useEffect9(() => {
28677
+ useEffect8(() => {
29004
28678
  return () => {
29005
28679
  for (const url of localImageUrlsRef.current.values()) {
29006
28680
  URL.revokeObjectURL(url);
@@ -29009,8 +28683,8 @@ function ChatInput({
29009
28683
  };
29010
28684
  }, []);
29011
28685
  const sessionHandle = useSessionHandle(activeSessionId);
29012
- const restoredPluginSelection = useRef9(null);
29013
- useEffect9(() => {
28686
+ const restoredPluginSelection = useRef7(null);
28687
+ useEffect8(() => {
29014
28688
  if (!sessionHandle || !activeSessionId || !editor) return;
29015
28689
  const restore = () => {
29016
28690
  if (restoredPluginSelection.current === activeSessionId) return;
@@ -29019,13 +28693,13 @@ function ChatInput({
29019
28693
  if (!latest || latest.turn_id.startsWith("local-user-")) return;
29020
28694
  restoredPluginSelection.current = activeSessionId;
29021
28695
  if (!getEditorText(editor).trim() && latest.refs?.length) {
29022
- editor.commands.setContent({ type: "doc", content: [{ type: "paragraph", content: latest.refs.flatMap((ref) => [{ type: "pluginMention", attrs: { ...ref } }, { type: "text", text: " " }]) }] });
28696
+ editor.commands.setContent(buildPluginSelectionDocument(latest.refs));
29023
28697
  }
29024
28698
  };
29025
28699
  restore();
29026
28700
  return sessionHandle.subscribe(restore);
29027
28701
  }, [sessionHandle, activeSessionId, editor]);
29028
- useEffect9(() => {
28702
+ useEffect8(() => {
29029
28703
  if (!sessionHandle || !activeSessionId) return;
29030
28704
  const offInsert = sessionHandle.on("insertTextRequested", ({ text }) => {
29031
28705
  const separate = /^\n/.test(text);
@@ -29060,7 +28734,7 @@ ${append2.text}` : append2.text;
29060
28734
  editor.chain().focus("end").insertContent(text).run();
29061
28735
  });
29062
28736
  const editorReady = editor != null;
29063
- useEffect9(() => {
28737
+ useEffect8(() => {
29064
28738
  if (!editorReady || !draftAppends?.length) {
29065
28739
  return;
29066
28740
  }
@@ -29076,7 +28750,7 @@ ${append2.text}` : append2.text;
29076
28750
  }
29077
28751
  void stableHandleSubmit();
29078
28752
  });
29079
- useEffect9(() => {
28753
+ useEffect8(() => {
29080
28754
  if (!sendRequests?.length) {
29081
28755
  return;
29082
28756
  }
@@ -29091,10 +28765,10 @@ ${append2.text}` : append2.text;
29091
28765
  });
29092
28766
  const { isRecording, level: voiceLevel } = voice;
29093
28767
  const isVoiceStarting = voice.status === "starting";
29094
- const voiceStopRef = useRef9(voice.stop);
28768
+ const voiceStopRef = useRef7(voice.stop);
29095
28769
  voiceStopRef.current = voice.stop;
29096
- const prevSessionIdRef = useRef9(activeSessionId);
29097
- useEffect9(() => {
28770
+ const prevSessionIdRef = useRef7(activeSessionId);
28771
+ useEffect8(() => {
29098
28772
  if (prevSessionIdRef.current !== activeSessionId) {
29099
28773
  prevSessionIdRef.current = activeSessionId;
29100
28774
  if (isRecording) {
@@ -29102,12 +28776,16 @@ ${append2.text}` : append2.text;
29102
28776
  }
29103
28777
  }
29104
28778
  }, [activeSessionId, isRecording]);
29105
- const handleSubmit = async () => {
28779
+ const hasRunningSendBlockers = () => {
28780
+ const json = editor?.getJSON();
28781
+ return composerAttachments.length > 0 || collectMessageMentions(json).length > 0 || collectTopicAssetMentions(json).length > 0;
28782
+ };
28783
+ const handleSubmit = async (queueWhenRunning = false) => {
29106
28784
  if (connectionStatus !== "connected") {
29107
28785
  return;
29108
28786
  }
29109
28787
  if (isCompacting) {
29110
- notifyChat(environment, "info", "\u5BF9\u8BDD\u6B63\u5728\u6574\u7406\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001");
28788
+ notifyChat(environment, "info", developer ? "\u5BF9\u8BDD\u6B63\u5728\u6574\u7406\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001" : "\u6B63\u5728\u5904\u7406\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001");
29111
28789
  return;
29112
28790
  }
29113
28791
  if (isStopping) {
@@ -29117,12 +28795,9 @@ ${append2.text}` : append2.text;
29117
28795
  notifyChat(environment, "info", "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\uFF0C\u8BF7\u7B49\u5F85\u672C\u8F6E\u7ED3\u675F\u540E\u518D\u53D1\u9001");
29118
28796
  return;
29119
28797
  }
29120
- if (isStreaming) {
29121
- const json = editor?.getJSON();
29122
- if (composerAttachments.length > 0 || collectPluginMentions(json).length > 0 || collectTopicAssetMentions(json).length > 0) {
29123
- notifyChat(environment, "info", "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\uFF0C\u5E26\u9644\u4EF6\u6216\u5F15\u7528\u7684\u6D88\u606F\u8BF7\u7B49\u5F85\u672C\u8F6E\u7ED3\u675F\u540E\u518D\u53D1\u9001");
29124
- return;
29125
- }
28798
+ if (isStreaming && hasRunningSendBlockers()) {
28799
+ notifyChat(environment, "info", "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\uFF0C\u5E26\u9644\u4EF6\u6216\u5F15\u7528\u7684\u6D88\u606F\u8BF7\u7B49\u5F85\u672C\u8F6E\u7ED3\u675F\u540E\u518D\u53D1\u9001");
28800
+ return;
29126
28801
  }
29127
28802
  if (!isStreaming) {
29128
28803
  const modelGate = gateSendWhileModelLoading(isModelLoading, hasComposerContent);
@@ -29151,21 +28826,17 @@ ${append2.text}` : append2.text;
29151
28826
  const rawText = serializeEditorContent(json);
29152
28827
  let submittedSessionId = activeSessionId;
29153
28828
  const submittedAttachmentIds = composerAttachments.map((attachment) => attachment.id);
29154
- const skill = findLeadingSkillMention(json);
29155
- const refs = collectPluginMentions(json);
28829
+ const refs = collectMessageMentions(json);
29156
28830
  if (refs.length > 20) {
29157
- notifyChat(environment, "error", "\u6BCF\u6761\u6D88\u606F\u6700\u591A\u9009\u62E9 20 \u4E2A\u63D2\u4EF6\u6761\u76EE");
28831
+ notifyChat(environment, "error", "\u6BCF\u6761\u6D88\u606F\u6700\u591A\u9009\u62E9 20 \u4E2A\u5F15\u7528");
29158
28832
  return;
29159
28833
  }
29160
28834
  const topicAssetRefs = collectTopicAssetMentions(json);
29161
28835
  if (topicAssetRefs.length > 20) {
29162
- notifyChat(environment, "error", "\u6BCF\u6761\u6D88\u606F\u6700\u591A\u5F15\u7528 20 \u4E2A\u4E3B\u9898\u8D44\u4EA7");
28836
+ notifyChat(environment, "error", "\u6BCF\u6761\u6D88\u606F\u6700\u591A\u5F15\u7528 20 \u4E2A\u5DE5\u4F5C\u7A7A\u95F4\u8D44\u4EA7");
29163
28837
  return;
29164
28838
  }
29165
- const text = skill ? transformSlashCommand(skill.skillId, rawText, {
29166
- local: skill.local,
29167
- installed: skill.installed
29168
- }) : rawText;
28839
+ const text = rawText;
29169
28840
  const pendingFiles = composerAttachments.filter(
29170
28841
  (a) => a.kind === "file" && a.status === "pending" && !!a.file
29171
28842
  );
@@ -29297,10 +28968,10 @@ ${append2.text}` : append2.text;
29297
28968
  try {
29298
28969
  accepted = await onSend(nextPayload, {
29299
28970
  targetSessionId: uploadTargetSessionId,
28971
+ queueWhenRunning,
29300
28972
  model: submitModels.sendModel,
29301
28973
  thinkingOverride: thinkingAvailable && selectedReasoningLevel ? true : void 0,
29302
28974
  reasoningLevel: thinkingAvailable ? selectedReasoningLevel || void 0 : void 0,
29303
- // 只有用户显式 @ 知识库才传选择;纯文本不附加知识库指令。
29304
28975
  refs: pluginRefsForSend(refs, sessionHandle?.getState().turns),
29305
28976
  topicAssetRefs: topicAssetRefs.length > 0 ? topicAssetRefs : void 0
29306
28977
  });
@@ -29318,7 +28989,7 @@ ${append2.text}` : append2.text;
29318
28989
  return;
29319
28990
  }
29320
28991
  if (refs.length && editor && !getEditorText(editor).trim()) {
29321
- editor.commands.setContent({ type: "doc", content: [{ type: "paragraph", content: refs.flatMap((ref) => [{ type: "pluginMention", attrs: { ...ref } }, { type: "text", text: " " }]) }] });
28992
+ editor.commands.setContent(buildPluginSelectionDocument(refs));
29322
28993
  }
29323
28994
  if (activeSessionId && activePendingContexts.length > 0) {
29324
28995
  composerChannels.consumePendingContexts(activeSessionId);
@@ -29331,7 +29002,7 @@ ${append2.text}` : append2.text;
29331
29002
  setIsSubmitting(false);
29332
29003
  }
29333
29004
  };
29334
- useEffect9(() => {
29005
+ useEffect8(() => {
29335
29006
  if (!editor || !activeSessionId || !queuedTopicRefs?.length) return;
29336
29007
  const existing = collectTopicAssetMentions(editor.getJSON());
29337
29008
  const refs = composerChannels.consumeTopicAssetReferences(activeSessionId).filter((ref) => !existing.some((item) => item.topic_id === ref.topic_id && item.path === ref.path));
@@ -29351,9 +29022,9 @@ ${append2.text}` : append2.text;
29351
29022
  const reduceMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
29352
29023
  return reduceMotion ? fullPlaceholder : "";
29353
29024
  });
29354
- const typewriterPlayedRef = useRef9(false);
29355
- const isTypingRef = useRef9(false);
29356
- useEffect9(() => {
29025
+ const typewriterPlayedRef = useRef7(false);
29026
+ const isTypingRef = useRef7(false);
29027
+ useEffect8(() => {
29357
29028
  if (!typewriterPlaceholder || typewriterPlayedRef.current) return;
29358
29029
  typewriterPlayedRef.current = true;
29359
29030
  const reduceMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
@@ -29374,7 +29045,7 @@ ${append2.text}` : append2.text;
29374
29045
  isTypingRef.current = false;
29375
29046
  };
29376
29047
  }, [typewriterPlaceholder]);
29377
- useEffect9(() => {
29048
+ useEffect8(() => {
29378
29049
  if (isTypingRef.current) return;
29379
29050
  setTypedPlaceholder(fullPlaceholder);
29380
29051
  }, [fullPlaceholder]);
@@ -29382,7 +29053,7 @@ ${append2.text}` : append2.text;
29382
29053
  const attachments = renderAttachments?.() ?? null;
29383
29054
  const hasRenderedAttachments = attachments !== null;
29384
29055
  const hasPendingContexts = (pendingContexts?.length ?? 0) > 0;
29385
- const isSkillEditor = currentSession?.solution_id === "skill_editor" || currentSession?.template_id === "skill_editor";
29056
+ const isSkillEditor = currentSession?.solution_id === "skill_editor";
29386
29057
  const imageAttachments = composerAttachments.filter(isImageAttachment);
29387
29058
  const fileAttachments = composerAttachments.filter(
29388
29059
  (attachment) => !isImageAttachment(attachment)
@@ -29394,11 +29065,12 @@ ${append2.text}` : append2.text;
29394
29065
  const submitWhileRunning = isStreaming && !isStopping && queueWhileRunning;
29395
29066
  const hasComposerContent = Boolean(input.trim()) || hasValidAttachments || hasRenderedAttachments || hasPendingContexts;
29396
29067
  const isSendDisabled = connectionStatus !== "connected" || isCompacting || !submitWhileRunning && isModelLoading || !submitWhileRunning && !hasAvailableModel || isSubmitting || hasUploadingFiles || !input.trim() && !hasValidAttachments && !hasRenderedAttachments && !hasPendingContexts;
29397
- return /* @__PURE__ */ jsxs12(Fragment5, { children: [
29398
- /* @__PURE__ */ jsx23("div", { className: `px-5 pb-3 pt-0 ${className ?? ""}`, children: /* @__PURE__ */ jsxs12("div", { className: `mx-auto ${maxWidthClassName} ${innerClassName ?? ""}`, children: [
29399
- statusBarAddon ? /* @__PURE__ */ jsx23("div", { className: "mb-2 flex flex-wrap items-center gap-2", children: statusBarAddon }) : null,
29400
- !isModelLoading && !hasAvailableModel ? /* @__PURE__ */ jsx23("div", { className: "mb-2 rounded-lg border border-[hsl(var(--destructive))]/30 bg-[hsl(var(--destructive))]/8 px-3 py-2 text-xs text-[hsl(var(--destructive))]", children: modelAvailabilityMessage }) : null,
29401
- /* @__PURE__ */ jsx23(
29068
+ const showQueueShortcut = Boolean(input.trim()) && !isSendDisabled && !isStopping && !isRecording && (!isStreaming || queueWhileRunning && !hasRunningSendBlockers());
29069
+ return /* @__PURE__ */ jsxs13(Fragment5, { children: [
29070
+ /* @__PURE__ */ jsx24("div", { className: `px-5 pb-3 pt-0 ${className ?? ""}`, children: /* @__PURE__ */ jsxs13("div", { className: `mx-auto ${maxWidthClassName} ${innerClassName ?? ""}`, children: [
29071
+ statusBarAddon ? /* @__PURE__ */ jsx24("div", { className: "mb-2 flex flex-wrap items-center gap-2", children: statusBarAddon }) : null,
29072
+ !isModelLoading && !hasAvailableModel ? /* @__PURE__ */ jsx24("div", { className: "mb-2 rounded-lg border border-[hsl(var(--destructive))]/30 bg-[hsl(var(--destructive))]/8 px-3 py-2 text-xs text-[hsl(var(--destructive))]", children: modelAvailabilityMessage }) : null,
29073
+ /* @__PURE__ */ jsx24(
29402
29074
  "div",
29403
29075
  {
29404
29076
  className: "relative",
@@ -29432,22 +29104,20 @@ ${append2.text}` : append2.text;
29432
29104
  if (files.length > 0) void stableAppendFiles(files);
29433
29105
  });
29434
29106
  },
29435
- children: /* @__PURE__ */ jsxs12(
29107
+ children: /* @__PURE__ */ jsxs13(
29436
29108
  "div",
29437
29109
  {
29438
- className: `overflow-visible border bg-[hsl(var(--card))] transition-[box-shadow,border-color] duration-300 ${// 上方贴着队列面板时上两角改直角:面板比输入框窄一圈,上角留着
29439
- // 22px 圆弧的话,这两段弧会从面板两侧露出来,就是截图里的尖角。
29440
- mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-[22px]"} ${isRecording ? "border-[hsl(var(--swf-success))]!" : isPlanning ? dragging || isEditorFocused ? "border-[hsl(var(--swf-warning)/0.6)]" : "border-[hsl(var(--swf-warning)/0.3)]" : dragging || isEditorFocused ? "border-[hsl(213_94%_60%/0.55)] shadow-[0_0_0_3px_hsl(213_94%_60%/0.16),0_8px_24px_-6px_hsl(213_94%_60%/0.3)]" : "border-[hsl(213_94%_60%/0.28)] shadow-[0_0_0_2px_hsl(213_94%_60%/0.08),0_4px_14px_-6px_hsl(213_94%_60%/0.16)]"}`,
29110
+ className: `overflow-visible border bg-[hsl(var(--card))] transition-[box-shadow,border-color] duration-300 ${mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-[22px]"} ${isRecording ? "border-[hsl(var(--swf-success))]!" : isPlanning ? dragging || isEditorFocused ? "border-[hsl(var(--swf-warning)/0.6)]" : "border-[hsl(var(--swf-warning)/0.3)]" : dragging || isEditorFocused ? "border-[hsl(213_94%_60%/0.55)] shadow-[0_0_0_3px_hsl(213_94%_60%/0.16),0_8px_24px_-6px_hsl(213_94%_60%/0.3)]" : "border-[hsl(213_94%_60%/0.28)] shadow-[0_0_0_2px_hsl(213_94%_60%/0.08),0_4px_14px_-6px_hsl(213_94%_60%/0.16)]"}`,
29441
29111
  children: [
29442
- dragging && /* @__PURE__ */ jsx23("div", { className: `pointer-events-none absolute inset-0 z-10 flex items-center justify-center bg-[hsl(var(--primary)/0.06)] ${mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-2xl"}`, children: /* @__PURE__ */ jsx23("span", { className: "rounded-full bg-[hsl(var(--primary)/0.12)] px-4 py-2 text-sm font-medium text-[hsl(var(--primary))]", children: "\u677E\u624B\u5F15\u7528\u6587\u4EF6" }) }),
29112
+ dragging && /* @__PURE__ */ jsx24("div", { className: `pointer-events-none absolute inset-0 z-10 flex items-center justify-center bg-[hsl(var(--primary)/0.06)] ${mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-2xl"}`, children: /* @__PURE__ */ jsx24("span", { className: "rounded-full bg-[hsl(var(--primary)/0.12)] px-4 py-2 text-sm font-medium text-[hsl(var(--primary))]", children: "\u677E\u624B\u5F15\u7528\u6587\u4EF6" }) }),
29443
29113
  planPanel,
29444
- composerAttachments.length > 0 && /* @__PURE__ */ jsxs12(ComposerAttachmentViewport, { className: "flex flex-col gap-2 border-b border-[hsl(var(--border))] px-4 py-2", children: [
29445
- imageAttachments.length > 0 && /* @__PURE__ */ jsx23("div", { className: "grid grid-cols-3 gap-2", children: imageAttachments.map((attachment) => /* @__PURE__ */ jsxs12(
29114
+ composerAttachments.length > 0 && /* @__PURE__ */ jsxs13(ComposerAttachmentViewport, { className: "flex flex-col gap-2 border-b border-[hsl(var(--border))] px-4 py-2", children: [
29115
+ imageAttachments.length > 0 && /* @__PURE__ */ jsx24("div", { className: "grid grid-cols-3 gap-2", children: imageAttachments.map((attachment) => /* @__PURE__ */ jsxs13(
29446
29116
  "div",
29447
29117
  {
29448
29118
  className: "relative overflow-hidden rounded-xl border border-[hsl(var(--border))]",
29449
29119
  children: [
29450
- /* @__PURE__ */ jsx23(
29120
+ /* @__PURE__ */ jsx24(
29451
29121
  "img",
29452
29122
  {
29453
29123
  src: getImagePreviewUrl(client, attachment, activeSessionId, localImageUrls),
@@ -29455,7 +29125,7 @@ ${append2.text}` : append2.text;
29455
29125
  className: "h-24 w-full object-cover"
29456
29126
  }
29457
29127
  ),
29458
- /* @__PURE__ */ jsx23(
29128
+ /* @__PURE__ */ jsx24(
29459
29129
  "button",
29460
29130
  {
29461
29131
  type: "button",
@@ -29463,14 +29133,14 @@ ${append2.text}` : append2.text;
29463
29133
  "aria-label": `\u79FB\u9664 ${attachment.name || "\u56FE\u7247"}`,
29464
29134
  title: "\u79FB\u9664",
29465
29135
  className: "absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-full bg-[hsl(var(--background)/0.85)] text-[hsl(var(--foreground))]",
29466
- children: /* @__PURE__ */ jsx23(X, { size: 12 })
29136
+ children: /* @__PURE__ */ jsx24(X, { size: 12 })
29467
29137
  }
29468
29138
  )
29469
29139
  ]
29470
29140
  },
29471
29141
  attachment.id
29472
29142
  )) }),
29473
- fileAttachments.length > 0 && /* @__PURE__ */ jsx23("div", { className: "flex flex-wrap gap-1.5", children: fileAttachments.map((attachment) => /* @__PURE__ */ jsx23(
29143
+ fileAttachments.length > 0 && /* @__PURE__ */ jsx24("div", { className: "flex flex-wrap gap-1.5", children: fileAttachments.map((attachment) => /* @__PURE__ */ jsx24(
29474
29144
  ComposerFilePill,
29475
29145
  {
29476
29146
  attachment,
@@ -29479,8 +29149,8 @@ ${append2.text}` : append2.text;
29479
29149
  attachment.id
29480
29150
  )) })
29481
29151
  ] }),
29482
- hasPendingContexts || isSkillEditor ? /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-1.5 border-b border-[hsl(var(--border))] px-4 py-2", children: [
29483
- pendingContexts?.map((context) => /* @__PURE__ */ jsx23(
29152
+ hasPendingContexts || isSkillEditor ? /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-1.5 border-b border-[hsl(var(--border))] px-4 py-2", children: [
29153
+ pendingContexts?.map((context) => /* @__PURE__ */ jsx24(
29484
29154
  ComposerContextPill,
29485
29155
  {
29486
29156
  id: context.id,
@@ -29496,18 +29166,18 @@ ${append2.text}` : append2.text;
29496
29166
  },
29497
29167
  context.id
29498
29168
  )),
29499
- isSkillEditor && /* @__PURE__ */ jsx23(
29169
+ isSkillEditor && /* @__PURE__ */ jsx24(
29500
29170
  "button",
29501
29171
  {
29502
29172
  type: "button",
29503
29173
  onClick: () => setShowAddContext(true),
29504
29174
  title: "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
29505
29175
  className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-dashed border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))]",
29506
- children: /* @__PURE__ */ jsx23(Plus, { size: 12 })
29176
+ children: /* @__PURE__ */ jsx24(Plus, { size: 12 })
29507
29177
  }
29508
29178
  )
29509
29179
  ] }) : null,
29510
- showAddContext && activeSessionId && /* @__PURE__ */ jsx23(
29180
+ showAddContext && activeSessionId && /* @__PURE__ */ jsx24(
29511
29181
  AddContextDialog,
29512
29182
  {
29513
29183
  sessionId: activeSessionId,
@@ -29519,15 +29189,15 @@ ${append2.text}` : append2.text;
29519
29189
  }
29520
29190
  }
29521
29191
  ),
29522
- attachments ? /* @__PURE__ */ jsx23("div", { className: "border-b border-[hsl(var(--border))] px-4 py-3", children: attachments }) : null,
29523
- slotAboveTextarea ? /* @__PURE__ */ jsx23("div", { className: "border-b border-[hsl(var(--border))] px-4 py-2", children: slotAboveTextarea }) : null,
29524
- /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
29525
- input.length === 0 && /* @__PURE__ */ jsx23("div", { className: "pointer-events-none absolute left-5 top-3 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.6)]", children: placeholder }),
29526
- /* @__PURE__ */ jsx23(EditorContent, { editor })
29192
+ attachments ? /* @__PURE__ */ jsx24("div", { className: "border-b border-[hsl(var(--border))] px-4 py-3", children: attachments }) : null,
29193
+ slotAboveTextarea ? /* @__PURE__ */ jsx24("div", { className: "border-b border-[hsl(var(--border))] px-4 py-2", children: slotAboveTextarea }) : null,
29194
+ /* @__PURE__ */ jsxs13("div", { className: "relative", children: [
29195
+ input.length === 0 && /* @__PURE__ */ jsx24("div", { className: "pointer-events-none absolute left-5 top-3 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.6)]", children: placeholder }),
29196
+ /* @__PURE__ */ jsx24(EditorContent, { editor })
29527
29197
  ] }),
29528
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-4 pb-3 pt-1", children: [
29529
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
29530
- /* @__PURE__ */ jsx23(
29198
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between px-4 pb-3 pt-1", children: [
29199
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
29200
+ /* @__PURE__ */ jsx24(
29531
29201
  "input",
29532
29202
  {
29533
29203
  ref: fileInputRef,
@@ -29543,7 +29213,7 @@ ${append2.text}` : append2.text;
29543
29213
  className: "hidden"
29544
29214
  }
29545
29215
  ),
29546
- /* @__PURE__ */ jsx23(
29216
+ /* @__PURE__ */ jsx24(
29547
29217
  "input",
29548
29218
  {
29549
29219
  ref: folderInputRef,
@@ -29559,7 +29229,7 @@ ${append2.text}` : append2.text;
29559
29229
  ...{ webkitdirectory: "" }
29560
29230
  }
29561
29231
  ),
29562
- /* @__PURE__ */ jsxs12(
29232
+ /* @__PURE__ */ jsxs13(
29563
29233
  dist_exports.Root,
29564
29234
  {
29565
29235
  open: actionMenuOpen,
@@ -29568,17 +29238,17 @@ ${append2.text}` : append2.text;
29568
29238
  if (open) setConnectMenuOpen(false);
29569
29239
  },
29570
29240
  children: [
29571
- /* @__PURE__ */ jsx23(dist_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx23(
29241
+ /* @__PURE__ */ jsx24(dist_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx24(
29572
29242
  "button",
29573
29243
  {
29574
29244
  type: "button",
29575
29245
  "aria-label": "\u6DFB\u52A0\u5185\u5BB9",
29576
29246
  title: "\u6DFB\u52A0\u5185\u5BB9",
29577
29247
  className: "flex h-9 w-9 shrink-0 cursor-pointer items-center justify-center rounded-full border border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))]",
29578
- children: /* @__PURE__ */ jsx23(Plus, { size: 14 })
29248
+ children: /* @__PURE__ */ jsx24(Plus, { size: 14 })
29579
29249
  }
29580
29250
  ) }),
29581
- /* @__PURE__ */ jsx23(dist_exports.Portal, { children: /* @__PURE__ */ jsxs12(
29251
+ /* @__PURE__ */ jsx24(dist_exports.Portal, { children: /* @__PURE__ */ jsxs13(
29582
29252
  dist_exports.Content,
29583
29253
  {
29584
29254
  side: "top",
@@ -29586,7 +29256,7 @@ ${append2.text}` : append2.text;
29586
29256
  sideOffset: 8,
29587
29257
  className: "z-30 w-[min(380px,calc(100vw-2rem))] origin-(--radix-popover-content-transform-origin) overflow-visible rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 text-[11px] text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)] outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
29588
29258
  children: [
29589
- /* @__PURE__ */ jsxs12(
29259
+ /* @__PURE__ */ jsxs13(
29590
29260
  "button",
29591
29261
  {
29592
29262
  type: "button",
@@ -29596,12 +29266,12 @@ ${append2.text}` : append2.text;
29596
29266
  },
29597
29267
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29598
29268
  children: [
29599
- /* @__PURE__ */ jsx23(Paperclip, { size: 14 }),
29269
+ /* @__PURE__ */ jsx24(Paperclip, { size: 14 }),
29600
29270
  "\u4E0A\u4F20\u6587\u4EF6"
29601
29271
  ]
29602
29272
  }
29603
29273
  ),
29604
- /* @__PURE__ */ jsxs12(
29274
+ /* @__PURE__ */ jsxs13(
29605
29275
  "button",
29606
29276
  {
29607
29277
  type: "button",
@@ -29611,12 +29281,12 @@ ${append2.text}` : append2.text;
29611
29281
  },
29612
29282
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29613
29283
  children: [
29614
- /* @__PURE__ */ jsx23(FolderUp, { size: 14 }),
29284
+ /* @__PURE__ */ jsx24(FolderUp, { size: 14 }),
29615
29285
  "\u4E0A\u4F20\u6587\u4EF6\u5939"
29616
29286
  ]
29617
29287
  }
29618
29288
  ),
29619
- onCommand && canCreateBoardTask && !lite ? /* @__PURE__ */ jsxs12(
29289
+ onCommand && canCreateBoardTask && !lite ? /* @__PURE__ */ jsxs13(
29620
29290
  "button",
29621
29291
  {
29622
29292
  type: "button",
@@ -29626,12 +29296,27 @@ ${append2.text}` : append2.text;
29626
29296
  },
29627
29297
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29628
29298
  children: [
29629
- /* @__PURE__ */ jsx23(ListPlus, { size: 14 }),
29299
+ /* @__PURE__ */ jsx24(ListPlus, { size: 14 }),
29630
29300
  "\u521B\u5EFA\u540E\u53F0\u4EFB\u52A1"
29631
29301
  ]
29632
29302
  }
29633
29303
  ) : null,
29634
- onDoubleEscape ? /* @__PURE__ */ jsxs12(
29304
+ onCommand && !lite ? /* @__PURE__ */ jsxs13(
29305
+ "button",
29306
+ {
29307
+ type: "button",
29308
+ onClick: () => {
29309
+ setActionMenuOpen(false);
29310
+ void onCommand("open_message_outline");
29311
+ },
29312
+ className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29313
+ children: [
29314
+ /* @__PURE__ */ jsx24(ListTree, { size: 14 }),
29315
+ "\u6D88\u606F\u8109\u7EDC"
29316
+ ]
29317
+ }
29318
+ ) : null,
29319
+ onDoubleEscape ? /* @__PURE__ */ jsxs13(
29635
29320
  "button",
29636
29321
  {
29637
29322
  type: "button",
@@ -29643,13 +29328,13 @@ ${append2.text}` : append2.text;
29643
29328
  },
29644
29329
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29645
29330
  children: [
29646
- /* @__PURE__ */ jsx23(RotateCcw, { size: 14 }),
29331
+ /* @__PURE__ */ jsx24(RotateCcw, { size: 14 }),
29647
29332
  "\u56DE\u5230\u4E4B\u524D\u7684\u67D0\u4E00\u6B65"
29648
29333
  ]
29649
29334
  }
29650
29335
  ) : null,
29651
- onCommand && !lite ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
29652
- /* @__PURE__ */ jsxs12(
29336
+ onCommand && !lite ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
29337
+ developer ? /* @__PURE__ */ jsxs13(
29653
29338
  "button",
29654
29339
  {
29655
29340
  type: "button",
@@ -29660,12 +29345,12 @@ ${append2.text}` : append2.text;
29660
29345
  disabled: isBusy,
29661
29346
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))] disabled:cursor-not-allowed disabled:opacity-50",
29662
29347
  children: [
29663
- isCompacting ? /* @__PURE__ */ jsx23(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx23(Scissors, { size: 14 }),
29348
+ isCompacting ? /* @__PURE__ */ jsx24(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx24(Scissors, { size: 14 }),
29664
29349
  "\u6574\u7406\u5BF9\u8BDD"
29665
29350
  ]
29666
29351
  }
29667
- ),
29668
- /* @__PURE__ */ jsxs12(
29352
+ ) : null,
29353
+ /* @__PURE__ */ jsxs13(
29669
29354
  "button",
29670
29355
  {
29671
29356
  type: "button",
@@ -29675,12 +29360,12 @@ ${append2.text}` : append2.text;
29675
29360
  },
29676
29361
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29677
29362
  children: [
29678
- /* @__PURE__ */ jsx23(Download, { size: 14 }),
29363
+ /* @__PURE__ */ jsx24(Download, { size: 14 }),
29679
29364
  "\u5BFC\u51FA\u4F1A\u8BDD"
29680
29365
  ]
29681
29366
  }
29682
29367
  ),
29683
- /* @__PURE__ */ jsxs12(
29368
+ /* @__PURE__ */ jsxs13(
29684
29369
  "button",
29685
29370
  {
29686
29371
  type: "button",
@@ -29690,12 +29375,12 @@ ${append2.text}` : append2.text;
29690
29375
  },
29691
29376
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29692
29377
  children: [
29693
- /* @__PURE__ */ jsx23(Play, { size: 14 }),
29378
+ /* @__PURE__ */ jsx24(Play, { size: 14 }),
29694
29379
  "\u56DE\u653E\u8FD9\u4E2A\u5BF9\u8BDD"
29695
29380
  ]
29696
29381
  }
29697
29382
  ),
29698
- canShareSession ? /* @__PURE__ */ jsxs12(
29383
+ canShareSession ? /* @__PURE__ */ jsxs13(
29699
29384
  "button",
29700
29385
  {
29701
29386
  type: "button",
@@ -29705,12 +29390,12 @@ ${append2.text}` : append2.text;
29705
29390
  },
29706
29391
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29707
29392
  children: [
29708
- /* @__PURE__ */ jsx23(Share2, { size: 14 }),
29393
+ /* @__PURE__ */ jsx24(Share2, { size: 14 }),
29709
29394
  "\u5206\u4EAB\u4F1A\u8BDD"
29710
29395
  ]
29711
29396
  }
29712
29397
  ) : null,
29713
- /* @__PURE__ */ jsxs12(
29398
+ /* @__PURE__ */ jsxs13(
29714
29399
  "button",
29715
29400
  {
29716
29401
  type: "button",
@@ -29720,12 +29405,12 @@ ${append2.text}` : append2.text;
29720
29405
  },
29721
29406
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29722
29407
  children: [
29723
- /* @__PURE__ */ jsx23(FlaskConical, { size: 14 }),
29408
+ /* @__PURE__ */ jsx24(FlaskConical, { size: 14 }),
29724
29409
  "\u63D0\u53D6\u6280\u80FD"
29725
29410
  ]
29726
29411
  }
29727
29412
  ),
29728
- /* @__PURE__ */ jsxs12(
29413
+ /* @__PURE__ */ jsxs13(
29729
29414
  "button",
29730
29415
  {
29731
29416
  type: "button",
@@ -29735,13 +29420,13 @@ ${append2.text}` : append2.text;
29735
29420
  },
29736
29421
  className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]",
29737
29422
  children: [
29738
- /* @__PURE__ */ jsx23(Rocket, { size: 14 }),
29423
+ /* @__PURE__ */ jsx24(Rocket, { size: 14 }),
29739
29424
  "\u751F\u6210\u5E94\u7528"
29740
29425
  ]
29741
29426
  }
29742
29427
  )
29743
29428
  ] }) : null,
29744
- onToggleMode && !lite ? /* @__PURE__ */ jsx23(
29429
+ onToggleMode && !lite ? /* @__PURE__ */ jsx24(
29745
29430
  PlanningToggle,
29746
29431
  {
29747
29432
  enabled: isPlanning,
@@ -29752,22 +29437,23 @@ ${append2.text}` : append2.text;
29752
29437
  disabled: isBusy
29753
29438
  }
29754
29439
  ) : null,
29755
- !lite && thinkingAvailable && reasoningLevels.length > 0 ? /* @__PURE__ */ jsx23(
29440
+ !lite && thinkingAvailable && reasoningLevels.length > 0 ? /* @__PURE__ */ jsx24(
29756
29441
  ReasoningModeSelect,
29757
29442
  {
29758
29443
  level: selectedReasoningLevel,
29759
29444
  levels: reasoningLevels,
29760
29445
  disabled: isCompacting,
29761
- disabledReason: "\u5BF9\u8BDD\u6574\u7406\u5B8C\u6210\u540E\u53EF\u8C03\u6574",
29446
+ disabledReason: developer ? "\u5BF9\u8BDD\u6574\u7406\u5B8C\u6210\u540E\u53EF\u8C03\u6574" : "\u5904\u7406\u5B8C\u6210\u540E\u53EF\u8C03\u6574",
29762
29447
  onChange: model.setReasoningLevel
29763
29448
  }
29764
29449
  ) : null,
29765
- !lite ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 px-3 py-2", children: [
29766
- /* @__PURE__ */ jsx23(Sparkles, { size: 14, className: "shrink-0", "aria-hidden": "true" }),
29767
- /* @__PURE__ */ jsx23("span", { className: "shrink-0", children: "\u6A21\u578B" }),
29768
- /* @__PURE__ */ jsx23(
29450
+ !lite ? /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 px-3 py-2", children: [
29451
+ /* @__PURE__ */ jsx24(Sparkles, { size: 14, className: "shrink-0", "aria-hidden": "true" }),
29452
+ /* @__PURE__ */ jsx24("span", { className: "shrink-0", children: "\u6A21\u578B" }),
29453
+ /* @__PURE__ */ jsx24(
29769
29454
  ModelSelector,
29770
29455
  {
29456
+ disabled: isModelLoading,
29771
29457
  value: selectedModel,
29772
29458
  onValueChange: model.selectModel,
29773
29459
  compact: true,
@@ -29775,8 +29461,8 @@ ${append2.text}` : append2.text;
29775
29461
  }
29776
29462
  )
29777
29463
  ] }) : null,
29778
- !lite && activeSessionId && actionMenuOpen ? /* @__PURE__ */ jsxs12("div", { className: "border-t border-[hsl(var(--border))] px-3 py-2.5", children: [
29779
- /* @__PURE__ */ jsx23(
29464
+ !lite && activeSessionId && actionMenuOpen ? /* @__PURE__ */ jsxs13("div", { className: "border-t border-[hsl(var(--border))] px-3 py-2.5", children: [
29465
+ /* @__PURE__ */ jsx24(
29780
29466
  SkillStatusBarComponent,
29781
29467
  {
29782
29468
  sessionId: activeSessionId,
@@ -29786,7 +29472,7 @@ ${append2.text}` : append2.text;
29786
29472
  innerClassName: skillStatusBarInnerClassName
29787
29473
  }
29788
29474
  ),
29789
- composerHint ? /* @__PURE__ */ jsx23("div", { className: "mt-2 border-t border-[hsl(var(--border))] pt-2 text-[hsl(var(--muted-foreground))]", children: composerHint }) : null
29475
+ composerHint ? /* @__PURE__ */ jsx24("div", { className: "mt-2 border-t border-[hsl(var(--border))] pt-2 text-[hsl(var(--muted-foreground))]", children: composerHint }) : null
29790
29476
  ] }) : null
29791
29477
  ]
29792
29478
  }
@@ -29794,7 +29480,7 @@ ${append2.text}` : append2.text;
29794
29480
  ]
29795
29481
  }
29796
29482
  ),
29797
- /* @__PURE__ */ jsx23(
29483
+ /* @__PURE__ */ jsx24(
29798
29484
  ConnectButton,
29799
29485
  {
29800
29486
  sessionId: activeSessionId,
@@ -29807,11 +29493,15 @@ ${append2.text}` : append2.text;
29807
29493
  }
29808
29494
  }
29809
29495
  ),
29810
- !lite && activeSessionId ? /* @__PURE__ */ jsx23(BackgroundTasksPill, { sessionId: activeSessionId }) : null
29496
+ !lite && activeSessionId ? /* @__PURE__ */ jsx24(BackgroundTasksPill, { sessionId: activeSessionId }) : null
29811
29497
  ] }),
29812
- /* @__PURE__ */ jsxs12("div", { className: "flex min-h-10 items-center gap-1.5", children: [
29498
+ /* @__PURE__ */ jsxs13("div", { className: "flex min-h-10 items-center gap-1.5", children: [
29499
+ showQueueShortcut && /* @__PURE__ */ jsxs13("span", { className: "mr-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
29500
+ queueShortcutLabel(),
29501
+ " \xB7 \u6392\u961F\u6D88\u606F"
29502
+ ] }),
29813
29503
  slotBeforeSend,
29814
- !isStreaming && !isCompacting && asrEnabled && (isRecording || isVoiceStarting || !hasComposerContent) ? /* @__PURE__ */ jsx23(
29504
+ !isStreaming && !isCompacting && asrEnabled && (isRecording || isVoiceStarting || !hasComposerContent) ? /* @__PURE__ */ jsx24(
29815
29505
  "button",
29816
29506
  {
29817
29507
  type: "button",
@@ -29819,23 +29509,23 @@ ${append2.text}` : append2.text;
29819
29509
  "aria-label": isRecording || isVoiceStarting ? "\u505C\u6B62\u8BED\u97F3\u8F93\u5165" : "\u5F00\u59CB\u8BED\u97F3\u8F93\u5165",
29820
29510
  title: isVoiceStarting ? "\u6B63\u5728\u8FDE\u63A5\u8BED\u97F3\u8F93\u5165\uFF0C\u70B9\u51FB\u53D6\u6D88" : isRecording ? "\u505C\u6B62\u8BED\u97F3\u8F93\u5165" : "\u8BED\u97F3\u8F93\u5165",
29821
29511
  className: `flex items-center justify-center rounded-full transition-[width,height,background-color,color,box-shadow] duration-300 disabled:opacity-40 ${isRecording ? "h-10 w-10 bg-[hsl(var(--swf-success-soft))] text-[hsl(var(--swf-success))]" : "h-10 w-10 bg-[hsl(213_94%_60%/0.10)] text-[hsl(213_94%_45%)] hover:bg-[hsl(213_94%_60%/0.18)]"}`,
29822
- children: isVoiceStarting ? /* @__PURE__ */ jsx23(LoaderCircle, { size: 20, className: "animate-spin" }) : isRecording ? /* @__PURE__ */ jsx23(VoiceWaveform, { level: voiceLevel, size: 20 }) : /* @__PURE__ */ jsx23(Mic, { size: 20 })
29512
+ children: isVoiceStarting ? /* @__PURE__ */ jsx24(LoaderCircle, { size: 20, className: "animate-spin" }) : isRecording ? /* @__PURE__ */ jsx24(VoiceWaveform, { level: voiceLevel, size: 20 }) : /* @__PURE__ */ jsx24(Mic, { size: 20 })
29823
29513
  }
29824
29514
  ) : null,
29825
- isStreaming ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
29826
- submitWhileRunning ? /* @__PURE__ */ jsx23(
29515
+ isStreaming ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
29516
+ submitWhileRunning ? /* @__PURE__ */ jsx24(
29827
29517
  "button",
29828
29518
  {
29829
29519
  type: "button",
29830
- onClick: handleSubmit,
29520
+ onClick: () => void handleSubmit(),
29831
29521
  disabled: isSendDisabled || isRecording,
29832
- "aria-label": "\u52A0\u5165\u6392\u961F",
29833
- title: "\u52A0\u5165\u6392\u961F",
29522
+ "aria-label": "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
29523
+ title: "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
29834
29524
  className: "flex h-10 w-10 items-center justify-center rounded-full bg-[hsl(213_94%_55%)] text-white disabled:opacity-25",
29835
- children: isSubmitting ? /* @__PURE__ */ jsx23(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx23(Send, { size: 16 })
29525
+ children: isSubmitting ? /* @__PURE__ */ jsx24(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx24(Send, { size: 16 })
29836
29526
  }
29837
29527
  ) : null,
29838
- /* @__PURE__ */ jsx23(
29528
+ /* @__PURE__ */ jsx24(
29839
29529
  "button",
29840
29530
  {
29841
29531
  type: "button",
@@ -29844,41 +29534,41 @@ ${append2.text}` : append2.text;
29844
29534
  "aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u751F\u6210",
29845
29535
  title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u751F\u6210",
29846
29536
  className: "flex h-10 w-10 items-center justify-center rounded-full bg-[hsl(var(--destructive))] text-[hsl(var(--destructive-foreground))] transition-opacity hover:opacity-80 disabled:cursor-wait disabled:opacity-70",
29847
- children: isStopping ? /* @__PURE__ */ jsx23(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx23(Square, { size: 16 })
29537
+ children: isStopping ? /* @__PURE__ */ jsx24(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx24(Square, { size: 16 })
29848
29538
  }
29849
29539
  )
29850
- ] }) : isCompacting ? /* @__PURE__ */ jsx23(
29540
+ ] }) : isCompacting ? /* @__PURE__ */ jsx24(
29851
29541
  "button",
29852
29542
  {
29853
29543
  type: "button",
29854
29544
  disabled: true,
29855
- "aria-label": "\u6B63\u5728\u6574\u7406\u5BF9\u8BDD",
29856
- title: "\u6B63\u5728\u6574\u7406\u5BF9\u8BDD",
29545
+ "aria-label": developer ? "\u6B63\u5728\u6574\u7406\u5BF9\u8BDD" : "\u6B63\u5728\u5904\u7406",
29546
+ title: developer ? "\u6B63\u5728\u6574\u7406\u5BF9\u8BDD" : "\u6B63\u5728\u5904\u7406",
29857
29547
  className: "flex h-10 w-10 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] opacity-50",
29858
- children: /* @__PURE__ */ jsx23(LoaderCircle, { size: 16, className: "animate-spin" })
29548
+ children: /* @__PURE__ */ jsx24(LoaderCircle, { size: 16, className: "animate-spin" })
29859
29549
  }
29860
- ) : !isRecording && hasComposerContent ? /* @__PURE__ */ jsx23(
29550
+ ) : !isRecording && hasComposerContent ? /* @__PURE__ */ jsx24(
29861
29551
  "button",
29862
29552
  {
29863
29553
  type: "button",
29864
- onClick: handleSubmit,
29554
+ onClick: () => void handleSubmit(),
29865
29555
  disabled: isSendDisabled,
29866
- "aria-label": "\u53D1\u9001\u6D88\u606F",
29867
- title: isModelLoading ? "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u914D\u7F6E" : !hasAvailableModel ? modelAvailabilityMessage : "\u53D1\u9001\u6D88\u606F",
29556
+ "aria-label": "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
29557
+ title: isModelLoading ? "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u914D\u7F6E" : !hasAvailableModel ? modelAvailabilityMessage : "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
29868
29558
  className: "flex h-10 w-10 items-center justify-center rounded-full bg-[hsl(213_94%_55%)] text-white transition-colors duration-[120ms] ease-out hover:bg-[hsl(213_94%_48%)] disabled:opacity-25",
29869
- children: isSubmitting ? /* @__PURE__ */ jsx23(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx23(Send, { size: 16 })
29559
+ children: isSubmitting ? /* @__PURE__ */ jsx24(LoaderCircle, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsx24(Send, { size: 16 })
29870
29560
  }
29871
29561
  ) : null
29872
29562
  ] })
29873
29563
  ] }),
29874
- slotBelowActions ? /* @__PURE__ */ jsx23("div", { className: "border-t border-[hsl(var(--border))] px-4 py-1.5", children: slotBelowActions }) : null
29564
+ slotBelowActions ? /* @__PURE__ */ jsx24("div", { className: "border-t border-[hsl(var(--border))] px-4 py-1.5", children: slotBelowActions }) : null
29875
29565
  ]
29876
29566
  }
29877
29567
  )
29878
29568
  }
29879
29569
  )
29880
29570
  ] }) }),
29881
- /* @__PURE__ */ jsx23(
29571
+ /* @__PURE__ */ jsx24(
29882
29572
  FileSizeLimitDialog,
29883
29573
  {
29884
29574
  open: oversizedFiles.length > 0,
@@ -29893,6 +29583,42 @@ ${append2.text}` : append2.text;
29893
29583
  )
29894
29584
  ] });
29895
29585
  }
29586
+
29587
+ // src/rich-input/SkillActionMenu.tsx
29588
+ import { useEffect as useEffect9, useState as useState12 } from "react";
29589
+ import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
29590
+ function SkillActionMenu({ open, onOpenChange, renderMode, onSelect, onManage, disabled }) {
29591
+ return /* @__PURE__ */ jsx25(InputActionSubmenu, { label: "\u6280\u80FD", icon: /* @__PURE__ */ jsx25(Sparkles, { size: 16, "aria-hidden": "true" }), open, onOpenChange, disabled, children: /* @__PURE__ */ jsx25(SkillPicker, { renderMode, onSelect, onManage }) });
29592
+ }
29593
+ function SkillPicker({ renderMode, onSelect, onManage }) {
29594
+ const client = useBladeClient();
29595
+ const [query, setQuery] = useState12("");
29596
+ const [skills, setSkills] = useState12(null);
29597
+ useEffect9(() => {
29598
+ let active = true;
29599
+ setSkills(null);
29600
+ getSlashSuggestions(query, { client, sessionId: null, renderMode }).then((items) => {
29601
+ if (active) setSkills(items);
29602
+ }).catch(() => {
29603
+ if (active) setSkills([]);
29604
+ });
29605
+ return () => {
29606
+ active = false;
29607
+ };
29608
+ }, [client, renderMode, query]);
29609
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
29610
+ /* @__PURE__ */ jsxs14("label", { className: "m-1 flex items-center gap-2 rounded-lg bg-[hsl(var(--muted))] px-3 py-2", children: [
29611
+ /* @__PURE__ */ jsx25(Search, { size: 14, "aria-hidden": "true" }),
29612
+ /* @__PURE__ */ jsx25("input", { "aria-label": "\u641C\u7D22\u6280\u80FD", placeholder: "\u641C\u7D22\u6280\u80FD", value: query, onChange: (event) => setQuery(event.target.value), className: "min-w-0 flex-1 bg-transparent outline-none" })
29613
+ ] }),
29614
+ /* @__PURE__ */ jsx25("div", { className: "max-h-60 overflow-y-auto", children: skills === null ? /* @__PURE__ */ jsx25("p", { className: "px-3 py-2 text-[hsl(var(--muted-foreground))]", children: "\u52A0\u8F7D\u6280\u80FD\u4E2D\u2026" }) : skills.length ? skills.map((skill) => skill.type === "skill" ? /* @__PURE__ */ jsxs14("button", { type: "button", onClick: () => onSelect(skill), className: "flex w-full flex-col gap-1 rounded-lg px-3 py-2 text-left hover:bg-[hsl(var(--accent))] focus-visible:bg-[hsl(var(--accent))]", children: [
29615
+ /* @__PURE__ */ jsx25("span", { children: skillDisplayName(skill) }),
29616
+ /* @__PURE__ */ jsx25("span", { className: "line-clamp-2 text-[11px] text-[hsl(var(--muted-foreground))]", children: skill.description })
29617
+ ] }, skill.skillId) : null) : /* @__PURE__ */ jsx25("p", { className: "px-3 py-2 text-[hsl(var(--muted-foreground))]", children: "\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD" }) }),
29618
+ /* @__PURE__ */ jsx25("div", { className: "my-1 border-t border-[hsl(var(--border))]" }),
29619
+ /* @__PURE__ */ jsx25("button", { type: "button", onClick: onManage, className: "w-full rounded-lg px-3 py-2 text-left hover:bg-[hsl(var(--accent))]", children: "\u7BA1\u7406\u6280\u80FD \u2192" })
29620
+ ] });
29621
+ }
29896
29622
  export {
29897
29623
  ATTACHMENT_SIZE_LIMIT_BYTES,
29898
29624
  ATTENTION_STATUSES,
@@ -29904,6 +29630,7 @@ export {
29904
29630
  FileMention,
29905
29631
  FileSizeLimitDialog,
29906
29632
  IMAGE_INPUT_UNSUPPORTED_MESSAGE,
29633
+ InputActionSubmenu,
29907
29634
  LIVE_STATUSES,
29908
29635
  MODEL_LOADING_SEND_HINT,
29909
29636
  MODEL_REASONING_LEVELS_KEY,
@@ -29916,16 +29643,18 @@ export {
29916
29643
  RichInputServicesProvider,
29917
29644
  STATUS_LABELS,
29918
29645
  STOPPABLE_STATUSES,
29646
+ SkillActionMenu,
29919
29647
  SkillCompletionMenu,
29920
29648
  SkillMention,
29921
29649
  SkillStatusBar,
29922
29650
  TopicAssetMention,
29923
29651
  VoiceWaveform,
29924
- WorkflowMention,
29925
29652
  buildEditorDocument,
29926
29653
  buildEditorDocumentWithMentions,
29654
+ buildPluginSelectionDocument,
29927
29655
  buildSubmitPayload,
29928
29656
  buildVoiceInputUnavailableError,
29657
+ collectMessageMentions,
29929
29658
  collectPluginMentions,
29930
29659
  collectTopicAssetMentions,
29931
29660
  entryLabel,
@@ -29938,13 +29667,11 @@ export {
29938
29667
  gateSendWhileModelLoading,
29939
29668
  getFileSuggestionItems,
29940
29669
  getInputModalities,
29941
- getLastUserHomeRuntime,
29942
29670
  getPluginSuggestionItems,
29943
29671
  getSkillSuggestions,
29944
29672
  getSlashSuggestions,
29945
29673
  getTopicAssetSuggestionItems,
29946
29674
  getUnsupportedImageFiles,
29947
- getUserHomeRuntime,
29948
29675
  getUserHomeSuggestionItems,
29949
29676
  installSuggestionOutsideDismiss,
29950
29677
  invalidateSlashSuggestions,
@@ -30001,9 +29728,7 @@ export {
30001
29728
  useSessionSkills,
30002
29729
  useSkillStats,
30003
29730
  useTiptapVoiceInput,
30004
- useVoiceInput,
30005
- workflowParamsTail,
30006
- workflowRunText
29731
+ useVoiceInput
30007
29732
  };
30008
29733
  /*! Bundled license information:
30009
29734