@blade-hq/agent-react 2610.0.0-beta.57 → 2610.0.0-beta.59

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.
package/dist/index.js CHANGED
@@ -2583,9 +2583,6 @@ var ChevronRight = createLucideIcon("ChevronRight", [
2583
2583
  ["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]
2584
2584
  ]);
2585
2585
 
2586
- // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/chevron-up.js
2587
- var ChevronUp = createLucideIcon("ChevronUp", [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]]);
2588
-
2589
2586
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/circle-alert.js
2590
2587
  var CircleAlert = createLucideIcon("CircleAlert", [
2591
2588
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
@@ -2733,6 +2730,13 @@ var Maximize2 = createLucideIcon("Maximize2", [
2733
2730
  ["line", { x1: "3", x2: "10", y1: "21", y2: "14", key: "1atl0r" }]
2734
2731
  ]);
2735
2732
 
2733
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/menu.js
2734
+ var Menu = createLucideIcon("Menu", [
2735
+ ["line", { x1: "4", x2: "20", y1: "12", y2: "12", key: "1e0a9i" }],
2736
+ ["line", { x1: "4", x2: "20", y1: "6", y2: "6", key: "1owob3" }],
2737
+ ["line", { x1: "4", x2: "20", y1: "18", y2: "18", key: "yk5zj1" }]
2738
+ ]);
2739
+
2736
2740
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/message-square-more.js
2737
2741
  var MessageSquareMore = createLucideIcon("MessageSquareMore", [
2738
2742
  ["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }],
@@ -15752,7 +15756,7 @@ function iconBlob(client, sessionId, name, token) {
15752
15756
  blobCache.set(key, pending);
15753
15757
  return pending;
15754
15758
  }
15755
- function SessionPluginIcon({ client, sessionId, plugin, className }) {
15759
+ function SessionPluginIcon({ client, sessionId, plugin, size = 20, shape = "rounded", className }) {
15756
15760
  const [url2, setUrl] = useState13(null);
15757
15761
  const token = plugin.icon;
15758
15762
  useEffect8(() => {
@@ -15770,11 +15774,12 @@ function SessionPluginIcon({ client, sessionId, plugin, className }) {
15770
15774
  if (objectUrl) URL.revokeObjectURL(objectUrl);
15771
15775
  };
15772
15776
  }, [client, sessionId, plugin.name, token]);
15773
- const frame = `flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded ${className ?? ""}`;
15777
+ const frame = `flex shrink-0 items-center justify-center overflow-hidden ${shape === "circle" ? "rounded-full" : "rounded"} ${className ?? ""}`;
15778
+ const frameStyle = { width: size, height: size };
15774
15779
  if (!url2) {
15775
- return /* @__PURE__ */ jsx3("span", { className: `${frame} bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]`, "data-plugin-icon": "placeholder", children: /* @__PURE__ */ jsx3(Puzzle, { "aria-hidden": true, className: "h-3.5 w-3.5" }) });
15780
+ return /* @__PURE__ */ jsx3("span", { className: `${frame} bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]`, style: frameStyle, "data-plugin-icon": "placeholder", children: /* @__PURE__ */ jsx3(Puzzle, { "aria-hidden": true, size: Math.round(size * 0.7) }) });
15776
15781
  }
15777
- return /* @__PURE__ */ jsx3("span", { className: frame, "data-plugin-icon": "image", children: /* @__PURE__ */ jsx3("img", { src: url2, alt: "", "aria-hidden": true, className: "h-full w-full object-cover", onError: () => setUrl(null) }) });
15782
+ return /* @__PURE__ */ jsx3("span", { className: frame, style: frameStyle, "data-plugin-icon": "image", children: /* @__PURE__ */ jsx3("img", { src: url2, alt: "", "aria-hidden": true, className: "h-full w-full object-cover", onError: () => setUrl(null) }) });
15778
15783
  }
15779
15784
 
15780
15785
  // src/components/SessionPluginConfigDialog.tsx
@@ -15978,65 +15983,6 @@ function ConfigDialogState({
15978
15983
  ] });
15979
15984
  }
15980
15985
 
15981
- // src/components/plugin-connector.ts
15982
- function catalogToConnectorItems(catalog) {
15983
- return catalog.map((entry) => ({
15984
- name: entry.name,
15985
- display_name: entry.display_name,
15986
- icon: entry.icon,
15987
- iconSource: "account",
15988
- installed: entry.installed,
15989
- active: false,
15990
- status: "not_prepared",
15991
- projected: false
15992
- }));
15993
- }
15994
- function mergeConnectorItems(sessionPlugins, catalog) {
15995
- const byName = new Map((catalog ?? []).map((entry) => [entry.name, entry]));
15996
- return sessionPlugins.map((plugin) => {
15997
- const entry = byName.get(plugin.name);
15998
- if (!entry) {
15999
- return {
16000
- name: plugin.name,
16001
- display_name: plugin.display_name ?? null,
16002
- icon: plugin.icon ?? null,
16003
- iconSource: "session",
16004
- installed: plugin.installed,
16005
- active: plugin.active,
16006
- status: plugin.status,
16007
- reason: plugin.reason,
16008
- config: plugin.config,
16009
- projected: plugin.projected
16010
- };
16011
- }
16012
- return {
16013
- name: plugin.name,
16014
- display_name: entry.display_name ?? plugin.display_name ?? null,
16015
- icon: entry.icon,
16016
- iconSource: "account",
16017
- installed: entry.installed,
16018
- active: plugin.active,
16019
- status: plugin.status,
16020
- reason: plugin.reason,
16021
- config: plugin.config,
16022
- projected: plugin.projected
16023
- };
16024
- });
16025
- }
16026
- function pluginConnectorSummary(state) {
16027
- if (state === "configured") return "\u914D\u7F6E\u5DF2\u4FDD\u5B58";
16028
- if (state === "required") return "\u8FD8\u9700\u8981\u586B\u5199\u914D\u7F6E";
16029
- if (state === "error") return "\u914D\u7F6E\u58F0\u660E\u6709\u95EE\u9898";
16030
- return null;
16031
- }
16032
- function filterConnectorItems(items, query) {
16033
- const needle = query.trim().toLowerCase();
16034
- if (!needle) return items;
16035
- return items.filter(
16036
- (item) => `${item.display_name ?? ""} ${item.name}`.toLowerCase().includes(needle)
16037
- );
16038
- }
16039
-
16040
15986
  // src/components/PluginConnectorList.tsx
16041
15987
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
16042
15988
  function PluginSwitch({
@@ -16093,11 +16039,10 @@ function PluginConnectorList({
16093
16039
  items.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "px-3 py-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: unavailableText ?? emptyText }) : null,
16094
16040
  items.map((item) => {
16095
16041
  const label = sessionPluginLabel(item);
16096
- const summary = pluginConnectorSummary(item.config);
16097
16042
  const actionable = !disabledReason && item.installed !== false || item.active;
16098
16043
  const pending = Boolean(inFlight[item.name]);
16099
16044
  const checked = item.active;
16100
- return /* @__PURE__ */ jsxs3("div", { className: "px-3 py-1", children: [
16045
+ return /* @__PURE__ */ jsxs3("div", { className: "group px-3 py-1", children: [
16101
16046
  /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
16102
16047
  /* @__PURE__ */ jsx5(
16103
16048
  SessionPluginIcon,
@@ -16108,6 +16053,28 @@ function PluginConnectorList({
16108
16053
  }
16109
16054
  ),
16110
16055
  /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate text-[11px]", title: label, children: label }),
16056
+ !draft && item.config === "configured" ? /* @__PURE__ */ jsx5(
16057
+ "button",
16058
+ {
16059
+ type: "button",
16060
+ title: "\u66F4\u65B0\u8BE5\u63D2\u4EF6\u7684\u914D\u7F6E",
16061
+ disabled: busy || !sessionId,
16062
+ onClick: () => onEditConfig(item),
16063
+ className: "shrink-0 text-[10px] text-[hsl(var(--muted-foreground))] underline opacity-0 transition-opacity focus-visible:opacity-100 group-hover:opacity-100 disabled:cursor-not-allowed disabled:opacity-50",
16064
+ children: "\u66F4\u65B0\u914D\u7F6E"
16065
+ }
16066
+ ) : null,
16067
+ !draft && (item.config === "required" || item.config === "error") ? /* @__PURE__ */ jsx5(
16068
+ "button",
16069
+ {
16070
+ type: "button",
16071
+ title: "\u8BE5\u63D2\u4EF6\u9700\u8981\u586B\u5199\u914D\u7F6E",
16072
+ disabled: busy || !sessionId,
16073
+ onClick: () => onEditConfig(item),
16074
+ className: "shrink-0 text-[10px] text-[hsl(var(--muted-foreground))] underline disabled:cursor-not-allowed disabled:opacity-50",
16075
+ children: "\u586B\u5199\u914D\u7F6E"
16076
+ }
16077
+ ) : null,
16111
16078
  /* @__PURE__ */ jsx5(
16112
16079
  PluginSwitch,
16113
16080
  {
@@ -16120,19 +16087,6 @@ function PluginConnectorList({
16120
16087
  }
16121
16088
  )
16122
16089
  ] }),
16123
- !draft && summary && item.config !== "not_required" ? /* @__PURE__ */ jsxs3("div", { className: "mt-0.5 flex items-center gap-2 pl-7 text-[10px] text-[hsl(var(--muted-foreground))]", children: [
16124
- /* @__PURE__ */ jsx5("span", { children: summary }),
16125
- item.config === "configured" ? /* @__PURE__ */ jsx5(
16126
- "button",
16127
- {
16128
- type: "button",
16129
- disabled: busy || !sessionId,
16130
- onClick: () => onEditConfig(item),
16131
- className: "underline disabled:cursor-not-allowed disabled:opacity-50",
16132
- children: "\u914D\u7F6E"
16133
- }
16134
- ) : null
16135
- ] }) : null,
16136
16090
  !draft && item.active && item.status !== "valid" && item.status !== "required" ? /* @__PURE__ */ jsxs3("div", { className: "mt-0.5 flex items-center gap-2 pl-7 text-[10px] text-[hsl(var(--muted-foreground))]", children: [
16137
16091
  /* @__PURE__ */ jsx5("span", { children: item.reason || "\u63D2\u4EF6\u6682\u4E0D\u53EF\u7528" }),
16138
16092
  /* @__PURE__ */ jsx5(
@@ -16164,6 +16118,61 @@ function PluginConnectorList({
16164
16118
 
16165
16119
  // src/components/use-session-plugin-activation.ts
16166
16120
  import { useCallback as useCallback22, useEffect as useEffect10, useMemo as useMemo11, useRef as useRef10, useState as useState15 } from "react";
16121
+
16122
+ // src/components/plugin-connector.ts
16123
+ function catalogToConnectorItems(catalog) {
16124
+ return catalog.map((entry) => ({
16125
+ name: entry.name,
16126
+ display_name: entry.display_name,
16127
+ icon: entry.icon,
16128
+ iconSource: "account",
16129
+ installed: entry.installed,
16130
+ active: false,
16131
+ status: "not_prepared",
16132
+ projected: false
16133
+ }));
16134
+ }
16135
+ function mergeConnectorItems(sessionPlugins, catalog) {
16136
+ const byName = new Map((catalog ?? []).map((entry) => [entry.name, entry]));
16137
+ return sessionPlugins.map((plugin) => {
16138
+ const entry = byName.get(plugin.name);
16139
+ if (!entry) {
16140
+ return {
16141
+ name: plugin.name,
16142
+ display_name: plugin.display_name ?? null,
16143
+ icon: plugin.icon ?? null,
16144
+ iconSource: "session",
16145
+ installed: plugin.installed,
16146
+ active: plugin.active,
16147
+ status: plugin.status,
16148
+ reason: plugin.reason,
16149
+ config: plugin.config,
16150
+ projected: plugin.projected
16151
+ };
16152
+ }
16153
+ return {
16154
+ name: plugin.name,
16155
+ display_name: entry.display_name ?? plugin.display_name ?? null,
16156
+ icon: entry.icon,
16157
+ iconSource: "account",
16158
+ installed: entry.installed,
16159
+ active: plugin.active,
16160
+ status: plugin.status,
16161
+ reason: plugin.reason,
16162
+ config: plugin.config,
16163
+ projected: plugin.projected
16164
+ };
16165
+ });
16166
+ }
16167
+ function filterConnectorItems(items, query) {
16168
+ const needle = query.trim().toLowerCase();
16169
+ if (!needle) return items;
16170
+ return items.filter(
16171
+ (item) => `${item.display_name ?? ""} ${item.name}`.toLowerCase().includes(needle)
16172
+ );
16173
+ }
16174
+
16175
+ // src/components/use-session-plugin-activation.ts
16167
16176
  function useSessionPluginActivation({
16168
16177
  client,
16169
16178
  sessionId,
@@ -16245,9 +16254,22 @@ function useSessionPluginActivation({
16245
16254
  setListError(false);
16246
16255
  try {
16247
16256
  const result = await client.sessions.listSessionPlugins(sessionId, { signal: controller.signal });
16257
+ const withConfig = await Promise.all(
16258
+ result.plugins.map(async (item) => {
16259
+ if (item.config !== void 0 && item.config !== "unchecked") return item;
16260
+ try {
16261
+ const { config: config2 } = await client.sessions.getSessionPluginConfig(sessionId, item.name, {
16262
+ signal: controller.signal
16263
+ });
16264
+ return { ...item, config: config2.state };
16265
+ } catch {
16266
+ return item;
16267
+ }
16268
+ })
16269
+ );
16248
16270
  if (alive.current && current === generation.current) {
16249
- serverActive.current = new Set(result.plugins.filter((item) => item.active).map((item) => item.name));
16250
- setPlugins(result.plugins.map((item) => {
16271
+ serverActive.current = new Set(withConfig.filter((item) => item.active).map((item) => item.name));
16272
+ setPlugins(withConfig.map((item) => {
16251
16273
  const desired = desiredActivations.current.get(item.name);
16252
16274
  return desired === void 0 ? item : { ...item, active: desired };
16253
16275
  }));
@@ -16528,7 +16550,8 @@ async function copyToClipboard(text) {
16528
16550
 
16529
16551
  // src/components/SessionQueuePanel.tsx
16530
16552
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
16531
- var ACTION_BUTTON = "flex h-6 w-6 items-center justify-center rounded text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent";
16553
+ var ICON_BUTTON = "flex h-6 w-6 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent";
16554
+ var LABEL_BUTTON = "inline-flex h-6 items-center gap-1 rounded-md px-2 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent";
16532
16555
  function SessionQueuePanel({
16533
16556
  snapshot,
16534
16557
  canDeliver,
@@ -16543,10 +16566,11 @@ function SessionQueuePanel({
16543
16566
  onDeliver
16544
16567
  }) {
16545
16568
  const [collapsed, setCollapsed] = useState17(false);
16546
- const [editing, setEditing] = useState17(
16547
- null
16548
- );
16569
+ const [editing, setEditing] = useState17(null);
16549
16570
  const [draggingId, setDraggingId] = useState17(null);
16571
+ const [dropAt, setDropAt] = useState17(null);
16572
+ const draggingRef = useRef11(null);
16573
+ const dropRef = useRef11(null);
16550
16574
  const requeuePending = useRef11(false);
16551
16575
  const [requeueing, setRequeueing] = useState17(false);
16552
16576
  const items = snapshot.items;
@@ -16575,235 +16599,274 @@ function SessionQueuePanel({
16575
16599
  setEditing((current) => current === submitted ? null : current);
16576
16600
  }
16577
16601
  };
16578
- const handleDrop = (targetId) => {
16579
- const sourceId = draggingId;
16602
+ const handleDrop = (targetId, edge) => {
16603
+ const sourceId = draggingRef.current;
16604
+ draggingRef.current = null;
16605
+ dropRef.current = null;
16580
16606
  setDraggingId(null);
16607
+ setDropAt(null);
16581
16608
  if (!sourceId || sourceId === targetId) return;
16582
16609
  const from = pendingIds.indexOf(sourceId);
16583
16610
  const to = pendingIds.indexOf(targetId);
16584
16611
  if (from < 0 || to < 0) return;
16585
16612
  const next = [...pendingIds];
16586
16613
  next.splice(from, 1);
16587
- next.splice(to, 0, sourceId);
16614
+ const target = next.indexOf(targetId);
16615
+ next.splice(edge === "after" ? target + 1 : target, 0, sourceId);
16588
16616
  onReorder(next);
16589
16617
  };
16590
- return /* @__PURE__ */ jsx7(
16591
- "section",
16592
- {
16593
- className: "blade-chat-queue shrink-0 border-t border-[hsl(var(--border))] px-4 pt-3",
16594
- "aria-label": "\u5F85\u6267\u884C\u6D88\u606F",
16595
- children: /* @__PURE__ */ jsxs5("div", { className: "mx-auto max-w-[748px]", children: [
16596
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
16597
- /* @__PURE__ */ jsxs5("span", { className: "font-medium text-[hsl(var(--foreground))]", children: [
16598
- "\u5F85\u6267\u884C \xB7 ",
16599
- items.length
16600
- ] }),
16601
- snapshot.paused && /* @__PURE__ */ jsxs5(Fragment4, { children: [
16602
- /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--destructive))]", children: [
16603
- /* @__PURE__ */ jsx7(CirclePause, { size: 12 }),
16604
- pauseLabel
16605
- ] }),
16618
+ return /* @__PURE__ */ jsx7("section", { className: "blade-chat-queue shrink-0 px-4 pt-2", "aria-label": "\u5F85\u6267\u884C\u6D88\u606F", children: /* @__PURE__ */ jsxs5("div", { className: "mx-auto max-w-[748px]", children: [
16619
+ snapshot.paused || collapsible ? /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 px-0.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
16620
+ /* @__PURE__ */ jsxs5("span", { className: "font-medium", children: [
16621
+ "\u5F85\u6267\u884C \xB7 ",
16622
+ items.length
16623
+ ] }),
16624
+ snapshot.paused && /* @__PURE__ */ jsxs5(Fragment4, { children: [
16625
+ /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--destructive))]", children: [
16626
+ /* @__PURE__ */ jsx7(CirclePause, { size: 12 }),
16627
+ pauseLabel
16628
+ ] }),
16629
+ /* @__PURE__ */ jsx7(
16630
+ "button",
16631
+ {
16632
+ type: "button",
16633
+ onClick: onResume,
16634
+ className: "h-6 rounded-md border border-[hsl(var(--border))] px-2 font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
16635
+ children: "\u7EE7\u7EED\u6267\u884C"
16636
+ }
16637
+ )
16638
+ ] }),
16639
+ collapsible && /* @__PURE__ */ jsxs5(
16640
+ "button",
16641
+ {
16642
+ type: "button",
16643
+ onClick: () => setCollapsed((value) => !value),
16644
+ "aria-expanded": !collapsed,
16645
+ className: "ml-auto inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
16646
+ children: [
16647
+ collapsed ? "\u5C55\u5F00" : "\u6298\u53E0",
16648
+ /* @__PURE__ */ jsx7(ChevronDown, { size: 12, className: cn(!collapsed && "rotate-180") })
16649
+ ]
16650
+ }
16651
+ )
16652
+ ] }) : null,
16653
+ notice && /* @__PURE__ */ jsxs5("div", { className: "blade-chat-queue-notice mt-2 flex items-start gap-1.5 text-xs text-[hsl(var(--destructive))]", children: [
16654
+ /* @__PURE__ */ jsx7(CircleAlert, { size: 13, className: "mt-0.5 shrink-0" }),
16655
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: notice })
16656
+ ] }),
16657
+ detachedEdit && /* @__PURE__ */ jsxs5("div", { className: "mt-2 flex flex-col gap-2 text-xs", children: [
16658
+ /* @__PURE__ */ jsx7("span", { children: "\u539F\u6D88\u606F\u5DF2\u53D8\u5316\uFF0C\u4FEE\u6539\u5185\u5BB9\u5DF2\u4FDD\u7559" }),
16659
+ /* @__PURE__ */ jsx7(
16660
+ "textarea",
16661
+ {
16662
+ "aria-label": "\u4FDD\u7559\u7684\u4FEE\u6539\u5185\u5BB9",
16663
+ value: detachedEdit.text,
16664
+ onChange: (event) => setEditing((current) => current ? { ...current, text: event.target.value } : current),
16665
+ rows: 2,
16666
+ className: "w-full rounded border border-[hsl(var(--border))] bg-transparent p-2"
16667
+ }
16668
+ ),
16669
+ /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-2", children: [
16670
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "rounded border border-[hsl(var(--border))] px-2 py-1", disabled: requeueing, onClick: stopEdit, children: "\u653E\u5F03\u4FEE\u6539" }),
16671
+ onRequeue && /* @__PURE__ */ jsx7("button", { type: "button", className: "rounded bg-[hsl(var(--primary))] px-2 py-1 text-[hsl(var(--primary-foreground))] disabled:opacity-40", disabled: requeueing || !detachedEdit.text.trim(), onClick: async () => {
16672
+ if (requeuePending.current) return;
16673
+ requeuePending.current = true;
16674
+ setRequeueing(true);
16675
+ const submitted = editing;
16676
+ try {
16677
+ if (await onRequeue(detachedEdit.text.trim())) {
16678
+ setEditing((current) => current === submitted ? null : current);
16679
+ }
16680
+ } finally {
16681
+ requeuePending.current = false;
16682
+ setRequeueing(false);
16683
+ }
16684
+ }, children: "\u4F5C\u4E3A\u65B0\u6D88\u606F\u6392\u961F" })
16685
+ ] })
16686
+ ] }),
16687
+ /* @__PURE__ */ jsx7("ul", { className: "mx-3 flex max-h-56 flex-col overflow-y-auto rounded-t-[22px] border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-1.5 py-1.5", children: visibleItems.map((item) => {
16688
+ const position = items.indexOf(item) + 1;
16689
+ const pending = canEditQueuedMessage(item);
16690
+ const busy = pendingItemId === item.id;
16691
+ const isEditing = activeEdit?.id === item.id;
16692
+ const pendingIndex = pendingIds.indexOf(item.id);
16693
+ const statusLabel = item.status === "pending" ? null : queuedMessageStatusLabel(item.status);
16694
+ const deliverable = canDeliver && canDeliverQueuedMessage(item);
16695
+ return /* @__PURE__ */ jsx7(
16696
+ "li",
16697
+ {
16698
+ draggable: pending && !busy && !isEditing,
16699
+ onDragStart: (event) => {
16700
+ draggingRef.current = item.id;
16701
+ setDraggingId(item.id);
16702
+ const text = event.currentTarget.querySelector("[data-queue-text]");
16703
+ if (text && event.dataTransfer) {
16704
+ const rect = text.getBoundingClientRect();
16705
+ event.dataTransfer.setDragImage(
16706
+ text,
16707
+ event.clientX - rect.left,
16708
+ event.clientY - rect.top
16709
+ );
16710
+ }
16711
+ },
16712
+ onDragEnd: () => {
16713
+ draggingRef.current = null;
16714
+ dropRef.current = null;
16715
+ setDraggingId(null);
16716
+ setDropAt(null);
16717
+ },
16718
+ onDragOver: (event) => {
16719
+ if (!pending) return;
16720
+ event.preventDefault();
16721
+ if (!draggingRef.current || draggingRef.current === item.id) return;
16722
+ const rect = event.currentTarget.getBoundingClientRect();
16723
+ const edge = event.clientY > rect.top + rect.height / 2 ? "after" : "before";
16724
+ dropRef.current = { id: item.id, edge };
16725
+ setDropAt(
16726
+ (current) => current?.id === item.id && current.edge === edge ? current : { id: item.id, edge }
16727
+ );
16728
+ },
16729
+ onDragLeave: () => {
16730
+ if (dropRef.current?.id === item.id) dropRef.current = null;
16731
+ setDropAt((current) => current?.id === item.id ? null : current);
16732
+ },
16733
+ onDrop: (event) => {
16734
+ event.preventDefault();
16735
+ const landed = dropRef.current;
16736
+ if (pending) handleDrop(item.id, landed?.id === item.id ? landed.edge : "before");
16737
+ },
16738
+ className: cn(
16739
+ "blade-chat-queue-item group relative flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[11px]",
16740
+ pending && !isEditing && "cursor-grab active:cursor-grabbing",
16741
+ busy && "opacity-60",
16742
+ draggingId === item.id && "opacity-40"
16743
+ ),
16744
+ children: isEditing ? /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
16745
+ /* @__PURE__ */ jsx7(
16746
+ "textarea",
16747
+ {
16748
+ value: activeEdit?.text ?? "",
16749
+ onChange: (event) => setEditing(
16750
+ (current) => current ? { ...current, text: event.target.value } : current
16751
+ ),
16752
+ rows: 2,
16753
+ "aria-label": `\u7F16\u8F91\u7B2C ${position} \u6761\u6D88\u606F`,
16754
+ className: "w-full resize-none rounded-md border border-[hsl(var(--border))] bg-transparent px-2 py-1.5 text-sm leading-5 text-[hsl(var(--foreground))] outline-none"
16755
+ }
16756
+ ),
16757
+ /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-1.5", children: [
16758
+ /* @__PURE__ */ jsx7(
16759
+ "button",
16760
+ {
16761
+ type: "button",
16762
+ onClick: stopEdit,
16763
+ className: "h-7 rounded-md border border-[hsl(var(--border))] px-2 text-xs text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
16764
+ children: "\u53D6\u6D88"
16765
+ }
16766
+ ),
16767
+ /* @__PURE__ */ jsx7(
16768
+ "button",
16769
+ {
16770
+ type: "button",
16771
+ onClick: () => commitEdit(item),
16772
+ disabled: busy || !activeEdit?.text.trim(),
16773
+ className: "h-7 rounded-md bg-[hsl(var(--primary))] px-2 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-40",
16774
+ children: "\u4FDD\u5B58"
16775
+ }
16776
+ )
16777
+ ] })
16778
+ ] }) : /* @__PURE__ */ jsxs5(Fragment4, { children: [
16779
+ dropAt?.id === item.id ? /* @__PURE__ */ jsx7(
16780
+ "span",
16781
+ {
16782
+ "aria-hidden": "true",
16783
+ style: { background: "var(--resize-line-hover, hsl(var(--foreground) / 0.55))" },
16784
+ className: cn(
16785
+ "pointer-events-none absolute inset-x-1 h-[2px] rounded-full",
16786
+ dropAt.edge === "before" ? "top-0" : "bottom-0"
16787
+ )
16788
+ }
16789
+ ) : null,
16606
16790
  /* @__PURE__ */ jsx7(
16607
16791
  "button",
16608
16792
  {
16609
16793
  type: "button",
16610
- onClick: onResume,
16611
- className: "h-6 rounded-md border border-[hsl(var(--border))] px-2 font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
16612
- children: "\u7EE7\u7EED\u6267\u884C"
16794
+ disabled: !pending || busy,
16795
+ "aria-label": `\u8C03\u6574\u7B2C ${position} \u6761\u7684\u987A\u5E8F\uFF08\u62D6\u52A8\uFF0C\u6216\u6309 Alt+\u4E0A/\u4E0B\uFF09`,
16796
+ title: "\u62D6\u52A8\u8C03\u6574\u987A\u5E8F\uFF08Alt+\u4E0A/\u4E0B \u4E5F\u884C\uFF09",
16797
+ onKeyDown: (event) => {
16798
+ if (!event.altKey) return;
16799
+ if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
16800
+ event.preventDefault();
16801
+ const delta = event.key === "ArrowUp" ? -1 : 1;
16802
+ if (pendingIndex < 0) return;
16803
+ if (delta < 0 && pendingIndex === 0) return;
16804
+ if (delta > 0 && pendingIndex === pendingIds.length - 1) return;
16805
+ onMove(item, delta);
16806
+ },
16807
+ className: "-ml-0.5 flex h-5 w-4 shrink-0 cursor-grab items-center justify-center rounded text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] active:cursor-grabbing disabled:cursor-default disabled:opacity-60 disabled:hover:bg-transparent",
16808
+ children: /* @__PURE__ */ jsx7(Menu, { size: 14, "aria-hidden": "true" })
16613
16809
  }
16614
- )
16615
- ] }),
16616
- collapsible && /* @__PURE__ */ jsxs5(
16617
- "button",
16618
- {
16619
- type: "button",
16620
- onClick: () => setCollapsed((value) => !value),
16621
- "aria-expanded": !collapsed,
16622
- className: "ml-auto inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
16623
- children: [
16624
- collapsed ? "\u5C55\u5F00" : "\u6298\u53E0",
16625
- /* @__PURE__ */ jsx7(ChevronDown, { size: 12, className: cn(!collapsed && "rotate-180") })
16626
- ]
16627
- }
16628
- )
16629
- ] }),
16630
- notice && /* @__PURE__ */ jsxs5("div", { className: "blade-chat-queue-notice mt-2 flex items-start gap-1.5 text-xs text-[hsl(var(--destructive))]", children: [
16631
- /* @__PURE__ */ jsx7(CircleAlert, { size: 13, className: "mt-0.5 shrink-0" }),
16632
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: notice })
16633
- ] }),
16634
- detachedEdit && /* @__PURE__ */ jsxs5("div", { className: "mt-2 flex flex-col gap-2 text-xs", children: [
16635
- /* @__PURE__ */ jsx7("span", { children: "\u539F\u6D88\u606F\u5DF2\u53D8\u5316\uFF0C\u4FEE\u6539\u5185\u5BB9\u5DF2\u4FDD\u7559" }),
16636
- /* @__PURE__ */ jsx7(
16637
- "textarea",
16638
- {
16639
- "aria-label": "\u4FDD\u7559\u7684\u4FEE\u6539\u5185\u5BB9",
16640
- value: detachedEdit.text,
16641
- onChange: (event) => setEditing((current) => current ? { ...current, text: event.target.value } : current),
16642
- rows: 2,
16643
- className: "w-full rounded border border-[hsl(var(--border))] bg-transparent p-2"
16644
- }
16645
- ),
16646
- /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-2", children: [
16647
- /* @__PURE__ */ jsx7("button", { type: "button", className: "rounded border border-[hsl(var(--border))] px-2 py-1", disabled: requeueing, onClick: stopEdit, children: "\u653E\u5F03\u4FEE\u6539" }),
16648
- onRequeue && /* @__PURE__ */ jsx7("button", { type: "button", className: "rounded bg-[hsl(var(--primary))] px-2 py-1 text-[hsl(var(--primary-foreground))] disabled:opacity-40", disabled: requeueing || !detachedEdit.text.trim(), onClick: async () => {
16649
- if (requeuePending.current) return;
16650
- requeuePending.current = true;
16651
- setRequeueing(true);
16652
- const submitted = editing;
16653
- try {
16654
- if (await onRequeue(detachedEdit.text.trim())) {
16655
- setEditing((current) => current === submitted ? null : current);
16656
- }
16657
- } finally {
16658
- requeuePending.current = false;
16659
- setRequeueing(false);
16810
+ ),
16811
+ /* @__PURE__ */ jsx7(
16812
+ "span",
16813
+ {
16814
+ "data-queue-text": true,
16815
+ className: "min-w-0 flex-1 truncate pt-px text-[hsl(var(--foreground))]",
16816
+ children: item.content
16660
16817
  }
16661
- }, children: "\u4F5C\u4E3A\u65B0\u6D88\u606F\u6392\u961F" })
16662
- ] })
16663
- ] }),
16664
- /* @__PURE__ */ jsx7("ul", { className: "mt-2 flex max-h-56 flex-col gap-1.5 overflow-y-auto", children: visibleItems.map((item) => {
16665
- const position = items.indexOf(item) + 1;
16666
- const pending = canEditQueuedMessage(item);
16667
- const busy = pendingItemId === item.id;
16668
- const isEditing = activeEdit?.id === item.id;
16669
- const pendingIndex = pendingIds.indexOf(item.id);
16670
- const statusLabel = queuedMessageStatusLabel(item.status);
16671
- const deliverable = canDeliver && canDeliverQueuedMessage(item);
16672
- return /* @__PURE__ */ jsxs5(
16673
- "li",
16674
- {
16675
- draggable: pending && !busy,
16676
- onDragStart: () => setDraggingId(item.id),
16677
- onDragEnd: () => setDraggingId(null),
16678
- onDragOver: (event) => {
16679
- if (pending) event.preventDefault();
16680
- },
16681
- onDrop: (event) => {
16682
- event.preventDefault();
16683
- if (pending) handleDrop(item.id);
16684
- },
16685
- className: cn(
16686
- "blade-chat-queue-item flex items-start gap-2 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2 py-1.5 text-xs",
16687
- busy && "opacity-60",
16688
- draggingId === item.id && "opacity-40"
16818
+ ),
16819
+ item.error ? /* @__PURE__ */ jsx7("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--destructive))]", children: item.error }) : busy ? /* @__PURE__ */ jsxs5("span", { className: "mt-0.5 inline-flex shrink-0 items-center gap-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
16820
+ /* @__PURE__ */ jsx7(LoaderCircle, { size: 11, className: "animate-spin" }),
16821
+ "\u5904\u7406\u4E2D"
16822
+ ] }) : statusLabel ? /* @__PURE__ */ jsx7("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: statusLabel }) : null,
16823
+ /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", children: [
16824
+ /* @__PURE__ */ jsxs5(
16825
+ "button",
16826
+ {
16827
+ type: "button",
16828
+ "aria-label": `\u7ACB\u523B\u53D1\u9001\u7B2C ${position} \u6761`,
16829
+ title: deliverable ? "\u7ACB\u523B\u53D1\u9001" : "\u5F53\u524D\u6CA1\u6709\u53EF\u63A5\u6536\u8865\u5145\u7684\u4EFB\u52A1",
16830
+ disabled: busy || !deliverable,
16831
+ onClick: () => onDeliver(item),
16832
+ className: LABEL_BUTTON,
16833
+ children: [
16834
+ /* @__PURE__ */ jsx7(Send, { size: 13, "aria-hidden": "true" }),
16835
+ "\u7ACB\u523B\u53D1\u9001"
16836
+ ]
16837
+ }
16689
16838
  ),
16690
- children: [
16691
- /* @__PURE__ */ jsx7("span", { className: "mt-0.5 w-4 shrink-0 text-right tabular-nums text-[hsl(var(--muted-foreground))]", children: position }),
16692
- /* @__PURE__ */ jsx7("div", { className: "min-w-0 flex-1", children: isEditing ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1.5", children: [
16693
- /* @__PURE__ */ jsx7(
16694
- "textarea",
16695
- {
16696
- value: activeEdit?.text ?? "",
16697
- onChange: (event) => setEditing(
16698
- (current) => current ? { ...current, text: event.target.value } : current
16699
- ),
16700
- rows: 2,
16701
- "aria-label": `\u7F16\u8F91\u7B2C ${position} \u6761\u6D88\u606F`,
16702
- className: "w-full resize-none rounded border border-[hsl(var(--border))] bg-transparent px-1.5 py-1 text-xs leading-5 text-[hsl(var(--foreground))] outline-none"
16703
- }
16704
- ),
16705
- /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-1.5", children: [
16706
- /* @__PURE__ */ jsx7(
16707
- "button",
16708
- {
16709
- type: "button",
16710
- onClick: stopEdit,
16711
- className: "h-6 rounded-md border border-[hsl(var(--border))] px-2 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
16712
- children: "\u53D6\u6D88"
16713
- }
16714
- ),
16715
- /* @__PURE__ */ jsx7(
16716
- "button",
16717
- {
16718
- type: "button",
16719
- onClick: () => commitEdit(item),
16720
- disabled: busy || !activeEdit?.text.trim(),
16721
- className: "h-6 rounded-md bg-[hsl(var(--primary))] px-2 font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-40",
16722
- children: "\u4FDD\u5B58"
16723
- }
16724
- )
16725
- ] })
16726
- ] }) : /* @__PURE__ */ jsxs5(Fragment4, { children: [
16727
- /* @__PURE__ */ jsx7("div", { className: "line-clamp-2 whitespace-pre-wrap break-words text-[hsl(var(--foreground))]", children: item.content }),
16728
- /* @__PURE__ */ jsxs5("div", { className: "mt-0.5 flex items-center gap-2 text-[hsl(var(--muted-foreground))]", children: [
16729
- statusLabel && /* @__PURE__ */ jsx7("span", { children: statusLabel }),
16730
- busy && /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1", children: [
16731
- /* @__PURE__ */ jsx7(LoaderCircle, { size: 11, className: "animate-spin" }),
16732
- "\u5904\u7406\u4E2D"
16733
- ] }),
16734
- item.error && /* @__PURE__ */ jsx7("span", { className: "text-[hsl(var(--destructive))]", children: item.error })
16735
- ] })
16736
- ] }) }),
16737
- /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-0.5", children: [
16738
- /* @__PURE__ */ jsx7(
16739
- "button",
16740
- {
16741
- type: "button",
16742
- "aria-label": `\u4E0A\u79FB\u7B2C ${position} \u6761`,
16743
- title: "\u4E0A\u79FB",
16744
- disabled: busy || pendingIndex <= 0,
16745
- onClick: () => onMove(item, -1),
16746
- className: ACTION_BUTTON,
16747
- children: /* @__PURE__ */ jsx7(ChevronUp, { size: 13 })
16748
- }
16749
- ),
16750
- /* @__PURE__ */ jsx7(
16751
- "button",
16752
- {
16753
- type: "button",
16754
- "aria-label": `\u4E0B\u79FB\u7B2C ${position} \u6761`,
16755
- title: "\u4E0B\u79FB",
16756
- disabled: busy || pendingIndex < 0 || pendingIndex >= pendingIds.length - 1,
16757
- onClick: () => onMove(item, 1),
16758
- className: ACTION_BUTTON,
16759
- children: /* @__PURE__ */ jsx7(ChevronDown, { size: 13 })
16760
- }
16761
- ),
16762
- /* @__PURE__ */ jsx7(
16763
- "button",
16764
- {
16765
- type: "button",
16766
- "aria-label": `\u7F16\u8F91\u7B2C ${position} \u6761`,
16767
- title: "\u7F16\u8F91",
16768
- disabled: busy || !canEditQueuedMessage(item),
16769
- onClick: () => startEdit(item),
16770
- className: ACTION_BUTTON,
16771
- children: /* @__PURE__ */ jsx7(Pencil, { size: 12 })
16772
- }
16773
- ),
16774
- /* @__PURE__ */ jsx7(
16775
- "button",
16776
- {
16777
- type: "button",
16778
- "aria-label": `\u5220\u9664\u7B2C ${position} \u6761`,
16779
- title: "\u5220\u9664",
16780
- disabled: busy || !canCancelQueuedMessage(item),
16781
- onClick: () => onCancel(item),
16782
- className: ACTION_BUTTON,
16783
- children: /* @__PURE__ */ jsx7(Trash2, { size: 12 })
16784
- }
16785
- ),
16786
- /* @__PURE__ */ jsx7(
16787
- "button",
16788
- {
16789
- type: "button",
16790
- "aria-label": `\u7ACB\u5373\u8865\u5145\u7B2C ${position} \u6761`,
16791
- title: deliverable ? "\u7ACB\u5373\u8865\u5145" : "\u5F53\u524D\u6CA1\u6709\u53EF\u63A5\u6536\u8865\u5145\u7684\u4EFB\u52A1",
16792
- disabled: busy || !deliverable,
16793
- onClick: () => onDeliver(item),
16794
- className: ACTION_BUTTON,
16795
- children: /* @__PURE__ */ jsx7(Send, { size: 12 })
16796
- }
16797
- )
16798
- ] })
16799
- ]
16800
- },
16801
- item.id
16802
- );
16803
- }) })
16804
- ] })
16805
- }
16806
- );
16839
+ /* @__PURE__ */ jsx7(
16840
+ "button",
16841
+ {
16842
+ type: "button",
16843
+ "aria-label": `\u7F16\u8F91\u7B2C ${position} \u6761`,
16844
+ title: "\u7F16\u8F91",
16845
+ disabled: busy || !pending,
16846
+ onClick: () => startEdit(item),
16847
+ className: ICON_BUTTON,
16848
+ children: /* @__PURE__ */ jsx7(Pencil, { size: 13, "aria-hidden": "true" })
16849
+ }
16850
+ ),
16851
+ /* @__PURE__ */ jsx7(
16852
+ "button",
16853
+ {
16854
+ type: "button",
16855
+ "aria-label": `\u5220\u9664\u7B2C ${position} \u6761`,
16856
+ title: "\u5220\u9664",
16857
+ disabled: busy || !canCancelQueuedMessage(item),
16858
+ onClick: () => onCancel(item),
16859
+ className: ICON_BUTTON,
16860
+ children: /* @__PURE__ */ jsx7(Trash2, { size: 13, "aria-hidden": "true" })
16861
+ }
16862
+ )
16863
+ ] })
16864
+ ] })
16865
+ },
16866
+ item.id
16867
+ );
16868
+ }) })
16869
+ ] }) });
16807
16870
  }
