ui-agent-annotation 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1783 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
31
+
32
+ // src/index.tsx
33
+ var index_exports = {};
34
+ __export(index_exports, {
35
+ AgentAnnotationProvider: () => AgentAnnotationProvider2,
36
+ AnnotationInput: () => AnnotationInput,
37
+ AnnotationList: () => AnnotationList,
38
+ Draggable: () => Draggable,
39
+ ErrorBoundary: () => ErrorBoundary,
40
+ Highlighter: () => Highlighter,
41
+ Toolbar: () => Toolbar,
42
+ captureScreenshot: () => captureScreenshot,
43
+ getComponentDisplayName: () => getComponentDisplayName,
44
+ getElementFromFiber: () => getElementFromFiber,
45
+ getPlatform: () => getPlatform,
46
+ getReactFiber: () => getReactFiber,
47
+ isNative: () => isNative,
48
+ isTauriEnv: () => isTauriEnv2,
49
+ isWeb: () => isWeb,
50
+ useAgentAnnotation: () => useAgentAnnotation
51
+ });
52
+ module.exports = __toCommonJS(index_exports);
53
+
54
+ // src/store.tsx
55
+ var import_react = require("react");
56
+ var import_jsx_runtime = require("react/jsx-runtime");
57
+ var initialState = {
58
+ mode: "disabled",
59
+ annotations: [],
60
+ hoveredElement: null,
61
+ hoveredComponentInfo: null,
62
+ isMinimized: false,
63
+ showList: false
64
+ };
65
+ var AnnotationContext = (0, import_react.createContext)(void 0);
66
+ function reducer(state, action) {
67
+ switch (action.type) {
68
+ case "SET_MODE":
69
+ return { ...state, mode: action.payload };
70
+ case "ADD_ANNOTATION":
71
+ return { ...state, annotations: [...state.annotations, action.payload] };
72
+ case "REMOVE_ANNOTATION":
73
+ return {
74
+ ...state,
75
+ annotations: state.annotations.filter((a) => a.id !== action.payload)
76
+ };
77
+ case "CLEAR_ALL_ANNOTATIONS":
78
+ return {
79
+ ...state,
80
+ annotations: []
81
+ };
82
+ case "SET_HOVERED":
83
+ if (state.hoveredElement === action.payload.element) return state;
84
+ return {
85
+ ...state,
86
+ hoveredElement: action.payload.element,
87
+ hoveredComponentInfo: action.payload.name ? { name: action.payload.name, details: action.payload.details } : null
88
+ };
89
+ case "RESET_HOVER":
90
+ return { ...state, hoveredElement: null, hoveredComponentInfo: null };
91
+ case "TOGGLE_MINIMIZED":
92
+ return { ...state, isMinimized: !state.isMinimized };
93
+ case "TOGGLE_LIST":
94
+ return { ...state, showList: !state.showList };
95
+ default:
96
+ return state;
97
+ }
98
+ }
99
+ function AgentAnnotationProvider({ children }) {
100
+ const [state, dispatch] = (0, import_react.useReducer)(reducer, initialState);
101
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnotationContext.Provider, { value: { state, dispatch }, children });
102
+ }
103
+ function useAgentAnnotation() {
104
+ const context = (0, import_react.useContext)(AnnotationContext);
105
+ if (!context) {
106
+ throw new Error("useAgentAnnotation must be used within an AgentAnnotationProvider");
107
+ }
108
+ return context;
109
+ }
110
+
111
+ // src/components/Toolbar.tsx
112
+ var import_react6 = require("react");
113
+
114
+ // src/components/Draggable.tsx
115
+ var import_react2 = require("react");
116
+ var import_jsx_runtime2 = require("react/jsx-runtime");
117
+ function Draggable({ children, initialPos = { x: 20, y: 20 } }) {
118
+ const [pos, setPos] = (0, import_react2.useState)(initialPos);
119
+ const [dragging, setDragging] = (0, import_react2.useState)(false);
120
+ const [rel, setRel] = (0, import_react2.useState)({ x: 0, y: 0 });
121
+ const nodeRef = (0, import_react2.useRef)(null);
122
+ const onMouseDown = (e) => {
123
+ if (e.button !== 0) return;
124
+ const node = nodeRef.current;
125
+ if (!node) return;
126
+ const rect = node.getBoundingClientRect();
127
+ setDragging(true);
128
+ setRel({
129
+ x: e.pageX - rect.left - window.scrollX,
130
+ y: e.pageY - rect.top - window.scrollY
131
+ });
132
+ e.preventDefault();
133
+ };
134
+ const onMouseMove = (e) => {
135
+ if (!dragging) return;
136
+ setPos({
137
+ x: e.pageX - rel.x,
138
+ y: e.pageY - rel.y
139
+ });
140
+ e.preventDefault();
141
+ };
142
+ const onMouseUp = () => {
143
+ setDragging(false);
144
+ };
145
+ (0, import_react2.useEffect)(() => {
146
+ if (dragging) {
147
+ document.addEventListener("mousemove", onMouseMove);
148
+ document.addEventListener("mouseup", onMouseUp);
149
+ } else {
150
+ document.removeEventListener("mousemove", onMouseMove);
151
+ document.removeEventListener("mouseup", onMouseUp);
152
+ }
153
+ return () => {
154
+ document.removeEventListener("mousemove", onMouseMove);
155
+ document.removeEventListener("mouseup", onMouseUp);
156
+ };
157
+ }, [dragging]);
158
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
159
+ "div",
160
+ {
161
+ ref: nodeRef,
162
+ style: {
163
+ position: "fixed",
164
+ left: pos.x,
165
+ top: pos.y,
166
+ zIndex: 9999,
167
+ cursor: dragging ? "grabbing" : "grab"
168
+ },
169
+ onMouseDown,
170
+ children
171
+ }
172
+ );
173
+ }
174
+
175
+ // src/components/Toolbar.tsx
176
+ var import_lucide_react3 = require("lucide-react");
177
+
178
+ // src/components/Highlighter.tsx
179
+ var import_react4 = require("react");
180
+
181
+ // src/components/AnnotationInput.tsx
182
+ var import_react3 = require("react");
183
+ var import_lucide_react = require("lucide-react");
184
+ var import_jsx_runtime3 = require("react/jsx-runtime");
185
+ function formatComponentDetails(details) {
186
+ const lines = [];
187
+ lines.push("## Element");
188
+ let elementStr = `<${details.elementInfo.tagName}`;
189
+ if (details.elementInfo.id) elementStr += ` id="${details.elementInfo.id}"`;
190
+ if (details.elementInfo.className) elementStr += ` class="${details.elementInfo.className}"`;
191
+ elementStr += ">";
192
+ lines.push(elementStr);
193
+ if (details.elementInfo.textContent) {
194
+ lines.push(`Text: "${details.elementInfo.textContent}"`);
195
+ }
196
+ lines.push(`Child elements: ${details.elementInfo.childElementCount}`);
197
+ if (Object.keys(details.elementInfo.attributes).length > 0) {
198
+ lines.push("");
199
+ lines.push("## Attributes");
200
+ for (const [key, value] of Object.entries(details.elementInfo.attributes)) {
201
+ lines.push(`${key}="${value}"`);
202
+ }
203
+ }
204
+ if (details.parentHierarchy.length > 0) {
205
+ lines.push("");
206
+ lines.push("## Parent Components");
207
+ lines.push(details.parentHierarchy.join(" \u2192 "));
208
+ }
209
+ if (details.childComponents.length > 0) {
210
+ lines.push("");
211
+ lines.push(`## Child Components (${details.childComponents.length})`);
212
+ const childLines = details.childComponents.slice(0, 15).map((child) => {
213
+ let str = child.name;
214
+ if (child.count > 1) str += ` \xD7${child.count}`;
215
+ if (child.hasChildren) str += " (has children)";
216
+ return str;
217
+ });
218
+ lines.push(childLines.join(", "));
219
+ if (details.childComponents.length > 15) {
220
+ lines.push(`... and ${details.childComponents.length - 15} more`);
221
+ }
222
+ }
223
+ return lines.join("\n");
224
+ }
225
+ function AnnotationInput({ onClose, componentName, componentDetails }) {
226
+ const { dispatch } = useAgentAnnotation();
227
+ const [note, setNote] = (0, import_react3.useState)("");
228
+ const [includeDetails, setIncludeDetails] = (0, import_react3.useState)(true);
229
+ const [isVisible, setIsVisible] = (0, import_react3.useState)(false);
230
+ const [isClosing, setIsClosing] = (0, import_react3.useState)(false);
231
+ (0, import_react3.useEffect)(() => {
232
+ requestAnimationFrame(() => {
233
+ setIsVisible(true);
234
+ });
235
+ }, []);
236
+ (0, import_react3.useEffect)(() => {
237
+ const handleKeyDown = (e) => {
238
+ if (e.key === "Escape") {
239
+ e.preventDefault();
240
+ e.stopPropagation();
241
+ handleClose();
242
+ }
243
+ };
244
+ document.addEventListener("keydown", handleKeyDown);
245
+ return () => document.removeEventListener("keydown", handleKeyDown);
246
+ }, []);
247
+ const handleClose = () => {
248
+ setIsClosing(true);
249
+ setTimeout(() => {
250
+ onClose();
251
+ }, 200);
252
+ };
253
+ const handleSubmit = (e) => {
254
+ e.preventDefault();
255
+ if (!note.trim()) return;
256
+ let finalNote = note.trim();
257
+ if (includeDetails && componentDetails) {
258
+ const detailsText = formatComponentDetails(componentDetails);
259
+ finalNote = `${note.trim()}
260
+
261
+ ---
262
+ ${detailsText}`;
263
+ }
264
+ dispatch({
265
+ type: "ADD_ANNOTATION",
266
+ payload: {
267
+ id: Date.now().toString(),
268
+ componentName,
269
+ note: finalNote,
270
+ timestamp: Date.now(),
271
+ details: componentDetails
272
+ }
273
+ });
274
+ handleClose();
275
+ };
276
+ const detailsPreview = componentDetails ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
277
+ fontSize: "0.75rem",
278
+ color: "rgba(255, 255, 255, 0.6)",
279
+ marginTop: "4px"
280
+ }, children: [
281
+ componentDetails.parentHierarchy.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
282
+ "Parents: ",
283
+ componentDetails.parentHierarchy.slice(0, 3).join(" \u2192 "),
284
+ componentDetails.parentHierarchy.length > 3 ? "..." : ""
285
+ ] }),
286
+ componentDetails.childComponents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
287
+ "Children: ",
288
+ componentDetails.childComponents.slice(0, 3).map((c) => c.name).join(", "),
289
+ componentDetails.childComponents.length > 3 ? "..." : ""
290
+ ] }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
292
+ "Element: <",
293
+ componentDetails.elementInfo.tagName,
294
+ "> (",
295
+ componentDetails.elementInfo.childElementCount,
296
+ " children)"
297
+ ] })
298
+ ] }) : null;
299
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
300
+ "div",
301
+ {
302
+ style: {
303
+ position: "fixed",
304
+ top: 0,
305
+ left: 0,
306
+ right: 0,
307
+ bottom: 0,
308
+ backgroundColor: isVisible && !isClosing ? "rgba(0,0,0,0.5)" : "rgba(0,0,0,0)",
309
+ display: "flex",
310
+ alignItems: "center",
311
+ justifyContent: "center",
312
+ zIndex: 1e4,
313
+ transition: "background-color 0.2s ease"
314
+ },
315
+ "data-ai-annotation-ui": true,
316
+ onClick: handleClose,
317
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
318
+ "div",
319
+ {
320
+ style: {
321
+ backgroundColor: "#1e1e1e",
322
+ color: "#e5e7eb",
323
+ padding: "20px",
324
+ borderRadius: "8px",
325
+ width: "500px",
326
+ maxWidth: "90%",
327
+ maxHeight: "80vh",
328
+ overflow: "auto",
329
+ boxShadow: "0 4px 6px rgba(0,0,0,0.3)",
330
+ transform: isVisible && !isClosing ? "scale(1) translateY(0)" : "scale(0.95) translateY(-10px)",
331
+ opacity: isVisible && !isClosing ? 1 : 0,
332
+ transition: "transform 0.2s ease, opacity 0.2s ease"
333
+ },
334
+ onClick: (e) => e.stopPropagation(),
335
+ children: [
336
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "16px" }, children: [
337
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { style: { margin: 0, fontSize: "1.1rem" }, children: "Add Annotation" }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { onClick: handleClose, style: { background: "none", border: "none", color: "inherit", cursor: "pointer" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.X, { size: 20 }) })
339
+ ] }),
340
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginBottom: "12px", fontSize: "0.9rem", opacity: 0.8 }, children: [
341
+ "Component: ",
342
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: componentName })
343
+ ] }),
344
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleSubmit, children: [
345
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
346
+ "textarea",
347
+ {
348
+ value: note,
349
+ onChange: (e) => setNote(e.target.value),
350
+ placeholder: "Describe what this component does or what changes you need...",
351
+ style: {
352
+ width: "100%",
353
+ height: "120px",
354
+ padding: "8px",
355
+ borderRadius: "4px",
356
+ backgroundColor: "#2d2d2d",
357
+ border: "1px solid #404040",
358
+ color: "white",
359
+ marginBottom: "12px",
360
+ resize: "vertical",
361
+ fontFamily: "inherit"
362
+ },
363
+ autoFocus: true
364
+ }
365
+ ),
366
+ componentDetails && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
367
+ "label",
368
+ {
369
+ style: {
370
+ display: "flex",
371
+ alignItems: "flex-start",
372
+ gap: "8px",
373
+ cursor: "pointer",
374
+ fontSize: "0.85rem"
375
+ },
376
+ children: [
377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
378
+ "input",
379
+ {
380
+ type: "checkbox",
381
+ checked: includeDetails,
382
+ onChange: (e) => setIncludeDetails(e.target.checked),
383
+ style: { marginTop: "2px" }
384
+ }
385
+ ),
386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { color: "#10b981", fontWeight: 500 }, children: "Include component details in annotation" }),
388
+ includeDetails && detailsPreview
389
+ ] })
390
+ ]
391
+ }
392
+ ) }),
393
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px" }, children: [
394
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
395
+ "button",
396
+ {
397
+ type: "button",
398
+ onClick: handleClose,
399
+ style: {
400
+ padding: "6px 12px",
401
+ borderRadius: "4px",
402
+ backgroundColor: "transparent",
403
+ border: "1px solid #404040",
404
+ color: "white",
405
+ cursor: "pointer"
406
+ },
407
+ children: "Cancel"
408
+ }
409
+ ),
410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
411
+ "button",
412
+ {
413
+ type: "submit",
414
+ style: {
415
+ padding: "6px 12px",
416
+ borderRadius: "4px",
417
+ backgroundColor: "#3b82f6",
418
+ border: "none",
419
+ color: "white",
420
+ cursor: "pointer"
421
+ },
422
+ children: "Save Annotation"
423
+ }
424
+ )
425
+ ] })
426
+ ] })
427
+ ]
428
+ }
429
+ )
430
+ }
431
+ );
432
+ }
433
+
434
+ // src/utils/screenshot.ts
435
+ var import_html2canvas = __toESM(require("html2canvas"));
436
+ function isTauriEnv() {
437
+ return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
438
+ }
439
+ async function copyToClipboardTauri(blob) {
440
+ if (typeof window.__TAURI_CLIPBOARD_WRITE_IMAGE__ === "function") {
441
+ const arrayBuffer = await blob.arrayBuffer();
442
+ const bytes = new Uint8Array(arrayBuffer);
443
+ await window.__TAURI_CLIPBOARD_WRITE_IMAGE__(bytes);
444
+ return;
445
+ }
446
+ throw new Error("Tauri clipboard function not available");
447
+ }
448
+ async function copyToClipboardBrowser(blob, dataUrl) {
449
+ try {
450
+ await navigator.clipboard.write([
451
+ new ClipboardItem({
452
+ "image/png": blob
453
+ })
454
+ ]);
455
+ } catch (clipboardError) {
456
+ console.warn("Failed to copy to clipboard:", clipboardError);
457
+ try {
458
+ await navigator.clipboard.writeText(dataUrl);
459
+ } catch {
460
+ }
461
+ }
462
+ }
463
+ async function captureScreenshot(element, options = {}) {
464
+ const {
465
+ scale = 2,
466
+ backgroundColor = null,
467
+ copyToClipboard = true,
468
+ download = false,
469
+ filename = "screenshot.png"
470
+ } = options;
471
+ try {
472
+ const canvas = await (0, import_html2canvas.default)(element, {
473
+ scale,
474
+ backgroundColor,
475
+ logging: false,
476
+ useCORS: true,
477
+ allowTaint: true,
478
+ // Capture just the element
479
+ x: window.scrollX,
480
+ y: window.scrollY,
481
+ scrollX: -window.scrollX,
482
+ scrollY: -window.scrollY,
483
+ windowWidth: document.documentElement.scrollWidth,
484
+ windowHeight: document.documentElement.scrollHeight,
485
+ // Ignore annotation UI elements
486
+ ignoreElements: (el) => {
487
+ return el.hasAttribute("data-ai-annotation-ui");
488
+ }
489
+ });
490
+ const blob = await new Promise((resolve, reject) => {
491
+ canvas.toBlob((b) => {
492
+ if (b) resolve(b);
493
+ else reject(new Error("Failed to create blob"));
494
+ }, "image/png");
495
+ });
496
+ const dataUrl = canvas.toDataURL("image/png");
497
+ if (copyToClipboard) {
498
+ if (isTauriEnv()) {
499
+ try {
500
+ await copyToClipboardTauri(blob);
501
+ } catch (tauriErr) {
502
+ console.warn("Tauri clipboard failed, falling back to browser API:", tauriErr);
503
+ await copyToClipboardBrowser(blob, dataUrl);
504
+ }
505
+ } else {
506
+ await copyToClipboardBrowser(blob, dataUrl);
507
+ }
508
+ }
509
+ if (download) {
510
+ const link = document.createElement("a");
511
+ link.href = dataUrl;
512
+ link.download = filename;
513
+ document.body.appendChild(link);
514
+ link.click();
515
+ document.body.removeChild(link);
516
+ }
517
+ return {
518
+ success: true,
519
+ dataUrl,
520
+ blob
521
+ };
522
+ } catch (error) {
523
+ const message = error instanceof Error ? error.message : "Unknown error";
524
+ console.error("Screenshot capture failed:", message);
525
+ return {
526
+ success: false,
527
+ error: message
528
+ };
529
+ }
530
+ }
531
+
532
+ // src/utils/fiber.ts
533
+ function getReactFiber(dom) {
534
+ const key = Object.keys(dom).find(
535
+ (key2) => key2.startsWith("__reactFiber$")
536
+ );
537
+ return key ? dom[key] : null;
538
+ }
539
+ function getComponentDisplayName(fiber) {
540
+ let curr = fiber;
541
+ while (curr) {
542
+ const name = curr.type?.displayName || curr.type?.name;
543
+ if (name && typeof curr.type === "function") return name;
544
+ curr = curr.return;
545
+ }
546
+ return "Unknown";
547
+ }
548
+ function getElementFromFiber(fiber) {
549
+ let curr = fiber;
550
+ while (curr) {
551
+ if (curr.stateNode instanceof HTMLElement) {
552
+ return curr.stateNode;
553
+ }
554
+ curr = curr.child;
555
+ }
556
+ return null;
557
+ }
558
+ function getParentHierarchy(fiber, maxDepth = 10) {
559
+ const hierarchy = [];
560
+ let curr = fiber?.return;
561
+ let depth = 0;
562
+ while (curr && depth < maxDepth) {
563
+ const name = curr.type?.displayName || curr.type?.name;
564
+ if (name && typeof curr.type === "function") {
565
+ if (!name.includes("$") && !name.startsWith("_")) {
566
+ hierarchy.push(name);
567
+ }
568
+ }
569
+ curr = curr.return;
570
+ depth++;
571
+ }
572
+ return hierarchy;
573
+ }
574
+ function getChildComponents(fiber, maxDepth = 5) {
575
+ const children = /* @__PURE__ */ new Map();
576
+ function traverse(node, depth) {
577
+ if (!node || depth > maxDepth) return;
578
+ const name = node.type?.displayName || node.type?.name;
579
+ if (name && typeof node.type === "function" && !name.includes("$") && !name.startsWith("_")) {
580
+ const existing = children.get(name);
581
+ const hasChildComponents = checkHasChildComponents(node.child);
582
+ if (existing) {
583
+ existing.count++;
584
+ if (depth < existing.depth) {
585
+ existing.depth = depth;
586
+ }
587
+ existing.hasChildren = existing.hasChildren || hasChildComponents;
588
+ } else {
589
+ children.set(name, { count: 1, depth, hasChildren: hasChildComponents });
590
+ }
591
+ }
592
+ if (node.child) traverse(node.child, depth + 1);
593
+ if (node.sibling) traverse(node.sibling, depth);
594
+ }
595
+ if (fiber?.child) {
596
+ traverse(fiber.child, 1);
597
+ }
598
+ return Array.from(children.entries()).map(([name, info]) => ({
599
+ name,
600
+ depth: info.depth,
601
+ count: info.count,
602
+ hasChildren: info.hasChildren
603
+ })).sort((a, b) => a.depth - b.depth);
604
+ }
605
+ function checkHasChildComponents(fiber, maxDepth = 3) {
606
+ if (!fiber || maxDepth <= 0) return false;
607
+ const name = fiber.type?.displayName || fiber.type?.name;
608
+ if (name && typeof fiber.type === "function" && !name.includes("$")) {
609
+ return true;
610
+ }
611
+ if (fiber.child && checkHasChildComponents(fiber.child, maxDepth - 1)) return true;
612
+ if (fiber.sibling && checkHasChildComponents(fiber.sibling, maxDepth - 1)) return true;
613
+ return false;
614
+ }
615
+ function getElementInfo(element) {
616
+ const importantAttributes = ["data-testid", "role", "aria-label", "type", "name", "href", "src"];
617
+ const attributes = {};
618
+ importantAttributes.forEach((attr) => {
619
+ const value = element.getAttribute(attr);
620
+ if (value) {
621
+ attributes[attr] = value;
622
+ }
623
+ });
624
+ let textContent;
625
+ const directText = Array.from(element.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).map((node) => node.textContent?.trim()).filter(Boolean).join(" ");
626
+ if (directText) {
627
+ textContent = directText.length > 100 ? directText.substring(0, 100) + "..." : directText;
628
+ }
629
+ return {
630
+ tagName: element.tagName.toLowerCase(),
631
+ id: element.id || void 0,
632
+ className: element.className && typeof element.className === "string" ? element.className.split(" ").slice(0, 5).join(" ") + (element.className.split(" ").length > 5 ? "..." : "") : void 0,
633
+ attributes,
634
+ childElementCount: element.childElementCount,
635
+ textContent
636
+ };
637
+ }
638
+ function getComponentProps(fiber, maxProps = 10) {
639
+ if (!fiber?.memoizedProps) return void 0;
640
+ const props = fiber.memoizedProps;
641
+ const safeProps = {};
642
+ let count = 0;
643
+ for (const key of Object.keys(props)) {
644
+ if (count >= maxProps) {
645
+ safeProps["..."] = `${Object.keys(props).length - maxProps} more props`;
646
+ break;
647
+ }
648
+ if (key === "children") continue;
649
+ const value = props[key];
650
+ const type = typeof value;
651
+ if (type === "function") {
652
+ safeProps[key] = "[Function]";
653
+ } else if (type === "object" && value !== null) {
654
+ if (Array.isArray(value)) {
655
+ safeProps[key] = `[Array(${value.length})]`;
656
+ } else if (value.$$typeof) {
657
+ safeProps[key] = "[ReactElement]";
658
+ } else {
659
+ try {
660
+ const json = JSON.stringify(value);
661
+ safeProps[key] = json.length > 100 ? "[Object]" : value;
662
+ } catch {
663
+ safeProps[key] = "[Object]";
664
+ }
665
+ }
666
+ } else {
667
+ safeProps[key] = value;
668
+ }
669
+ count++;
670
+ }
671
+ return Object.keys(safeProps).length > 0 ? safeProps : void 0;
672
+ }
673
+ function getComponentDetails(element, options) {
674
+ const { includeProps = false, maxParentDepth = 10, maxChildDepth = 5 } = options || {};
675
+ const fiber = getReactFiber(element);
676
+ const name = fiber ? getComponentDisplayName(fiber) : "Unknown";
677
+ let componentFiber = fiber;
678
+ while (componentFiber && typeof componentFiber.type !== "function") {
679
+ componentFiber = componentFiber.return;
680
+ }
681
+ return {
682
+ name,
683
+ parentHierarchy: getParentHierarchy(componentFiber, maxParentDepth),
684
+ childComponents: getChildComponents(componentFiber, maxChildDepth),
685
+ elementInfo: getElementInfo(element),
686
+ props: includeProps ? getComponentProps(componentFiber) : void 0
687
+ };
688
+ }
689
+
690
+ // src/components/Highlighter.tsx
691
+ var import_jsx_runtime4 = require("react/jsx-runtime");
692
+ function Highlighter() {
693
+ const { state, dispatch } = useAgentAnnotation();
694
+ const { hoveredElement, mode, hoveredComponentInfo } = state;
695
+ const [rect, setRect] = (0, import_react4.useState)(null);
696
+ const [showInput, setShowInput] = (0, import_react4.useState)(false);
697
+ const [mousePos, setMousePos] = (0, import_react4.useState)({ x: 0, y: 0 });
698
+ const [isLocked, setIsLocked] = (0, import_react4.useState)(false);
699
+ const [lockedPos, setLockedPos] = (0, import_react4.useState)({ x: 0, y: 0 });
700
+ const [isCapturing, setIsCapturing] = (0, import_react4.useState)(false);
701
+ const [captureSuccess, setCaptureSuccess] = (0, import_react4.useState)(false);
702
+ const [showDetails, setShowDetails] = (0, import_react4.useState)(false);
703
+ const componentName = hoveredComponentInfo?.name || "";
704
+ const componentDetails = hoveredComponentInfo?.details;
705
+ (0, import_react4.useEffect)(() => {
706
+ if (mode !== "inspecting") return;
707
+ const handleMouseOver = (e) => {
708
+ if (isLocked) return;
709
+ const target = e.target;
710
+ if (target.closest("[data-ai-annotation-ui]") || target.closest("[data-annotation-tooltip]")) {
711
+ return;
712
+ }
713
+ const details = getComponentDetails(target, {
714
+ includeProps: false,
715
+ maxParentDepth: 10,
716
+ maxChildDepth: 5
717
+ });
718
+ dispatch({
719
+ type: "SET_HOVERED",
720
+ payload: { element: target, name: details.name, details }
721
+ });
722
+ };
723
+ document.addEventListener("mouseover", handleMouseOver);
724
+ return () => {
725
+ document.removeEventListener("mouseover", handleMouseOver);
726
+ };
727
+ }, [mode, isLocked, dispatch]);
728
+ (0, import_react4.useEffect)(() => {
729
+ if (mode !== "inspecting") return;
730
+ const handleGlobalEsc = (e) => {
731
+ if (e.key === "Escape" && !isLocked) {
732
+ e.preventDefault();
733
+ e.stopPropagation();
734
+ dispatch({ type: "SET_MODE", payload: "disabled" });
735
+ }
736
+ };
737
+ document.addEventListener("keydown", handleGlobalEsc);
738
+ return () => document.removeEventListener("keydown", handleGlobalEsc);
739
+ }, [mode, isLocked, dispatch]);
740
+ (0, import_react4.useEffect)(() => {
741
+ if (mode === "disabled") {
742
+ setRect(null);
743
+ setShowInput(false);
744
+ setIsLocked(false);
745
+ setMousePos({ x: 0, y: 0 });
746
+ setLockedPos({ x: 0, y: 0 });
747
+ setIsCapturing(false);
748
+ setCaptureSuccess(false);
749
+ setShowDetails(false);
750
+ dispatch({ type: "RESET_HOVER" });
751
+ }
752
+ }, [mode, dispatch]);
753
+ (0, import_react4.useEffect)(() => {
754
+ if (!hoveredElement) {
755
+ setRect(null);
756
+ setShowInput(false);
757
+ setIsLocked(false);
758
+ return;
759
+ }
760
+ const updateRect = () => {
761
+ const newRect = hoveredElement.getBoundingClientRect();
762
+ setRect(newRect);
763
+ };
764
+ updateRect();
765
+ const handleMouseMove = (e) => {
766
+ if (!isLocked) {
767
+ setMousePos({ x: e.clientX, y: e.clientY });
768
+ }
769
+ };
770
+ const handleClick = (e) => {
771
+ const target = e.target;
772
+ if (target.closest("[data-annotation-tooltip]")) {
773
+ return;
774
+ }
775
+ if (target.closest("[data-ai-annotation-ui]")) {
776
+ return;
777
+ }
778
+ if (!isLocked) {
779
+ e.preventDefault();
780
+ e.stopPropagation();
781
+ setIsLocked(true);
782
+ setLockedPos({ x: e.clientX, y: e.clientY });
783
+ } else {
784
+ setIsLocked(false);
785
+ }
786
+ };
787
+ const handleKeyDown = (e) => {
788
+ if (e.key === "Escape" && isLocked) {
789
+ e.preventDefault();
790
+ e.stopPropagation();
791
+ setIsLocked(false);
792
+ setShowInput(false);
793
+ }
794
+ };
795
+ window.addEventListener("scroll", updateRect, true);
796
+ window.addEventListener("resize", updateRect);
797
+ document.addEventListener("mousemove", handleMouseMove);
798
+ document.addEventListener("click", handleClick, true);
799
+ document.addEventListener("keydown", handleKeyDown);
800
+ return () => {
801
+ window.removeEventListener("scroll", updateRect, true);
802
+ window.removeEventListener("resize", updateRect);
803
+ document.removeEventListener("mousemove", handleMouseMove);
804
+ document.removeEventListener("click", handleClick, true);
805
+ document.removeEventListener("keydown", handleKeyDown);
806
+ };
807
+ }, [hoveredElement, isLocked]);
808
+ const handleScreenshot = async (e) => {
809
+ e.stopPropagation();
810
+ if (!hoveredElement || isCapturing) return;
811
+ setIsCapturing(true);
812
+ try {
813
+ const result = await captureScreenshot(hoveredElement, {
814
+ copyToClipboard: true,
815
+ scale: 2
816
+ });
817
+ if (result.success) {
818
+ setCaptureSuccess(true);
819
+ setTimeout(() => {
820
+ setCaptureSuccess(false);
821
+ setIsLocked(false);
822
+ }, 1500);
823
+ }
824
+ } catch (error) {
825
+ console.error("Screenshot failed:", error);
826
+ } finally {
827
+ setIsCapturing(false);
828
+ }
829
+ };
830
+ const handleAddClick = (e) => {
831
+ e.stopPropagation();
832
+ setShowInput(true);
833
+ setShowDetails(false);
834
+ setIsLocked(false);
835
+ };
836
+ const handleDetailsClick = (e) => {
837
+ e.stopPropagation();
838
+ setShowDetails(!showDetails);
839
+ };
840
+ const handleCloseInput = () => {
841
+ setShowInput(false);
842
+ };
843
+ if (mode !== "inspecting" || !rect) return null;
844
+ const tooltipX = isLocked ? lockedPos.x : mousePos.x;
845
+ const tooltipY = isLocked ? lockedPos.y : mousePos.y;
846
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
848
+ "div",
849
+ {
850
+ "data-annotation-ui": "true",
851
+ style: {
852
+ position: "fixed",
853
+ left: rect.left - 2,
854
+ top: rect.top - 2,
855
+ width: rect.width + 4,
856
+ height: rect.height + 4,
857
+ border: "2px solid #3b82f6",
858
+ borderRadius: 4,
859
+ pointerEvents: "none",
860
+ zIndex: 99998,
861
+ backgroundColor: "rgba(59, 130, 246, 0.1)"
862
+ }
863
+ }
864
+ ),
865
+ componentName && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
866
+ "div",
867
+ {
868
+ "data-annotation-ui": "true",
869
+ style: {
870
+ position: "fixed",
871
+ left: rect.left,
872
+ top: rect.top - 24,
873
+ backgroundColor: "#3b82f6",
874
+ color: "white",
875
+ padding: "2px 8px",
876
+ borderRadius: 4,
877
+ fontSize: 12,
878
+ fontFamily: "monospace",
879
+ pointerEvents: "none",
880
+ zIndex: 99999
881
+ },
882
+ children: componentName
883
+ }
884
+ ),
885
+ !showInput && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
886
+ "div",
887
+ {
888
+ "data-annotation-ui": "true",
889
+ "data-annotation-tooltip": "true",
890
+ style: {
891
+ position: "fixed",
892
+ left: tooltipX + 16,
893
+ top: tooltipY + 16,
894
+ display: "flex",
895
+ flexDirection: "column",
896
+ gap: 6,
897
+ padding: 6,
898
+ backgroundColor: isLocked ? "rgba(0, 0, 0, 0.95)" : "rgba(0, 0, 0, 0.85)",
899
+ borderRadius: 8,
900
+ boxShadow: isLocked ? "0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 2px rgba(59, 130, 246, 0.5)" : "0 4px 12px rgba(0, 0, 0, 0.3)",
901
+ zIndex: 1e5,
902
+ pointerEvents: isLocked ? "auto" : "none",
903
+ backdropFilter: "blur(8px)",
904
+ transition: isLocked ? "none" : "left 0.05s ease-out, top 0.05s ease-out",
905
+ maxWidth: showDetails ? 400 : "auto"
906
+ },
907
+ children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 6 }, children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
910
+ "button",
911
+ {
912
+ onClick: handleScreenshot,
913
+ disabled: isCapturing || !isLocked,
914
+ style: {
915
+ width: 32,
916
+ height: 32,
917
+ borderRadius: 6,
918
+ border: "none",
919
+ backgroundColor: captureSuccess ? "#22c55e" : isCapturing ? "#6b7280" : "#8b5cf6",
920
+ color: "white",
921
+ cursor: isLocked ? "pointer" : "default",
922
+ display: "flex",
923
+ alignItems: "center",
924
+ justifyContent: "center",
925
+ fontSize: 16,
926
+ transition: "all 0.15s ease",
927
+ opacity: isLocked ? 1 : 0.7
928
+ },
929
+ title: "Capture screenshot",
930
+ children: captureSuccess ? "\u2713" : isCapturing ? "..." : "\u{1F4F7}"
931
+ }
932
+ ),
933
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
934
+ "button",
935
+ {
936
+ onClick: handleAddClick,
937
+ disabled: !isLocked,
938
+ style: {
939
+ width: 32,
940
+ height: 32,
941
+ borderRadius: 6,
942
+ border: "none",
943
+ backgroundColor: "#3b82f6",
944
+ color: "white",
945
+ cursor: isLocked ? "pointer" : "default",
946
+ display: "flex",
947
+ alignItems: "center",
948
+ justifyContent: "center",
949
+ fontSize: 18,
950
+ fontWeight: "bold",
951
+ transition: "all 0.15s ease",
952
+ opacity: isLocked ? 1 : 0.7
953
+ },
954
+ title: "Add annotation",
955
+ children: "+"
956
+ }
957
+ ),
958
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
959
+ "button",
960
+ {
961
+ onClick: handleDetailsClick,
962
+ disabled: !isLocked,
963
+ style: {
964
+ width: 32,
965
+ height: 32,
966
+ borderRadius: 6,
967
+ border: showDetails ? "2px solid #10b981" : "none",
968
+ backgroundColor: showDetails ? "#10b981" : "#6b7280",
969
+ color: "white",
970
+ cursor: isLocked ? "pointer" : "default",
971
+ display: "flex",
972
+ alignItems: "center",
973
+ justifyContent: "center",
974
+ fontSize: 14,
975
+ transition: "all 0.15s ease",
976
+ opacity: isLocked ? 1 : 0.7
977
+ },
978
+ title: "Show component details",
979
+ children: "\u24D8"
980
+ }
981
+ )
982
+ ] }),
983
+ !isLocked && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
984
+ "div",
985
+ {
986
+ style: {
987
+ position: "absolute",
988
+ bottom: -20,
989
+ left: "50%",
990
+ transform: "translateX(-50%)",
991
+ fontSize: 10,
992
+ color: "rgba(255, 255, 255, 0.7)",
993
+ whiteSpace: "nowrap",
994
+ pointerEvents: "none"
995
+ },
996
+ children: "Click to lock"
997
+ }
998
+ ),
999
+ showDetails && componentDetails && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1000
+ "div",
1001
+ {
1002
+ style: {
1003
+ padding: "8px 4px 4px 4px",
1004
+ borderTop: "1px solid rgba(255, 255, 255, 0.2)",
1005
+ fontSize: 11,
1006
+ color: "rgba(255, 255, 255, 0.9)",
1007
+ maxHeight: 300,
1008
+ overflowY: "auto"
1009
+ },
1010
+ children: [
1011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: 8 }, children: [
1012
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Element" }),
1013
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontFamily: "monospace", color: "#f59e0b" }, children: [
1014
+ "<",
1015
+ componentDetails.elementInfo.tagName,
1016
+ componentDetails.elementInfo.id && ` id="${componentDetails.elementInfo.id}"`,
1017
+ componentDetails.elementInfo.className && ` class="${componentDetails.elementInfo.className}"`,
1018
+ ">"
1019
+ ] }),
1020
+ componentDetails.elementInfo.textContent && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "rgba(255, 255, 255, 0.6)", marginTop: 2, fontStyle: "italic" }, children: [
1021
+ '"',
1022
+ componentDetails.elementInfo.textContent,
1023
+ '"'
1024
+ ] }),
1025
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "rgba(255, 255, 255, 0.5)", marginTop: 2 }, children: [
1026
+ componentDetails.elementInfo.childElementCount,
1027
+ " child element(s)"
1028
+ ] })
1029
+ ] }),
1030
+ componentDetails.parentHierarchy.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: 8 }, children: [
1031
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Parent Components" }),
1032
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontFamily: "monospace" }, children: [
1033
+ componentDetails.parentHierarchy.slice(0, 5).map((parent, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#a78bfa", paddingLeft: i * 8 }, children: [
1034
+ "\u2190 ",
1035
+ parent
1036
+ ] }, i)),
1037
+ componentDetails.parentHierarchy.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
1038
+ "... and ",
1039
+ componentDetails.parentHierarchy.length - 5,
1040
+ " more"
1041
+ ] })
1042
+ ] })
1043
+ ] }),
1044
+ componentDetails.childComponents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: 8 }, children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: [
1046
+ "Child Components (",
1047
+ componentDetails.childComponents.length,
1048
+ ")"
1049
+ ] }),
1050
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontFamily: "monospace" }, children: [
1051
+ componentDetails.childComponents.slice(0, 10).map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1052
+ "div",
1053
+ {
1054
+ style: {
1055
+ display: "flex",
1056
+ justifyContent: "space-between",
1057
+ gap: 8,
1058
+ color: "#34d399"
1059
+ },
1060
+ children: [
1061
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1062
+ "\u2192 ",
1063
+ child.name,
1064
+ child.hasChildren && " \u25BE"
1065
+ ] }),
1066
+ child.count > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
1067
+ "\xD7",
1068
+ child.count
1069
+ ] })
1070
+ ]
1071
+ },
1072
+ i
1073
+ )),
1074
+ componentDetails.childComponents.length > 10 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
1075
+ "... and ",
1076
+ componentDetails.childComponents.length - 10,
1077
+ " more"
1078
+ ] })
1079
+ ] })
1080
+ ] }),
1081
+ Object.keys(componentDetails.elementInfo.attributes).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1082
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Attributes" }),
1083
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontFamily: "monospace" }, children: Object.entries(componentDetails.elementInfo.attributes).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#fbbf24" }, children: [
1084
+ key,
1085
+ '="',
1086
+ value,
1087
+ '"'
1088
+ ] }, key)) })
1089
+ ] })
1090
+ ]
1091
+ }
1092
+ )
1093
+ ]
1094
+ }
1095
+ ),
1096
+ showInput && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1097
+ AnnotationInput,
1098
+ {
1099
+ onClose: handleCloseInput,
1100
+ componentName: componentName || "Unknown",
1101
+ componentDetails
1102
+ }
1103
+ )
1104
+ ] });
1105
+ }
1106
+
1107
+ // src/components/AnnotationList.tsx
1108
+ var import_react5 = require("react");
1109
+ var import_lucide_react2 = require("lucide-react");
1110
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1111
+ function AnnotationList() {
1112
+ const { state, dispatch } = useAgentAnnotation();
1113
+ const [expandedId, setExpandedId] = (0, import_react5.useState)(null);
1114
+ if (!state.showList) return null;
1115
+ const toggleExpand = (id) => {
1116
+ setExpandedId(expandedId === id ? null : id);
1117
+ };
1118
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1119
+ "div",
1120
+ {
1121
+ style: {
1122
+ position: "fixed",
1123
+ top: 0,
1124
+ left: 0,
1125
+ right: 0,
1126
+ bottom: 0,
1127
+ backgroundColor: "rgba(0,0,0,0.5)",
1128
+ display: "flex",
1129
+ alignItems: "center",
1130
+ justifyContent: "center",
1131
+ zIndex: 1e4
1132
+ },
1133
+ "data-ai-annotation-ui": true,
1134
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1135
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1136
+ "div",
1137
+ {
1138
+ style: {
1139
+ backgroundColor: "#1e1e1e",
1140
+ color: "#e5e7eb",
1141
+ padding: "20px",
1142
+ borderRadius: "8px",
1143
+ width: "600px",
1144
+ maxWidth: "90%",
1145
+ maxHeight: "80vh",
1146
+ display: "flex",
1147
+ flexDirection: "column",
1148
+ boxShadow: "0 4px 6px rgba(0,0,0,0.3)"
1149
+ },
1150
+ onClick: (e) => e.stopPropagation(),
1151
+ children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "16px", alignItems: "center" }, children: [
1153
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h3", { style: { margin: 0 }, children: [
1154
+ "Annotations (",
1155
+ state.annotations.length,
1156
+ ")"
1157
+ ] }),
1158
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1159
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1160
+ "button",
1161
+ {
1162
+ onClick: () => dispatch({ type: "CLEAR_ALL_ANNOTATIONS" }),
1163
+ style: {
1164
+ background: "#ef4444",
1165
+ border: "none",
1166
+ color: "white",
1167
+ cursor: "pointer",
1168
+ padding: "6px 12px",
1169
+ borderRadius: "4px",
1170
+ fontSize: "12px",
1171
+ display: "flex",
1172
+ alignItems: "center",
1173
+ gap: "4px"
1174
+ },
1175
+ title: "Clear all annotations",
1176
+ children: [
1177
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Trash, { size: 14 }),
1178
+ "Clear All"
1179
+ ]
1180
+ }
1181
+ ),
1182
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1183
+ "button",
1184
+ {
1185
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1186
+ style: { background: "none", border: "none", color: "inherit", cursor: "pointer" },
1187
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.X, { size: 20 })
1188
+ }
1189
+ )
1190
+ ] })
1191
+ ] }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { overflowY: "auto", flex: 1, display: "flex", flexDirection: "column", gap: "8px" }, children: state.annotations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { textAlign: "center", opacity: 0.6, padding: "20px" }, children: "No annotations yet." }) : state.annotations.map((ann) => {
1193
+ const isExpanded = expandedId === ann.id;
1194
+ const hasDetails = !!ann.details;
1195
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1196
+ "div",
1197
+ {
1198
+ style: {
1199
+ backgroundColor: "#2d2d2d",
1200
+ borderRadius: "4px",
1201
+ overflow: "hidden"
1202
+ },
1203
+ children: [
1204
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1205
+ "div",
1206
+ {
1207
+ style: {
1208
+ padding: "12px",
1209
+ display: "flex",
1210
+ justifyContent: "space-between",
1211
+ alignItems: "flex-start",
1212
+ gap: "12px"
1213
+ },
1214
+ children: [
1215
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1 }, children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
1217
+ hasDetails && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1218
+ "button",
1219
+ {
1220
+ onClick: () => toggleExpand(ann.id),
1221
+ style: {
1222
+ background: "none",
1223
+ border: "none",
1224
+ color: "#60a5fa",
1225
+ cursor: "pointer",
1226
+ padding: 0,
1227
+ display: "flex",
1228
+ alignItems: "center"
1229
+ },
1230
+ children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ChevronRight, { size: 16 })
1231
+ }
1232
+ ),
1233
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontWeight: "bold", fontSize: "0.9rem", color: "#60a5fa" }, children: ann.componentName })
1234
+ ] }),
1235
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "0.9rem", whiteSpace: "pre-wrap", marginLeft: hasDetails ? 24 : 0 }, children: ann.note })
1236
+ ] }),
1237
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1238
+ "button",
1239
+ {
1240
+ onClick: () => dispatch({ type: "REMOVE_ANNOTATION", payload: ann.id }),
1241
+ style: {
1242
+ background: "none",
1243
+ border: "none",
1244
+ color: "#ef4444",
1245
+ cursor: "pointer",
1246
+ padding: "4px",
1247
+ flexShrink: 0
1248
+ },
1249
+ title: "Remove annotation",
1250
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Trash2, { size: 16 })
1251
+ }
1252
+ )
1253
+ ]
1254
+ }
1255
+ ),
1256
+ isExpanded && ann.details && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1257
+ "div",
1258
+ {
1259
+ style: {
1260
+ padding: "12px",
1261
+ paddingTop: 0,
1262
+ borderTop: "1px solid #404040",
1263
+ marginTop: "8px",
1264
+ fontSize: "0.8rem"
1265
+ },
1266
+ children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginBottom: "12px" }, children: [
1268
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Element" }),
1269
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { fontFamily: "monospace", color: "#f59e0b", fontSize: "0.75rem" }, children: [
1270
+ "<",
1271
+ ann.details.elementInfo.tagName,
1272
+ ann.details.elementInfo.id && ` id="${ann.details.elementInfo.id}"`,
1273
+ ann.details.elementInfo.className && ` class="${ann.details.elementInfo.className}"`,
1274
+ ">"
1275
+ ] }),
1276
+ ann.details.elementInfo.textContent && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { color: "rgba(255, 255, 255, 0.6)", marginTop: "4px", fontStyle: "italic" }, children: [
1277
+ 'Text: "',
1278
+ ann.details.elementInfo.textContent,
1279
+ '"'
1280
+ ] })
1281
+ ] }),
1282
+ ann.details.parentHierarchy.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginBottom: "12px" }, children: [
1283
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Parent Components" }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontFamily: "monospace", fontSize: "0.75rem" }, children: ann.details.parentHierarchy.map((parent, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { color: "#a78bfa" }, children: [
1285
+ i > 0 && " \u2192 ",
1286
+ parent
1287
+ ] }, i)) })
1288
+ ] }),
1289
+ ann.details.childComponents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginBottom: "12px" }, children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: [
1291
+ "Child Components (",
1292
+ ann.details.childComponents.length,
1293
+ ")"
1294
+ ] }),
1295
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: ann.details.childComponents.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1296
+ "span",
1297
+ {
1298
+ style: {
1299
+ backgroundColor: "#374151",
1300
+ padding: "2px 8px",
1301
+ borderRadius: "4px",
1302
+ fontFamily: "monospace",
1303
+ fontSize: "0.75rem",
1304
+ color: "#34d399"
1305
+ },
1306
+ children: [
1307
+ child.name,
1308
+ child.count > 1 && ` \xD7${child.count}`,
1309
+ child.hasChildren && " \u25BE"
1310
+ ]
1311
+ },
1312
+ i
1313
+ )) })
1314
+ ] }),
1315
+ Object.keys(ann.details.elementInfo.attributes).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1316
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Attributes" }),
1317
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontFamily: "monospace", fontSize: "0.75rem" }, children: Object.entries(ann.details.elementInfo.attributes).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { color: "#fbbf24" }, children: [
1318
+ key,
1319
+ '="',
1320
+ value,
1321
+ '"'
1322
+ ] }, key)) })
1323
+ ] })
1324
+ ]
1325
+ }
1326
+ )
1327
+ ]
1328
+ },
1329
+ ann.id
1330
+ );
1331
+ }) })
1332
+ ]
1333
+ }
1334
+ )
1335
+ }
1336
+ );
1337
+ }
1338
+
1339
+ // src/components/Toolbar.tsx
1340
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1341
+ function Toolbar() {
1342
+ const { state, dispatch } = useAgentAnnotation();
1343
+ const [showCopied, setShowCopied] = (0, import_react6.useState)(false);
1344
+ const [isAnimating, setIsAnimating] = (0, import_react6.useState)(false);
1345
+ const contentRef = (0, import_react6.useRef)(null);
1346
+ const [contentWidth, setContentWidth] = (0, import_react6.useState)(null);
1347
+ (0, import_react6.useEffect)(() => {
1348
+ if (contentRef.current && !state.isMinimized) {
1349
+ requestAnimationFrame(() => {
1350
+ if (contentRef.current) {
1351
+ setContentWidth(contentRef.current.scrollWidth);
1352
+ }
1353
+ });
1354
+ }
1355
+ }, [state.isMinimized, showCopied, state.annotations.length]);
1356
+ const handleToggleMinimized = () => {
1357
+ setIsAnimating(true);
1358
+ dispatch({ type: "TOGGLE_MINIMIZED" });
1359
+ setTimeout(() => setIsAnimating(false), 300);
1360
+ };
1361
+ const handleCopy = () => {
1362
+ if (state.annotations.length === 0) return;
1363
+ const sections = state.annotations.map((a, index) => {
1364
+ const lines = [];
1365
+ lines.push(`${"=".repeat(50)}`);
1366
+ lines.push(`Annotation ${index + 1}`);
1367
+ lines.push(`Component: ${a.componentName}`);
1368
+ lines.push(`${"=".repeat(50)}`);
1369
+ lines.push("");
1370
+ lines.push("## Instruction");
1371
+ lines.push(a.note);
1372
+ return lines.join("\n");
1373
+ });
1374
+ const text = sections.join("\n\n");
1375
+ navigator.clipboard.writeText(text).then(() => {
1376
+ setShowCopied(true);
1377
+ setTimeout(() => setShowCopied(false), 2e3);
1378
+ });
1379
+ };
1380
+ const toggleMode = () => {
1381
+ dispatch({
1382
+ type: "SET_MODE",
1383
+ payload: state.mode === "disabled" ? "inspecting" : "disabled"
1384
+ });
1385
+ };
1386
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1387
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Highlighter, {}),
1388
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AnnotationList, {}),
1389
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Draggable, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1390
+ "div",
1391
+ {
1392
+ style: {
1393
+ backgroundColor: "#1e1e1e",
1394
+ border: "1px solid #333",
1395
+ borderRadius: "8px",
1396
+ padding: "8px",
1397
+ boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
1398
+ display: "flex",
1399
+ alignItems: "center",
1400
+ gap: "8px",
1401
+ color: "#e5e7eb",
1402
+ transition: "width 0.2s"
1403
+ },
1404
+ "data-ai-annotation-ui": true,
1405
+ children: [
1406
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { cursor: "grab", color: "#666", display: "flex" }, title: "Drag", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.GripVertical, { size: 20 }) }),
1407
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1408
+ "div",
1409
+ {
1410
+ ref: contentRef,
1411
+ style: {
1412
+ display: "flex",
1413
+ alignItems: "center",
1414
+ gap: "8px",
1415
+ overflow: "hidden",
1416
+ transition: "max-width 0.3s ease, opacity 0.2s ease",
1417
+ maxWidth: state.isMinimized ? 0 : contentWidth || 300,
1418
+ opacity: state.isMinimized ? 0 : 1,
1419
+ paddingTop: "4px",
1420
+ paddingBottom: "4px",
1421
+ marginTop: "-4px",
1422
+ marginBottom: "-4px"
1423
+ },
1424
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1425
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "1px", height: "24px", backgroundColor: "#333" } }),
1426
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1427
+ "button",
1428
+ {
1429
+ onClick: toggleMode,
1430
+ title: state.mode === "inspecting" ? "Disable Inspection" : "Enable Inspection",
1431
+ style: {
1432
+ background: state.mode === "inspecting" ? "#3b82f6" : "transparent",
1433
+ border: "none",
1434
+ borderRadius: "4px",
1435
+ padding: "6px",
1436
+ color: state.mode === "inspecting" ? "white" : "inherit",
1437
+ cursor: "pointer",
1438
+ display: "flex"
1439
+ },
1440
+ children: state.mode === "inspecting" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.MousePointer2, { size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Ban, { size: 18 })
1441
+ }
1442
+ ),
1443
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1444
+ "button",
1445
+ {
1446
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1447
+ title: "List Annotations",
1448
+ style: {
1449
+ background: "transparent",
1450
+ border: "none",
1451
+ borderRadius: "4px",
1452
+ padding: "6px",
1453
+ color: "inherit",
1454
+ cursor: "pointer",
1455
+ display: "flex",
1456
+ position: "relative"
1457
+ },
1458
+ children: [
1459
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.List, { size: 18 }),
1460
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
1461
+ position: "absolute",
1462
+ top: -2,
1463
+ right: -2,
1464
+ background: "#ef4444",
1465
+ color: "white",
1466
+ fontSize: "9px",
1467
+ width: "14px",
1468
+ height: "14px",
1469
+ borderRadius: "50%",
1470
+ display: "flex",
1471
+ alignItems: "center",
1472
+ justifyContent: "center"
1473
+ }, children: state.annotations.length })
1474
+ ]
1475
+ }
1476
+ ),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1478
+ "button",
1479
+ {
1480
+ onClick: handleCopy,
1481
+ title: "Copy Annotations",
1482
+ style: {
1483
+ background: showCopied ? "#22c55e" : "transparent",
1484
+ border: "none",
1485
+ borderRadius: "4px",
1486
+ padding: "6px",
1487
+ color: showCopied ? "white" : "inherit",
1488
+ cursor: "pointer",
1489
+ display: "flex",
1490
+ alignItems: "center",
1491
+ gap: "4px",
1492
+ transition: "background-color 0.2s, color 0.2s",
1493
+ minWidth: showCopied ? "75px" : "auto"
1494
+ },
1495
+ children: showCopied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1496
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Check, { size: 18 }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "12px", whiteSpace: "nowrap" }, children: "Copied!" })
1498
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Copy, { size: 18 })
1499
+ }
1500
+ )
1501
+ ] })
1502
+ }
1503
+ ),
1504
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "1px", height: "24px", backgroundColor: "#333", marginLeft: state.isMinimized ? 0 : "auto" } }),
1505
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1506
+ "button",
1507
+ {
1508
+ onClick: handleToggleMinimized,
1509
+ title: state.isMinimized ? "Expand" : "Minimize",
1510
+ style: {
1511
+ background: "transparent",
1512
+ border: "none",
1513
+ borderRadius: "4px",
1514
+ padding: "6px",
1515
+ color: "inherit",
1516
+ cursor: "pointer",
1517
+ display: "flex"
1518
+ },
1519
+ children: state.isMinimized ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Maximize2, { size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Minus, { size: 18 })
1520
+ }
1521
+ )
1522
+ ]
1523
+ }
1524
+ ) })
1525
+ ] });
1526
+ }
1527
+
1528
+ // src/components/ErrorBoundary.tsx
1529
+ var import_react7 = require("react");
1530
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1531
+ var defaultStyles = {
1532
+ container: {
1533
+ display: "flex",
1534
+ flexDirection: "column",
1535
+ alignItems: "center",
1536
+ justifyContent: "center",
1537
+ minHeight: "100vh",
1538
+ padding: "24px",
1539
+ backgroundColor: "#1e1e1e",
1540
+ color: "#e5e7eb",
1541
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
1542
+ },
1543
+ content: {
1544
+ maxWidth: "600px",
1545
+ width: "100%",
1546
+ textAlign: "center"
1547
+ },
1548
+ icon: {
1549
+ fontSize: "48px",
1550
+ marginBottom: "16px"
1551
+ },
1552
+ title: {
1553
+ fontSize: "24px",
1554
+ fontWeight: 600,
1555
+ marginBottom: "8px",
1556
+ color: "#f87171"
1557
+ },
1558
+ subtitle: {
1559
+ fontSize: "16px",
1560
+ color: "#9ca3af",
1561
+ marginBottom: "24px"
1562
+ },
1563
+ errorBox: {
1564
+ backgroundColor: "#2d2d2d",
1565
+ border: "1px solid #404040",
1566
+ borderRadius: "8px",
1567
+ padding: "16px",
1568
+ marginBottom: "24px",
1569
+ textAlign: "left",
1570
+ maxHeight: "200px",
1571
+ overflow: "auto"
1572
+ },
1573
+ errorText: {
1574
+ fontFamily: "monospace",
1575
+ fontSize: "12px",
1576
+ color: "#f87171",
1577
+ whiteSpace: "pre-wrap",
1578
+ wordBreak: "break-word",
1579
+ margin: 0
1580
+ },
1581
+ buttonContainer: {
1582
+ display: "flex",
1583
+ gap: "12px",
1584
+ justifyContent: "center",
1585
+ flexWrap: "wrap"
1586
+ },
1587
+ button: {
1588
+ padding: "10px 20px",
1589
+ borderRadius: "6px",
1590
+ border: "none",
1591
+ fontSize: "14px",
1592
+ fontWeight: 500,
1593
+ cursor: "pointer",
1594
+ transition: "all 0.2s"
1595
+ },
1596
+ primaryButton: {
1597
+ backgroundColor: "#3b82f6",
1598
+ color: "white"
1599
+ },
1600
+ secondaryButton: {
1601
+ backgroundColor: "#404040",
1602
+ color: "#e5e7eb"
1603
+ },
1604
+ successButton: {
1605
+ backgroundColor: "#22c55e",
1606
+ color: "white"
1607
+ }
1608
+ };
1609
+ var ErrorBoundary = class extends import_react7.Component {
1610
+ constructor(props) {
1611
+ super(props);
1612
+ __publicField(this, "handleReset", () => {
1613
+ this.props.onReset?.();
1614
+ this.setState({
1615
+ hasError: false,
1616
+ error: null,
1617
+ errorInfo: null,
1618
+ copied: false
1619
+ });
1620
+ });
1621
+ __publicField(this, "handleCopyToClipboard", async () => {
1622
+ const text = this.formatError();
1623
+ try {
1624
+ await navigator.clipboard.writeText(text);
1625
+ this.setState({ copied: true });
1626
+ setTimeout(() => this.setState({ copied: false }), 2e3);
1627
+ } catch (err) {
1628
+ console.error("Failed to copy error details:", err);
1629
+ }
1630
+ });
1631
+ this.state = {
1632
+ hasError: false,
1633
+ error: null,
1634
+ errorInfo: null,
1635
+ copied: false
1636
+ };
1637
+ }
1638
+ static getDerivedStateFromError(error) {
1639
+ return { hasError: true, error };
1640
+ }
1641
+ componentDidCatch(error, errorInfo) {
1642
+ this.setState({ errorInfo });
1643
+ this.props.onError?.(error, errorInfo);
1644
+ }
1645
+ formatError() {
1646
+ const { error, errorInfo } = this.state;
1647
+ if (!error) return "";
1648
+ const lines = [
1649
+ "=".repeat(50),
1650
+ "ERROR REPORT",
1651
+ "=".repeat(50),
1652
+ "",
1653
+ `Error: ${error.name}`,
1654
+ `Message: ${error.message}`,
1655
+ "",
1656
+ "Stack Trace:",
1657
+ error.stack || "No stack trace available"
1658
+ ];
1659
+ if (errorInfo?.componentStack) {
1660
+ lines.push("", "Component Stack:", errorInfo.componentStack);
1661
+ }
1662
+ lines.push("", `Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1663
+ lines.push(`User Agent: ${typeof navigator !== "undefined" ? navigator.userAgent : "N/A"}`);
1664
+ return lines.join("\n");
1665
+ }
1666
+ getErrorInfo() {
1667
+ return {
1668
+ error: this.state.error,
1669
+ errorInfo: this.state.errorInfo,
1670
+ formattedError: this.formatError(),
1671
+ reset: this.handleReset
1672
+ };
1673
+ }
1674
+ renderDefaultFallback() {
1675
+ const {
1676
+ title = "Something went wrong",
1677
+ subtitle = "An unexpected error occurred",
1678
+ showErrorDetails = true,
1679
+ showCopyButton = true,
1680
+ showRetryButton = true,
1681
+ retryButtonLabel = "Try Again",
1682
+ copyButtonLabel = "Copy Error Details",
1683
+ customButtons = [],
1684
+ containerStyle,
1685
+ errorDetailsStyle
1686
+ } = this.props;
1687
+ const { error, copied } = this.state;
1688
+ const errorInfo = this.getErrorInfo();
1689
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...defaultStyles.container, ...containerStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: defaultStyles.content, children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: defaultStyles.icon, children: "\u26A0\uFE0F" }),
1691
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: defaultStyles.title, children: title }),
1692
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: defaultStyles.subtitle, children: subtitle }),
1693
+ showErrorDetails && error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...defaultStyles.errorBox, ...errorDetailsStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("pre", { style: defaultStyles.errorText, children: [
1694
+ error.name,
1695
+ ": ",
1696
+ error.message,
1697
+ error.stack && `
1698
+
1699
+ ${error.stack.split("\n").slice(1, 5).join("\n")}`
1700
+ ] }) }),
1701
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: defaultStyles.buttonContainer, children: [
1702
+ showRetryButton && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1703
+ "button",
1704
+ {
1705
+ onClick: this.handleReset,
1706
+ style: { ...defaultStyles.button, ...defaultStyles.primaryButton },
1707
+ children: retryButtonLabel
1708
+ }
1709
+ ),
1710
+ showCopyButton && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1711
+ "button",
1712
+ {
1713
+ onClick: this.handleCopyToClipboard,
1714
+ style: {
1715
+ ...defaultStyles.button,
1716
+ ...copied ? defaultStyles.successButton : defaultStyles.secondaryButton
1717
+ },
1718
+ children: copied ? "\u2713 Copied!" : copyButtonLabel
1719
+ }
1720
+ ),
1721
+ customButtons.map((btn, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1722
+ "button",
1723
+ {
1724
+ onClick: () => btn.onClick(errorInfo),
1725
+ style: { ...defaultStyles.button, ...defaultStyles.secondaryButton, ...btn.style },
1726
+ className: btn.className,
1727
+ children: btn.label
1728
+ },
1729
+ index
1730
+ ))
1731
+ ] })
1732
+ ] }) });
1733
+ }
1734
+ render() {
1735
+ const { hasError } = this.state;
1736
+ const { children, fallback: FallbackComponent, fallbackElement } = this.props;
1737
+ if (hasError) {
1738
+ if (FallbackComponent) {
1739
+ const errorInfo = this.getErrorInfo();
1740
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1741
+ FallbackComponent,
1742
+ {
1743
+ ...errorInfo,
1744
+ copyToClipboard: this.handleCopyToClipboard
1745
+ }
1746
+ );
1747
+ }
1748
+ if (fallbackElement) {
1749
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallbackElement });
1750
+ }
1751
+ return this.renderDefaultFallback();
1752
+ }
1753
+ return children;
1754
+ }
1755
+ };
1756
+
1757
+ // src/utils/platform.ts
1758
+ var isWeb = typeof document !== "undefined" && typeof window !== "undefined";
1759
+ var isNative = !isWeb && typeof global !== "undefined";
1760
+ function getPlatform() {
1761
+ if (isWeb) return "web";
1762
+ try {
1763
+ const { Platform } = require("react-native");
1764
+ if (Platform.OS === "ios") return "ios";
1765
+ if (Platform.OS === "android") return "android";
1766
+ return "native";
1767
+ } catch {
1768
+ return "native";
1769
+ }
1770
+ }
1771
+ function isTauriEnv2() {
1772
+ return isWeb && typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
1773
+ }
1774
+
1775
+ // src/index.tsx
1776
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1777
+ function AgentAnnotationProvider2({ children }) {
1778
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(AgentAnnotationProvider, { children: [
1779
+ children,
1780
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Toolbar, {})
1781
+ ] });
1782
+ }
1783
+ //# sourceMappingURL=index.cjs.map