@particle-academy/agent-integrations 0.3.4 → 0.5.0
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/README.md +65 -0
- package/dist/bridges/charts.d.cts +4 -4
- package/dist/bridges/charts.d.ts +4 -4
- package/dist/bridges/code.d.cts +4 -4
- package/dist/bridges/code.d.ts +4 -4
- package/dist/bridges/flow.d.cts +4 -4
- package/dist/bridges/flow.d.ts +4 -4
- package/dist/bridges/forms.d.cts +4 -4
- package/dist/bridges/forms.d.ts +4 -4
- package/dist/bridges/scene.d.cts +4 -4
- package/dist/bridges/scene.d.ts +4 -4
- package/dist/bridges/screens.d.cts +78 -0
- package/dist/bridges/screens.d.ts +78 -0
- package/dist/bridges/sheets.d.cts +4 -4
- package/dist/bridges/sheets.d.ts +4 -4
- package/dist/bridges/whiteboard.d.cts +4 -4
- package/dist/bridges/whiteboard.d.ts +4 -4
- package/dist/bridges-charts.cjs +2 -2
- package/dist/bridges-charts.cjs.map +1 -1
- package/dist/bridges-charts.js +2 -2
- package/dist/bridges-code.cjs +2 -2
- package/dist/bridges-code.cjs.map +1 -1
- package/dist/bridges-code.js +2 -2
- package/dist/bridges-flow.cjs +2 -2
- package/dist/bridges-flow.cjs.map +1 -1
- package/dist/bridges-flow.js +340 -3
- package/dist/bridges-flow.js.map +1 -1
- package/dist/bridges-forms.cjs +2 -2
- package/dist/bridges-forms.cjs.map +1 -1
- package/dist/bridges-forms.js +2 -2
- package/dist/bridges-scene.cjs +2 -2
- package/dist/bridges-scene.cjs.map +1 -1
- package/dist/bridges-scene.js +2 -2
- package/dist/bridges-screens.cjs +227 -0
- package/dist/bridges-screens.cjs.map +1 -0
- package/dist/bridges-screens.js +6 -0
- package/dist/bridges-screens.js.map +1 -0
- package/dist/bridges-sheets.cjs +2 -2
- package/dist/bridges-sheets.cjs.map +1 -1
- package/dist/bridges-sheets.js +2 -2
- package/dist/bridges-whiteboard.cjs +12 -12
- package/dist/bridges-whiteboard.cjs.map +1 -1
- package/dist/bridges-whiteboard.js +3 -3
- package/dist/{chunk-TBEITXF4.js → chunk-3KSZNGNW.js} +7 -7
- package/dist/chunk-3KSZNGNW.js.map +1 -0
- package/dist/{chunk-OEIULP2L.js → chunk-4BL5M3U3.js} +5 -5
- package/dist/chunk-4BL5M3U3.js.map +1 -0
- package/dist/{chunk-QGCF7YKW.js → chunk-4KAIV6OD.js} +40 -12
- package/dist/chunk-4KAIV6OD.js.map +1 -0
- package/dist/chunk-57ZDHD53.js +180 -0
- package/dist/chunk-57ZDHD53.js.map +1 -0
- package/dist/chunk-5XELJIJR.js +83 -0
- package/dist/chunk-5XELJIJR.js.map +1 -0
- package/dist/{chunk-6LTKCNLF.js → chunk-AFUULW5E.js} +3 -34
- package/dist/chunk-AFUULW5E.js.map +1 -0
- package/dist/chunk-G6N2TQVO.js +34 -0
- package/dist/chunk-G6N2TQVO.js.map +1 -0
- package/dist/{chunk-ACBENYYO.js → chunk-GQ7XXK7G.js} +12 -12
- package/dist/chunk-GQ7XXK7G.js.map +1 -0
- package/dist/{chunk-XYYSTJHW.js → chunk-HSTW7ZNO.js} +5 -5
- package/dist/chunk-HSTW7ZNO.js.map +1 -0
- package/dist/{chunk-PDBF4W7E.js → chunk-IANI25IT.js} +5 -5
- package/dist/chunk-IANI25IT.js.map +1 -0
- package/dist/chunk-IJ6JX5VC.js +3 -0
- package/dist/chunk-IJ6JX5VC.js.map +1 -0
- package/dist/{chunk-JMYPUAFH.js → chunk-LVQXIUJH.js} +2 -2
- package/dist/{chunk-JMYPUAFH.js.map → chunk-LVQXIUJH.js.map} +1 -1
- package/dist/{chunk-PHPXKSWI.js → chunk-NTDZWGYB.js} +5 -5
- package/dist/chunk-NTDZWGYB.js.map +1 -0
- package/dist/{chunk-DJOWMF6Q.js → chunk-RGO42EQ6.js} +3 -3
- package/dist/{chunk-DJOWMF6Q.js.map → chunk-RGO42EQ6.js.map} +1 -1
- package/dist/{chunk-QJUTISFC.js → chunk-XRAJSOPS.js} +5 -5
- package/dist/chunk-XRAJSOPS.js.map +1 -0
- package/dist/chunk-ZHAK2DQR.js +289 -0
- package/dist/chunk-ZHAK2DQR.js.map +1 -0
- package/dist/components/SharedWhiteboard/index.d.cts +55 -0
- package/dist/components/SharedWhiteboard/index.d.ts +55 -0
- package/dist/components-shared-whiteboard.cjs +1533 -0
- package/dist/components-shared-whiteboard.cjs.map +1 -0
- package/dist/components-shared-whiteboard.js +285 -0
- package/dist/components-shared-whiteboard.js.map +1 -0
- package/dist/index.cjs +618 -1371
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -59
- package/dist/index.d.ts +11 -59
- package/dist/index.js +19 -571
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.cts +5 -4
- package/dist/mcp/index.d.ts +5 -4
- package/dist/mcp.cjs +37 -9
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +3 -2
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/{server-BJu_AMH3.d.ts → server-BsSwfemr.d.cts} +4 -5
- package/dist/{server-si-VvFxI.d.cts → server-Du3-IGqM.d.ts} +4 -5
- package/dist/sharing/index.d.cts +5 -36
- package/dist/sharing/index.d.ts +5 -36
- package/dist/sharing.js +2 -1
- package/dist/sheets-adapter.cjs +96 -0
- package/dist/sheets-adapter.cjs.map +1 -0
- package/dist/sheets-adapter.d.cts +119 -0
- package/dist/sheets-adapter.d.ts +119 -0
- package/dist/sheets-adapter.js +4 -0
- package/dist/sheets-adapter.js.map +1 -0
- package/dist/token-CrJF76oH.d.cts +34 -0
- package/dist/token-CrJF76oH.d.ts +34 -0
- package/dist/tool-host-BQuUygLF.d.cts +60 -0
- package/dist/tool-host-C8JMMGYq.d.ts +60 -0
- package/dist/{types-DXKpLuia.d.ts → types-CCSBGW9T.d.cts} +2 -2
- package/dist/{types-Bf1ZoGmI.d.cts → types-DIVNcIQO.d.ts} +2 -2
- package/dist/{types-DksGd5Y7.d.cts → types-aOQLTW0E.d.cts} +1 -1
- package/dist/{types-DksGd5Y7.d.ts → types-aOQLTW0E.d.ts} +1 -1
- package/dist/undo/index.d.cts +4 -4
- package/dist/undo/index.d.ts +4 -4
- package/dist/undo.cjs +9 -9
- package/dist/undo.cjs.map +1 -1
- package/dist/undo.js +3 -3
- package/package.json +57 -7
- package/dist/chunk-4IAVAFUV.js +0 -342
- package/dist/chunk-4IAVAFUV.js.map +0 -1
- package/dist/chunk-6LTKCNLF.js.map +0 -1
- package/dist/chunk-ACBENYYO.js.map +0 -1
- package/dist/chunk-OEIULP2L.js.map +0 -1
- package/dist/chunk-PDBF4W7E.js.map +0 -1
- package/dist/chunk-PHPXKSWI.js.map +0 -1
- package/dist/chunk-QGCF7YKW.js.map +0 -1
- package/dist/chunk-QJUTISFC.js.map +0 -1
- package/dist/chunk-TBEITXF4.js.map +0 -1
- package/dist/chunk-XYYSTJHW.js.map +0 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { ShareControls, AgentCursor, AgentActivityHighlight, AgentPanel } from './chunk-ZHAK2DQR.js';
|
|
2
|
+
import { createSessionDescriptor, attachSseRelay } from './chunk-LVQXIUJH.js';
|
|
3
|
+
import { attachInProcess } from './chunk-AFUULW5E.js';
|
|
4
|
+
import { registerWhiteboardBridge } from './chunk-3KSZNGNW.js';
|
|
5
|
+
import './chunk-GQ7XXK7G.js';
|
|
6
|
+
import './chunk-52S7XYZK.js';
|
|
7
|
+
import './chunk-JU2N4KK6.js';
|
|
8
|
+
import { MicroMcpServer } from './chunk-4KAIV6OD.js';
|
|
9
|
+
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
10
|
+
import { Board, Connector, Shape, StickyNote, CursorLayer } from '@particle-academy/fancy-whiteboard';
|
|
11
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
12
|
+
|
|
13
|
+
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
14
|
+
function SharedWhiteboard({
|
|
15
|
+
initialNotes = [],
|
|
16
|
+
initialShapes = [],
|
|
17
|
+
initialConnectors = [],
|
|
18
|
+
initialStrokes = [],
|
|
19
|
+
initialViewport = { x: 0, y: 0, zoom: 1 },
|
|
20
|
+
agent = DEFAULT_AGENT,
|
|
21
|
+
shareBaseUrl = "/whiteboard-share",
|
|
22
|
+
onRegisterSession,
|
|
23
|
+
showAgentPanel = true,
|
|
24
|
+
showShareControls = true,
|
|
25
|
+
broadcastEdits = true,
|
|
26
|
+
height = 640,
|
|
27
|
+
header,
|
|
28
|
+
className,
|
|
29
|
+
style
|
|
30
|
+
}) {
|
|
31
|
+
const [notes, setNotes] = useState(initialNotes);
|
|
32
|
+
const [shapes, setShapes] = useState(initialShapes);
|
|
33
|
+
const [connectors, setConnectors] = useState(initialConnectors);
|
|
34
|
+
const [strokes, setStrokes] = useState(initialStrokes);
|
|
35
|
+
const [viewport, setViewport] = useState(initialViewport);
|
|
36
|
+
const [agentCursor, setAgentCursor] = useState(null);
|
|
37
|
+
const [activity, setActivity] = useState([]);
|
|
38
|
+
const [highlight, setHighlight] = useState(null);
|
|
39
|
+
const stateRefs = useRef({ notes, shapes, connectors, strokes, viewport });
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
stateRefs.current = { notes, shapes, connectors, strokes, viewport };
|
|
42
|
+
}, [notes, shapes, connectors, strokes, viewport]);
|
|
43
|
+
const serverRef = useRef(null);
|
|
44
|
+
const inProcRef = useRef(null);
|
|
45
|
+
const bridgeRef = useRef(null);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const server = new MicroMcpServer({
|
|
48
|
+
info: { name: "shared-whiteboard", version: "0.2.0" },
|
|
49
|
+
instructions: "Collaborative whiteboard. Use whiteboard_* tools to read or modify the board."
|
|
50
|
+
});
|
|
51
|
+
bridgeRef.current = registerWhiteboardBridge(server, {
|
|
52
|
+
adapter: {
|
|
53
|
+
getNotes: () => stateRefs.current.notes,
|
|
54
|
+
setNotes: (next) => setNotes(typeof next === "function" ? next : () => next),
|
|
55
|
+
getShapes: () => stateRefs.current.shapes,
|
|
56
|
+
setShapes: (next) => setShapes(typeof next === "function" ? next : () => next),
|
|
57
|
+
getConnectors: () => stateRefs.current.connectors,
|
|
58
|
+
setConnectors: (next) => setConnectors(typeof next === "function" ? next : () => next),
|
|
59
|
+
getStrokes: () => stateRefs.current.strokes,
|
|
60
|
+
setStrokes: (next) => setStrokes(typeof next === "function" ? next : () => next),
|
|
61
|
+
getViewport: () => stateRefs.current.viewport,
|
|
62
|
+
setViewport,
|
|
63
|
+
setAgentCursor
|
|
64
|
+
},
|
|
65
|
+
agent
|
|
66
|
+
});
|
|
67
|
+
inProcRef.current = attachInProcess(server);
|
|
68
|
+
serverRef.current = server;
|
|
69
|
+
const off = inProcRef.current.onServerMessage((msg) => {
|
|
70
|
+
if (msg?.id !== void 0 && "result" in msg && msg.result?.structuredContent?.id) {
|
|
71
|
+
const id = msg.result.structuredContent.id;
|
|
72
|
+
requestAnimationFrame(() => pulseFor(id));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return () => {
|
|
76
|
+
off();
|
|
77
|
+
bridgeRef.current?.dispose();
|
|
78
|
+
bridgeRef.current = null;
|
|
79
|
+
if (inProcRef.current) server.detach(inProcRef.current);
|
|
80
|
+
};
|
|
81
|
+
}, []);
|
|
82
|
+
const pulseFor = (id) => {
|
|
83
|
+
const n = stateRefs.current.notes.find((x) => x.id === id);
|
|
84
|
+
if (n) return setHighlight({ pulseKey: Date.now(), bounds: { x: n.x, y: n.y, width: n.width, height: n.height } });
|
|
85
|
+
const s = stateRefs.current.shapes.find((x) => x.id === id);
|
|
86
|
+
if (s) return setHighlight({ pulseKey: Date.now(), bounds: { x: s.x, y: s.y, width: s.width, height: s.height } });
|
|
87
|
+
};
|
|
88
|
+
const log = useCallback((entry) => {
|
|
89
|
+
setActivity((all) => [...all.slice(-200), { id: `a_${Date.now()}_${all.length}`, at: Date.now(), ...entry }]);
|
|
90
|
+
}, []);
|
|
91
|
+
const [session, setSession] = useState(null);
|
|
92
|
+
const [relayState, setRelayState] = useState("idle");
|
|
93
|
+
const sseRef = useRef(null);
|
|
94
|
+
const logEsRef = useRef(null);
|
|
95
|
+
const startShare = async () => {
|
|
96
|
+
if (session || !serverRef.current || !shareBaseUrl) return;
|
|
97
|
+
const desc = createSessionDescriptor();
|
|
98
|
+
try {
|
|
99
|
+
if (onRegisterSession) {
|
|
100
|
+
await onRegisterSession(desc);
|
|
101
|
+
} else {
|
|
102
|
+
const csrf = document.querySelector('meta[name="csrf-token"]')?.content ?? "";
|
|
103
|
+
const reg = await fetch(`${shareBaseUrl}/register`, {
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers: { "content-type": "application/json", "x-csrf-token": csrf, accept: "application/json" },
|
|
106
|
+
body: JSON.stringify({ session: desc.id, token: desc.token })
|
|
107
|
+
});
|
|
108
|
+
if (!reg.ok) throw new Error(`registration failed (HTTP ${reg.status})`);
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
log({ kind: "error", source: "share", text: e instanceof Error ? e.message : String(e) });
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const relay = attachSseRelay(serverRef.current, {
|
|
115
|
+
baseUrl: shareBaseUrl,
|
|
116
|
+
sessionId: desc.id,
|
|
117
|
+
token: desc.token
|
|
118
|
+
});
|
|
119
|
+
sseRef.current = relay;
|
|
120
|
+
relay.onStateChange(setRelayState);
|
|
121
|
+
const es = new EventSource(`${shareBaseUrl}/${desc.id}/events?token=${desc.token}&direction=inbound`);
|
|
122
|
+
es.addEventListener("mcp", (ev) => {
|
|
123
|
+
try {
|
|
124
|
+
const frame = JSON.parse(ev.data);
|
|
125
|
+
if (frame.method === "notifications/peer_joined") {
|
|
126
|
+
setAgentCursor((c) => c ?? { userId: agent.id, name: agent.name, color: agent.color, x: 60, y: 60 });
|
|
127
|
+
log({ kind: "info", source: "presence", text: `${agent.name ?? "Agent"} connected` });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (frame.method === "notifications/peer_left") {
|
|
131
|
+
setAgentCursor(null);
|
|
132
|
+
log({ kind: "info", source: "presence", text: `${agent.name ?? "Agent"} disconnected` });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (frame.method === "notifications/agent_message") {
|
|
136
|
+
log({ kind: "message", source: agent.name ?? "Agent", text: String(frame.params?.text ?? "") });
|
|
137
|
+
} else if (frame.method === "notifications/agent_status") {
|
|
138
|
+
log({ kind: "info", source: agent.name ?? "Agent", text: String(frame.params?.text ?? "") });
|
|
139
|
+
} else if (frame.method?.startsWith("notifications/")) {
|
|
140
|
+
} else {
|
|
141
|
+
log({ kind: "tool", source: "remote", text: `\u2190 ${frame.method ?? `id:${frame.id}`}`, detail: frame });
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
logEsRef.current = es;
|
|
147
|
+
setSession(desc);
|
|
148
|
+
log({ kind: "info", source: "share", text: `Sharing started \xB7 session ${desc.id}` });
|
|
149
|
+
};
|
|
150
|
+
const stopShare = async () => {
|
|
151
|
+
if (!session) return;
|
|
152
|
+
const desc = session;
|
|
153
|
+
setSession(null);
|
|
154
|
+
logEsRef.current?.close();
|
|
155
|
+
logEsRef.current = null;
|
|
156
|
+
if (sseRef.current && serverRef.current) serverRef.current.detach(sseRef.current);
|
|
157
|
+
sseRef.current = null;
|
|
158
|
+
setRelayState("closed");
|
|
159
|
+
if (shareBaseUrl) {
|
|
160
|
+
const csrf = document.querySelector('meta[name="csrf-token"]')?.content ?? "";
|
|
161
|
+
await fetch(`${shareBaseUrl}/${desc.id}/unregister?token=${encodeURIComponent(desc.token)}`, {
|
|
162
|
+
method: "POST",
|
|
163
|
+
headers: { "x-csrf-token": csrf, accept: "application/json" }
|
|
164
|
+
}).catch(() => {
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
log({ kind: "info", source: "share", text: "Sharing stopped." });
|
|
168
|
+
};
|
|
169
|
+
const lastBroadcastRef = useRef(0);
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (!broadcastEdits || !sseRef.current || !session) return;
|
|
172
|
+
const now = Date.now();
|
|
173
|
+
if (now - lastBroadcastRef.current < 80) return;
|
|
174
|
+
lastBroadcastRef.current = now;
|
|
175
|
+
sseRef.current.send({
|
|
176
|
+
jsonrpc: "2.0",
|
|
177
|
+
method: "notifications/state_update",
|
|
178
|
+
params: { notes, shapes, connectors, viewport, ts: now }
|
|
179
|
+
});
|
|
180
|
+
}, [notes, shapes, connectors, viewport, session, broadcastEdits]);
|
|
181
|
+
const handleSubmit = (text) => {
|
|
182
|
+
if (!sseRef.current) {
|
|
183
|
+
log({ kind: "error", source: "you", text: "Start a shared session first." });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
sseRef.current.send({
|
|
187
|
+
jsonrpc: "2.0",
|
|
188
|
+
method: "notifications/user_message",
|
|
189
|
+
params: { text, ts: Date.now() }
|
|
190
|
+
});
|
|
191
|
+
log({ kind: "message", source: "You", text });
|
|
192
|
+
};
|
|
193
|
+
const cursors = useMemo(() => [], []);
|
|
194
|
+
const statusText = (() => {
|
|
195
|
+
switch (relayState) {
|
|
196
|
+
case "open":
|
|
197
|
+
return "live";
|
|
198
|
+
case "connecting":
|
|
199
|
+
return "connecting\u2026";
|
|
200
|
+
case "error":
|
|
201
|
+
return "error";
|
|
202
|
+
case "closed":
|
|
203
|
+
return "closed";
|
|
204
|
+
default:
|
|
205
|
+
return void 0;
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
208
|
+
return /* @__PURE__ */ jsxs("div", { className: ["fai-shared-whiteboard", className ?? ""].filter(Boolean).join(" "), style, children: [
|
|
209
|
+
header,
|
|
210
|
+
showShareControls && shareBaseUrl !== null && /* @__PURE__ */ jsx("div", { className: "fai-shared-whiteboard__controls", children: /* @__PURE__ */ jsx(ShareControls, { session, onStart: startShare, onStop: stopShare, status: statusText }) }),
|
|
211
|
+
/* @__PURE__ */ jsxs(
|
|
212
|
+
"div",
|
|
213
|
+
{
|
|
214
|
+
className: "fai-shared-whiteboard__layout",
|
|
215
|
+
style: {
|
|
216
|
+
display: "grid",
|
|
217
|
+
gap: 16,
|
|
218
|
+
gridTemplateColumns: showAgentPanel ? "1fr 360px" : "1fr"
|
|
219
|
+
},
|
|
220
|
+
children: [
|
|
221
|
+
/* @__PURE__ */ jsx(
|
|
222
|
+
"div",
|
|
223
|
+
{
|
|
224
|
+
className: "fai-shared-whiteboard__board",
|
|
225
|
+
style: {
|
|
226
|
+
position: "relative",
|
|
227
|
+
overflow: "hidden",
|
|
228
|
+
borderRadius: 12,
|
|
229
|
+
border: "1px solid #e4e4e7",
|
|
230
|
+
background: "radial-gradient(circle at 1px 1px, rgba(0,0,0,0.07) 1px, transparent 0)",
|
|
231
|
+
backgroundSize: "20px 20px",
|
|
232
|
+
height
|
|
233
|
+
},
|
|
234
|
+
children: /* @__PURE__ */ jsxs(Board, { viewport, onViewportChange: setViewport, style: { width: "100%", height: "100%" }, children: [
|
|
235
|
+
connectors.map((c) => {
|
|
236
|
+
const a = resolveCenter(c.from, notes, shapes);
|
|
237
|
+
const b = resolveCenter(c.to, notes, shapes);
|
|
238
|
+
if (!a || !b) return null;
|
|
239
|
+
return /* @__PURE__ */ jsx(Connector, { from: a, to: b, color: c.color ?? "#64748b" }, c.id);
|
|
240
|
+
}),
|
|
241
|
+
shapes.map((s) => /* @__PURE__ */ jsx(Shape, { item: s, onChange: (next) => setShapes((all) => all.map((x) => x.id === next.id ? next : x)) }, s.id)),
|
|
242
|
+
notes.map((n) => /* @__PURE__ */ jsx(StickyNote, { item: n, onChange: (next) => setNotes((all) => all.map((x) => x.id === next.id ? next : x)) }, n.id)),
|
|
243
|
+
/* @__PURE__ */ jsx(CursorLayer, { cursors }),
|
|
244
|
+
agentCursor && /* @__PURE__ */ jsx(AgentCursor, { x: agentCursor.x, y: agentCursor.y, name: agentCursor.name, color: agentCursor.color }),
|
|
245
|
+
highlight && /* @__PURE__ */ jsx(
|
|
246
|
+
AgentActivityHighlight,
|
|
247
|
+
{
|
|
248
|
+
x: highlight.bounds.x,
|
|
249
|
+
y: highlight.bounds.y,
|
|
250
|
+
width: highlight.bounds.width,
|
|
251
|
+
height: highlight.bounds.height,
|
|
252
|
+
color: agent.color ?? "#a855f7",
|
|
253
|
+
pulseKey: highlight.pulseKey
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
] })
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
showAgentPanel && /* @__PURE__ */ jsx("div", { style: { height }, children: /* @__PURE__ */ jsx(
|
|
260
|
+
AgentPanel,
|
|
261
|
+
{
|
|
262
|
+
agent,
|
|
263
|
+
activity,
|
|
264
|
+
onSubmit: handleSubmit
|
|
265
|
+
}
|
|
266
|
+
) })
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
function resolveCenter(ref, notes, shapes) {
|
|
273
|
+
if (typeof ref === "string") {
|
|
274
|
+
const n = notes.find((x) => x.id === ref);
|
|
275
|
+
if (n) return { x: n.x + n.width / 2, y: n.y + n.height / 2 };
|
|
276
|
+
const s = shapes.find((x) => x.id === ref);
|
|
277
|
+
if (s) return { x: s.x + s.width / 2, y: s.y + s.height / 2 };
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
return ref;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export { SharedWhiteboard };
|
|
284
|
+
//# sourceMappingURL=components-shared-whiteboard.js.map
|
|
285
|
+
//# sourceMappingURL=components-shared-whiteboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SharedWhiteboard/SharedWhiteboard.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAqEA,IAAM,gBAAgB,EAAE,EAAA,EAAI,SAAS,IAAA,EAAM,OAAA,EAAS,OAAO,SAAA,EAAU;AAW9D,SAAS,gBAAA,CAAiB;AAAA,EAC/B,eAAe,EAAC;AAAA,EAChB,gBAAgB,EAAC;AAAA,EACjB,oBAAoB,EAAC;AAAA,EACrB,iBAAiB,EAAC;AAAA,EAClB,kBAAkB,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,MAAM,CAAA,EAAE;AAAA,EACxC,KAAA,GAAQ,aAAA;AAAA,EACR,YAAA,GAAe,mBAAA;AAAA,EACf,iBAAA;AAAA,EACA,cAAA,GAAiB,IAAA;AAAA,EACjB,iBAAA,GAAoB,IAAA;AAAA,EACpB,cAAA,GAAiB,IAAA;AAAA,EACjB,MAAA,GAAS,GAAA;AAAA,EACT,MAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAA0B;AAExB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAA2B,YAAY,CAAA;AACjE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAsB,aAAa,CAAA;AAC/D,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAA0B,iBAAiB,CAAA;AAC/E,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAmB,cAAc,CAAA;AAC/D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAmB,eAAe,CAAA;AAClE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAA8B,IAAI,CAAA;AAGxE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAA0B,EAAE,CAAA;AAC5D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAuG,IAAI,CAAA;AAE7I,EAAA,MAAM,SAAA,GAAY,OAAO,EAAE,KAAA,EAAO,QAAQ,UAAA,EAAY,OAAA,EAAS,UAAU,CAAA;AACzE,EAAA,SAAA,CAAU,MAAM;AAAE,IAAA,SAAA,CAAU,UAAU,EAAE,KAAA,EAAO,MAAA,EAAQ,UAAA,EAAY,SAAS,QAAA,EAAS;AAAA,EAAG,GAAG,CAAC,KAAA,EAAO,QAAQ,UAAA,EAAY,OAAA,EAAS,QAAQ,CAAC,CAAA;AAGzI,EAAA,MAAM,SAAA,GAAY,OAA8B,IAAI,CAAA;AACpD,EAAA,MAAM,SAAA,GAAY,OAAkC,IAAI,CAAA;AACxD,EAAA,MAAM,SAAA,GAAY,OAAsB,IAAI,CAAA;AAE5C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAAe;AAAA,MAChC,IAAA,EAAM,EAAE,IAAA,EAAM,mBAAA,EAAqB,SAAS,OAAA,EAAQ;AAAA,MACpD,YAAA,EAAc;AAAA,KACf,CAAA;AACD,IAAA,SAAA,CAAU,OAAA,GAAU,yBAAyB,MAAA,EAAQ;AAAA,MACnD,OAAA,EAAS;AAAA,QACP,QAAA,EAAU,MAAM,SAAA,CAAU,OAAA,CAAQ,KAAA;AAAA,QAClC,QAAA,EAAU,CAAC,IAAA,KAAS,QAAA,CAAS,OAAO,IAAA,KAAS,UAAA,GAAa,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,QAC3E,SAAA,EAAW,MAAM,SAAA,CAAU,OAAA,CAAQ,MAAA;AAAA,QACnC,SAAA,EAAW,CAAC,IAAA,KAAS,SAAA,CAAU,OAAO,IAAA,KAAS,UAAA,GAAa,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,QAC7E,aAAA,EAAe,MAAM,SAAA,CAAU,OAAA,CAAQ,UAAA;AAAA,QACvC,aAAA,EAAe,CAAC,IAAA,KAAS,aAAA,CAAc,OAAO,IAAA,KAAS,UAAA,GAAa,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,QACrF,UAAA,EAAY,MAAM,SAAA,CAAU,OAAA,CAAQ,OAAA;AAAA,QACpC,UAAA,EAAY,CAAC,IAAA,KAAS,UAAA,CAAW,OAAO,IAAA,KAAS,UAAA,GAAa,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,QAC/E,WAAA,EAAa,MAAM,SAAA,CAAU,OAAA,CAAQ,QAAA;AAAA,QACrC,WAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA;AAAA,KACD,CAAA;AACD,IAAA,SAAA,CAAU,OAAA,GAAU,gBAAgB,MAAM,CAAA;AAC1C,IAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAGpB,IAAA,MAAM,GAAA,GAAM,SAAA,CAAU,OAAA,CAAQ,eAAA,CAAgB,CAAC,GAAA,KAAa;AAC1D,MAAA,IAAI,GAAA,EAAK,OAAO,MAAA,IAAa,QAAA,IAAY,OAAO,GAAA,CAAI,MAAA,EAAQ,mBAAmB,EAAA,EAAI;AACjF,QAAA,MAAM,EAAA,GAAK,GAAA,CAAI,MAAA,CAAO,iBAAA,CAAkB,EAAA;AACxC,QAAA,qBAAA,CAAsB,MAAM,QAAA,CAAS,EAAE,CAAC,CAAA;AAAA,MAC1C;AAAA,IACF,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,EAAI;AACJ,MAAA,SAAA,CAAU,SAAS,OAAA,EAAQ;AAC3B,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,MAAA,IAAI,SAAA,CAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAU,OAAO,CAAA;AAAA,IACxD,CAAA;AAAA,EAEF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAW,CAAC,EAAA,KAAe;AAC/B,IAAA,MAAM,CAAA,GAAI,UAAU,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA;AACzD,IAAA,IAAI,CAAA,SAAU,YAAA,CAAa,EAAE,UAAU,IAAA,CAAK,GAAA,EAAI,EAAG,MAAA,EAAQ,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,OAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,EAAG,CAAA;AACjH,IAAA,MAAM,CAAA,GAAI,UAAU,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA;AAC1D,IAAA,IAAI,CAAA,SAAU,YAAA,CAAa,EAAE,UAAU,IAAA,CAAK,GAAA,EAAI,EAAG,MAAA,EAAQ,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,OAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,EAAG,CAAA;AAAA,EACnH,CAAA;AAEA,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,CAAC,KAAA,KAA4C;AACnE,IAAA,WAAA,CAAY,CAAC,GAAA,KAAQ,CAAC,GAAG,GAAA,CAAI,MAAM,IAAI,CAAA,EAAG,EAAE,EAAA,EAAI,CAAA,EAAA,EAAK,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,EAAA,EAAI,IAAA,CAAK,GAAA,EAAI,EAAG,GAAG,KAAA,EAAO,CAAC,CAAA;AAAA,EAC9G,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAmC,IAAI,CAAA;AACrE,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAqB,MAAM,CAAA;AAC/D,EAAA,MAAM,MAAA,GAAS,OAAiC,IAAI,CAAA;AACpD,EAAA,MAAM,QAAA,GAAW,OAA2B,IAAI,CAAA;AAEhD,EAAA,MAAM,aAAa,YAAY;AAC7B,IAAA,IAAI,OAAA,IAAW,CAAC,SAAA,CAAU,OAAA,IAAW,CAAC,YAAA,EAAc;AACpD,IAAA,MAAM,OAAO,uBAAA,EAAwB;AAErC,IAAA,IAAI;AACF,MAAA,IAAI,iBAAA,EAAmB;AACrB,QAAA,MAAM,kBAAkB,IAAI,CAAA;AAAA,MAC9B,CAAA,MAAO;AACL,QAAA,MAAM,IAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,yBAAyB,GAA8B,OAAA,IAAW,EAAA;AACvG,QAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,SAAA,CAAA,EAAa;AAAA,UAClD,MAAA,EAAQ,MAAA;AAAA,UACR,SAAS,EAAE,cAAA,EAAgB,oBAAoB,cAAA,EAAgB,IAAA,EAAM,QAAQ,kBAAA,EAAmB;AAAA,UAChG,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAA,EAAS,KAAK,EAAA,EAAI,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO;AAAA,SAC7D,CAAA;AACD,QAAA,IAAI,CAAC,IAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,GAAA,CAAI,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,MACzE;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,GAAA,CAAI,EAAE,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,MAAA,CAAO,CAAC,GAAG,CAAA;AACxF,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,SAAA,CAAU,OAAA,EAAS;AAAA,MAC9C,OAAA,EAAS,YAAA;AAAA,MACT,WAAW,IAAA,CAAK,EAAA;AAAA,MAChB,OAAO,IAAA,CAAK;AAAA,KACb,CAAA;AACD,IAAA,MAAA,CAAO,OAAA,GAAU,KAAA;AACjB,IAAA,KAAA,CAAM,cAAc,aAAa,CAAA;AAGjC,IAAA,MAAM,EAAA,GAAK,IAAI,WAAA,CAAY,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,IAAA,CAAK,EAAE,CAAA,cAAA,EAAiB,IAAA,CAAK,KAAK,CAAA,kBAAA,CAAoB,CAAA;AACpG,IAAA,EAAA,CAAG,gBAAA,CAAiB,KAAA,EAAO,CAAC,EAAA,KAAqB;AAC/C,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,IAAI,CAAA;AAChC,QAAA,IAAI,KAAA,CAAM,WAAW,2BAAA,EAA6B;AAMhD,UAAA,cAAA,CAAe,CAAC,CAAA,KAAM,CAAA,IAAK,EAAE,MAAA,EAAQ,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,CAAM,IAAA,EAAM,OAAO,KAAA,CAAM,KAAA,EAAO,GAAG,EAAA,EAAI,CAAA,EAAG,IAAI,CAAA;AACnG,UAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,IAAA,EAAM,CAAA,EAAG,KAAA,CAAM,IAAA,IAAQ,OAAO,CAAA,UAAA,CAAA,EAAc,CAAA;AACpF,UAAA;AAAA,QACF;AACA,QAAA,IAAI,KAAA,CAAM,WAAW,yBAAA,EAA2B;AAC9C,UAAA,cAAA,CAAe,IAAI,CAAA;AACnB,UAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,IAAA,EAAM,CAAA,EAAG,KAAA,CAAM,IAAA,IAAQ,OAAO,CAAA,aAAA,CAAA,EAAiB,CAAA;AACvF,UAAA;AAAA,QACF;AACA,QAAA,IAAI,KAAA,CAAM,WAAW,6BAAA,EAA+B;AAClD,UAAA,GAAA,CAAI,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,MAAM,IAAA,IAAQ,OAAA,EAAS,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,MAAA,EAAQ,IAAA,IAAQ,EAAE,GAAG,CAAA;AAAA,QAChG,CAAA,MAAA,IAAW,KAAA,CAAM,MAAA,KAAW,4BAAA,EAA8B;AACxD,UAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,MAAM,IAAA,IAAQ,OAAA,EAAS,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,MAAA,EAAQ,IAAA,IAAQ,EAAE,GAAG,CAAA;AAAA,QAC7F,CAAA,MAAA,IAAW,KAAA,CAAM,MAAA,EAAQ,UAAA,CAAW,gBAAgB,CAAA,EAAG;AAAA,QAEvD,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,MAAM,CAAA,OAAA,EAAK,KAAA,CAAM,MAAA,IAAU,CAAA,GAAA,EAAM,MAAM,EAAE,CAAA,CAAE,CAAA,CAAA,EAAI,MAAA,EAAQ,OAAO,CAAA;AAAA,QACtG;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,OAAA,GAAU,EAAA;AAEnB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,MAAM,CAAA,6BAAA,EAA6B,IAAA,CAAK,EAAE,CAAA,CAAA,EAAI,CAAA;AAAA,EACrF,CAAA;AAEA,EAAA,MAAM,YAAY,YAAY;AAC5B,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,IAAA,GAAO,OAAA;AACb,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,IAAI,MAAA,CAAO,WAAW,SAAA,CAAU,OAAA,YAAmB,OAAA,CAAQ,MAAA,CAAO,OAAO,OAAO,CAAA;AAChF,IAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AACjB,IAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,IAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,yBAAyB,GAA8B,OAAA,IAAW,EAAA;AACvG,MAAA,MAAM,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,IAAA,CAAK,EAAE,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,QAC3F,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,IAAA,EAAM,QAAQ,kBAAA;AAAmB,OAC7D,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IACnB;AACA,IAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,OAAA,EAAS,IAAA,EAAM,oBAAoB,CAAA;AAAA,EACjE,CAAA;AAIA,EAAA,MAAM,gBAAA,GAAmB,OAAO,CAAC,CAAA;AACjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,OAAA,EAAS;AACpD,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,gBAAA,CAAiB,OAAA,GAAU,EAAA,EAAI;AACzC,IAAA,gBAAA,CAAiB,OAAA,GAAU,GAAA;AAC3B,IAAA,MAAA,CAAO,QAAQ,IAAA,CAAK;AAAA,MAClB,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,4BAAA;AAAA,MACR,QAAQ,EAAE,KAAA,EAAO,QAAQ,UAAA,EAAY,QAAA,EAAU,IAAI,GAAA;AAAI,KACxD,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,EAAO,MAAA,EAAQ,YAAY,QAAA,EAAU,OAAA,EAAS,cAAc,CAAC,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAe,CAAC,IAAA,KAAiB;AACrC,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,GAAA,CAAI,EAAE,IAAA,EAAM,OAAA,EAAS,QAAQ,KAAA,EAAO,IAAA,EAAM,iCAAiC,CAAA;AAC3E,MAAA;AAAA,IACF;AACA,IAAA,MAAA,CAAO,QAAQ,IAAA,CAAK;AAAA,MAClB,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,4BAAA;AAAA,MACR,QAAQ,EAAE,IAAA,EAAM,EAAA,EAAI,IAAA,CAAK,KAAI;AAAE,KAChC,CAAA;AACD,IAAA,GAAA,CAAI,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA;AAAA,EAC9C,CAAA;AAKA,EAAA,MAAM,UAA0B,OAAA,CAAQ,MAAM,EAAC,EAAG,EAAE,CAAA;AACpD,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,QAAQ,UAAA;AAAY,MAClB,KAAK,MAAA;AAAQ,QAAA,OAAO,MAAA;AAAA,MACpB,KAAK,YAAA;AAAc,QAAA,OAAO,kBAAA;AAAA,MAC1B,KAAK,OAAA;AAAS,QAAA,OAAO,OAAA;AAAA,MACrB,KAAK,QAAA;AAAU,QAAA,OAAO,QAAA;AAAA,MACtB;AAAS,QAAA,OAAO,MAAA;AAAA;AAClB,EACF,CAAA,GAAG;AAEH,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAC,yBAAyB,SAAA,IAAa,EAAE,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,GAAG,KAAA,EACnF,QAAA,EAAA;AAAA,IAAA,MAAA;AAAA,IACA,qBAAqB,YAAA,KAAiB,IAAA,oBACrC,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,iCAAA,EACb,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,OAAA,EAAkB,SAAS,UAAA,EAAY,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ,YAAY,CAAA,EAC/F,CAAA;AAAA,oBAEF,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,+BAAA;AAAA,QACV,KAAA,EAAO;AAAA,UACL,OAAA,EAAS,MAAA;AAAA,UACT,GAAA,EAAK,EAAA;AAAA,UACL,mBAAA,EAAqB,iBAAiB,WAAA,GAAc;AAAA,SACtD;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,8BAAA;AAAA,cACV,KAAA,EAAO;AAAA,gBACL,QAAA,EAAU,UAAA;AAAA,gBACV,QAAA,EAAU,QAAA;AAAA,gBACV,YAAA,EAAc,EAAA;AAAA,gBACd,MAAA,EAAQ,mBAAA;AAAA,gBACR,UAAA,EACE,yEAAA;AAAA,gBACF,cAAA,EAAgB,WAAA;AAAA,gBAChB;AAAA,eACF;AAAA,cAEA,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAM,QAAA,EAAoB,gBAAA,EAAkB,WAAA,EAAa,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO,EAC9F,QAAA,EAAA;AAAA,gBAAA,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM;AACrB,kBAAA,MAAM,CAAA,GAAI,aAAA,CAAc,CAAA,CAAE,IAAA,EAAM,OAAO,MAAM,CAAA;AAC7C,kBAAA,MAAM,CAAA,GAAI,aAAA,CAAc,CAAA,CAAE,EAAA,EAAI,OAAO,MAAM,CAAA;AAC3C,kBAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG,OAAO,IAAA;AACrB,kBAAA,uBAAO,GAAA,CAAC,SAAA,EAAA,EAAqB,IAAA,EAAM,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,KAAA,IAAS,SAAA,EAAA,EAAxC,CAAA,CAAE,EAAiD,CAAA;AAAA,gBAC5E,CAAC,CAAA;AAAA,gBACA,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,qBACX,GAAA,CAAC,KAAA,EAAA,EAAiB,IAAA,EAAM,CAAA,EAAG,QAAA,EAAU,CAAC,IAAA,KAAS,SAAA,CAAU,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,IAAA,CAAK,EAAA,GAAK,IAAA,GAAO,CAAE,CAAC,CAAA,EAAA,EAAnG,CAAA,CAAE,EAAoG,CACnH,CAAA;AAAA,gBACA,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,qBACV,GAAA,CAAC,UAAA,EAAA,EAAsB,IAAA,EAAM,CAAA,EAAG,QAAA,EAAU,CAAC,IAAA,KAAS,QAAA,CAAS,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,IAAA,CAAK,EAAA,GAAK,IAAA,GAAO,CAAE,CAAC,CAAA,EAAA,EAAlG,CAAA,CAAE,EAAmG,CACvH,CAAA;AAAA,gCACD,GAAA,CAAC,eAAY,OAAA,EAAkB,CAAA;AAAA,gBAC9B,WAAA,oBACC,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EAAG,YAAY,CAAA,EAAG,CAAA,EAAG,WAAA,CAAY,CAAA,EAAG,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,KAAA,EAAO,YAAY,KAAA,EAAO,CAAA;AAAA,gBAEpG,SAAA,oBACC,GAAA;AAAA,kBAAC,sBAAA;AAAA,kBAAA;AAAA,oBACC,CAAA,EAAG,UAAU,MAAA,CAAO,CAAA;AAAA,oBACpB,CAAA,EAAG,UAAU,MAAA,CAAO,CAAA;AAAA,oBACpB,KAAA,EAAO,UAAU,MAAA,CAAO,KAAA;AAAA,oBACxB,MAAA,EAAQ,UAAU,MAAA,CAAO,MAAA;AAAA,oBACzB,KAAA,EAAO,MAAM,KAAA,IAAS,SAAA;AAAA,oBACtB,UAAU,SAAA,CAAU;AAAA;AAAA;AACtB,eAAA,EAEJ;AAAA;AAAA,WACF;AAAA,UACC,kCACC,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAO,EACnB,QAAA,kBAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,KAAA;AAAA,cACA,QAAA;AAAA,cACA,QAAA,EAAU;AAAA;AAAA,WACZ,EACF;AAAA;AAAA;AAAA;AAEJ,GAAA,EACF,CAAA;AAEJ;AAEA,SAAS,aAAA,CACP,GAAA,EACA,KAAA,EACA,MAAA,EACiC;AACjC,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,GAAG,CAAA;AACxC,IAAA,IAAI,CAAA,EAAG,OAAO,EAAE,CAAA,EAAG,EAAE,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,SAAS,CAAA,EAAE;AAC5D,IAAA,MAAM,IAAI,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,GAAG,CAAA;AACzC,IAAA,IAAI,CAAA,EAAG,OAAO,EAAE,CAAA,EAAG,EAAE,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,SAAS,CAAA,EAAE;AAC5D,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA;AACT","file":"components-shared-whiteboard.js","sourcesContent":["import { type CSSProperties, type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n Board,\n StickyNote,\n Connector,\n Shape,\n CursorLayer,\n type StickyNoteItem,\n type ShapeItem,\n type ConnectorItem,\n type Stroke,\n type RemoteCursor,\n type Viewport,\n} from \"@particle-academy/fancy-whiteboard\";\nimport { MicroMcpServer, type Transport } from \"../../mcp/server\";\nimport { attachInProcess, type InProcessTransport } from \"../../mcp/transports/in-process\";\nimport { attachSseRelay, type RelayState, type SseRelayTransport } from \"../../sharing/sse-relay\";\nimport { createSessionDescriptor, type SessionDescriptor } from \"../../sharing/token\";\nimport { registerWhiteboardBridge } from \"../../bridges/whiteboard\";\nimport type { Bridge } from \"../../bridges/types\";\nimport { ShareControls } from \"../ShareControls\";\nimport { AgentPanel, type AgentActivity } from \"../AgentPanel\";\nimport { AgentCursor } from \"../AgentCursor\";\nimport { AgentActivityHighlight } from \"../AgentActivityHighlight\";\n\nexport type SharedWhiteboardProps = {\n /** Initial board contents. */\n initialNotes?: StickyNoteItem[];\n initialShapes?: ShapeItem[];\n initialConnectors?: ConnectorItem[];\n initialStrokes?: Stroke[];\n initialViewport?: Viewport;\n\n /** Agent identity displayed in the panel + cursor. */\n agent?: { id: string; name?: string; color?: string };\n\n /**\n * Where the relay HTTP endpoints live. The host app implements these (see\n * docs/relay-protocol.md). Pass `null` to disable sharing — the board\n * still works locally with the in-process MCP server.\n */\n shareBaseUrl?: string | null;\n\n /**\n * Optional callback to register a new session token with the host's\n * relay broker. Receives `{ session, token }` and should return after\n * registration. Defaults to POSTing JSON to `${shareBaseUrl}/register`.\n */\n onRegisterSession?: (descriptor: SessionDescriptor) => Promise<void>;\n\n /** Show the agent panel. Default true. */\n showAgentPanel?: boolean;\n\n /** Show share controls. Default true. */\n showShareControls?: boolean;\n\n /** Auto-broadcast local edits as `notifications/state_update`. Default true. */\n broadcastEdits?: boolean;\n\n /** Pixel height of the board area. Default 640. */\n height?: number;\n\n /** Header content rendered above the board. */\n header?: ReactNode;\n\n className?: string;\n style?: CSSProperties;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * SharedWhiteboard — drop-in component that bundles every piece of the\n * \"agent-collaborative whiteboard\" UX: board with all primitives, in-page\n * MCP server, share controls, agent panel, presence cursor, activity\n * highlight, and outbound state broadcast.\n *\n * Most apps only need this one component. For deeper customization, swap\n * it for the lower-level primitives (Board, MicroMcpServer, ShareControls).\n */\nexport function SharedWhiteboard({\n initialNotes = [],\n initialShapes = [],\n initialConnectors = [],\n initialStrokes = [],\n initialViewport = { x: 0, y: 0, zoom: 1 },\n agent = DEFAULT_AGENT,\n shareBaseUrl = \"/whiteboard-share\",\n onRegisterSession,\n showAgentPanel = true,\n showShareControls = true,\n broadcastEdits = true,\n height = 640,\n header,\n className,\n style,\n}: SharedWhiteboardProps) {\n // Board state\n const [notes, setNotes] = useState<StickyNoteItem[]>(initialNotes);\n const [shapes, setShapes] = useState<ShapeItem[]>(initialShapes);\n const [connectors, setConnectors] = useState<ConnectorItem[]>(initialConnectors);\n const [strokes, setStrokes] = useState<Stroke[]>(initialStrokes);\n const [viewport, setViewport] = useState<Viewport>(initialViewport);\n const [agentCursor, setAgentCursor] = useState<RemoteCursor | null>(null);\n\n // Agent UX state\n const [activity, setActivity] = useState<AgentActivity[]>([]);\n const [highlight, setHighlight] = useState<{ pulseKey: number; bounds: { x: number; y: number; width: number; height: number } } | null>(null);\n\n const stateRefs = useRef({ notes, shapes, connectors, strokes, viewport });\n useEffect(() => { stateRefs.current = { notes, shapes, connectors, strokes, viewport }; }, [notes, shapes, connectors, strokes, viewport]);\n\n // MCP server + bridge\n const serverRef = useRef<MicroMcpServer | null>(null);\n const inProcRef = useRef<InProcessTransport | null>(null);\n const bridgeRef = useRef<Bridge | null>(null);\n\n useEffect(() => {\n const server = new MicroMcpServer({\n info: { name: \"shared-whiteboard\", version: \"0.2.0\" },\n instructions: \"Collaborative whiteboard. Use whiteboard_* tools to read or modify the board.\",\n });\n bridgeRef.current = registerWhiteboardBridge(server, {\n adapter: {\n getNotes: () => stateRefs.current.notes,\n setNotes: (next) => setNotes(typeof next === \"function\" ? next : () => next),\n getShapes: () => stateRefs.current.shapes,\n setShapes: (next) => setShapes(typeof next === \"function\" ? next : () => next),\n getConnectors: () => stateRefs.current.connectors,\n setConnectors: (next) => setConnectors(typeof next === \"function\" ? next : () => next),\n getStrokes: () => stateRefs.current.strokes,\n setStrokes: (next) => setStrokes(typeof next === \"function\" ? next : () => next),\n getViewport: () => stateRefs.current.viewport,\n setViewport,\n setAgentCursor,\n },\n agent,\n });\n inProcRef.current = attachInProcess(server);\n serverRef.current = server;\n\n // Pulse a highlight whenever a tool call returns a structured id.\n const off = inProcRef.current.onServerMessage((msg: any) => {\n if (msg?.id !== undefined && \"result\" in msg && msg.result?.structuredContent?.id) {\n const id = msg.result.structuredContent.id;\n requestAnimationFrame(() => pulseFor(id));\n }\n });\n return () => {\n off();\n bridgeRef.current?.dispose();\n bridgeRef.current = null;\n if (inProcRef.current) server.detach(inProcRef.current);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const pulseFor = (id: string) => {\n const n = stateRefs.current.notes.find((x) => x.id === id);\n if (n) return setHighlight({ pulseKey: Date.now(), bounds: { x: n.x, y: n.y, width: n.width, height: n.height } });\n const s = stateRefs.current.shapes.find((x) => x.id === id);\n if (s) return setHighlight({ pulseKey: Date.now(), bounds: { x: s.x, y: s.y, width: s.width, height: s.height } });\n };\n\n const log = useCallback((entry: Omit<AgentActivity, \"id\" | \"at\">) => {\n setActivity((all) => [...all.slice(-200), { id: `a_${Date.now()}_${all.length}`, at: Date.now(), ...entry }]);\n }, []);\n\n // Sharing\n const [session, setSession] = useState<SessionDescriptor | null>(null);\n const [relayState, setRelayState] = useState<RelayState>(\"idle\");\n const sseRef = useRef<SseRelayTransport | null>(null);\n const logEsRef = useRef<EventSource | null>(null);\n\n const startShare = async () => {\n if (session || !serverRef.current || !shareBaseUrl) return;\n const desc = createSessionDescriptor();\n\n try {\n if (onRegisterSession) {\n await onRegisterSession(desc);\n } else {\n const csrf = (document.querySelector('meta[name=\"csrf-token\"]') as HTMLMetaElement | null)?.content ?? \"\";\n const reg = await fetch(`${shareBaseUrl}/register`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-csrf-token\": csrf, accept: \"application/json\" },\n body: JSON.stringify({ session: desc.id, token: desc.token }),\n });\n if (!reg.ok) throw new Error(`registration failed (HTTP ${reg.status})`);\n }\n } catch (e) {\n log({ kind: \"error\", source: \"share\", text: e instanceof Error ? e.message : String(e) });\n return;\n }\n\n const relay = attachSseRelay(serverRef.current, {\n baseUrl: shareBaseUrl,\n sessionId: desc.id,\n token: desc.token,\n });\n sseRef.current = relay;\n relay.onStateChange(setRelayState);\n\n // Activity log mirror — does NOT call deliverFromRemote (relay does it).\n const es = new EventSource(`${shareBaseUrl}/${desc.id}/events?token=${desc.token}&direction=inbound`);\n es.addEventListener(\"mcp\", (ev: MessageEvent) => {\n try {\n const frame = JSON.parse(ev.data);\n if (frame.method === \"notifications/peer_joined\") {\n // External agent just opened an outbound subscription. Surface it\n // so the human can see \"an agent is connecting\" before any tools\n // arrive. The agent itself should follow up with set_agent_cursor\n // immediately, but in case it doesn't, drop a placeholder cursor\n // at the canvas origin so presence is visible right away.\n setAgentCursor((c) => c ?? { userId: agent.id, name: agent.name, color: agent.color, x: 60, y: 60 });\n log({ kind: \"info\", source: \"presence\", text: `${agent.name ?? \"Agent\"} connected` });\n return;\n }\n if (frame.method === \"notifications/peer_left\") {\n setAgentCursor(null);\n log({ kind: \"info\", source: \"presence\", text: `${agent.name ?? \"Agent\"} disconnected` });\n return;\n }\n if (frame.method === \"notifications/agent_message\") {\n log({ kind: \"message\", source: agent.name ?? \"Agent\", text: String(frame.params?.text ?? \"\") });\n } else if (frame.method === \"notifications/agent_status\") {\n log({ kind: \"info\", source: agent.name ?? \"Agent\", text: String(frame.params?.text ?? \"\") });\n } else if (frame.method?.startsWith(\"notifications/\")) {\n // ignore other notifications in the feed\n } else {\n log({ kind: \"tool\", source: \"remote\", text: `← ${frame.method ?? `id:${frame.id}`}`, detail: frame });\n }\n } catch {\n /* noop */\n }\n });\n logEsRef.current = es;\n\n setSession(desc);\n log({ kind: \"info\", source: \"share\", text: `Sharing started · session ${desc.id}` });\n };\n\n const stopShare = async () => {\n if (!session) return;\n const desc = session;\n setSession(null);\n logEsRef.current?.close();\n logEsRef.current = null;\n if (sseRef.current && serverRef.current) serverRef.current.detach(sseRef.current);\n sseRef.current = null;\n setRelayState(\"closed\");\n if (shareBaseUrl) {\n const csrf = (document.querySelector('meta[name=\"csrf-token\"]') as HTMLMetaElement | null)?.content ?? \"\";\n await fetch(`${shareBaseUrl}/${desc.id}/unregister?token=${encodeURIComponent(desc.token)}`, {\n method: \"POST\",\n headers: { \"x-csrf-token\": csrf, accept: \"application/json\" },\n }).catch(() => {});\n }\n log({ kind: \"info\", source: \"share\", text: \"Sharing stopped.\" });\n };\n\n // Outbound state broadcast — every state change pushes a notification on\n // the relay (capped to ~12 Hz) so external agents see human edits live.\n const lastBroadcastRef = useRef(0);\n useEffect(() => {\n if (!broadcastEdits || !sseRef.current || !session) return;\n const now = Date.now();\n if (now - lastBroadcastRef.current < 80) return;\n lastBroadcastRef.current = now;\n sseRef.current.send({\n jsonrpc: \"2.0\",\n method: \"notifications/state_update\",\n params: { notes, shapes, connectors, viewport, ts: now },\n });\n }, [notes, shapes, connectors, viewport, session, broadcastEdits]);\n\n const handleSubmit = (text: string) => {\n if (!sseRef.current) {\n log({ kind: \"error\", source: \"you\", text: \"Start a shared session first.\" });\n return;\n }\n sseRef.current.send({\n jsonrpc: \"2.0\",\n method: \"notifications/user_message\",\n params: { text, ts: Date.now() },\n });\n log({ kind: \"message\", source: \"You\", text });\n };\n\n // The agent cursor is rendered by <AgentCursor> below — keep it OUT of\n // the cursors array so we don't double-render it via CursorLayer.\n // (CursorLayer is reserved for human participants once relay sync lands.)\n const cursors: RemoteCursor[] = useMemo(() => [], []);\n const statusText = (() => {\n switch (relayState) {\n case \"open\": return \"live\";\n case \"connecting\": return \"connecting…\";\n case \"error\": return \"error\";\n case \"closed\": return \"closed\";\n default: return undefined;\n }\n })();\n\n return (\n <div className={[\"fai-shared-whiteboard\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n {header}\n {showShareControls && shareBaseUrl !== null && (\n <div className=\"fai-shared-whiteboard__controls\">\n <ShareControls session={session} onStart={startShare} onStop={stopShare} status={statusText} />\n </div>\n )}\n <div\n className=\"fai-shared-whiteboard__layout\"\n style={{\n display: \"grid\",\n gap: 16,\n gridTemplateColumns: showAgentPanel ? \"1fr 360px\" : \"1fr\",\n }}\n >\n <div\n className=\"fai-shared-whiteboard__board\"\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n borderRadius: 12,\n border: \"1px solid #e4e4e7\",\n background:\n \"radial-gradient(circle at 1px 1px, rgba(0,0,0,0.07) 1px, transparent 0)\",\n backgroundSize: \"20px 20px\",\n height,\n }}\n >\n <Board viewport={viewport} onViewportChange={setViewport} style={{ width: \"100%\", height: \"100%\" }}>\n {connectors.map((c) => {\n const a = resolveCenter(c.from, notes, shapes);\n const b = resolveCenter(c.to, notes, shapes);\n if (!a || !b) return null;\n return <Connector key={c.id} from={a} to={b} color={c.color ?? \"#64748b\"} />;\n })}\n {shapes.map((s) => (\n <Shape key={s.id} item={s} onChange={(next) => setShapes((all) => all.map((x) => (x.id === next.id ? next : x)))} />\n ))}\n {notes.map((n) => (\n <StickyNote key={n.id} item={n} onChange={(next) => setNotes((all) => all.map((x) => (x.id === next.id ? next : x)))} />\n ))}\n <CursorLayer cursors={cursors} />\n {agentCursor && (\n <AgentCursor x={agentCursor.x} y={agentCursor.y} name={agentCursor.name} color={agentCursor.color} />\n )}\n {highlight && (\n <AgentActivityHighlight\n x={highlight.bounds.x}\n y={highlight.bounds.y}\n width={highlight.bounds.width}\n height={highlight.bounds.height}\n color={agent.color ?? \"#a855f7\"}\n pulseKey={highlight.pulseKey}\n />\n )}\n </Board>\n </div>\n {showAgentPanel && (\n <div style={{ height }}>\n <AgentPanel\n agent={agent}\n activity={activity}\n onSubmit={handleSubmit}\n />\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction resolveCenter(\n ref: ConnectorItem[\"from\"],\n notes: StickyNoteItem[],\n shapes: ShapeItem[],\n): { x: number; y: number } | null {\n if (typeof ref === \"string\") {\n const n = notes.find((x) => x.id === ref);\n if (n) return { x: n.x + n.width / 2, y: n.y + n.height / 2 };\n const s = shapes.find((x) => x.id === ref);\n if (s) return { x: s.x + s.width / 2, y: s.y + s.height / 2 };\n return null;\n }\n return ref;\n}\n\n// Internal-import safety\ntype _UseTransport = Transport;\n"]}
|