@blade-hq/agent-kit 0.0.0-placeholder.0 → 0.4.4

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 (39) hide show
  1. package/README.md +66 -3
  2. package/dist/AskUserQuestionBlock-CjvG_pUY.d.ts +116 -0
  3. package/dist/SkillStatusBar-DItrW2vv.d.ts +203 -0
  4. package/dist/blade-client-nOsdVlb1.d.ts +1498 -0
  5. package/dist/client/index.d.ts +8036 -0
  6. package/dist/client/index.js +1057 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/licenses-Cxl1xGVy.d.ts +16 -0
  9. package/dist/projection-DIfyh6RK.d.ts +85 -0
  10. package/dist/react/api/licenses.d.ts +7 -0
  11. package/dist/react/api/licenses.js +1477 -0
  12. package/dist/react/api/licenses.js.map +1 -0
  13. package/dist/react/api/vibe-coding.d.ts +55 -0
  14. package/dist/react/api/vibe-coding.js +1503 -0
  15. package/dist/react/api/vibe-coding.js.map +1 -0
  16. package/dist/react/cards/register.d.ts +2 -0
  17. package/dist/react/cards/register.js +4367 -0
  18. package/dist/react/cards/register.js.map +1 -0
  19. package/dist/react/components/chat/index.d.ts +128 -0
  20. package/dist/react/components/chat/index.js +11389 -0
  21. package/dist/react/components/chat/index.js.map +1 -0
  22. package/dist/react/components/plan/index.d.ts +111 -0
  23. package/dist/react/components/plan/index.js +3490 -0
  24. package/dist/react/components/plan/index.js.map +1 -0
  25. package/dist/react/components/session/index.d.ts +53 -0
  26. package/dist/react/components/session/index.js +2175 -0
  27. package/dist/react/components/session/index.js.map +1 -0
  28. package/dist/react/components/workspace/index.d.ts +35 -0
  29. package/dist/react/components/workspace/index.js +2886 -0
  30. package/dist/react/components/workspace/index.js.map +1 -0
  31. package/dist/react/devtools/bridge-devtools/index.d.ts +36 -0
  32. package/dist/react/devtools/bridge-devtools/index.js +692 -0
  33. package/dist/react/devtools/bridge-devtools/index.js.map +1 -0
  34. package/dist/react/index.d.ts +1283 -0
  35. package/dist/react/index.js +14299 -0
  36. package/dist/react/index.js.map +1 -0
  37. package/dist/session-CDeiO81j.d.ts +128 -0
  38. package/package.json +73 -7
  39. package/index.js +0 -1
