@blade-hq/agent-kit 0.4.5 → 0.4.6

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 (48) hide show
  1. package/README.md +5 -1
  2. package/dist/chunk-2UP7MG3J.js +66 -0
  3. package/dist/chunk-2UP7MG3J.js.map +1 -0
  4. package/dist/chunk-4VWLTG5L.js +2984 -0
  5. package/dist/chunk-4VWLTG5L.js.map +1 -0
  6. package/dist/chunk-7LEKQI47.js +32 -0
  7. package/dist/chunk-7LEKQI47.js.map +1 -0
  8. package/dist/chunk-DQCXSPHP.js +33 -0
  9. package/dist/chunk-DQCXSPHP.js.map +1 -0
  10. package/dist/chunk-I3FFV63W.js +30 -0
  11. package/dist/chunk-I3FFV63W.js.map +1 -0
  12. package/dist/chunk-J3XVFPOV.js +58 -0
  13. package/dist/chunk-J3XVFPOV.js.map +1 -0
  14. package/dist/chunk-JCJFFJ42.js +39 -0
  15. package/dist/chunk-JCJFFJ42.js.map +1 -0
  16. package/dist/chunk-LIL4FIZP.js +7992 -0
  17. package/dist/chunk-LIL4FIZP.js.map +1 -0
  18. package/dist/chunk-OKQWPNE3.js +1077 -0
  19. package/dist/chunk-OKQWPNE3.js.map +1 -0
  20. package/dist/chunk-PZ5AY32C.js +10 -0
  21. package/dist/chunk-PZ5AY32C.js.map +1 -0
  22. package/dist/chunk-TC5BBLWO.js +29 -0
  23. package/dist/chunk-TC5BBLWO.js.map +1 -0
  24. package/dist/chunk-VD4CKRMT.js +127 -0
  25. package/dist/chunk-VD4CKRMT.js.map +1 -0
  26. package/dist/chunk-X6MEYCU7.js +1401 -0
  27. package/dist/chunk-X6MEYCU7.js.map +1 -0
  28. package/dist/client/index.js +24 -1052
  29. package/dist/client/index.js.map +1 -1
  30. package/dist/react/api/licenses.js +11 -1470
  31. package/dist/react/api/licenses.js.map +1 -1
  32. package/dist/react/api/vibe-coding.js +25 -1481
  33. package/dist/react/api/vibe-coding.js.map +1 -1
  34. package/dist/react/cards/register.js +45 -138
  35. package/dist/react/cards/register.js.map +1 -1
  36. package/dist/react/components/chat/index.js +28 -11366
  37. package/dist/react/components/chat/index.js.map +1 -1
  38. package/dist/react/components/plan/index.js +135 -3054
  39. package/dist/react/components/plan/index.js.map +1 -1
  40. package/dist/react/components/session/index.js +21 -1499
  41. package/dist/react/components/session/index.js.map +1 -1
  42. package/dist/react/components/workspace/index.js +116 -1715
  43. package/dist/react/components/workspace/index.js.map +1 -1
  44. package/dist/react/devtools/bridge-devtools/index.js +8 -51
  45. package/dist/react/devtools/bridge-devtools/index.js.map +1 -1
  46. package/dist/react/index.js +625 -14035
  47. package/dist/react/index.js.map +1 -1
  48. package/package.json +1 -1
@@ -1,3 +1,11 @@
1
+ import {
2
+ flushPendingBridgeEvents,
3
+ flushPendingIframeRegistrations,
4
+ registerBridgeIframe,
5
+ tapBridgeEvent
6
+ } from "../../../chunk-J3XVFPOV.js";
7
+ import "../../../chunk-PZ5AY32C.js";
8
+
1
9
  // src/react/devtools/bridge-devtools/mount.tsx
2
10
  import { StrictMode } from "react";
3
11
  import { createRoot } from "react-dom/client";
@@ -43,57 +51,6 @@ var useBridgeDevtoolsStore = create()((set) => ({
43
51
  }
44
52
  }));
45
53
 
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
54
  // src/react/devtools/bridge-devtools/BridgeDevtoolsFab.tsx
98
55
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
99
56
  var FAB_HEIGHT = 44;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/react/devtools/bridge-devtools/mount.tsx","../../../../src/react/devtools/bridge-devtools/BridgeDevtoolsFab.tsx","../../../../src/react/devtools/bridge-devtools/store.ts","../../../../src/react/devtools/bridge-devtools/tap.ts"],"sourcesContent":["import { StrictMode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\nimport { BridgeDevtoolsFab } from \"./BridgeDevtoolsFab\"\nimport { useBridgeDevtoolsStore } from \"./store\"\nimport { flushPendingBridgeEvents, flushPendingIframeRegistrations } from \"./tap\"\nimport type { BridgeDevtoolsHook } from \"./types\"\n\nlet mounted = false\n\nexport function mountBridgeDevtools() {\n if (mounted || typeof document === \"undefined\") return\n mounted = true\n\n const hook: BridgeDevtoolsHook = {\n record: (event) => useBridgeDevtoolsStore.getState().record(event),\n registerIframe: (entry) => useBridgeDevtoolsStore.getState().registerIframe(entry),\n }\n globalThis.__bladeBridgeDevtools = hook\n flushPendingBridgeEvents()\n flushPendingIframeRegistrations()\n\n const container = document.createElement(\"div\")\n container.id = \"blade-bridge-devtools-root\"\n document.body.appendChild(container)\n createRoot(container).render(\n <StrictMode>\n <BridgeDevtoolsFab />\n </StrictMode>,\n )\n}\n","import { animate, motion, type PanInfo, useMotionValue } from \"motion/react\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { useShallow } from \"zustand/react/shallow\"\nimport { useBridgeDevtoolsStore } from \"./store\"\nimport { tapBridgeEvent } from \"./tap\"\nimport type {\n BridgeEventDirection,\n BridgeEventRecord,\n BridgeEventSide,\n} from \"./types\"\n\nconst FAB_HEIGHT = 44\nconst FAB_PEEK = 18\nconst FAB_POS_STORAGE = \"blade.bridge-devtools-fab.pos\"\nconst FAB_SPRING = { type: \"spring\" as const, stiffness: 380, damping: 32 }\n\ninterface FabSavedPos {\n x: number\n y: number\n}\n\nfunction clamp(v: number, min: number, max: number) {\n return Math.min(Math.max(v, min), max)\n}\n\nfunction loadFabPos(): FabSavedPos | null {\n if (typeof window === \"undefined\") return null\n try {\n const raw = window.localStorage.getItem(FAB_POS_STORAGE)\n if (!raw) return null\n const parsed = JSON.parse(raw)\n if (typeof parsed?.x === \"number\" && typeof parsed?.y === \"number\") {\n return { x: parsed.x, y: parsed.y }\n }\n } catch {\n /* ignore */\n }\n return null\n}\n\nfunction saveFabPos(pos: FabSavedPos) {\n if (typeof window === \"undefined\") return\n try {\n window.localStorage.setItem(FAB_POS_STORAGE, JSON.stringify(pos))\n } catch {\n /* ignore */\n }\n}\n\nfunction snapXToEdge(currentX: number, btnW: number) {\n const maxX = Math.max(0, window.innerWidth - btnW)\n const center = currentX + btnW / 2\n return center < window.innerWidth / 2 ? 0 : maxX\n}\n\nfunction hiddenXFor(snappedX: number, btnW: number) {\n const maxX = Math.max(0, window.innerWidth - btnW)\n const offset = Math.max(0, btnW - FAB_PEEK)\n return snappedX <= maxX / 2 ? snappedX - offset : snappedX + offset\n}\n\nfunction defaultFabPos(): FabSavedPos {\n if (typeof window === \"undefined\") return { x: 0, y: 0 }\n return {\n x: window.innerWidth,\n y: window.innerHeight - FAB_HEIGHT - 80,\n }\n}\n\ntype SideTab = \"agent\" | \"host\" | string\n\nconst DIRECTION_LABEL: Record<BridgeEventDirection, string> = {\n \"host-to-agent\": \"host → agent\",\n \"agent-to-host\": \"agent → host\",\n \"host-to-iframe\": \"host → iframe\",\n \"iframe-to-host\": \"iframe → host\",\n}\n\nconst ALL_DIRECTIONS: BridgeEventDirection[] = [\n \"host-to-agent\",\n \"agent-to-host\",\n \"host-to-iframe\",\n \"iframe-to-host\",\n]\n\nfunction safeStringify(value: unknown, indent?: number) {\n // 通过 postMessage 结构化克隆进来的 payload 可能带 BigInt、cyclic、\n // 或其它 JSON.stringify 处理不了的值,必须包一层 fallback,否则\n // 任何搜索/展开/导出都会把 devtools 自己炸掉。\n const seen = new WeakSet<object>()\n try {\n return JSON.stringify(\n value,\n (_k, v) => {\n if (typeof v === \"bigint\") return `${v.toString()}n`\n if (typeof v === \"object\" && v !== null) {\n if (seen.has(v)) return \"[Circular]\"\n seen.add(v)\n }\n return v\n },\n indent,\n ) ?? String(value)\n } catch (err) {\n return `[unserializable: ${(err as Error).message}]`\n }\n}\n\nfunction formatTime(ts: number) {\n const d = new Date(ts)\n const pad = (n: number) => n.toString().padStart(2, \"0\")\n const ms = d.getMilliseconds().toString().padStart(3, \"0\")\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`\n}\n\nfunction filterEvents(\n events: BridgeEventRecord[],\n tab: SideTab,\n search: string,\n enabledDirections: Set<BridgeEventDirection>,\n) {\n const needle = search.trim().toLowerCase()\n return events.filter((e) => {\n if (tab === \"agent\" && e.side !== \"agent\") return false\n if (tab !== \"agent\" && tab !== \"host\" && e.iframeKey !== tab) return false\n if (tab === \"host\" && e.side !== \"host\") return false\n if (!enabledDirections.has(e.direction)) return false\n if (needle) {\n const hay = `${e.action} ${safeStringify(e.payload ?? \"\")} ${e.note ?? \"\"}`.toLowerCase()\n if (!hay.includes(needle)) return false\n }\n return true\n })\n}\n\nfunction downloadJson(filename: string, data: unknown) {\n const blob = new Blob([safeStringify(data, 2)], { type: \"application/json\" })\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = filename\n a.click()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n}\n\nexport function BridgeDevtoolsFab() {\n const [open, setOpen] = useState(false)\n const [tab, setTab] = useState<SideTab>(\"agent\")\n const [search, setSearch] = useState(\"\")\n const [enabled, setEnabled] = useState<Set<BridgeEventDirection>>(\n () => new Set(ALL_DIRECTIONS),\n )\n const [expandedId, setExpandedId] = useState<string | null>(null)\n\n const events = useBridgeDevtoolsStore((s) => s.events)\n const iframes = useBridgeDevtoolsStore(useShallow((s) => Object.values(s.iframes)))\n const clear = useBridgeDevtoolsStore((s) => s.clear)\n\n const filtered = useMemo(\n () => filterEvents(events, tab, search, enabled),\n [events, tab, search, enabled],\n )\n\n const counts = useMemo(() => {\n const c = { agent: 0, host: 0 as number }\n const perIframe: Record<string, number> = {}\n for (const e of events) {\n if (e.side === \"agent\") c.agent++\n else c.host++\n if (e.iframeKey) perIframe[e.iframeKey] = (perIframe[e.iframeKey] ?? 0) + 1\n }\n return { ...c, perIframe }\n }, [events])\n\n const rejectedCount = events.filter((e) => e.rejected).length\n\n const initialPos = useMemo(() => {\n const saved = loadFabPos() ?? defaultFabPos()\n if (typeof window === \"undefined\") return saved\n return {\n x: saved.x,\n y: clamp(saved.y, 0, Math.max(0, window.innerHeight - FAB_HEIGHT)),\n }\n }, [])\n const [snapped, setSnapped] = useState<FabSavedPos>(initialPos)\n const [btnW, setBtnW] = useState(FAB_HEIGHT)\n const [hover, setHover] = useState(false)\n const [dragging, setDragging] = useState(false)\n const x = useMotionValue(initialPos.x)\n const y = useMotionValue(initialPos.y)\n const btnRef = useRef<HTMLButtonElement | null>(null)\n\n // Measure rendered button width — needed for edge snapping math.\n useEffect(() => {\n const el = btnRef.current\n if (!el) return\n const update = () => setBtnW(el.offsetWidth || FAB_HEIGHT)\n update()\n const ro = new ResizeObserver(update)\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // Drive the visible/hidden animation imperatively against the motion value.\n // Recompute edgeX each tick so width measurement / viewport resize stay correct.\n const visible = open || hover || dragging\n useEffect(() => {\n if (dragging) return\n const edgeX = snapXToEdge(snapped.x, btnW)\n const targetX = visible ? edgeX : hiddenXFor(edgeX, btnW)\n const ctrl = animate(x, targetX, FAB_SPRING)\n return () => ctrl.stop()\n }, [visible, snapped.x, btnW, dragging, x])\n\n // Re-snap to nearest edge on viewport resize.\n useEffect(() => {\n const onResize = () => {\n const newX = snapXToEdge(snapped.x, btnW)\n const newY = clamp(snapped.y, 0, window.innerHeight - FAB_HEIGHT)\n if (newX !== snapped.x || newY !== snapped.y) {\n setSnapped({ x: newX, y: newY })\n saveFabPos({ x: newX, y: newY })\n y.set(newY)\n }\n }\n window.addEventListener(\"resize\", onResize)\n return () => window.removeEventListener(\"resize\", onResize)\n }, [snapped.x, snapped.y, btnW, y])\n\n const handleDragEnd = (_: PointerEvent | MouseEvent | TouchEvent, _info: PanInfo) => {\n const newX = snapXToEdge(x.get(), btnW)\n const newY = clamp(y.get(), 0, window.innerHeight - FAB_HEIGHT)\n setSnapped({ x: newX, y: newY })\n saveFabPos({ x: newX, y: newY })\n setDragging(false)\n animate(x, newX, FAB_SPRING)\n animate(y, newY, FAB_SPRING)\n }\n\n return (\n <>\n <motion.div\n style={{\n x,\n y,\n position: \"fixed\",\n top: 0,\n left: 0,\n zIndex: 9998,\n touchAction: \"none\",\n }}\n drag\n dragMomentum={false}\n dragElastic={0.05}\n onDragStart={() => setDragging(true)}\n onDragEnd={handleDragEnd}\n onPointerEnter={() => setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n <button\n ref={btnRef}\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n 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\"\n title=\"Bridge 事件调试(可拖动到任意边缘)\"\n >\n <span className=\"text-base\">🌉</span>\n <span className=\"tabular-nums\">{events.length}</span>\n {rejectedCount > 0 ? (\n <span className=\"rounded bg-red-500/15 px-1 text-xs text-red-500 tabular-nums\">\n {rejectedCount}\n </span>\n ) : null}\n </button>\n </motion.div>\n {open && typeof document !== \"undefined\"\n ? createPortal(\n <BridgeDevtoolsPanel\n onClose={() => setOpen(false)}\n tab={tab}\n setTab={setTab}\n search={search}\n setSearch={setSearch}\n enabled={enabled}\n setEnabled={setEnabled}\n events={filtered}\n totalEvents={events}\n expandedId={expandedId}\n setExpandedId={setExpandedId}\n counts={counts}\n iframes={iframes}\n onClear={clear}\n />,\n document.body,\n )\n : null}\n </>\n )\n}\n\ninterface PanelProps {\n onClose: () => void\n tab: SideTab\n setTab: (t: SideTab) => void\n search: string\n setSearch: (s: string) => void\n enabled: Set<BridgeEventDirection>\n setEnabled: (s: Set<BridgeEventDirection>) => void\n events: BridgeEventRecord[]\n totalEvents: BridgeEventRecord[]\n expandedId: string | null\n setExpandedId: (id: string | null) => void\n counts: { agent: number; host: number; perIframe: Record<string, number> }\n iframes: Array<{ key: string; label: string; getContentWindow: () => Window | null }>\n onClear: () => void\n}\n\nfunction BridgeDevtoolsPanel(props: PanelProps) {\n const {\n onClose,\n tab,\n setTab,\n search,\n setSearch,\n enabled,\n setEnabled,\n events,\n totalEvents,\n expandedId,\n setExpandedId,\n counts,\n iframes,\n onClear,\n } = props\n\n const toggleDirection = (d: BridgeEventDirection) => {\n const next = new Set(enabled)\n if (next.has(d)) next.delete(d)\n else next.add(d)\n setEnabled(next)\n }\n\n return (\n <div className=\"fixed inset-0 z-[9999] flex items-end justify-end\">\n <button\n type=\"button\"\n aria-label=\"关闭调试面板\"\n className=\"absolute inset-0 bg-black/20\"\n onClick={onClose}\n />\n <div\n 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\"\n >\n <header className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-2\">\n <div className=\"flex items-center gap-2 text-sm font-semibold\">\n <span>🌉 Bridge 事件调试</span>\n <span className=\"text-xs text-[hsl(var(--muted-foreground))]\">\n {totalEvents.length} / 500\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={() =>\n downloadJson(`bridge-events-${Date.now()}.json`, totalEvents)\n }\n >\n 导出 JSON\n </button>\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={onClear}\n >\n 清空\n </button>\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={onClose}\n >\n ✕\n </button>\n </div>\n </header>\n\n <nav className=\"flex items-center gap-1 overflow-x-auto border-b border-[hsl(var(--border))] px-3 py-2 text-xs\">\n <TabButton active={tab === \"agent\"} onClick={() => setTab(\"agent\")}>\n Agent 侧 ({counts.agent})\n </TabButton>\n <TabButton active={tab === \"host\"} onClick={() => setTab(\"host\")}>\n Host 全部 ({counts.host})\n </TabButton>\n {iframes.map((f) => (\n <TabButton\n key={f.key}\n active={tab === f.key}\n onClick={() => setTab(f.key)}\n title={f.label}\n >\n 📄 {f.label.length > 16 ? `${f.label.slice(0, 16)}…` : f.label} (\n {counts.perIframe[f.key] ?? 0})\n </TabButton>\n ))}\n </nav>\n\n <div className=\"flex flex-wrap items-center gap-2 border-b border-[hsl(var(--border))] px-3 py-2 text-xs\">\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"搜索 action / payload / note…\"\n className=\"min-w-[160px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n />\n {ALL_DIRECTIONS.map((d) => (\n <label key={d} className=\"flex items-center gap-1\">\n <input\n type=\"checkbox\"\n checked={enabled.has(d)}\n onChange={() => toggleDirection(d)}\n />\n <span>{DIRECTION_LABEL[d]}</span>\n </label>\n ))}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n {events.length === 0 ? (\n <div className=\"p-6 text-center text-sm text-[hsl(var(--muted-foreground))]\">\n 无匹配事件\n </div>\n ) : (\n <ul className=\"divide-y divide-[hsl(var(--border))]\">\n {events.map((e) => (\n <EventRow\n key={e.id}\n event={e}\n expanded={expandedId === e.id}\n onToggle={() => setExpandedId(expandedId === e.id ? null : e.id)}\n />\n ))}\n </ul>\n )}\n </div>\n\n <ManualSendBar tab={tab} iframes={iframes} />\n </div>\n </div>\n )\n}\n\nfunction TabButton(props: {\n active: boolean\n onClick: () => void\n title?: string\n children: React.ReactNode\n}) {\n return (\n <button\n type=\"button\"\n onClick={props.onClick}\n title={props.title}\n className={`whitespace-nowrap rounded px-2 py-1 ${\n props.active\n ? \"bg-[hsl(var(--accent))] font-semibold\"\n : \"hover:bg-[hsl(var(--accent))]/50\"\n }`}\n >\n {props.children}\n </button>\n )\n}\n\nfunction EventRow({\n event,\n expanded,\n onToggle,\n}: {\n event: BridgeEventRecord\n expanded: boolean\n onToggle: () => void\n}) {\n return (\n <li\n className={`px-3 py-1.5 text-xs ${event.rejected ? \"bg-red-500/5\" : \"\"}`}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n className=\"flex w-full items-center gap-2 text-left\"\n >\n <span className=\"w-[90px] font-mono tabular-nums text-[hsl(var(--muted-foreground))]\">\n {formatTime(event.ts)}\n </span>\n <span\n className={`w-[120px] font-mono ${\n event.side === \"agent\" ? \"text-blue-500\" : \"text-purple-500\"\n }`}\n >\n {DIRECTION_LABEL[event.direction]}\n </span>\n <span className=\"flex-1 truncate font-semibold\">{event.action}</span>\n {event.rejected ? (\n <span className=\"rounded bg-red-500/20 px-1.5 text-[10px] text-red-500\">\n rejected\n </span>\n ) : null}\n <span className=\"text-[hsl(var(--muted-foreground))]\">{expanded ? \"▼\" : \"▶\"}</span>\n </button>\n {expanded ? (\n <div className=\"mt-2 space-y-1 pl-[90px] font-mono\">\n {event.note ? (\n <div className=\"text-red-500\">note: {event.note}</div>\n ) : null}\n {event.iframeLabel ? (\n <div className=\"text-[hsl(var(--muted-foreground))]\">\n iframe: {event.iframeLabel}\n </div>\n ) : null}\n {event.meta ? (\n <pre className=\"whitespace-pre-wrap break-words text-[hsl(var(--muted-foreground))]\">\n meta: {safeStringify(event.meta, 2)}\n </pre>\n ) : null}\n <pre className=\"whitespace-pre-wrap break-words\">\n payload: {safeStringify(event.payload, 2)}\n </pre>\n </div>\n ) : null}\n </li>\n )\n}\n\nfunction ManualSendBar({\n tab,\n iframes,\n}: {\n tab: SideTab\n iframes: Array<{ key: string; label: string; getContentWindow: () => Window | null }>\n}) {\n const [action, setAction] = useState(\"\")\n const [payloadText, setPayloadText] = useState(\"{}\")\n const [error, setError] = useState<string | null>(null)\n const [targetKey, setTargetKey] = useState<string>(\"\")\n\n const effectiveSide: BridgeEventSide = tab === \"agent\" ? \"agent\" : \"host\"\n\n const send = () => {\n setError(null)\n let payload: unknown\n try {\n payload = payloadText.trim() ? JSON.parse(payloadText) : undefined\n } catch (err) {\n setError(`payload JSON 解析失败: ${(err as Error).message}`)\n return\n }\n if (!action.trim()) {\n setError(\"action 不能为空\")\n return\n }\n\n if (effectiveSide === \"agent\") {\n // 模拟 host → agent:直接 dispatch 到 window,parent-bridge 监听器会收到\n window.postMessage(\n {\n __bladeBridge: true,\n direction: \"host-to-agent\",\n action,\n payload,\n meta: { timestamp: Date.now(), injectedBy: \"devtools\" },\n },\n \"*\",\n )\n return\n }\n\n // host 侧:发送给某个 iframe\n const target = tab !== \"host\" && tab !== \"agent\" ? tab : targetKey\n const entry = iframes.find((f) => f.key === target)\n if (!entry) {\n setError(\"请选择目标 iframe\")\n return\n }\n const win = entry.getContentWindow()\n if (!win) {\n setError(\"目标 iframe contentWindow 为空(可能未加载)\")\n return\n }\n win.postMessage(\n {\n __resourceBridge: true,\n direction: \"host-to-iframe\",\n event: action,\n action,\n payload,\n },\n \"*\",\n )\n tapBridgeEvent({\n side: \"host\",\n direction: \"host-to-iframe\",\n action,\n payload,\n iframeKey: entry.key,\n iframeLabel: entry.label,\n note: \"injected by devtools\",\n })\n }\n\n return (\n <div className=\"border-t border-[hsl(var(--border))] bg-[hsl(var(--muted))]/30 px-3 py-2\">\n <div className=\"mb-1 text-xs font-semibold text-[hsl(var(--muted-foreground))]\">\n 手动发送 envelope({effectiveSide === \"agent\" ? \"模拟 host → agent\" : \"host → iframe\"})\n </div>\n <div className=\"flex flex-wrap items-start gap-2 text-xs\">\n {effectiveSide === \"host\" && tab === \"host\" ? (\n <select\n value={targetKey}\n onChange={(e) => setTargetKey(e.target.value)}\n className=\"rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n >\n <option value=\"\">选择 iframe…</option>\n {iframes.map((f) => (\n <option key={f.key} value={f.key}>\n {f.label}\n </option>\n ))}\n </select>\n ) : null}\n <input\n value={action}\n onChange={(e) => setAction(e.target.value)}\n placeholder=\"action(如 addContext / theme)\"\n className=\"min-w-[140px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n />\n <input\n value={payloadText}\n onChange={(e) => setPayloadText(e.target.value)}\n placeholder='payload JSON(如 {\"foo\":1})'\n className=\"min-w-[180px] flex-[2] rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1 font-mono\"\n />\n <button\n type=\"button\"\n onClick={send}\n className=\"rounded bg-[hsl(var(--primary))] px-3 py-1 text-[hsl(var(--primary-foreground))] hover:opacity-90\"\n >\n 发送\n </button>\n </div>\n {error ? <div className=\"mt-1 text-xs text-red-500\">{error}</div> : null}\n </div>\n )\n}\n","import { create } from \"zustand\"\nimport type { BridgeEventInput, BridgeEventRecord } from \"./types\"\n\nconst MAX_EVENTS = 500\n\nfunction buildId() {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID()\n }\n return `bev-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport interface RegisteredIframe {\n key: string\n label: string\n getContentWindow: () => Window | null\n}\n\ninterface BridgeDevtoolsState {\n events: BridgeEventRecord[]\n iframes: Record<string, RegisteredIframe>\n record: (event: BridgeEventInput) => void\n clear: () => void\n registerIframe: (entry: RegisteredIframe) => () => void\n}\n\nexport const useBridgeDevtoolsStore = create<BridgeDevtoolsState>()((set) => ({\n events: [],\n iframes: {},\n record: (input) =>\n set((state) => {\n const record: BridgeEventRecord = {\n id: buildId(),\n ts: Date.now(),\n ...input,\n }\n const events =\n state.events.length >= MAX_EVENTS\n ? [...state.events.slice(state.events.length - MAX_EVENTS + 1), record]\n : [...state.events, record]\n return { events }\n }),\n clear: () => set({ events: [] }),\n registerIframe: (entry) => {\n set((state) => ({ iframes: { ...state.iframes, [entry.key]: entry } }))\n return () => {\n set((state) => {\n if (!(entry.key in state.iframes)) return state\n const next = { ...state.iframes }\n delete next[entry.key]\n return { iframes: next }\n })\n }\n },\n}))\n","import type { BridgeEventInput, RegisteredIframeEntry } from \"./types\"\n\nfunction isDev() {\n return (import.meta as unknown as { env?: { DEV?: boolean } }).env?.DEV === true\n}\n\nconst PENDING_EVENT_LIMIT = 500\nconst pendingEvents: BridgeEventInput[] = []\n\nexport function tapBridgeEvent(event: BridgeEventInput) {\n if (!isDev()) return\n const hook = globalThis.__bladeBridgeDevtools\n if (hook) {\n hook.record(event)\n return\n }\n // hook 异步安装,启动阶段事件(如首个 postTheme、早期 host 消息)\n // 在 mount 前触达,直接丢弃会让 debugger 错过初始化链,故先入队。\n if (pendingEvents.length >= PENDING_EVENT_LIMIT) {\n pendingEvents.shift()\n }\n pendingEvents.push(event)\n}\n\nexport function flushPendingBridgeEvents() {\n const hook = globalThis.__bladeBridgeDevtools\n if (!hook) return\n for (const event of pendingEvents) {\n hook.record(event)\n }\n pendingEvents.length = 0\n}\n\ninterface PendingRegistration {\n entry: RegisteredIframeEntry\n unregister: (() => void) | null\n}\n\nconst pendingRegistrations: PendingRegistration[] = []\n\nexport function registerBridgeIframe(entry: RegisteredIframeEntry) {\n if (!isDev()) return () => {}\n const hook = globalThis.__bladeBridgeDevtools\n if (hook) {\n return hook.registerIframe(entry)\n }\n // devtools hook 在 main.tsx 里通过动态 import 异步安装,ResourceIframe\n // 可能先于 hook mount。先把 entry 排进队列,mount 时 flush 掉。\n const pending: PendingRegistration = { entry, unregister: null }\n pendingRegistrations.push(pending)\n return () => {\n const idx = pendingRegistrations.indexOf(pending)\n if (idx >= 0) pendingRegistrations.splice(idx, 1)\n pending.unregister?.()\n }\n}\n\nexport function flushPendingIframeRegistrations() {\n const hook = globalThis.__bladeBridgeDevtools\n if (!hook) return\n for (const pending of pendingRegistrations) {\n pending.unregister = hook.registerIframe(pending.entry)\n }\n pendingRegistrations.length = 0\n}\n"],"mappings":"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","names":["jsx"]}
1
+ {"version":3,"sources":["../../../../src/react/devtools/bridge-devtools/mount.tsx","../../../../src/react/devtools/bridge-devtools/BridgeDevtoolsFab.tsx","../../../../src/react/devtools/bridge-devtools/store.ts"],"sourcesContent":["import { StrictMode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\nimport { BridgeDevtoolsFab } from \"./BridgeDevtoolsFab\"\nimport { useBridgeDevtoolsStore } from \"./store\"\nimport { flushPendingBridgeEvents, flushPendingIframeRegistrations } from \"./tap\"\nimport type { BridgeDevtoolsHook } from \"./types\"\n\nlet mounted = false\n\nexport function mountBridgeDevtools() {\n if (mounted || typeof document === \"undefined\") return\n mounted = true\n\n const hook: BridgeDevtoolsHook = {\n record: (event) => useBridgeDevtoolsStore.getState().record(event),\n registerIframe: (entry) => useBridgeDevtoolsStore.getState().registerIframe(entry),\n }\n globalThis.__bladeBridgeDevtools = hook\n flushPendingBridgeEvents()\n flushPendingIframeRegistrations()\n\n const container = document.createElement(\"div\")\n container.id = \"blade-bridge-devtools-root\"\n document.body.appendChild(container)\n createRoot(container).render(\n <StrictMode>\n <BridgeDevtoolsFab />\n </StrictMode>,\n )\n}\n","import { animate, motion, type PanInfo, useMotionValue } from \"motion/react\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { useShallow } from \"zustand/react/shallow\"\nimport { useBridgeDevtoolsStore } from \"./store\"\nimport { tapBridgeEvent } from \"./tap\"\nimport type {\n BridgeEventDirection,\n BridgeEventRecord,\n BridgeEventSide,\n} from \"./types\"\n\nconst FAB_HEIGHT = 44\nconst FAB_PEEK = 18\nconst FAB_POS_STORAGE = \"blade.bridge-devtools-fab.pos\"\nconst FAB_SPRING = { type: \"spring\" as const, stiffness: 380, damping: 32 }\n\ninterface FabSavedPos {\n x: number\n y: number\n}\n\nfunction clamp(v: number, min: number, max: number) {\n return Math.min(Math.max(v, min), max)\n}\n\nfunction loadFabPos(): FabSavedPos | null {\n if (typeof window === \"undefined\") return null\n try {\n const raw = window.localStorage.getItem(FAB_POS_STORAGE)\n if (!raw) return null\n const parsed = JSON.parse(raw)\n if (typeof parsed?.x === \"number\" && typeof parsed?.y === \"number\") {\n return { x: parsed.x, y: parsed.y }\n }\n } catch {\n /* ignore */\n }\n return null\n}\n\nfunction saveFabPos(pos: FabSavedPos) {\n if (typeof window === \"undefined\") return\n try {\n window.localStorage.setItem(FAB_POS_STORAGE, JSON.stringify(pos))\n } catch {\n /* ignore */\n }\n}\n\nfunction snapXToEdge(currentX: number, btnW: number) {\n const maxX = Math.max(0, window.innerWidth - btnW)\n const center = currentX + btnW / 2\n return center < window.innerWidth / 2 ? 0 : maxX\n}\n\nfunction hiddenXFor(snappedX: number, btnW: number) {\n const maxX = Math.max(0, window.innerWidth - btnW)\n const offset = Math.max(0, btnW - FAB_PEEK)\n return snappedX <= maxX / 2 ? snappedX - offset : snappedX + offset\n}\n\nfunction defaultFabPos(): FabSavedPos {\n if (typeof window === \"undefined\") return { x: 0, y: 0 }\n return {\n x: window.innerWidth,\n y: window.innerHeight - FAB_HEIGHT - 80,\n }\n}\n\ntype SideTab = \"agent\" | \"host\" | string\n\nconst DIRECTION_LABEL: Record<BridgeEventDirection, string> = {\n \"host-to-agent\": \"host → agent\",\n \"agent-to-host\": \"agent → host\",\n \"host-to-iframe\": \"host → iframe\",\n \"iframe-to-host\": \"iframe → host\",\n}\n\nconst ALL_DIRECTIONS: BridgeEventDirection[] = [\n \"host-to-agent\",\n \"agent-to-host\",\n \"host-to-iframe\",\n \"iframe-to-host\",\n]\n\nfunction safeStringify(value: unknown, indent?: number) {\n // 通过 postMessage 结构化克隆进来的 payload 可能带 BigInt、cyclic、\n // 或其它 JSON.stringify 处理不了的值,必须包一层 fallback,否则\n // 任何搜索/展开/导出都会把 devtools 自己炸掉。\n const seen = new WeakSet<object>()\n try {\n return JSON.stringify(\n value,\n (_k, v) => {\n if (typeof v === \"bigint\") return `${v.toString()}n`\n if (typeof v === \"object\" && v !== null) {\n if (seen.has(v)) return \"[Circular]\"\n seen.add(v)\n }\n return v\n },\n indent,\n ) ?? String(value)\n } catch (err) {\n return `[unserializable: ${(err as Error).message}]`\n }\n}\n\nfunction formatTime(ts: number) {\n const d = new Date(ts)\n const pad = (n: number) => n.toString().padStart(2, \"0\")\n const ms = d.getMilliseconds().toString().padStart(3, \"0\")\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`\n}\n\nfunction filterEvents(\n events: BridgeEventRecord[],\n tab: SideTab,\n search: string,\n enabledDirections: Set<BridgeEventDirection>,\n) {\n const needle = search.trim().toLowerCase()\n return events.filter((e) => {\n if (tab === \"agent\" && e.side !== \"agent\") return false\n if (tab !== \"agent\" && tab !== \"host\" && e.iframeKey !== tab) return false\n if (tab === \"host\" && e.side !== \"host\") return false\n if (!enabledDirections.has(e.direction)) return false\n if (needle) {\n const hay = `${e.action} ${safeStringify(e.payload ?? \"\")} ${e.note ?? \"\"}`.toLowerCase()\n if (!hay.includes(needle)) return false\n }\n return true\n })\n}\n\nfunction downloadJson(filename: string, data: unknown) {\n const blob = new Blob([safeStringify(data, 2)], { type: \"application/json\" })\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = filename\n a.click()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n}\n\nexport function BridgeDevtoolsFab() {\n const [open, setOpen] = useState(false)\n const [tab, setTab] = useState<SideTab>(\"agent\")\n const [search, setSearch] = useState(\"\")\n const [enabled, setEnabled] = useState<Set<BridgeEventDirection>>(\n () => new Set(ALL_DIRECTIONS),\n )\n const [expandedId, setExpandedId] = useState<string | null>(null)\n\n const events = useBridgeDevtoolsStore((s) => s.events)\n const iframes = useBridgeDevtoolsStore(useShallow((s) => Object.values(s.iframes)))\n const clear = useBridgeDevtoolsStore((s) => s.clear)\n\n const filtered = useMemo(\n () => filterEvents(events, tab, search, enabled),\n [events, tab, search, enabled],\n )\n\n const counts = useMemo(() => {\n const c = { agent: 0, host: 0 as number }\n const perIframe: Record<string, number> = {}\n for (const e of events) {\n if (e.side === \"agent\") c.agent++\n else c.host++\n if (e.iframeKey) perIframe[e.iframeKey] = (perIframe[e.iframeKey] ?? 0) + 1\n }\n return { ...c, perIframe }\n }, [events])\n\n const rejectedCount = events.filter((e) => e.rejected).length\n\n const initialPos = useMemo(() => {\n const saved = loadFabPos() ?? defaultFabPos()\n if (typeof window === \"undefined\") return saved\n return {\n x: saved.x,\n y: clamp(saved.y, 0, Math.max(0, window.innerHeight - FAB_HEIGHT)),\n }\n }, [])\n const [snapped, setSnapped] = useState<FabSavedPos>(initialPos)\n const [btnW, setBtnW] = useState(FAB_HEIGHT)\n const [hover, setHover] = useState(false)\n const [dragging, setDragging] = useState(false)\n const x = useMotionValue(initialPos.x)\n const y = useMotionValue(initialPos.y)\n const btnRef = useRef<HTMLButtonElement | null>(null)\n\n // Measure rendered button width — needed for edge snapping math.\n useEffect(() => {\n const el = btnRef.current\n if (!el) return\n const update = () => setBtnW(el.offsetWidth || FAB_HEIGHT)\n update()\n const ro = new ResizeObserver(update)\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // Drive the visible/hidden animation imperatively against the motion value.\n // Recompute edgeX each tick so width measurement / viewport resize stay correct.\n const visible = open || hover || dragging\n useEffect(() => {\n if (dragging) return\n const edgeX = snapXToEdge(snapped.x, btnW)\n const targetX = visible ? edgeX : hiddenXFor(edgeX, btnW)\n const ctrl = animate(x, targetX, FAB_SPRING)\n return () => ctrl.stop()\n }, [visible, snapped.x, btnW, dragging, x])\n\n // Re-snap to nearest edge on viewport resize.\n useEffect(() => {\n const onResize = () => {\n const newX = snapXToEdge(snapped.x, btnW)\n const newY = clamp(snapped.y, 0, window.innerHeight - FAB_HEIGHT)\n if (newX !== snapped.x || newY !== snapped.y) {\n setSnapped({ x: newX, y: newY })\n saveFabPos({ x: newX, y: newY })\n y.set(newY)\n }\n }\n window.addEventListener(\"resize\", onResize)\n return () => window.removeEventListener(\"resize\", onResize)\n }, [snapped.x, snapped.y, btnW, y])\n\n const handleDragEnd = (_: PointerEvent | MouseEvent | TouchEvent, _info: PanInfo) => {\n const newX = snapXToEdge(x.get(), btnW)\n const newY = clamp(y.get(), 0, window.innerHeight - FAB_HEIGHT)\n setSnapped({ x: newX, y: newY })\n saveFabPos({ x: newX, y: newY })\n setDragging(false)\n animate(x, newX, FAB_SPRING)\n animate(y, newY, FAB_SPRING)\n }\n\n return (\n <>\n <motion.div\n style={{\n x,\n y,\n position: \"fixed\",\n top: 0,\n left: 0,\n zIndex: 9998,\n touchAction: \"none\",\n }}\n drag\n dragMomentum={false}\n dragElastic={0.05}\n onDragStart={() => setDragging(true)}\n onDragEnd={handleDragEnd}\n onPointerEnter={() => setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n <button\n ref={btnRef}\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n 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\"\n title=\"Bridge 事件调试(可拖动到任意边缘)\"\n >\n <span className=\"text-base\">🌉</span>\n <span className=\"tabular-nums\">{events.length}</span>\n {rejectedCount > 0 ? (\n <span className=\"rounded bg-red-500/15 px-1 text-xs text-red-500 tabular-nums\">\n {rejectedCount}\n </span>\n ) : null}\n </button>\n </motion.div>\n {open && typeof document !== \"undefined\"\n ? createPortal(\n <BridgeDevtoolsPanel\n onClose={() => setOpen(false)}\n tab={tab}\n setTab={setTab}\n search={search}\n setSearch={setSearch}\n enabled={enabled}\n setEnabled={setEnabled}\n events={filtered}\n totalEvents={events}\n expandedId={expandedId}\n setExpandedId={setExpandedId}\n counts={counts}\n iframes={iframes}\n onClear={clear}\n />,\n document.body,\n )\n : null}\n </>\n )\n}\n\ninterface PanelProps {\n onClose: () => void\n tab: SideTab\n setTab: (t: SideTab) => void\n search: string\n setSearch: (s: string) => void\n enabled: Set<BridgeEventDirection>\n setEnabled: (s: Set<BridgeEventDirection>) => void\n events: BridgeEventRecord[]\n totalEvents: BridgeEventRecord[]\n expandedId: string | null\n setExpandedId: (id: string | null) => void\n counts: { agent: number; host: number; perIframe: Record<string, number> }\n iframes: Array<{ key: string; label: string; getContentWindow: () => Window | null }>\n onClear: () => void\n}\n\nfunction BridgeDevtoolsPanel(props: PanelProps) {\n const {\n onClose,\n tab,\n setTab,\n search,\n setSearch,\n enabled,\n setEnabled,\n events,\n totalEvents,\n expandedId,\n setExpandedId,\n counts,\n iframes,\n onClear,\n } = props\n\n const toggleDirection = (d: BridgeEventDirection) => {\n const next = new Set(enabled)\n if (next.has(d)) next.delete(d)\n else next.add(d)\n setEnabled(next)\n }\n\n return (\n <div className=\"fixed inset-0 z-[9999] flex items-end justify-end\">\n <button\n type=\"button\"\n aria-label=\"关闭调试面板\"\n className=\"absolute inset-0 bg-black/20\"\n onClick={onClose}\n />\n <div\n 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\"\n >\n <header className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-2\">\n <div className=\"flex items-center gap-2 text-sm font-semibold\">\n <span>🌉 Bridge 事件调试</span>\n <span className=\"text-xs text-[hsl(var(--muted-foreground))]\">\n {totalEvents.length} / 500\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={() =>\n downloadJson(`bridge-events-${Date.now()}.json`, totalEvents)\n }\n >\n 导出 JSON\n </button>\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={onClear}\n >\n 清空\n </button>\n <button\n type=\"button\"\n className=\"rounded px-2 py-1 text-xs hover:bg-[hsl(var(--accent))]\"\n onClick={onClose}\n >\n ✕\n </button>\n </div>\n </header>\n\n <nav className=\"flex items-center gap-1 overflow-x-auto border-b border-[hsl(var(--border))] px-3 py-2 text-xs\">\n <TabButton active={tab === \"agent\"} onClick={() => setTab(\"agent\")}>\n Agent 侧 ({counts.agent})\n </TabButton>\n <TabButton active={tab === \"host\"} onClick={() => setTab(\"host\")}>\n Host 全部 ({counts.host})\n </TabButton>\n {iframes.map((f) => (\n <TabButton\n key={f.key}\n active={tab === f.key}\n onClick={() => setTab(f.key)}\n title={f.label}\n >\n 📄 {f.label.length > 16 ? `${f.label.slice(0, 16)}…` : f.label} (\n {counts.perIframe[f.key] ?? 0})\n </TabButton>\n ))}\n </nav>\n\n <div className=\"flex flex-wrap items-center gap-2 border-b border-[hsl(var(--border))] px-3 py-2 text-xs\">\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"搜索 action / payload / note…\"\n className=\"min-w-[160px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n />\n {ALL_DIRECTIONS.map((d) => (\n <label key={d} className=\"flex items-center gap-1\">\n <input\n type=\"checkbox\"\n checked={enabled.has(d)}\n onChange={() => toggleDirection(d)}\n />\n <span>{DIRECTION_LABEL[d]}</span>\n </label>\n ))}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n {events.length === 0 ? (\n <div className=\"p-6 text-center text-sm text-[hsl(var(--muted-foreground))]\">\n 无匹配事件\n </div>\n ) : (\n <ul className=\"divide-y divide-[hsl(var(--border))]\">\n {events.map((e) => (\n <EventRow\n key={e.id}\n event={e}\n expanded={expandedId === e.id}\n onToggle={() => setExpandedId(expandedId === e.id ? null : e.id)}\n />\n ))}\n </ul>\n )}\n </div>\n\n <ManualSendBar tab={tab} iframes={iframes} />\n </div>\n </div>\n )\n}\n\nfunction TabButton(props: {\n active: boolean\n onClick: () => void\n title?: string\n children: React.ReactNode\n}) {\n return (\n <button\n type=\"button\"\n onClick={props.onClick}\n title={props.title}\n className={`whitespace-nowrap rounded px-2 py-1 ${\n props.active\n ? \"bg-[hsl(var(--accent))] font-semibold\"\n : \"hover:bg-[hsl(var(--accent))]/50\"\n }`}\n >\n {props.children}\n </button>\n )\n}\n\nfunction EventRow({\n event,\n expanded,\n onToggle,\n}: {\n event: BridgeEventRecord\n expanded: boolean\n onToggle: () => void\n}) {\n return (\n <li\n className={`px-3 py-1.5 text-xs ${event.rejected ? \"bg-red-500/5\" : \"\"}`}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n className=\"flex w-full items-center gap-2 text-left\"\n >\n <span className=\"w-[90px] font-mono tabular-nums text-[hsl(var(--muted-foreground))]\">\n {formatTime(event.ts)}\n </span>\n <span\n className={`w-[120px] font-mono ${\n event.side === \"agent\" ? \"text-blue-500\" : \"text-purple-500\"\n }`}\n >\n {DIRECTION_LABEL[event.direction]}\n </span>\n <span className=\"flex-1 truncate font-semibold\">{event.action}</span>\n {event.rejected ? (\n <span className=\"rounded bg-red-500/20 px-1.5 text-[10px] text-red-500\">\n rejected\n </span>\n ) : null}\n <span className=\"text-[hsl(var(--muted-foreground))]\">{expanded ? \"▼\" : \"▶\"}</span>\n </button>\n {expanded ? (\n <div className=\"mt-2 space-y-1 pl-[90px] font-mono\">\n {event.note ? (\n <div className=\"text-red-500\">note: {event.note}</div>\n ) : null}\n {event.iframeLabel ? (\n <div className=\"text-[hsl(var(--muted-foreground))]\">\n iframe: {event.iframeLabel}\n </div>\n ) : null}\n {event.meta ? (\n <pre className=\"whitespace-pre-wrap break-words text-[hsl(var(--muted-foreground))]\">\n meta: {safeStringify(event.meta, 2)}\n </pre>\n ) : null}\n <pre className=\"whitespace-pre-wrap break-words\">\n payload: {safeStringify(event.payload, 2)}\n </pre>\n </div>\n ) : null}\n </li>\n )\n}\n\nfunction ManualSendBar({\n tab,\n iframes,\n}: {\n tab: SideTab\n iframes: Array<{ key: string; label: string; getContentWindow: () => Window | null }>\n}) {\n const [action, setAction] = useState(\"\")\n const [payloadText, setPayloadText] = useState(\"{}\")\n const [error, setError] = useState<string | null>(null)\n const [targetKey, setTargetKey] = useState<string>(\"\")\n\n const effectiveSide: BridgeEventSide = tab === \"agent\" ? \"agent\" : \"host\"\n\n const send = () => {\n setError(null)\n let payload: unknown\n try {\n payload = payloadText.trim() ? JSON.parse(payloadText) : undefined\n } catch (err) {\n setError(`payload JSON 解析失败: ${(err as Error).message}`)\n return\n }\n if (!action.trim()) {\n setError(\"action 不能为空\")\n return\n }\n\n if (effectiveSide === \"agent\") {\n // 模拟 host → agent:直接 dispatch 到 window,parent-bridge 监听器会收到\n window.postMessage(\n {\n __bladeBridge: true,\n direction: \"host-to-agent\",\n action,\n payload,\n meta: { timestamp: Date.now(), injectedBy: \"devtools\" },\n },\n \"*\",\n )\n return\n }\n\n // host 侧:发送给某个 iframe\n const target = tab !== \"host\" && tab !== \"agent\" ? tab : targetKey\n const entry = iframes.find((f) => f.key === target)\n if (!entry) {\n setError(\"请选择目标 iframe\")\n return\n }\n const win = entry.getContentWindow()\n if (!win) {\n setError(\"目标 iframe contentWindow 为空(可能未加载)\")\n return\n }\n win.postMessage(\n {\n __resourceBridge: true,\n direction: \"host-to-iframe\",\n event: action,\n action,\n payload,\n },\n \"*\",\n )\n tapBridgeEvent({\n side: \"host\",\n direction: \"host-to-iframe\",\n action,\n payload,\n iframeKey: entry.key,\n iframeLabel: entry.label,\n note: \"injected by devtools\",\n })\n }\n\n return (\n <div className=\"border-t border-[hsl(var(--border))] bg-[hsl(var(--muted))]/30 px-3 py-2\">\n <div className=\"mb-1 text-xs font-semibold text-[hsl(var(--muted-foreground))]\">\n 手动发送 envelope({effectiveSide === \"agent\" ? \"模拟 host → agent\" : \"host → iframe\"})\n </div>\n <div className=\"flex flex-wrap items-start gap-2 text-xs\">\n {effectiveSide === \"host\" && tab === \"host\" ? (\n <select\n value={targetKey}\n onChange={(e) => setTargetKey(e.target.value)}\n className=\"rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n >\n <option value=\"\">选择 iframe…</option>\n {iframes.map((f) => (\n <option key={f.key} value={f.key}>\n {f.label}\n </option>\n ))}\n </select>\n ) : null}\n <input\n value={action}\n onChange={(e) => setAction(e.target.value)}\n placeholder=\"action(如 addContext / theme)\"\n className=\"min-w-[140px] flex-1 rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1\"\n />\n <input\n value={payloadText}\n onChange={(e) => setPayloadText(e.target.value)}\n placeholder='payload JSON(如 {\"foo\":1})'\n className=\"min-w-[180px] flex-[2] rounded border border-[hsl(var(--border))] bg-transparent px-2 py-1 font-mono\"\n />\n <button\n type=\"button\"\n onClick={send}\n className=\"rounded bg-[hsl(var(--primary))] px-3 py-1 text-[hsl(var(--primary-foreground))] hover:opacity-90\"\n >\n 发送\n </button>\n </div>\n {error ? <div className=\"mt-1 text-xs text-red-500\">{error}</div> : null}\n </div>\n )\n}\n","import { create } from \"zustand\"\nimport type { BridgeEventInput, BridgeEventRecord } from \"./types\"\n\nconst MAX_EVENTS = 500\n\nfunction buildId() {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID()\n }\n return `bev-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport interface RegisteredIframe {\n key: string\n label: string\n getContentWindow: () => Window | null\n}\n\ninterface BridgeDevtoolsState {\n events: BridgeEventRecord[]\n iframes: Record<string, RegisteredIframe>\n record: (event: BridgeEventInput) => void\n clear: () => void\n registerIframe: (entry: RegisteredIframe) => () => void\n}\n\nexport const useBridgeDevtoolsStore = create<BridgeDevtoolsState>()((set) => ({\n events: [],\n iframes: {},\n record: (input) =>\n set((state) => {\n const record: BridgeEventRecord = {\n id: buildId(),\n ts: Date.now(),\n ...input,\n }\n const events =\n state.events.length >= MAX_EVENTS\n ? [...state.events.slice(state.events.length - MAX_EVENTS + 1), record]\n : [...state.events, record]\n return { events }\n }),\n clear: () => set({ events: [] }),\n registerIframe: (entry) => {\n set((state) => ({ iframes: { ...state.iframes, [entry.key]: entry } }))\n return () => {\n set((state) => {\n if (!(entry.key in state.iframes)) return state\n const next = { ...state.iframes }\n delete next[entry.key]\n return { iframes: next }\n })\n }\n },\n}))\n"],"mappings":"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","names":["jsx"]}