16808
16871
 
16809
16872
  // src/components/ReplayBar.tsx
@@ -45960,10 +46023,10 @@ function selectionFromItem(item) {
45960
46023
  }
45961
46024
  var TRIGGER_ICON_LIMIT = 3;
45962
46025
  function triggerSummary(items) {
45963
- const withIcon = items.filter((item) => Boolean(item.icon));
46026
+ const visible = items.slice(0, TRIGGER_ICON_LIMIT);
45964
46027
  return {
45965
- icons: withIcon.slice(0, TRIGGER_ICON_LIMIT),
45966
- overflow: Math.max(0, items.length - Math.min(withIcon.length, TRIGGER_ICON_LIMIT)),
46028
+ visible,
46029
+ overflow: items.length - visible.length,
45967
46030
  total: items.length
45968
46031
  };
45969
46032
  }
@@ -46127,21 +46190,82 @@ function ConnectorPanel({
46127
46190
  ] });
46128
46191
  }
46129
46192
 
46193
+ // src/components/PluginTriggerStack.tsx
46194
+ import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
46195
+ var AVATAR_SIZE = 20;
46196
+ function hueOf(name) {
46197
+ let hash2 = 0;
46198
+ for (const char of name) hash2 = (hash2 * 31 + char.codePointAt(0)) % 1000003;
46199
+ return hash2 % 360;
46200
+ }
46201
+ var AVATAR_PALETTE = [
46202
+ "bg-violet-100 text-violet-800 dark:bg-violet-500/25 dark:text-violet-200",
46203
+ "bg-sky-100 text-sky-800 dark:bg-sky-500/25 dark:text-sky-200",
46204
+ "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/25 dark:text-emerald-200",
46205
+ "bg-amber-100 text-amber-800 dark:bg-amber-500/25 dark:text-amber-200",
46206
+ "bg-rose-100 text-rose-800 dark:bg-rose-500/25 dark:text-rose-200",
46207
+ "bg-indigo-100 text-indigo-800 dark:bg-indigo-500/25 dark:text-indigo-200",
46208
+ "bg-teal-100 text-teal-800 dark:bg-teal-500/25 dark:text-teal-200",
46209
+ "bg-fuchsia-100 text-fuchsia-800 dark:bg-fuchsia-500/25 dark:text-fuchsia-200"
46210
+ ];
46211
+ function PluginTriggerStack({ client, sessionId, summary, className }) {
46212
+ if (summary.total === 0) return null;
46213
+ const ring = "ring-2 ring-[hsl(var(--background))]";
46214
+ return /* @__PURE__ */ jsxs26("span", { className: `flex items-center -space-x-1 ${className ?? ""}`, children: [
46215
+ summary.visible.map((item) => {
46216
+ const label = item.displayName?.trim() || item.name;
46217
+ const tone = AVATAR_PALETTE[hueOf(item.name) % AVATAR_PALETTE.length];
46218
+ return item.icon ? /* @__PURE__ */ jsx32(
46219
+ SessionPluginIcon,
46220
+ {
46221
+ client,
46222
+ sessionId: item.iconSource === "account" ? null : sessionId,
46223
+ plugin: item,
46224
+ size: AVATAR_SIZE,
46225
+ shape: "circle",
46226
+ className: ring
46227
+ },
46228
+ item.name
46229
+ ) : /* @__PURE__ */ jsx32(
46230
+ "span",
46231
+ {
46232
+ title: label,
46233
+ className: `flex shrink-0 items-center justify-center rounded-full font-semibold text-[11px] ${tone} ${ring}`,
46234
+ style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
46235
+ children: Array.from(label.trim())[0]?.toUpperCase() ?? "?"
46236
+ },
46237
+ item.name
46238
+ );
46239
+ }),
46240
+ summary.overflow > 0 ? /* @__PURE__ */ jsxs26(
46241
+ "span",
46242
+ {
46243
+ className: `flex shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] font-medium text-[hsl(var(--muted-foreground))] text-[10px] ${ring}`,
46244
+ style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
46245
+ children: [
46246
+ "+",
46247
+ summary.overflow
46248
+ ]
46249
+ }
46250
+ ) : null
46251
+ ] });
46252
+ }
46253
+
46130
46254
  // src/components/ContextCard.tsx