@@ -0,0 +1,692 @@
1
+ // src/react/devtools/bridge-devtools/mount.tsx
2
+ import { StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+
5
+ // src/react/devtools/bridge-devtools/BridgeDevtoolsFab.tsx
6
+ import { animate, motion, useMotionValue } from "motion/react";
7
+ import { useEffect, useMemo, useRef, useState } from "react";
8
+ import { createPortal } from "react-dom";
9
+ import { useShallow } from "zustand/react/shallow";
10
+
11
+ // src/react/devtools/bridge-devtools/store.ts
12
+ import { create } from "zustand";
13
+ var MAX_EVENTS = 500;
14
+ function buildId() {
15
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
16
+ return crypto.randomUUID();
17
+ }
18
+ return `bev-${Date.now()}-${Math.random().toString(36).slice(2)}`;
19
+ }
20
+ var useBridgeDevtoolsStore = create()((set) => ({
21
+ events: [],
22
+ iframes: {},
23
+ record: (input) => set((state) => {
24
+ const record = {
25
+ id: buildId(),
26
+ ts: Date.now(),
27
+ ...input
28
+ };
29
+ const events = state.events.length >= MAX_EVENTS ? [...state.events.slice(state.events.length - MAX_EVENTS + 1), record] : [...state.events, record];
30
+ return { events };
31
+ }),
32
+ clear: () => set({ events: [] }),
33
+ registerIframe: (entry) => {
34
+ set((state) => ({ iframes: { ...state.iframes, [entry.key]: entry } }));
35
+ return () => {
36
+ set((state) => {
37
+ if (!(entry.key in state.iframes)) return state;
38
+ const next = { ...state.iframes };
39
+ delete next[entry.key];
40
+ return { iframes: next };
41
+ });
42
+ };
43
+ }
44
+ }));
45
+
46
+ // src/react/devtools/bridge-devtools/tap.ts
47
+ function isDev() {
48
+ return import.meta.env?.DEV === true;
49
+ }
50
+ var PENDING_EVENT_LIMIT = 500;
51
+ var pendingEvents = [];
52
+ function tapBridgeEvent(event) {
53
+ if (!isDev()) return;
54
+ const hook = globalThis.__bladeBridgeDevtools;
55
+ if (hook) {
56
+ hook.record(event);
57
+ return;
58
+ }
59
+ if (pendingEvents.length >= PENDING_EVENT_LIMIT) {
60
+ pendingEvents.shift();
61
+ }
62
+ pendingEvents.push(event);
63
+ }
64
+ function flushPendingBridgeEvents() {
65
+ const hook = globalThis.__bladeBridgeDevtools;
66
+ if (!hook) return;
67
+ for (const event of pendingEvents) {
68
+ hook.record(event);
69
+ }
70
+ pendingEvents.length = 0;
71
+ }
72
+ var pendingRegistrations = [];
73
+ function registerBridgeIframe(entry) {
74
+ if (!isDev()) return () => {
75
+ };
76
+ const hook = globalThis.__bladeBridgeDevtools;
77
+ if (hook) {
78
+ return hook.registerIframe(entry);
79
+ }
80
+ const pending = { entry, unregister: null };
81
+ pendingRegistrations.push(pending);
82
+ return () => {
83
+ const idx = pendingRegistrations.indexOf(pending);
84
+ if (idx >= 0) pendingRegistrations.splice(idx, 1);
85
+ pending.unregister?.();
86
+ };
87
+ }
88
+ function flushPendingIframeRegistrations() {
89
+ const hook = globalThis.__bladeBridgeDevtools;
90
+ if (!hook) return;
91
+ for (const pending of pendingRegistrations) {
92
+ pending.unregister = hook.registerIframe(pending.entry);
93
+ }
94
+ pendingRegistrations.length = 0;
95
+ }
96
+
97
+ // src/react/devtools/bridge-devtools/BridgeDevtoolsFab.tsx
98
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
99
+ var FAB_HEIGHT = 44;
100
+ var FAB_PEEK = 18;
101
+ var FAB_POS_STORAGE = "blade.bridge-devtools-fab.pos";
102
+ var FAB_SPRING = { type: "spring", stiffness: 380, damping: 32 };
103
+ function clamp(v, min, max) {
104
+ return Math.min(Math.max(v, min), max);
105
+ }
106
+ function loadFabPos() {
107
+ if (typeof window === "undefined") return null;
108
+ try {
109
+ const raw = window.localStorage.getItem(FAB_POS_STORAGE);
110
+ if (!raw) return null;
111
+ const parsed = JSON.parse(raw);
112
+ if (typeof parsed?.x === "number" && typeof parsed?.y === "number") {
113
+ return { x: parsed.x, y: parsed.y };
114
+ }
115
+ } catch {
116
+ }
117
+ return null;
118
+ }
119
+ function saveFabPos(pos) {
120
+ if (typeof window === "undefined") return;
121
+ try {
122
+ window.localStorage.setItem(FAB_POS_STORAGE, JSON.stringify(pos));
123
+ } catch {
124
+ }
125
+ }
126
+ function snapXToEdge(currentX, btnW) {
127
+ const maxX = Math.max(0, window.innerWidth - btnW);
128
+ const center = currentX + btnW / 2;
129
+ return center < window.innerWidth / 2 ? 0 : maxX;
130
+ }
131
+ function hiddenXFor(snappedX, btnW) {
132
+ const maxX = Math.max(0, window.innerWidth - btnW);
133
+ const offset = Math.max(0, btnW - FAB_PEEK);
134
+ return snappedX <= maxX / 2 ? snappedX - offset : snappedX + offset;
135
+ }
136
+ function defaultFabPos() {
137
+ if (typeof window === "undefined") return { x: 0, y: 0 };
138
+ return {
139
+ x: window.innerWidth,
140
+ y: window.innerHeight - FAB_HEIGHT - 80
141
+ };
142
+ }
143
+ var DIRECTION_LABEL = {
144
+ "host-to-agent": "host \u2192 agent",
145
+ "agent-to-host": "agent \u2192 host",
146
+ "host-to-iframe": "host \u2192 iframe",
147
+ "iframe-to-host": "iframe \u2192 host"
148
+ };
149
+ var ALL_DIRECTIONS = [
150
+ "host-to-agent",
151
+ "agent-to-host",
152
+ "host-to-iframe",
153
+ "iframe-to-host"
154
+ ];
155
+ function safeStringify(value, indent) {
156
+ const seen = /* @__PURE__ */ new WeakSet();
157
+ try {
158
+ return JSON.stringify(
159
+ value,
160
+ (_k, v) => {
161
+ if (typeof v === "bigint") return `${v.toString()}n`;
162
+ if (typeof v === "object" && v !== null) {
163
+ if (seen.has(v)) return "[Circular]";
164
+ seen.add(v);
165
+ }
166
+ return v;
167
+ },
168
+ indent
169
+ ) ?? String(value);
170
+ } catch (err) {
171
+ return `[unserializable: ${err.message}]`;
172
+ }
173
+ }
174
+ function formatTime(ts) {
175
+ const d = new Date(ts);
176
+ const pad = (n) => n.toString().padStart(2, "0");
177
+ const ms = d.getMilliseconds().toString().padStart(3, "0");
178
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`;
179
+ }
180
+ function filterEvents(events, tab, search, enabledDirections) {
181
+ const needle = search.trim().toLowerCase();
182
+ return events.filter((e) => {
183
+ if (tab === "agent" && e.side !== "agent") return false;
184
+ if (tab !== "agent" && tab !== "host" && e.iframeKey !== tab) return false;
185
+ if (tab === "host" && e.side !== "host") return false;
186
+ if (!enabledDirections.has(e.direction)) return false;
187
+ if (needle) {
188
+ const hay = `${e.action} ${safeStringify(e.payload ?? "")} ${e.note ?? ""}`.toLowerCase();
189
+ if (!hay.includes(needle)) return false;
190
+ }
191
+ return true;
192
+ });
193
+ }
194
+ function downloadJson(filename, data) {
195
+ const blob = new Blob([safeStringify(data, 2)], { type: "application/json" });
196
+ const url = URL.createObjectURL(blob);
197
+ const a = document.createElement("a");
198
+ a.href = url;
199
+ a.download = filename;
200
+ a.click();
201
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
202
+ }
203
+ function BridgeDevtoolsFab() {
204
+ const [open, setOpen] = useState(false);
205
+ const [tab, setTab] = useState("agent");
206
+ const [search, setSearch] = useState("");
207
+ const [enabled, setEnabled] = useState(
208
+ () => new Set(ALL_DIRECTIONS)
209
+ );
210
+ const [expandedId, setExpandedId] = useState(null);
211
+ const events = useBridgeDevtoolsStore((s) => s.events);
212
+ const iframes = useBridgeDevtoolsStore(useShallow((s) => Object.values(s.iframes)));
213
+ const clear = useBridgeDevtoolsStore((s) => s.clear);
214
+ const filtered = useMemo(
215
+ () => filterEvents(events, tab, search, enabled),
216
+ [events, tab, search, enabled]
217
+ );
218
+ const counts = useMemo(() => {
219
+ const c = { agent: 0, host: 0 };
220
+ const perIframe = {};
221
+ for (const e of events) {
222
+ if (e.side === "agent") c.agent++;
223
+ else c.host++;
224
+ if (e.iframeKey) perIframe[e.iframeKey] = (perIframe[e.iframeKey] ?? 0) + 1;
225
+ }
226
+ return { ...c, perIframe };
227
+ }, [events]);
228
+ const rejectedCount = events.filter((e) => e.rejected).length;
229
+ const initialPos = useMemo(() => {
230
+ const saved = loadFabPos() ?? defaultFabPos();
231
+ if (typeof window === "undefined") return saved;
232
+ return {
233
+ x: saved.x,
234
+ y: clamp(saved.y, 0, Math.max(0, window.innerHeight - FAB_HEIGHT))
235
+ };
236
+ }, []);
237
+ const [snapped, setSnapped] = useState(initialPos);
238
+ const [btnW, setBtnW] = useState(FAB_HEIGHT);
239
+ const [hover, setHover] = useState(false);
240
+ const [dragging, setDragging] = useState(false);
241
+ const x = useMotionValue(initialPos.x);
242
+ const y = useMotionValue(initialPos.y);
243
+ const btnRef = useRef(null);
244
+ useEffect(() => {
245
+ const el = btnRef.current;
246
+ if (!el) return;
247
+ const update = () => setBtnW(el.offsetWidth || FAB_HEIGHT);
248
+ update();
249
+ const ro = new ResizeObserver(update);
250
+ ro.observe(el);
251
+ return () => ro.disconnect();
252
+ }, []);
253
+ const visible = open || hover || dragging;
254
+ useEffect(() => {
255
+ if (dragging) return;
256
+ const edgeX = snapXToEdge(snapped.x, btnW);
257
+ const targetX = visible ? edgeX : hiddenXFor(edgeX, btnW);
258
+ const ctrl = animate(x, targetX, FAB_SPRING);
259
+ return () => ctrl.stop();
260
+ }, [visible, snapped.x, btnW, dragging, x]);
261
+ useEffect(() => {
262
+ const onResize = () => {
263
+ const newX = snapXToEdge(snapped.x, btnW);
264
+ const newY = clamp(snapped.y, 0, window.innerHeight - FAB_HEIGHT);
265
+ if (newX !== snapped.x || newY !== snapped.y) {
266
+ setSnapped({ x: newX, y: newY });
267
+ saveFabPos({ x: newX, y: newY });
268
+ y.set(newY);
269
+ }
270
+ };
271
+ window.addEventListener("resize", onResize);
272
+ return () => window.removeEventListener("resize", onResize);
273
+ }, [snapped.x, snapped.y, btnW, y]);
274
+ const handleDragEnd = (_, _info) => {
275
+ const newX = snapXToEdge(x.get(), btnW);
276
+ const newY = clamp(y.get(), 0, window.innerHeight - FAB_HEIGHT);
277
+ setSnapped({ x: newX, y: newY });
278
+ saveFabPos({ x: newX, y: newY });
279
+ setDragging(false);
280
+ animate(x, newX, FAB_SPRING);
281
+ animate(y, newY, FAB_SPRING);
282
+ };
283
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
284
+ /* @__PURE__ */ jsx(
285
+ motion.div,
286
+ {
287
+ style: {
288
+ x,
289
+ y,
290
+ position: "fixed",
291
+ top: 0,
292
+ left: 0,
293
+ zIndex: 9998,
294
+ touchAction: "none"
295
+ },
296
+ drag: true,
297
+ dragMomentum: false,
298
+ dragElastic: 0.05,
299
+ onDragStart: () => setDragging(true),
300
+ onDragEnd: handleDragEnd,
301
+ onPointerEnter: () => setHover(true),
302
+ onPointerLeave: () => setHover(false),
303
+ children: /* @__PURE__ */ jsxs(
304
+ "button",
305
+ {
306
+ ref: btnRef,
307
+ type: "button",
308
+ onClick: () => setOpen((v) => !v),
309
+ className: "inline-flex h-11 min-w-[44px] cursor-grab items-center justify-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--background))]/95 px-3 text-sm font-medium text-[hsl(var(--foreground))] shadow-xl backdrop-blur hover:bg-[hsl(var(--accent))] active:cursor-grabbing",
310
+ title: "Bridge \u4E8B\u4EF6\u8C03\u8BD5\uFF08\u53EF\u62D6\u52A8\u5230\u4EFB\u610F\u8FB9\u7F18\uFF09",
311
+ children: [
312
+ /* @__PURE__ */ jsx("span", { className: "text-base", children: "\u{1F309}" }),
313
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: events.length }),
314
+ rejectedCount > 0 ? /* @__PURE__ */ jsx("span", { className: "rounded bg-red-500/15 px-1 text-xs text-red-500 tabular-nums", children: rejectedCount }) : null
315
+ ]
316
+ }
317
+ )
318
+ }
319
+ ),
320
+ open && typeof document !== "undefined" ? createPortal(
321
+ /* @__PURE__ */ jsx(
322
+ BridgeDevtoolsPanel,
323
+ {
324
+ onClose: () => setOpen(false),
325
+ tab,
326
+ setTab,
327
+ search,
328
+ setSearch,
329
+ enabled,
330
+ setEnabled,
331
+ events: filtered,
332
+ totalEvents: events,
333
+ expandedId,
334
+ setExpandedId,
335
+ counts,
336
+ iframes,
337
+ onClear: clear
338
+ }
339
+ ),
340
+ document.body
341
+ ) : null
342
+ ] });
343
+ }
344
+ function BridgeDevtoolsPanel(props) {
345
+ const {
346
+ onClose,
347
+ tab,
348
+ setTab,
349
+ search,
350
+ setSearch,
351
+ enabled,
352
+ setEnabled,
353
+ events,
354
+ totalEvents,
355
+ expandedId,
356
+ setExpandedId,
357
+ counts,
358
+ iframes,
359
+ onClear
360
+ } = props;
361
+ const toggleDirection = (d) => {
362
+ const next = new Set(enabled);
363
+ if (next.has(d)) next.delete(d);
364
+ else next.add(d);
365
+ setEnabled(next);
366
+ };
367
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[9999] flex items-end justify-end", children: [
368
+ /* @__PURE__ */ jsx(
369
+ "button",
370
+ {
371
+ type: "button",
372
+ "aria-label": "\u5173\u95ED\u8C03\u8BD5\u9762\u677F",
373
+ className: "absolute inset-0 bg-black/20",
374
+ onClick: onClose
375
+ }
376
+ ),
377
+ /* @__PURE__ */ jsxs(
378
+ "div",
379
+ {
380
+ className: "relative flex h-[85vh] w-full max-w-[720px] flex-col overflow-hidden rounded-t-xl border border-[hsl(var(--border))] bg-[hsl(var(--background))] shadow-2xl",
381
+ children: [
382
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-2", children: [
383
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
384
+ /* @__PURE__ */ jsx("span", { children: "\u{1F309} Bridge \u4E8B\u4EF6\u8C03\u8BD5" }),
385
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: [
386
+ totalEvents.length,
387
+ " / 500"
388
+ ] })
389
+ ] }),
390
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
391
+ /* @__PURE__ */ jsx(
392
+ "button",
393
+ {
394
+ type: "button",
395
+ className: "rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]",
396
+ onClick: () => downloadJson(`bridge-events-${Date.now()}.json`, totalEvents),
397
+ children: "\u5BFC\u51FA JSON"
398
+ }
399
+ ),
400
+ /* @__PURE__ */ jsx(
401
+ "button",
402
+ {
403
+ type: "button",
404
+ className: "rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]",
405
+ onClick: onClear,
406
+ children: "\u6E05\u7A7A"
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsx(
410
+ "button",
411
+ {
412
+ type: "button",
413
+ className: "rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]",
414
+ onClick: onClose,
415
+ children: "\u2715"
416
+ }
417
+ )
418
+ ] })
419
+ ] }),
420
+ /* @__PURE__ */ jsxs("nav", { className: "flex items-center gap-1 overflow-x-auto border-b border-[hsl(var(--border))] px-3 py-2 text-xs", children: [
421
+ /* @__PURE__ */ jsxs(TabButton, { active: tab === "agent", onClick: () => setTab("agent"), children: [
422
+ "Agent \u4FA7 (",
423
+ counts.agent,
424
+ ")"
425
+ ] }),
426
+ /* @__PURE__ */ jsxs(TabButton, { active: tab === "host", onClick: () => setTab("host"), children: [
427
+ "Host \u5168\u90E8 (",
428
+ counts.host,
429
+ ")"
430
+ ] }),
431
+ iframes.map((f) => /* @__PURE__ */ jsxs(
432
+ TabButton,
433
+ {
434
+ active: tab === f.key,
435
+ onClick: () => setTab(f.key),
436
+ title: f.label,
437
+ children: [
438
+ "\u{1F4C4} ",
439
+ f.label.length > 16 ? `${f.label.slice(0, 16)}\u2026` : f.label,
440
+ " (",
441
+ counts.perIframe[f.key] ?? 0,
442
+ ")"
443
+ ]
444
+ },
445
+ f.key
446
+ ))
447
+ ] }),
448
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-[hsl(var(--border))] px-3 py-2 text-xs", children: [
449
+ /* @__PURE__ */ jsx(
450
+ "input",
451
+ {
452
+ value: search,
453
+ onChange: (e) => setSearch(e.target.value),
454
+ placeholder: "\u641C\u7D22 action / payload / note\u2026",
455
+ className: "min-w-[160px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1"
456
+ }
457
+ ),
458
+ ALL_DIRECTIONS.map((d) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1", children: [
459
+ /* @__PURE__ */ jsx(
460
+ "input",
461
+ {
462
+ type: "checkbox",
463
+ checked: enabled.has(d),
464
+ onChange: () => toggleDirection(d)
465
+ }
466
+ ),
467
+ /* @__PURE__ */ jsx("span", { children: DIRECTION_LABEL[d] })
468
+ ] }, d))
469
+ ] }),
470
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: events.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-6 text-center text-sm text-[hsl(var(--muted-foreground))]", children: "\u65E0\u5339\u914D\u4E8B\u4EF6" }) : /* @__PURE__ */ jsx("ul", { className: "divide-y divide-[hsl(var(--border))]", children: events.map((e) => /* @__PURE__ */ jsx(
471
+ EventRow,
472
+ {
473
+ event: e,
474
+ expanded: expandedId === e.id,
475
+ onToggle: () => setExpandedId(expandedId === e.id ? null : e.id)
476
+ },
477
+ e.id
478
+ )) }) }),
479
+ /* @__PURE__ */ jsx(ManualSendBar, { tab, iframes })
480
+ ]
481
+ }
482
+ )
483
+ ] });
484
+ }
485
+ function TabButton(props) {
486
+ return /* @__PURE__ */ jsx(
487
+ "button",
488
+ {
489
+ type: "button",
490
+ onClick: props.onClick,
491
+ title: props.title,
492
+ className: `whitespace-nowrap rounded px-2 py-1 ${props.active ? "bg-[hsl(var(--accent))] font-semibold" : "hover:bg-[hsl(var(--accent))]/50"}`,
493
+ children: props.children
494
+ }
495
+ );
496
+ }
497
+ function EventRow({
498
+ event,
499
+ expanded,
500
+ onToggle
501
+ }) {
502
+ return /* @__PURE__ */ jsxs(
503
+ "li",
504
+ {
505
+ className: `px-3 py-1.5 text-xs ${event.rejected ? "bg-red-500/5" : ""}`,
506
+ children: [
507
+ /* @__PURE__ */ jsxs(
508
+ "button",
509
+ {
510
+ type: "button",
511
+ onClick: onToggle,
512
+ className: "flex w-full items-center gap-2 text-left",
513
+ children: [
514
+ /* @__PURE__ */ jsx("span", { className: "w-[90px] font-mono tabular-nums text-[hsl(var(--muted-foreground))]", children: formatTime(event.ts) }),
515
+ /* @__PURE__ */ jsx(
516
+ "span",
517
+ {
518
+ className: `w-[120px] font-mono ${event.side === "agent" ? "text-blue-500" : "text-purple-500"}`,
519
+ children: DIRECTION_LABEL[event.direction]
520
+ }
521
+ ),
522
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-semibold", children: event.action }),
523
+ event.rejected ? /* @__PURE__ */ jsx("span", { className: "rounded bg-red-500/20 px-1.5 text-[10px] text-red-500", children: "rejected" }) : null,
524
+ /* @__PURE__ */ jsx("span", { className: "text-[hsl(var(--muted-foreground))]", children: expanded ? "\u25BC" : "\u25B6" })
525
+ ]
526
+ }
527
+ ),
528
+ expanded ? /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1 pl-[90px] font-mono", children: [
529
+ event.note ? /* @__PURE__ */ jsxs("div", { className: "text-red-500", children: [
530
+ "note: ",
531
+ event.note
532
+ ] }) : null,
533
+ event.iframeLabel ? /* @__PURE__ */ jsxs("div", { className: "text-[hsl(var(--muted-foreground))]", children: [
534
+ "iframe: ",
535
+ event.iframeLabel
536
+ ] }) : null,
537
+ event.meta ? /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap break-words text-[hsl(var(--muted-foreground))]", children: [
538
+ "meta: ",
539
+ safeStringify(event.meta, 2)
540
+ ] }) : null,
541
+ /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap break-words", children: [
542
+ "payload: ",
543
+ safeStringify(event.payload, 2)
544
+ ] })
545
+ ] }) : null
546
+ ]
547
+ }
548
+ );
549
+ }
550
+ function ManualSendBar({
551
+ tab,
552
+ iframes
553
+ }) {
554
+ const [action, setAction] = useState("");
555
+ const [payloadText, setPayloadText] = useState("{}");
556
+ const [error, setError] = useState(null);
557
+ const [targetKey, setTargetKey] = useState("");
558
+ const effectiveSide = tab === "agent" ? "agent" : "host";
559
+ const send = () => {
560
+ setError(null);
561
+ let payload;
562
+ try {
563
+ payload = payloadText.trim() ? JSON.parse(payloadText) : void 0;
564
+ } catch (err) {
565
+ setError(`payload JSON \u89E3\u6790\u5931\u8D25: ${err.message}`);
566
+ return;
567
+ }
568
+ if (!action.trim()) {
569
+ setError("action \u4E0D\u80FD\u4E3A\u7A7A");
570
+ return;
571
+ }
572
+ if (effectiveSide === "agent") {
573
+ window.postMessage(
574
+ {
575
+ __bladeBridge: true,
576
+ direction: "host-to-agent",
577
+ action,
578
+ payload,
579
+ meta: { timestamp: Date.now(), injectedBy: "devtools" }
580
+ },
581
+ "*"
582
+ );
583
+ return;
584
+ }
585
+ const target = tab !== "host" && tab !== "agent" ? tab : targetKey;
586
+ const entry = iframes.find((f) => f.key === target);
587
+ if (!entry) {
588
+ setError("\u8BF7\u9009\u62E9\u76EE\u6807 iframe");
589
+ return;
590
+ }
591
+ const win = entry.getContentWindow();
592
+ if (!win) {
593
+ setError("\u76EE\u6807 iframe contentWindow \u4E3A\u7A7A\uFF08\u53EF\u80FD\u672A\u52A0\u8F7D\uFF09");
594
+ return;
595
+ }
596
+ win.postMessage(
597
+ {
598
+ __resourceBridge: true,
599
+ direction: "host-to-iframe",
600
+ event: action,
601
+ action,
602
+ payload
603
+ },
604
+ "*"
605
+ );
606
+ tapBridgeEvent({
607
+ side: "host",
608
+ direction: "host-to-iframe",
609
+ action,
610
+ payload,
611
+ iframeKey: entry.key,
612
+ iframeLabel: entry.label,
613
+ note: "injected by devtools"
614
+ });
615
+ };
616
+ return /* @__PURE__ */ jsxs("div", { className: "border-t border-[hsl(var(--border))] bg-[hsl(var(--muted))]/30 px-3 py-2", children: [
617
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 text-xs font-semibold text-[hsl(var(--muted-foreground))]", children: [
618
+ "\u624B\u52A8\u53D1\u9001 envelope\uFF08",
619
+ effectiveSide === "agent" ? "\u6A21\u62DF host \u2192 agent" : "host \u2192 iframe",
620
+ "\uFF09"
621
+ ] }),
622
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start gap-2 text-xs", children: [
623
+ effectiveSide === "host" && tab === "host" ? /* @__PURE__ */ jsxs(
624
+ "select",
625
+ {
626
+ value: targetKey,
627
+ onChange: (e) => setTargetKey(e.target.value),
628
+ className: "rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1",
629
+ children: [
630
+ /* @__PURE__ */ jsx("option", { value: "", children: "\u9009\u62E9 iframe\u2026" }),
631
+ iframes.map((f) => /* @__PURE__ */ jsx("option", { value: f.key, children: f.label }, f.key))
632
+ ]
633
+ }
634
+ ) : null,
635
+ /* @__PURE__ */ jsx(
636
+ "input",
637
+ {
638
+ value: action,
639
+ onChange: (e) => setAction(e.target.value),
640
+ placeholder: "action\uFF08\u5982 addContext / theme\uFF09",
641
+ className: "min-w-[140px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1"
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsx(
645
+ "input",
646
+ {
647
+ value: payloadText,
648
+ onChange: (e) => setPayloadText(e.target.value),
649
+ placeholder: 'payload JSON\uFF08\u5982 {"foo":1}\uFF09',
650
+ className: "min-w-[180px] flex-[2] rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1 font-mono"
651
+ }
652
+ ),
653
+ /* @__PURE__ */ jsx(
654
+ "button",
655
+ {
656
+ type: "button",
657
+ onClick: send,
658
+ className: "rounded bg-[hsl(var(--primary))] px-3 py-1 text-[hsl(var(--primary-foreground))] hover:opacity-90",
659
+ children: "\u53D1\u9001"
660
+ }
661
+ )
662
+ ] }),
663
+ error ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-red-500", children: error }) : null
664
+ ] });
665
+ }
666
+
667
+ // src/react/devtools/bridge-devtools/mount.tsx
668
+ import { jsx as jsx2 } from "react/jsx-runtime";
669
+ var mounted = false;
670
+ function mountBridgeDevtools() {
671
+ if (mounted || typeof document === "undefined") return;
672
+ mounted = true;
673
+ const hook = {
674
+ record: (event) => useBridgeDevtoolsStore.getState().record(event),
675
+ registerIframe: (entry) => useBridgeDevtoolsStore.getState().registerIframe(entry)
676
+ };
677
+ globalThis.__bladeBridgeDevtools = hook;
678
+ flushPendingBridgeEvents();
679
+ flushPendingIframeRegistrations();
680
+ const container = document.createElement("div");
681
+ container.id = "blade-bridge-devtools-root";
682
+ document.body.appendChild(container);
683
+ createRoot(container).render(
684
+ /* @__PURE__ */ jsx2(StrictMode, { children: /* @__PURE__ */ jsx2(BridgeDevtoolsFab, {}) })
685
+ );
686
+ }
687
+ export {
688
+ mountBridgeDevtools,
689
+ registerBridgeIframe,
690
+ tapBridgeEvent
691
+ };
692
+ //# sourceMappingURL=index.js.map