46131
46255
  import {
46132
46256
  getContextDisplayState,
46133
46257
  getContextGroupDisplayState
46134
46258
  } from "@blade-hq/agent-client";
46135
- import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
46259
+ import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
46136
46260
  function ContextCard({ context, className }) {
46137
46261
  const display = getContextDisplayState(context);
46138
- return /* @__PURE__ */ jsxs26(
46262
+ return /* @__PURE__ */ jsxs27(
46139
46263
  "details",
46140
46264
  {
46141
46265
  className: `blade-chat-context-card group/context-card rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
46142
46266
  children: [
46143
- /* @__PURE__ */ jsxs26("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
46144
- /* @__PURE__ */ jsx32(
46267
+ /* @__PURE__ */ jsxs27("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
46268
+ /* @__PURE__ */ jsx33(
46145
46269
  Layers,
46146
46270
  {
46147
46271
  size: 15,
@@ -46149,11 +46273,11 @@ function ContextCard({ context, className }) {
46149
46273
  "aria-hidden": "true"
46150
46274
  }
46151
46275
  ),
46152
- /* @__PURE__ */ jsxs26("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
46153
- /* @__PURE__ */ jsx32("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
46154
- /* @__PURE__ */ jsx32("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
46276
+ /* @__PURE__ */ jsxs27("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
46277
+ /* @__PURE__ */ jsx33("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
46278
+ /* @__PURE__ */ jsx33("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
46155
46279
  ] }),
46156
- /* @__PURE__ */ jsx32(
46280
+ /* @__PURE__ */ jsx33(
46157
46281
  ChevronDown,
46158
46282
  {
46159
46283
  size: 14,
@@ -46162,7 +46286,7 @@ function ContextCard({ context, className }) {
46162
46286
  }
46163
46287
  )
46164
46288
  ] }),
46165
- /* @__PURE__ */ jsx32("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: display.detail })
46289
+ /* @__PURE__ */ jsx33("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: display.detail })
46166
46290
  ]
46167
46291
  }
46168
46292
  );
@@ -46171,9 +46295,9 @@ function ContextGroupCard({ contexts, className }) {
46171
46295
  if (contexts.length === 0) return null;
46172
46296
  const single = contexts.length === 1 ? getContextDisplayState(contexts[0]) : null;
46173
46297
  const group = single ? null : getContextGroupDisplayState(contexts);
46174
- return /* @__PURE__ */ jsxs26("details", { className: `blade-chat-context-card group/context-group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`, children: [
46175
- /* @__PURE__ */ jsxs26("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
46176
- /* @__PURE__ */ jsx32(
46298
+ return /* @__PURE__ */ jsxs27("details", { className: `blade-chat-context-card group/context-group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`, children: [
46299
+ /* @__PURE__ */ jsxs27("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
46300
+ /* @__PURE__ */ jsx33(
46177
46301
  Layers,
46178
46302
  {
46179
46303
  size: 15,
@@ -46181,11 +46305,11 @@ function ContextGroupCard({ contexts, className }) {
46181
46305
  "aria-hidden": "true"
46182
46306
  }
46183
46307
  ),
46184
- /* @__PURE__ */ jsxs26("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
46185
- /* @__PURE__ */ jsx32("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: single ? single.title : `${group?.title} \xB7 ${group?.count} \u9879` }),
46186
- /* @__PURE__ */ jsx32("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: single ? single.summary : group?.summary })
46308
+ /* @__PURE__ */ jsxs27("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
46309
+ /* @__PURE__ */ jsx33("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: single ? single.title : `${group?.title} \xB7 ${group?.count} \u9879` }),
46310
+ /* @__PURE__ */ jsx33("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: single ? single.summary : group?.summary })
46187
46311
  ] }),
46188
- /* @__PURE__ */ jsx32(
46312
+ /* @__PURE__ */ jsx33(
46189
46313
  ChevronDown,
46190
46314
  {
46191
46315
  size: 14,
@@ -46194,7 +46318,7 @@ function ContextGroupCard({ contexts, className }) {
46194
46318
  }
46195
46319
  )
46196
46320
  ] }),
46197
- single ? /* @__PURE__ */ jsx32("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: single.detail }) : /* @__PURE__ */ jsx32("div", { className: "blade-chat-context-group-items flex flex-col gap-1.5 border-t border-[hsl(var(--border))] p-2", children: contexts.map((context) => /* @__PURE__ */ jsx32(
46321
+ single ? /* @__PURE__ */ jsx33("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: single.detail }) : /* @__PURE__ */ jsx33("div", { className: "blade-chat-context-group-items flex flex-col gap-1.5 border-t border-[hsl(var(--border))] p-2", children: contexts.map((context) => /* @__PURE__ */ jsx33(
46198
46322
  ContextCard,
46199
46323
  {
46200
46324
  context
@@ -46206,7 +46330,7 @@ function ContextGroupCard({ contexts, className }) {
46206
46330
 
46207
46331
  // src/components/SessionMemoryToggle.tsx
46208
46332
  import { useCallback as useCallback29, useEffect as useEffect24, useRef as useRef25, useState as useState35, useSyncExternalStore as useSyncExternalStore2 } from "react";
46209
- import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
46333
+ import { jsx as jsx34, jsxs as jsxs28 } from "react/jsx-runtime";
46210
46334
  var saveStates = /* @__PURE__ */ new WeakMap();
46211
46335
  function getSaveState(client, sessionId) {
46212
46336
  let clientStates = saveStates.get(client);
@@ -46295,9 +46419,9 @@ function SessionMemoryToggle({
46295
46419
  },
46296
46420
  [client, enabled, onError, onSaved, sessionId]
46297
46421
  );
46298
- return /* @__PURE__ */ jsxs27("label", { className: cn("flex items-center justify-between", className), children: [
46299
- /* @__PURE__ */ jsx33("span", { className: labelClassName, children: label }),
46300
- /* @__PURE__ */ jsx33(
46422
+ return /* @__PURE__ */ jsxs28("label", { className: cn("flex items-center justify-between", className), children: [
46423
+ /* @__PURE__ */ jsx34("span", { className: labelClassName, children: label }),
46424
+ /* @__PURE__ */ jsx34(
46301
46425
  "input",
46302
46426
  {
46303
46427
  type: "checkbox",
@@ -46369,6 +46493,7 @@ export {
46369
46493
  PLAN_AUTO_COLLAPSE_MS,
46370
46494
  PlanUpdateBlock,
46371
46495
  PluginConnectorList,
46496
+ PluginTriggerStack,
46372
46497
  ReplayBar,
46373
46498
  ReplayMismatchPrompt,
46374
46499
  SessionMemoryToggle,
@@ -46393,7 +46518,6 @@ export {
46393
46518
  parsePlanUpdate,
46394
46519
  parseWhatIfPrompt,
46395
46520
  pickCurrentPlanStep,
46396
- pluginConnectorSummary,
46397
46521
  selectionFromItem,
46398
46522
  sessionPluginLabel,
46399
46523
  triggerSummary,
@@ -46429,7 +46553,6 @@ lucide-react/dist/esm/icons/bot.js:
46429
46553
  lucide-react/dist/esm/icons/check.js:
46430
46554
  lucide-react/dist/esm/icons/chevron-down.js:
46431
46555
  lucide-react/dist/esm/icons/chevron-right.js:
46432
- lucide-react/dist/esm/icons/chevron-up.js:
46433
46556
  lucide-react/dist/esm/icons/circle-alert.js:
46434
46557
  lucide-react/dist/esm/icons/circle-dot.js:
46435
46558
  lucide-react/dist/esm/icons/circle-pause.js:
@@ -46445,6 +46568,7 @@ lucide-react/dist/esm/icons/list-checks.js:
46445
46568
  lucide-react/dist/esm/icons/loader-circle.js:
46446
46569
  lucide-react/dist/esm/icons/lock-keyhole.js:
46447
46570
  lucide-react/dist/esm/icons/maximize-2.js:
46571
+ lucide-react/dist/esm/icons/menu.js:
46448
46572
  lucide-react/dist/esm/icons/message-square-more.js:
46449
46573
  lucide-react/dist/esm/icons/message-square.js:
46450
46574
  lucide-react/dist/esm/icons/minimize-2.js: