openmagic 0.1.0 → 0.4.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/LICENSE +1 -1
- package/README.md +20 -14
- package/dist/cli.js +1071 -121
- package/dist/cli.js.map +1 -1
- package/dist/toolbar/index.global.js +78 -13
- package/dist/toolbar/index.global.js.map +1 -1
- package/package.json +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/toolbar/styles/toolbar.css.ts","../../src/toolbar/services/ws-client.ts","../../src/toolbar/services/dom-inspector.ts","../../src/toolbar/services/capture.ts","../../src/toolbar/services/context-builder.ts","../../src/toolbar/index.ts"],"sourcesContent":["// CSS as a JS string so it can be injected into Shadow DOM\nexport const TOOLBAR_CSS = `\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #e0e0e0;\n line-height: 1.5;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* Floating Pill */\n.om-pill {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 16px;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n border: 1px solid rgba(108, 92, 231, 0.3);\n border-radius: 50px;\n cursor: grab;\n user-select: none;\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(108, 92, 231, 0.1);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n\n.om-pill:hover {\n box-shadow: 0 6px 32px rgba(108, 92, 231, 0.3), 0 0 0 1px rgba(108, 92, 231, 0.3);\n transform: translateY(-1px);\n}\n\n.om-pill:active {\n cursor: grabbing;\n}\n\n.om-pill-logo {\n font-size: 18px;\n line-height: 1;\n}\n\n.om-pill-text {\n font-size: 12px;\n font-weight: 600;\n color: #a29bfe;\n letter-spacing: 0.5px;\n}\n\n.om-pill-btn {\n background: none;\n border: none;\n color: #e0e0e0;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 6px;\n font-size: 16px;\n line-height: 1;\n transition: background 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.om-pill-btn:hover {\n background: rgba(108, 92, 231, 0.2);\n}\n\n.om-pill-btn.active {\n background: rgba(108, 92, 231, 0.3);\n color: #a29bfe;\n}\n\n.om-pill-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.1);\n margin: 0 4px;\n}\n\n/* Panel */\n.om-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n z-index: 2147483647;\n width: 420px;\n max-height: 600px;\n background: #1a1a2e;\n border: 1px solid rgba(108, 92, 231, 0.2);\n border-radius: 16px;\n box-shadow: 0 8px 48px rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: om-slide-up 0.2s ease;\n}\n\n@keyframes om-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.om-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n background: rgba(108, 92, 231, 0.05);\n}\n\n.om-panel-title {\n font-size: 13px;\n font-weight: 600;\n color: #a29bfe;\n}\n\n.om-panel-close {\n background: none;\n border: none;\n color: #666;\n cursor: pointer;\n font-size: 18px;\n padding: 2px 6px;\n border-radius: 4px;\n line-height: 1;\n}\n\n.om-panel-close:hover {\n color: #e0e0e0;\n background: rgba(255, 255, 255, 0.05);\n}\n\n.om-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n.om-panel-body::-webkit-scrollbar {\n width: 6px;\n}\n\n.om-panel-body::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.om-panel-body::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 3px;\n}\n\n/* Chat */\n.om-chat-messages {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-height: 200px;\n max-height: 380px;\n overflow-y: auto;\n padding-bottom: 8px;\n}\n\n.om-chat-messages::-webkit-scrollbar {\n width: 4px;\n}\n\n.om-chat-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 2px;\n}\n\n.om-msg {\n padding: 10px 14px;\n border-radius: 12px;\n font-size: 13px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.om-msg-user {\n background: rgba(108, 92, 231, 0.15);\n color: #e0e0e0;\n margin-left: 32px;\n border-bottom-right-radius: 4px;\n}\n\n.om-msg-assistant {\n background: rgba(255, 255, 255, 0.03);\n color: #ccc;\n margin-right: 32px;\n border-bottom-left-radius: 4px;\n border: 1px solid rgba(255, 255, 255, 0.05);\n}\n\n.om-msg-system {\n background: rgba(233, 69, 96, 0.1);\n color: #e94560;\n font-size: 12px;\n text-align: center;\n padding: 8px;\n}\n\n.om-chat-input-wrap {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n\n.om-chat-input {\n flex: 1;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n padding: 10px 14px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n resize: none;\n min-height: 40px;\n max-height: 120px;\n}\n\n.om-chat-input:focus {\n border-color: rgba(108, 92, 231, 0.5);\n}\n\n.om-chat-input::placeholder {\n color: #555;\n}\n\n.om-chat-send {\n background: #6c5ce7;\n border: none;\n color: white;\n cursor: pointer;\n padding: 10px 16px;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.om-chat-send:hover {\n background: #7c6cf7;\n}\n\n.om-chat-send:disabled {\n background: #333;\n color: #666;\n cursor: not-allowed;\n}\n\n/* Settings */\n.om-settings {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.om-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.om-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #888;\n}\n\n.om-select, .om-input {\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 8px;\n padding: 10px 12px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n width: 100%;\n}\n\n.om-select:focus, .om-input:focus {\n border-color: rgba(108, 92, 231, 0.5);\n}\n\n.om-select option {\n background: #1a1a2e;\n color: #e0e0e0;\n}\n\n.om-btn {\n background: #6c5ce7;\n border: none;\n color: white;\n cursor: pointer;\n padding: 10px 16px;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n}\n\n.om-btn:hover {\n background: #7c6cf7;\n}\n\n.om-btn-secondary {\n background: rgba(255, 255, 255, 0.05);\n color: #e0e0e0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.om-btn-secondary:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.om-status {\n font-size: 12px;\n padding: 6px 10px;\n border-radius: 6px;\n text-align: center;\n}\n\n.om-status-success {\n background: rgba(0, 184, 148, 0.1);\n color: #00b894;\n}\n\n.om-status-error {\n background: rgba(233, 69, 96, 0.1);\n color: #e94560;\n}\n\n/* Context bar */\n.om-context-bar {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n\n.om-context-chip {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: rgba(108, 92, 231, 0.1);\n border: 1px solid rgba(108, 92, 231, 0.2);\n border-radius: 20px;\n font-size: 11px;\n color: #a29bfe;\n}\n\n.om-context-chip-remove {\n background: none;\n border: none;\n color: #a29bfe;\n cursor: pointer;\n font-size: 14px;\n padding: 0 2px;\n line-height: 1;\n}\n\n/* Diff */\n.om-diff {\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 12px;\n border-radius: 8px;\n overflow: hidden;\n border: 1px solid rgba(255, 255, 255, 0.05);\n margin: 8px 0;\n}\n\n.om-diff-header {\n padding: 8px 12px;\n background: rgba(255, 255, 255, 0.03);\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n color: #888;\n font-size: 11px;\n}\n\n.om-diff-line {\n padding: 2px 12px;\n white-space: pre;\n overflow-x: auto;\n}\n\n.om-diff-add {\n background: rgba(0, 184, 148, 0.1);\n color: #55efc4;\n}\n\n.om-diff-remove {\n background: rgba(233, 69, 96, 0.1);\n color: #fab1a0;\n}\n\n.om-diff-actions {\n display: flex;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.05);\n background: rgba(255, 255, 255, 0.02);\n}\n\n/* Element info */\n.om-element-info {\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 10px 12px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 11px;\n color: #888;\n margin: 8px 0;\n max-height: 100px;\n overflow-y: auto;\n}\n\n.om-hidden {\n display: none !important;\n}\n\n/* Loading */\n.om-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n color: #888;\n font-size: 12px;\n}\n\n.om-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(108, 92, 231, 0.2);\n border-top-color: #6c5ce7;\n border-radius: 50%;\n animation: om-spin 0.6s linear infinite;\n}\n\n@keyframes om-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Tooltip */\n.om-tooltip {\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n background: #1a1a2e;\n color: #e0e0e0;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 11px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.15s;\n margin-bottom: 4px;\n}\n\n.om-pill-btn:hover .om-tooltip {\n opacity: 1;\n}\n`;\n","type MessageHandler = (msg: any) => void;\n\nlet ws: WebSocket | null = null;\nlet handlers: Map<string, MessageHandler> = new Map();\nlet globalHandlers: ((msg: any) => void)[] = [];\nlet messageQueue: string[] = [];\nlet connected = false;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction generateId(): string {\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nexport function connect(port: number, token: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n ws = new WebSocket(`ws://127.0.0.1:${port}/__openmagic__/ws`);\n\n ws.onopen = () => {\n // Send handshake\n const handshakeId = generateId();\n send({ id: handshakeId, type: \"handshake\", payload: { token } });\n\n // Wait for handshake.ok\n handlers.set(handshakeId, (msg) => {\n if (msg.type === \"handshake.ok\") {\n connected = true;\n // Flush queued messages\n for (const queued of messageQueue) {\n ws?.send(queued);\n }\n messageQueue = [];\n resolve();\n } else if (msg.type === \"error\") {\n reject(new Error(msg.payload?.message || \"Handshake failed\"));\n }\n });\n };\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n\n // Route to specific handler if exists\n if (msg.id && handlers.has(msg.id)) {\n const handler = handlers.get(msg.id)!;\n handler(msg);\n // Don't delete handler for streaming responses\n if (msg.type === \"llm.done\" || msg.type === \"llm.error\" || !msg.type.startsWith(\"llm.\")) {\n handlers.delete(msg.id);\n }\n }\n\n // Notify global handlers\n for (const handler of globalHandlers) {\n handler(msg);\n }\n } catch {\n // Ignore parse errors\n }\n };\n\n ws.onclose = () => {\n connected = false;\n // Reconnect after 2 seconds\n if (!reconnectTimer) {\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect(port, token).catch(() => {});\n }, 2000);\n }\n };\n\n ws.onerror = () => {\n // Will trigger onclose\n };\n } catch (e) {\n reject(e);\n }\n });\n}\n\nexport function send(msg: { id: string; type: string; payload?: any }): void {\n const data = JSON.stringify(msg);\n if (ws && connected) {\n ws.send(data);\n } else {\n messageQueue.push(data);\n }\n}\n\nexport function request(type: string, payload?: any): Promise<any> {\n return new Promise((resolve, reject) => {\n const id = generateId();\n const timeout = setTimeout(() => {\n handlers.delete(id);\n reject(new Error(\"Request timeout\"));\n }, 30000);\n\n handlers.set(id, (msg) => {\n clearTimeout(timeout);\n if (msg.type === \"error\") {\n reject(new Error(msg.payload?.message || \"Unknown error\"));\n } else {\n resolve(msg);\n }\n });\n\n send({ id, type, payload });\n });\n}\n\nexport function stream(\n type: string,\n payload: any,\n onChunk: (chunk: string) => void\n): Promise<any> {\n return new Promise((resolve, reject) => {\n const id = generateId();\n const timeout = setTimeout(() => {\n handlers.delete(id);\n reject(new Error(\"Stream timeout\"));\n }, 120000); // 2 min timeout for LLM responses\n\n handlers.set(id, (msg) => {\n if (msg.type === \"llm.chunk\") {\n onChunk(msg.payload?.delta || \"\");\n } else if (msg.type === \"llm.done\") {\n clearTimeout(timeout);\n handlers.delete(id);\n resolve(msg.payload);\n } else if (msg.type === \"llm.error\" || msg.type === \"error\") {\n clearTimeout(timeout);\n handlers.delete(id);\n reject(new Error(msg.payload?.message || \"Stream error\"));\n }\n });\n\n send({ id, type, payload });\n });\n}\n\nexport function onMessage(handler: (msg: any) => void): () => void {\n globalHandlers.push(handler);\n return () => {\n globalHandlers = globalHandlers.filter((h) => h !== handler);\n };\n}\n\nexport function isConnected(): boolean {\n return connected;\n}\n\nexport function disconnect(): void {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n ws.close();\n ws = null;\n }\n connected = false;\n}\n","export interface SelectedElement {\n tagName: string;\n id: string;\n className: string;\n textContent: string;\n outerHTML: string;\n cssSelector: string;\n xpath: string;\n computedStyles: Record<string, string>;\n rect: { x: number; y: number; width: number; height: number };\n}\n\nconst IMPORTANT_STYLES = [\n \"display\",\n \"position\",\n \"width\",\n \"height\",\n \"margin\",\n \"padding\",\n \"color\",\n \"background-color\",\n \"background\",\n \"font-size\",\n \"font-weight\",\n \"font-family\",\n \"border\",\n \"border-radius\",\n \"box-shadow\",\n \"flex-direction\",\n \"justify-content\",\n \"align-items\",\n \"gap\",\n \"grid-template-columns\",\n \"grid-template-rows\",\n \"overflow\",\n \"opacity\",\n \"z-index\",\n \"text-align\",\n \"line-height\",\n \"letter-spacing\",\n];\n\nexport function inspectElement(el: HTMLElement): SelectedElement {\n const computed = window.getComputedStyle(el);\n const styles: Record<string, string> = {};\n for (const prop of IMPORTANT_STYLES) {\n styles[prop] = computed.getPropertyValue(prop);\n }\n\n const rect = el.getBoundingClientRect();\n\n return {\n tagName: el.tagName.toLowerCase(),\n id: el.id || \"\",\n className: el.className || \"\",\n textContent: (el.textContent || \"\").trim().slice(0, 200),\n outerHTML: getCleanOuterHTML(el),\n cssSelector: getCssSelector(el),\n xpath: getXPath(el),\n computedStyles: styles,\n rect: {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n },\n };\n}\n\nfunction getCleanOuterHTML(el: HTMLElement): string {\n const clone = el.cloneNode(true) as HTMLElement;\n\n // Remove script tags and large content\n const scripts = clone.querySelectorAll(\"script, style, svg\");\n scripts.forEach((s) => s.remove());\n\n // Truncate children if too many\n let html = clone.outerHTML;\n if (html.length > 2000) {\n // Just get the opening tag + first level children hints\n const tag = el.tagName.toLowerCase();\n const attrs = Array.from(el.attributes)\n .map((a) => `${a.name}=\"${a.value}\"`)\n .join(\" \");\n const childSummary = Array.from(el.children)\n .slice(0, 5)\n .map((c) => `<${c.tagName.toLowerCase()} .../>`)\n .join(\"\\n \");\n html = `<${tag} ${attrs}>\\n ${childSummary}\\n ${el.children.length > 5 ? `<!-- +${el.children.length - 5} more children -->` : \"\"}\\n</${tag}>`;\n }\n\n return html;\n}\n\nfunction getCssSelector(el: HTMLElement): string {\n if (el.id) return `#${el.id}`;\n\n const parts: string[] = [];\n let current: HTMLElement | null = el;\n\n while (current && current !== document.body) {\n let selector = current.tagName.toLowerCase();\n\n if (current.id) {\n parts.unshift(`#${current.id}`);\n break;\n }\n\n if (current.className && typeof current.className === \"string\") {\n const classes = current.className\n .trim()\n .split(/\\s+/)\n .filter((c) => !c.startsWith(\"__\") && c.length < 30)\n .slice(0, 2);\n if (classes.length > 0) {\n selector += \".\" + classes.join(\".\");\n }\n }\n\n // Add nth-child if needed for uniqueness\n const parent = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (s) => s.tagName === current!.tagName\n );\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n selector += `:nth-child(${index})`;\n }\n }\n\n parts.unshift(selector);\n current = current.parentElement;\n }\n\n return parts.join(\" > \");\n}\n\nfunction getXPath(el: HTMLElement): string {\n const parts: string[] = [];\n let current: Node | null = el;\n\n while (current && current !== document) {\n if (current.nodeType === Node.ELEMENT_NODE) {\n const element = current as HTMLElement;\n let index = 1;\n let sibling = element.previousElementSibling;\n while (sibling) {\n if (sibling.tagName === element.tagName) index++;\n sibling = sibling.previousElementSibling;\n }\n parts.unshift(`${element.tagName.toLowerCase()}[${index}]`);\n }\n current = current.parentNode;\n }\n\n return \"/\" + parts.join(\"/\");\n}\n\n// --- Highlight Overlay ---\n\nlet highlightEl: HTMLDivElement | null = null;\n\nexport function showHighlight(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n}): void {\n if (!highlightEl) {\n highlightEl = document.createElement(\"div\");\n highlightEl.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: 2147483646;\n border: 2px solid #6c5ce7;\n background: rgba(108, 92, 231, 0.1);\n transition: all 0.1s ease;\n `;\n highlightEl.dataset.openmagic = \"highlight\";\n document.body.appendChild(highlightEl);\n }\n\n highlightEl.style.left = `${rect.x}px`;\n highlightEl.style.top = `${rect.y}px`;\n highlightEl.style.width = `${rect.width}px`;\n highlightEl.style.height = `${rect.height}px`;\n highlightEl.style.display = \"block\";\n}\n\nexport function hideHighlight(): void {\n if (highlightEl) {\n highlightEl.style.display = \"none\";\n }\n}\n\nexport function removeHighlight(): void {\n if (highlightEl) {\n highlightEl.remove();\n highlightEl = null;\n }\n}\n","// Simple screenshot capture using Canvas API\n// Falls back to a simpler approach if html-to-image isn't available\n\nexport async function captureScreenshot(\n target?: HTMLElement\n): Promise<string | null> {\n try {\n // Try using the Canvas approach for element capture\n if (target) {\n return await captureElementViaCanvas(target);\n }\n\n // Full page: use a simple canvas capture of the viewport\n return await captureViewport();\n } catch (e) {\n console.warn(\"[OpenMagic] Screenshot capture failed:\", e);\n return null;\n }\n}\n\nasync function captureViewport(): Promise<string | null> {\n // Create a canvas the size of the viewport\n const canvas = document.createElement(\"canvas\");\n const dpr = window.devicePixelRatio || 1;\n canvas.width = window.innerWidth * dpr;\n canvas.height = window.innerHeight * dpr;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.scale(dpr, dpr);\n\n // We can't directly capture the viewport without html2canvas or similar\n // Instead, we use the SVG foreignObject approach (snapdom-like)\n try {\n const svgData = await elementToSvg(document.body);\n const img = await svgToImage(svgData, window.innerWidth, window.innerHeight);\n ctx.drawImage(img, 0, 0);\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null;\n }\n}\n\nasync function captureElementViaCanvas(\n element: HTMLElement\n): Promise<string | null> {\n const rect = element.getBoundingClientRect();\n const canvas = document.createElement(\"canvas\");\n const dpr = window.devicePixelRatio || 1;\n canvas.width = rect.width * dpr;\n canvas.height = rect.height * dpr;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.scale(dpr, dpr);\n\n try {\n const svgData = await elementToSvg(element);\n const img = await svgToImage(svgData, rect.width, rect.height);\n ctx.drawImage(img, 0, 0);\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null;\n }\n}\n\nfunction elementToSvg(element: HTMLElement): Promise<string> {\n return new Promise((resolve) => {\n const clone = element.cloneNode(true) as HTMLElement;\n\n // Inline computed styles on the clone\n inlineStyles(element, clone);\n\n const rect = element.getBoundingClientRect();\n const width = rect.width;\n const height = rect.height;\n\n const foreignObject = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n <foreignObject width=\"100%\" height=\"100%\">\n <div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"width:${width}px;height:${height}px;overflow:hidden;\">\n ${clone.outerHTML}\n </div>\n </foreignObject>\n </svg>`;\n\n resolve(foreignObject);\n });\n}\n\nfunction inlineStyles(source: HTMLElement, target: HTMLElement): void {\n const computed = window.getComputedStyle(source);\n let cssText = \"\";\n for (let i = 0; i < computed.length; i++) {\n const prop = computed[i];\n cssText += `${prop}:${computed.getPropertyValue(prop)};`;\n }\n target.style.cssText = cssText;\n\n const sourceChildren = source.children;\n const targetChildren = target.children;\n for (let i = 0; i < sourceChildren.length && i < targetChildren.length; i++) {\n inlineStyles(\n sourceChildren[i] as HTMLElement,\n targetChildren[i] as HTMLElement\n );\n }\n}\n\nfunction svgToImage(\n svgData: string,\n width: number,\n height: number\n): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const blob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error(\"Failed to load SVG image\"));\n };\n\n img.width = width;\n img.height = height;\n img.src = url;\n });\n}\n","import type { SelectedElement } from \"./dom-inspector.js\";\n\n// --- Network Log Capture ---\n\ninterface NetworkEntry {\n method: string;\n url: string;\n status?: number;\n duration?: number;\n timestamp: number;\n}\n\nconst networkLogs: NetworkEntry[] = [];\nconst MAX_NETWORK_LOGS = 50;\n\nlet networkCaptureInstalled = false;\n\nexport function installNetworkCapture(): void {\n if (networkCaptureInstalled) return;\n networkCaptureInstalled = true;\n\n // Intercept fetch\n const originalFetch = window.fetch;\n window.fetch = async function (...args) {\n const request = new Request(...args);\n const entry: NetworkEntry = {\n method: request.method,\n url: request.url,\n timestamp: Date.now(),\n };\n\n try {\n const response = await originalFetch.apply(this, args);\n entry.status = response.status;\n entry.duration = Date.now() - entry.timestamp;\n addNetworkEntry(entry);\n return response;\n } catch (e) {\n entry.status = 0;\n entry.duration = Date.now() - entry.timestamp;\n addNetworkEntry(entry);\n throw e;\n }\n };\n\n // Intercept XMLHttpRequest\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method: string, url: string, ...rest: any[]) {\n (this as any).__om_method = method;\n (this as any).__om_url = url;\n (this as any).__om_start = Date.now();\n return originalOpen.apply(this, [method, url, ...rest] as any);\n };\n\n XMLHttpRequest.prototype.send = function (...args) {\n this.addEventListener(\"loadend\", () => {\n addNetworkEntry({\n method: (this as any).__om_method || \"GET\",\n url: (this as any).__om_url || \"\",\n status: this.status,\n duration: Date.now() - ((this as any).__om_start || Date.now()),\n timestamp: (this as any).__om_start || Date.now(),\n });\n });\n return originalSend.apply(this, args);\n };\n}\n\nfunction addNetworkEntry(entry: NetworkEntry): void {\n // Filter out OpenMagic's own requests\n if (entry.url.includes(\"__openmagic__\")) return;\n networkLogs.push(entry);\n if (networkLogs.length > MAX_NETWORK_LOGS) {\n networkLogs.shift();\n }\n}\n\nexport function getNetworkLogs(): NetworkEntry[] {\n return [...networkLogs];\n}\n\nexport function clearNetworkLogs(): void {\n networkLogs.length = 0;\n}\n\n// --- Console Log Capture ---\n\ninterface ConsoleEntry {\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n args: string[];\n timestamp: number;\n}\n\nconst consoleLogs: ConsoleEntry[] = [];\nconst MAX_CONSOLE_LOGS = 100;\n\nlet consoleCaptureInstalled = false;\n\nexport function installConsoleCapture(): void {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n\n const levels: ConsoleEntry[\"level\"][] = [\"log\", \"warn\", \"error\", \"info\", \"debug\"];\n\n for (const level of levels) {\n const original = console[level];\n console[level] = function (...args: any[]) {\n consoleLogs.push({\n level,\n args: args.map((a) => {\n try {\n return typeof a === \"object\" ? JSON.stringify(a).slice(0, 500) : String(a);\n } catch {\n return String(a);\n }\n }),\n timestamp: Date.now(),\n });\n\n if (consoleLogs.length > MAX_CONSOLE_LOGS) {\n consoleLogs.shift();\n }\n\n original.apply(console, args);\n };\n }\n}\n\nexport function getConsoleLogs(): ConsoleEntry[] {\n return [...consoleLogs];\n}\n\nexport function clearConsoleLogs(): void {\n consoleLogs.length = 0;\n}\n\n// --- Context Builder ---\n\nexport function buildContext(\n selectedElement: SelectedElement | null,\n screenshot: string | null\n) {\n return {\n selectedElement: selectedElement\n ? {\n tagName: selectedElement.tagName,\n id: selectedElement.id,\n className: selectedElement.className,\n textContent: selectedElement.textContent,\n outerHTML: selectedElement.outerHTML,\n cssSelector: selectedElement.cssSelector,\n computedStyles: selectedElement.computedStyles,\n }\n : undefined,\n screenshot: screenshot || undefined,\n networkLogs: getNetworkLogs().map((l) => ({\n method: l.method,\n url: l.url,\n status: l.status,\n duration: l.duration,\n timestamp: l.timestamp,\n })),\n consoleLogs: getConsoleLogs().map((l) => ({\n level: l.level,\n args: l.args,\n timestamp: l.timestamp,\n })),\n };\n}\n","import { TOOLBAR_CSS } from \"./styles/toolbar.css.js\";\nimport * as ws from \"./services/ws-client.js\";\nimport {\n inspectElement,\n showHighlight,\n hideHighlight,\n removeHighlight,\n type SelectedElement,\n} from \"./services/dom-inspector.js\";\nimport { captureScreenshot } from \"./services/capture.js\";\nimport {\n installNetworkCapture,\n installConsoleCapture,\n buildContext,\n} from \"./services/context-builder.js\";\n\n// Import the model registry inline (bundled into toolbar IIFE)\nconst MODEL_REGISTRY: Record<string, { name: string; models: { id: string; name: string }[]; keyPlaceholder: string; local?: boolean }> = {\n openai: { name: \"OpenAI\", models: [\n { id: \"gpt-4.1\", name: \"GPT-4.1\" }, { id: \"gpt-4.1-mini\", name: \"GPT-4.1 Mini\" },\n { id: \"gpt-4.1-nano\", name: \"GPT-4.1 Nano\" },\n { id: \"gpt-4o\", name: \"GPT-4o\" }, { id: \"gpt-4o-mini\", name: \"GPT-4o Mini\" },\n { id: \"o3\", name: \"o3 (Reasoning)\" }, { id: \"o4-mini\", name: \"o4-mini (Reasoning)\" },\n ], keyPlaceholder: \"sk-...\" },\n anthropic: { name: \"Anthropic\", models: [\n { id: \"claude-opus-4-20250514\", name: \"Claude Opus 4\" },\n { id: \"claude-sonnet-4-20250514\", name: \"Claude Sonnet 4\" },\n { id: \"claude-haiku-4-20250514\", name: \"Claude Haiku 4\" },\n ], keyPlaceholder: \"sk-ant-...\" },\n google: { name: \"Google Gemini\", models: [\n { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\" },\n { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\" },\n { id: \"gemini-2.0-flash\", name: \"Gemini 2.0 Flash\" },\n ], keyPlaceholder: \"AIza...\" },\n deepseek: { name: \"DeepSeek\", models: [\n { id: \"deepseek-chat\", name: \"DeepSeek V3\" },\n { id: \"deepseek-reasoner\", name: \"DeepSeek R1\" },\n ], keyPlaceholder: \"sk-...\" },\n groq: { name: \"Groq\", models: [\n { id: \"llama-3.3-70b-versatile\", name: \"Llama 3.3 70B\" },\n { id: \"llama-3.1-8b-instant\", name: \"Llama 3.1 8B\" },\n ], keyPlaceholder: \"gsk_...\" },\n mistral: { name: \"Mistral\", models: [\n { id: \"mistral-large-latest\", name: \"Mistral Large\" },\n { id: \"codestral-latest\", name: \"Codestral\" },\n ], keyPlaceholder: \"...\" },\n xai: { name: \"xAI (Grok)\", models: [\n { id: \"grok-3\", name: \"Grok 3\" }, { id: \"grok-3-mini\", name: \"Grok 3 Mini\" },\n ], keyPlaceholder: \"xai-...\" },\n ollama: { name: \"Ollama (Local)\", models: [], keyPlaceholder: \"not required\", local: true },\n openrouter: { name: \"OpenRouter\", models: [], keyPlaceholder: \"sk-or-...\" },\n};\n\n// --- State ---\ninterface AppState {\n connected: boolean;\n panelOpen: boolean;\n activePanel: \"chat\" | \"settings\" | null;\n selecting: boolean;\n selectedElement: SelectedElement | null;\n screenshot: string | null;\n messages: Array<{ role: \"user\" | \"assistant\" | \"system\"; content: string }>;\n streaming: boolean;\n streamContent: string;\n provider: string;\n model: string;\n hasApiKey: boolean;\n roots: string[];\n}\n\nconst state: AppState = {\n connected: false,\n panelOpen: false,\n activePanel: null,\n selecting: false,\n selectedElement: null,\n screenshot: null,\n messages: [],\n streaming: false,\n streamContent: \"\",\n provider: \"\",\n model: \"\",\n hasApiKey: false,\n roots: [],\n};\n\n// --- DOM References ---\nlet shadow: ShadowRoot;\nlet container: HTMLDivElement;\n\n// --- Initialize ---\nfunction init() {\n // Don't initialize if already loaded\n if (document.querySelector(\"openmagic-toolbar\")) return;\n\n // Create custom element\n const host = document.createElement(\"openmagic-toolbar\");\n host.dataset.openmagic = \"true\";\n shadow = host.attachShadow({ mode: \"closed\" });\n\n // Inject styles\n const style = document.createElement(\"style\");\n style.textContent = TOOLBAR_CSS;\n shadow.appendChild(style);\n\n // Create container\n container = document.createElement(\"div\");\n shadow.appendChild(container);\n\n // Mount\n document.body.appendChild(host);\n\n // Install captures\n installNetworkCapture();\n installConsoleCapture();\n\n // Connect to server\n const config = (window as any).__OPENMAGIC_CONFIG__;\n if (config) {\n ws.connect(config.wsPort, config.token)\n .then(() => {\n state.connected = true;\n // Fetch config\n ws.request(\"config.get\").then((msg: any) => {\n state.provider = msg.payload?.provider || \"\";\n state.model = msg.payload?.model || \"\";\n state.hasApiKey = msg.payload?.hasApiKey || false;\n state.roots = msg.payload?.roots || [];\n\n // If not configured, open settings\n if (!state.provider || !state.hasApiKey) {\n state.panelOpen = true;\n state.activePanel = \"settings\";\n }\n\n render();\n });\n })\n .catch((e: Error) => {\n console.error(\"[OpenMagic] Connection failed:\", e);\n state.connected = false;\n render();\n });\n }\n\n render();\n}\n\n// --- Render ---\nfunction render() {\n container.innerHTML = \"\";\n\n // Panel (if open)\n if (state.panelOpen && state.activePanel) {\n const panel = document.createElement(\"div\");\n panel.className = \"om-panel\";\n\n if (state.activePanel === \"settings\") {\n panel.innerHTML = renderSettings();\n } else if (state.activePanel === \"chat\") {\n panel.innerHTML = renderChat();\n }\n\n container.appendChild(panel);\n attachPanelEvents(panel);\n }\n\n // Floating pill\n const pill = document.createElement(\"div\");\n pill.className = \"om-pill\";\n pill.innerHTML = `\n <span class=\"om-pill-logo\">✨</span>\n <span class=\"om-pill-text\">Magic</span>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn ${state.selecting ? \"active\" : \"\"}\" data-action=\"select\" title=\"Select Element\">\n 🎯\n </button>\n <button class=\"om-pill-btn\" data-action=\"screenshot\" title=\"Screenshot\">\n 📸\n </button>\n <button class=\"om-pill-btn ${state.activePanel === \"chat\" ? \"active\" : \"\"}\" data-action=\"chat\" title=\"Chat\">\n 💬\n </button>\n <button class=\"om-pill-btn ${state.activePanel === \"settings\" ? \"active\" : \"\"}\" data-action=\"settings\" title=\"Settings\">\n ⚙️\n </button>\n `;\n\n // Connection indicator\n if (!state.connected) {\n const dot = document.createElement(\"span\");\n dot.style.cssText = \"width:8px;height:8px;border-radius:50%;background:#e94560;margin-left:4px;\";\n pill.appendChild(dot);\n }\n\n container.appendChild(pill);\n\n // Draggable\n makeDraggable(pill);\n\n // Pill button events\n pill.querySelectorAll(\".om-pill-btn\").forEach((btn) => {\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n const action = (btn as HTMLElement).dataset.action;\n\n if (action === \"select\") {\n toggleSelectMode();\n } else if (action === \"screenshot\") {\n takeScreenshot();\n } else if (action === \"chat\") {\n togglePanel(\"chat\");\n } else if (action === \"settings\") {\n togglePanel(\"settings\");\n }\n });\n });\n}\n\n// --- Renderers ---\n\nfunction renderSettings(): string {\n const providerOptions = Object.entries(MODEL_REGISTRY)\n .map(([key, p]) => `<option value=\"${key}\" ${state.provider === key ? \"selected\" : \"\"}>${p.name}</option>`)\n .join(\"\");\n\n const currentProvider = MODEL_REGISTRY[state.provider];\n const modelOptions = currentProvider\n ? currentProvider.models.map((m) =>\n `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`\n ).join(\"\")\n : '<option value=\"\">Select a provider first</option>';\n\n const keyPlaceholder = currentProvider?.keyPlaceholder || \"Enter API key...\";\n const isLocal = currentProvider?.local || false;\n\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Settings</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n <div class=\"om-settings\">\n <div class=\"om-field\">\n <label class=\"om-label\">Provider</label>\n <select class=\"om-select\" data-field=\"provider\">\n <option value=\"\">Select Provider...</option>\n ${providerOptions}\n </select>\n </div>\n\n <div class=\"om-field\">\n <label class=\"om-label\">Model</label>\n <select class=\"om-select\" data-field=\"model\">\n <option value=\"\">Select Model...</option>\n ${modelOptions}\n </select>\n </div>\n\n <div class=\"om-field ${isLocal ? \"om-hidden\" : \"\"}\">\n <label class=\"om-label\">API Key</label>\n <input type=\"password\" class=\"om-input\" data-field=\"apiKey\"\n placeholder=\"${keyPlaceholder}\"\n value=\"\" />\n </div>\n\n <button class=\"om-btn\" data-action=\"save-settings\">Save Configuration</button>\n\n ${state.hasApiKey ? '<div class=\"om-status om-status-success\">API key configured</div>' : \"\"}\n </div>\n </div>\n `;\n}\n\nfunction renderChat(): string {\n if (!state.hasApiKey || !state.provider) {\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Chat</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n <div class=\"om-status om-status-error\">\n Configure your LLM provider in Settings first\n </div>\n </div>\n `;\n }\n\n const messagesHtml = state.messages\n .map((m) => `<div class=\"om-msg om-msg-${m.role}\">${escapeHtml(m.content)}</div>`)\n .join(\"\");\n\n const streamHtml = state.streaming\n ? `<div class=\"om-msg om-msg-assistant\"><div class=\"om-loading\"><div class=\"om-spinner\"></div> Thinking...</div>${escapeHtml(state.streamContent)}</div>`\n : \"\";\n\n const contextChips: string[] = [];\n if (state.selectedElement) {\n contextChips.push(`<span class=\"om-context-chip\">🎯 ${state.selectedElement.tagName}${state.selectedElement.id ? \"#\" + state.selectedElement.id : \"\"} <button class=\"om-context-chip-remove\" data-action=\"clear-element\">×</button></span>`);\n }\n if (state.screenshot) {\n contextChips.push(`<span class=\"om-context-chip\">📸 Screenshot <button class=\"om-context-chip-remove\" data-action=\"clear-screenshot\">×</button></span>`);\n }\n\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Chat — ${MODEL_REGISTRY[state.provider]?.name || state.provider} / ${state.model}</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n ${contextChips.length > 0 ? `<div class=\"om-context-bar\">${contextChips.join(\"\")}</div>` : \"\"}\n ${state.selectedElement ? `<div class=\"om-element-info\"><${state.selectedElement.tagName}${state.selectedElement.id ? ' id=\"' + state.selectedElement.id + '\"' : \"\"}${state.selectedElement.className ? ' class=\"' + state.selectedElement.className.toString().slice(0, 60) + '\"' : \"\"}></div>` : \"\"}\n <div class=\"om-chat-messages\">\n ${messagesHtml || '<div style=\"color:#555;text-align:center;padding:40px 0;font-size:13px;\">Select an element or describe what you want to change</div>'}\n ${streamHtml}\n </div>\n <div class=\"om-chat-input-wrap\">\n <textarea class=\"om-chat-input\" placeholder=\"Describe the change you want...\"\n rows=\"1\" ${state.streaming ? \"disabled\" : \"\"}></textarea>\n <button class=\"om-chat-send\" data-action=\"send\" ${state.streaming ? \"disabled\" : \"\"}>\n ${state.streaming ? \"...\" : \"Send\"}\n </button>\n </div>\n </div>\n `;\n}\n\n// --- Event Handlers ---\n\nfunction attachPanelEvents(panel: HTMLElement) {\n // Close button\n panel.querySelector('[data-action=\"close\"]')?.addEventListener(\"click\", () => {\n state.panelOpen = false;\n state.activePanel = null;\n render();\n });\n\n // Settings: provider change\n panel.querySelector('[data-field=\"provider\"]')?.addEventListener(\"change\", (e) => {\n state.provider = (e.target as HTMLSelectElement).value;\n state.model = \"\";\n render();\n });\n\n // Settings: model change\n panel.querySelector('[data-field=\"model\"]')?.addEventListener(\"change\", (e) => {\n state.model = (e.target as HTMLSelectElement).value;\n });\n\n // Settings: save\n panel.querySelector('[data-action=\"save-settings\"]')?.addEventListener(\"click\", () => {\n const apiKeyInput = panel.querySelector('[data-field=\"apiKey\"]') as HTMLInputElement;\n const apiKey = apiKeyInput?.value || \"\";\n\n const payload: any = {\n provider: state.provider,\n model: state.model,\n };\n if (apiKey) {\n payload.apiKey = apiKey;\n }\n\n ws.request(\"config.set\", payload).then(() => {\n state.hasApiKey = true;\n render();\n }).catch((e: Error) => {\n console.error(\"[OpenMagic] Failed to save config:\", e);\n });\n });\n\n // Chat: send\n panel.querySelector('[data-action=\"send\"]')?.addEventListener(\"click\", () => {\n sendMessage(panel);\n });\n\n // Chat: enter to send\n const input = panel.querySelector(\".om-chat-input\") as HTMLTextAreaElement;\n input?.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendMessage(panel);\n }\n });\n\n // Auto-resize textarea\n input?.addEventListener(\"input\", () => {\n input.style.height = \"auto\";\n input.style.height = Math.min(input.scrollHeight, 120) + \"px\";\n });\n\n // Clear context\n panel.querySelector('[data-action=\"clear-element\"]')?.addEventListener(\"click\", () => {\n state.selectedElement = null;\n render();\n });\n\n panel.querySelector('[data-action=\"clear-screenshot\"]')?.addEventListener(\"click\", () => {\n state.screenshot = null;\n render();\n });\n}\n\nasync function sendMessage(panel: HTMLElement) {\n const input = panel.querySelector(\".om-chat-input\") as HTMLTextAreaElement;\n if (!input) return;\n\n const text = input.value.trim();\n if (!text || state.streaming) return;\n\n // Add user message\n state.messages.push({ role: \"user\", content: text });\n state.streaming = true;\n state.streamContent = \"\";\n render();\n\n // Build context\n const context = buildContext(state.selectedElement, state.screenshot);\n\n try {\n const result = await ws.stream(\n \"llm.chat\",\n {\n provider: state.provider,\n model: state.model,\n messages: state.messages.map((m) => ({ role: m.role, content: m.content })),\n context,\n },\n (chunk: string) => {\n state.streamContent += chunk;\n // Update streaming message in place\n const msgContainer = shadow.querySelector(\".om-chat-messages\");\n const streamEl = msgContainer?.querySelector(\".om-msg-assistant:last-child\");\n if (streamEl) {\n streamEl.innerHTML = escapeHtml(state.streamContent);\n }\n }\n );\n\n // Add assistant message\n state.messages.push({ role: \"assistant\", content: state.streamContent || result?.content || \"\" });\n\n // Handle modifications\n if (result?.modifications && result.modifications.length > 0) {\n for (const mod of result.modifications) {\n if (mod.type === \"edit\" && mod.file && mod.search && mod.replace) {\n // Read the file first\n try {\n const fileResult = await ws.request(\"fs.read\", { path: resolveFilePath(mod.file) });\n const content = fileResult.payload?.content;\n if (content && content.includes(mod.search)) {\n const newContent = content.replace(mod.search, mod.replace);\n await ws.request(\"fs.write\", { path: resolveFilePath(mod.file), content: newContent });\n state.messages.push({\n role: \"system\",\n content: `Applied change to ${mod.file}`,\n });\n }\n } catch (e: any) {\n state.messages.push({\n role: \"system\",\n content: `Failed to apply change to ${mod.file}: ${e.message}`,\n });\n }\n }\n }\n }\n } catch (e: any) {\n state.messages.push({ role: \"system\", content: `Error: ${e.message}` });\n }\n\n state.streaming = false;\n state.streamContent = \"\";\n render();\n}\n\nfunction resolveFilePath(relativePath: string): string {\n // Resolve relative to first root\n if (state.roots.length > 0) {\n return state.roots[0] + \"/\" + relativePath;\n }\n return relativePath;\n}\n\n// --- Select Mode ---\n\nlet selectHandler: ((e: MouseEvent) => void) | null = null;\nlet hoverHandler: ((e: MouseEvent) => void) | null = null;\n\nfunction toggleSelectMode() {\n if (state.selecting) {\n exitSelectMode();\n } else {\n enterSelectMode();\n }\n}\n\nfunction enterSelectMode() {\n state.selecting = true;\n document.body.style.cursor = \"crosshair\";\n\n hoverHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (isOpenMagicElement(target)) return;\n const rect = target.getBoundingClientRect();\n showHighlight({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n };\n\n selectHandler = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const target = e.target as HTMLElement;\n if (isOpenMagicElement(target)) return;\n\n state.selectedElement = inspectElement(target);\n exitSelectMode();\n\n // Open chat if not open\n if (state.activePanel !== \"chat\") {\n state.panelOpen = true;\n state.activePanel = \"chat\";\n }\n\n render();\n };\n\n document.addEventListener(\"mousemove\", hoverHandler, true);\n document.addEventListener(\"click\", selectHandler, true);\n\n render();\n}\n\nfunction exitSelectMode() {\n state.selecting = false;\n document.body.style.cursor = \"\";\n hideHighlight();\n\n if (hoverHandler) {\n document.removeEventListener(\"mousemove\", hoverHandler, true);\n hoverHandler = null;\n }\n if (selectHandler) {\n document.removeEventListener(\"click\", selectHandler, true);\n selectHandler = null;\n }\n\n render();\n}\n\n// --- Screenshot ---\n\nasync function takeScreenshot() {\n const screenshot = await captureScreenshot();\n if (screenshot) {\n state.screenshot = screenshot;\n // Open chat\n state.panelOpen = true;\n state.activePanel = \"chat\";\n render();\n }\n}\n\n// --- Panel Toggle ---\n\nfunction togglePanel(panel: \"chat\" | \"settings\") {\n if (state.panelOpen && state.activePanel === panel) {\n state.panelOpen = false;\n state.activePanel = null;\n } else {\n state.panelOpen = true;\n state.activePanel = panel;\n }\n render();\n}\n\n// --- Draggable ---\n\nfunction makeDraggable(el: HTMLElement) {\n let isDragging = false;\n let startX = 0;\n let startY = 0;\n let origX = 0;\n let origY = 0;\n\n el.addEventListener(\"mousedown\", (e) => {\n // Only drag from the pill itself, not buttons\n if ((e.target as HTMLElement).closest(\".om-pill-btn\")) return;\n\n isDragging = true;\n startX = e.clientX;\n startY = e.clientY;\n const rect = el.getBoundingClientRect();\n origX = rect.left;\n origY = rect.top;\n e.preventDefault();\n });\n\n document.addEventListener(\"mousemove\", (e) => {\n if (!isDragging) return;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n el.style.position = \"fixed\";\n el.style.left = origX + dx + \"px\";\n el.style.top = origY + dy + \"px\";\n el.style.right = \"auto\";\n el.style.bottom = \"auto\";\n });\n\n document.addEventListener(\"mouseup\", () => {\n isDragging = false;\n });\n}\n\n// --- Helpers ---\n\nfunction isOpenMagicElement(el: HTMLElement): boolean {\n return !!el.closest(\"openmagic-toolbar\") || !!el.dataset?.openmagic;\n}\n\nfunction escapeHtml(text: string): string {\n const div = document.createElement(\"div\");\n div.textContent = text;\n return div.innerHTML;\n}\n\n// --- Boot ---\nif (typeof window !== \"undefined\") {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n}\n"],"mappings":";wCACO,IAAMA,EAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["TOOLBAR_CSS","ws","handlers","globalHandlers","messageQueue","connected","reconnectTimer","generateId","connect","port","token","resolve","reject","handshakeId","send","msg","queued","event","handler","e","data","request","type","payload","id","timeout","stream","onChunk","IMPORTANT_STYLES","inspectElement","el","computed","styles","prop","rect","getCleanOuterHTML","getCssSelector","getXPath","clone","s","html","tag","attrs","a","childSummary","c","parts","current","selector","classes","parent","siblings","index","element","sibling","highlightEl","showHighlight","hideHighlight","captureScreenshot","target","captureElementViaCanvas","captureViewport","e","canvas","dpr","ctx","svgData","elementToSvg","img","svgToImage","element","rect","resolve","clone","inlineStyles","width","height","foreignObject","source","computed","cssText","i","prop","sourceChildren","targetChildren","reject","blob","url","networkLogs","networkCaptureInstalled","installNetworkCapture","originalFetch","args","request","entry","response","addNetworkEntry","e","originalOpen","originalSend","method","url","rest","networkLogs","getNetworkLogs","consoleLogs","MAX_CONSOLE_LOGS","consoleCaptureInstalled","installConsoleCapture","levels","level","original","args","a","getConsoleLogs","buildContext","selectedElement","screenshot","getNetworkLogs","l","getConsoleLogs","MODEL_REGISTRY","state","shadow","container","init","host","style","TOOLBAR_CSS","installNetworkCapture","installConsoleCapture","config","connect","request","msg","render","e","panel","renderSettings","renderChat","attachPanelEvents","pill","dot","makeDraggable","btn","action","toggleSelectMode","takeScreenshot","togglePanel","providerOptions","key","p","currentProvider","modelOptions","m","keyPlaceholder","isLocal","messagesHtml","escapeHtml","streamHtml","contextChips","apiKey","payload","sendMessage","input","text","context","buildContext","result","stream","chunk","streamEl","mod","content","resolveFilePath","newContent","relativePath","selectHandler","hoverHandler","exitSelectMode","enterSelectMode","target","isOpenMagicElement","rect","showHighlight","inspectElement","hideHighlight","screenshot","captureScreenshot","el","isDragging","startX","startY","origX","origY","dx","dy","div"]}
|
|
1
|
+
{"version":3,"sources":["../../src/toolbar/styles/toolbar.css.ts","../../src/toolbar/services/ws-client.ts","../../src/toolbar/services/dom-inspector.ts","../../src/toolbar/services/capture.ts","../../src/toolbar/services/context-builder.ts","../../src/toolbar/index.ts"],"sourcesContent":["// CSS as a JS string so it can be injected into Shadow DOM\nexport const TOOLBAR_CSS = `\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #e0e0e0;\n line-height: 1.5;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* Floating Pill */\n.om-pill {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 16px;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n border: 1px solid rgba(108, 92, 231, 0.3);\n border-radius: 50px;\n cursor: grab;\n user-select: none;\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(108, 92, 231, 0.1);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n\n.om-pill:hover {\n box-shadow: 0 6px 32px rgba(108, 92, 231, 0.3), 0 0 0 1px rgba(108, 92, 231, 0.3);\n transform: translateY(-1px);\n}\n\n.om-pill:active {\n cursor: grabbing;\n}\n\n.om-pill-logo {\n font-size: 18px;\n line-height: 1;\n}\n\n.om-pill-text {\n font-size: 12px;\n font-weight: 600;\n color: #a29bfe;\n letter-spacing: 0.5px;\n}\n\n.om-pill-btn {\n background: none;\n border: none;\n color: #e0e0e0;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 6px;\n font-size: 16px;\n line-height: 1;\n transition: background 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.om-pill-btn:hover {\n background: rgba(108, 92, 231, 0.2);\n}\n\n.om-pill-btn.active {\n background: rgba(108, 92, 231, 0.3);\n color: #a29bfe;\n}\n\n.om-pill-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.1);\n margin: 0 4px;\n}\n\n/* Panel */\n.om-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n z-index: 2147483647;\n width: 420px;\n max-height: 600px;\n background: #1a1a2e;\n border: 1px solid rgba(108, 92, 231, 0.2);\n border-radius: 16px;\n box-shadow: 0 8px 48px rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: om-slide-up 0.2s ease;\n}\n\n@keyframes om-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.om-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n background: rgba(108, 92, 231, 0.05);\n}\n\n.om-panel-title {\n font-size: 13px;\n font-weight: 600;\n color: #a29bfe;\n}\n\n.om-panel-close {\n background: none;\n border: none;\n color: #666;\n cursor: pointer;\n font-size: 18px;\n padding: 2px 6px;\n border-radius: 4px;\n line-height: 1;\n}\n\n.om-panel-close:hover {\n color: #e0e0e0;\n background: rgba(255, 255, 255, 0.05);\n}\n\n.om-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n.om-panel-body::-webkit-scrollbar {\n width: 6px;\n}\n\n.om-panel-body::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.om-panel-body::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 3px;\n}\n\n/* Chat */\n.om-chat-messages {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-height: 200px;\n max-height: 380px;\n overflow-y: auto;\n padding-bottom: 8px;\n}\n\n.om-chat-messages::-webkit-scrollbar {\n width: 4px;\n}\n\n.om-chat-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 2px;\n}\n\n.om-msg {\n padding: 10px 14px;\n border-radius: 12px;\n font-size: 13px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.om-msg-user {\n background: rgba(108, 92, 231, 0.15);\n color: #e0e0e0;\n margin-left: 32px;\n border-bottom-right-radius: 4px;\n}\n\n.om-msg-assistant {\n background: rgba(255, 255, 255, 0.03);\n color: #ccc;\n margin-right: 32px;\n border-bottom-left-radius: 4px;\n border: 1px solid rgba(255, 255, 255, 0.05);\n}\n\n.om-msg-system {\n background: rgba(233, 69, 96, 0.1);\n color: #e94560;\n font-size: 12px;\n text-align: center;\n padding: 8px;\n}\n\n.om-chat-input-wrap {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n\n.om-chat-input {\n flex: 1;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n padding: 10px 14px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n resize: none;\n min-height: 40px;\n max-height: 120px;\n}\n\n.om-chat-input:focus {\n border-color: rgba(108, 92, 231, 0.5);\n}\n\n.om-chat-input::placeholder {\n color: #555;\n}\n\n.om-chat-send {\n background: #6c5ce7;\n border: none;\n color: white;\n cursor: pointer;\n padding: 10px 16px;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.om-chat-send:hover {\n background: #7c6cf7;\n}\n\n.om-chat-send:disabled {\n background: #333;\n color: #666;\n cursor: not-allowed;\n}\n\n/* Settings */\n.om-settings {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.om-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.om-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #888;\n}\n\n.om-select, .om-input {\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 8px;\n padding: 10px 12px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n width: 100%;\n}\n\n.om-select:focus, .om-input:focus {\n border-color: rgba(108, 92, 231, 0.5);\n}\n\n.om-select option {\n background: #1a1a2e;\n color: #e0e0e0;\n}\n\n.om-btn {\n background: #6c5ce7;\n border: none;\n color: white;\n cursor: pointer;\n padding: 10px 16px;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n}\n\n.om-btn:hover {\n background: #7c6cf7;\n}\n\n.om-btn-secondary {\n background: rgba(255, 255, 255, 0.05);\n color: #e0e0e0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.om-btn-secondary:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.om-status {\n font-size: 12px;\n padding: 6px 10px;\n border-radius: 6px;\n text-align: center;\n}\n\n.om-status-success {\n background: rgba(0, 184, 148, 0.1);\n color: #00b894;\n}\n\n.om-status-error {\n background: rgba(233, 69, 96, 0.1);\n color: #e94560;\n}\n\n/* Context bar */\n.om-context-bar {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n\n.om-context-chip {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: rgba(108, 92, 231, 0.1);\n border: 1px solid rgba(108, 92, 231, 0.2);\n border-radius: 20px;\n font-size: 11px;\n color: #a29bfe;\n}\n\n.om-context-chip-remove {\n background: none;\n border: none;\n color: #a29bfe;\n cursor: pointer;\n font-size: 14px;\n padding: 0 2px;\n line-height: 1;\n}\n\n/* Diff */\n.om-diff {\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 12px;\n border-radius: 8px;\n overflow: hidden;\n border: 1px solid rgba(255, 255, 255, 0.05);\n margin: 8px 0;\n}\n\n.om-diff-header {\n padding: 8px 12px;\n background: rgba(255, 255, 255, 0.03);\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n color: #888;\n font-size: 11px;\n}\n\n.om-diff-line {\n padding: 2px 12px;\n white-space: pre;\n overflow-x: auto;\n}\n\n.om-diff-add {\n background: rgba(0, 184, 148, 0.1);\n color: #55efc4;\n}\n\n.om-diff-remove {\n background: rgba(233, 69, 96, 0.1);\n color: #fab1a0;\n}\n\n.om-diff-actions {\n display: flex;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.05);\n background: rgba(255, 255, 255, 0.02);\n}\n\n/* Element info */\n.om-element-info {\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 10px 12px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 11px;\n color: #888;\n margin: 8px 0;\n max-height: 100px;\n overflow-y: auto;\n}\n\n.om-hidden {\n display: none !important;\n}\n\n/* Loading */\n.om-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n color: #888;\n font-size: 12px;\n}\n\n.om-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(108, 92, 231, 0.2);\n border-top-color: #6c5ce7;\n border-radius: 50%;\n animation: om-spin 0.6s linear infinite;\n}\n\n@keyframes om-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Tooltip */\n.om-tooltip {\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n background: #1a1a2e;\n color: #e0e0e0;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 11px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.15s;\n margin-bottom: 4px;\n}\n\n.om-pill-btn:hover .om-tooltip {\n opacity: 1;\n}\n\n/* Update indicator dot on pill */\n.om-update-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #00b894;\n margin-left: 6px;\n cursor: pointer;\n position: relative;\n animation: om-pulse-green 2s ease infinite;\n flex-shrink: 0;\n}\n\n@keyframes om-pulse-green {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(0, 184, 148, 0.5); }\n 50% { box-shadow: 0 0 0 6px rgba(0, 184, 148, 0); }\n}\n\n/* Update banner in settings */\n.om-update-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n padding: 10px 14px;\n margin-bottom: 16px;\n background: rgba(0, 184, 148, 0.08);\n border: 1px solid rgba(0, 184, 148, 0.2);\n border-radius: 10px;\n font-size: 13px;\n color: #00b894;\n}\n\n.om-update-current {\n font-size: 11px;\n color: #888;\n}\n\n.om-update-cmd {\n display: block;\n width: 100%;\n margin-top: 4px;\n padding: 6px 10px;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 12px;\n color: #55efc4;\n user-select: all;\n}\n\n/* Version in panel header */\n.om-panel-version {\n font-size: 11px;\n color: #555;\n margin-left: auto;\n margin-right: 8px;\n}\n`;\n","type MessageHandler = (msg: any) => void;\n\nlet ws: WebSocket | null = null;\nlet handlers: Map<string, MessageHandler> = new Map();\nlet globalHandlers: ((msg: any) => void)[] = [];\nlet messageQueue: string[] = [];\nlet connected = false;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction generateId(): string {\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nexport function connect(port: number, token: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n ws = new WebSocket(`ws://127.0.0.1:${port}/__openmagic__/ws`);\n\n ws.onopen = () => {\n // Send handshake\n const handshakeId = generateId();\n send({ id: handshakeId, type: \"handshake\", payload: { token } });\n\n // Wait for handshake.ok\n handlers.set(handshakeId, (msg) => {\n if (msg.type === \"handshake.ok\") {\n connected = true;\n // Flush queued messages\n for (const queued of messageQueue) {\n ws?.send(queued);\n }\n messageQueue = [];\n resolve();\n } else if (msg.type === \"error\") {\n reject(new Error(msg.payload?.message || \"Handshake failed\"));\n }\n });\n };\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n\n // Route to specific handler if exists\n if (msg.id && handlers.has(msg.id)) {\n const handler = handlers.get(msg.id)!;\n handler(msg);\n // Don't delete handler for streaming responses\n if (msg.type === \"llm.done\" || msg.type === \"llm.error\" || !msg.type.startsWith(\"llm.\")) {\n handlers.delete(msg.id);\n }\n }\n\n // Notify global handlers\n for (const handler of globalHandlers) {\n handler(msg);\n }\n } catch {\n // Ignore parse errors\n }\n };\n\n ws.onclose = () => {\n connected = false;\n // Reconnect after 2 seconds\n if (!reconnectTimer) {\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect(port, token).catch(() => {});\n }, 2000);\n }\n };\n\n ws.onerror = () => {\n // Will trigger onclose\n };\n } catch (e) {\n reject(e);\n }\n });\n}\n\nexport function send(msg: { id: string; type: string; payload?: any }): void {\n const data = JSON.stringify(msg);\n if (ws && connected) {\n ws.send(data);\n } else {\n messageQueue.push(data);\n }\n}\n\nexport function request(type: string, payload?: any): Promise<any> {\n return new Promise((resolve, reject) => {\n const id = generateId();\n const timeout = setTimeout(() => {\n handlers.delete(id);\n reject(new Error(\"Request timeout\"));\n }, 30000);\n\n handlers.set(id, (msg) => {\n clearTimeout(timeout);\n if (msg.type === \"error\") {\n reject(new Error(msg.payload?.message || \"Unknown error\"));\n } else {\n resolve(msg);\n }\n });\n\n send({ id, type, payload });\n });\n}\n\nexport function stream(\n type: string,\n payload: any,\n onChunk: (chunk: string) => void\n): Promise<any> {\n return new Promise((resolve, reject) => {\n const id = generateId();\n const timeout = setTimeout(() => {\n handlers.delete(id);\n reject(new Error(\"Stream timeout\"));\n }, 120000); // 2 min timeout for LLM responses\n\n handlers.set(id, (msg) => {\n if (msg.type === \"llm.chunk\") {\n onChunk(msg.payload?.delta || \"\");\n } else if (msg.type === \"llm.done\") {\n clearTimeout(timeout);\n handlers.delete(id);\n resolve(msg.payload);\n } else if (msg.type === \"llm.error\" || msg.type === \"error\") {\n clearTimeout(timeout);\n handlers.delete(id);\n reject(new Error(msg.payload?.message || \"Stream error\"));\n }\n });\n\n send({ id, type, payload });\n });\n}\n\nexport function onMessage(handler: (msg: any) => void): () => void {\n globalHandlers.push(handler);\n return () => {\n globalHandlers = globalHandlers.filter((h) => h !== handler);\n };\n}\n\nexport function isConnected(): boolean {\n return connected;\n}\n\nexport function disconnect(): void {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n ws.close();\n ws = null;\n }\n connected = false;\n}\n","export interface SelectedElement {\n tagName: string;\n id: string;\n className: string;\n textContent: string;\n outerHTML: string;\n cssSelector: string;\n xpath: string;\n computedStyles: Record<string, string>;\n rect: { x: number; y: number; width: number; height: number };\n}\n\nconst IMPORTANT_STYLES = [\n \"display\",\n \"position\",\n \"width\",\n \"height\",\n \"margin\",\n \"padding\",\n \"color\",\n \"background-color\",\n \"background\",\n \"font-size\",\n \"font-weight\",\n \"font-family\",\n \"border\",\n \"border-radius\",\n \"box-shadow\",\n \"flex-direction\",\n \"justify-content\",\n \"align-items\",\n \"gap\",\n \"grid-template-columns\",\n \"grid-template-rows\",\n \"overflow\",\n \"opacity\",\n \"z-index\",\n \"text-align\",\n \"line-height\",\n \"letter-spacing\",\n];\n\nexport function inspectElement(el: HTMLElement): SelectedElement {\n const computed = window.getComputedStyle(el);\n const styles: Record<string, string> = {};\n for (const prop of IMPORTANT_STYLES) {\n styles[prop] = computed.getPropertyValue(prop);\n }\n\n const rect = el.getBoundingClientRect();\n\n return {\n tagName: el.tagName.toLowerCase(),\n id: el.id || \"\",\n className: el.className || \"\",\n textContent: (el.textContent || \"\").trim().slice(0, 200),\n outerHTML: getCleanOuterHTML(el),\n cssSelector: getCssSelector(el),\n xpath: getXPath(el),\n computedStyles: styles,\n rect: {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n },\n };\n}\n\nfunction getCleanOuterHTML(el: HTMLElement): string {\n const clone = el.cloneNode(true) as HTMLElement;\n\n // Remove script tags and large content\n const scripts = clone.querySelectorAll(\"script, style, svg\");\n scripts.forEach((s) => s.remove());\n\n // Truncate children if too many\n let html = clone.outerHTML;\n if (html.length > 2000) {\n // Just get the opening tag + first level children hints\n const tag = el.tagName.toLowerCase();\n const attrs = Array.from(el.attributes)\n .map((a) => `${a.name}=\"${a.value}\"`)\n .join(\" \");\n const childSummary = Array.from(el.children)\n .slice(0, 5)\n .map((c) => `<${c.tagName.toLowerCase()} .../>`)\n .join(\"\\n \");\n html = `<${tag} ${attrs}>\\n ${childSummary}\\n ${el.children.length > 5 ? `<!-- +${el.children.length - 5} more children -->` : \"\"}\\n</${tag}>`;\n }\n\n return html;\n}\n\nfunction getCssSelector(el: HTMLElement): string {\n if (el.id) return `#${el.id}`;\n\n const parts: string[] = [];\n let current: HTMLElement | null = el;\n\n while (current && current !== document.body) {\n let selector = current.tagName.toLowerCase();\n\n if (current.id) {\n parts.unshift(`#${current.id}`);\n break;\n }\n\n if (current.className && typeof current.className === \"string\") {\n const classes = current.className\n .trim()\n .split(/\\s+/)\n .filter((c) => !c.startsWith(\"__\") && c.length < 30)\n .slice(0, 2);\n if (classes.length > 0) {\n selector += \".\" + classes.join(\".\");\n }\n }\n\n // Add nth-child if needed for uniqueness\n const parent = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (s) => s.tagName === current!.tagName\n );\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n selector += `:nth-child(${index})`;\n }\n }\n\n parts.unshift(selector);\n current = current.parentElement;\n }\n\n return parts.join(\" > \");\n}\n\nfunction getXPath(el: HTMLElement): string {\n const parts: string[] = [];\n let current: Node | null = el;\n\n while (current && current !== document) {\n if (current.nodeType === Node.ELEMENT_NODE) {\n const element = current as HTMLElement;\n let index = 1;\n let sibling = element.previousElementSibling;\n while (sibling) {\n if (sibling.tagName === element.tagName) index++;\n sibling = sibling.previousElementSibling;\n }\n parts.unshift(`${element.tagName.toLowerCase()}[${index}]`);\n }\n current = current.parentNode;\n }\n\n return \"/\" + parts.join(\"/\");\n}\n\n// --- Highlight Overlay ---\n\nlet highlightEl: HTMLDivElement | null = null;\n\nexport function showHighlight(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n}): void {\n if (!highlightEl) {\n highlightEl = document.createElement(\"div\");\n highlightEl.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: 2147483646;\n border: 2px solid #6c5ce7;\n background: rgba(108, 92, 231, 0.1);\n transition: all 0.1s ease;\n `;\n highlightEl.dataset.openmagic = \"highlight\";\n document.body.appendChild(highlightEl);\n }\n\n highlightEl.style.left = `${rect.x}px`;\n highlightEl.style.top = `${rect.y}px`;\n highlightEl.style.width = `${rect.width}px`;\n highlightEl.style.height = `${rect.height}px`;\n highlightEl.style.display = \"block\";\n}\n\nexport function hideHighlight(): void {\n if (highlightEl) {\n highlightEl.style.display = \"none\";\n }\n}\n\nexport function removeHighlight(): void {\n if (highlightEl) {\n highlightEl.remove();\n highlightEl = null;\n }\n}\n","// Simple screenshot capture using Canvas API\n// Falls back to a simpler approach if html-to-image isn't available\n\nexport async function captureScreenshot(\n target?: HTMLElement\n): Promise<string | null> {\n try {\n // Try using the Canvas approach for element capture\n if (target) {\n return await captureElementViaCanvas(target);\n }\n\n // Full page: use a simple canvas capture of the viewport\n return await captureViewport();\n } catch (e) {\n console.warn(\"[OpenMagic] Screenshot capture failed:\", e);\n return null;\n }\n}\n\nasync function captureViewport(): Promise<string | null> {\n // Create a canvas the size of the viewport\n const canvas = document.createElement(\"canvas\");\n const dpr = window.devicePixelRatio || 1;\n canvas.width = window.innerWidth * dpr;\n canvas.height = window.innerHeight * dpr;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.scale(dpr, dpr);\n\n // We can't directly capture the viewport without html2canvas or similar\n // Instead, we use the SVG foreignObject approach (snapdom-like)\n try {\n const svgData = await elementToSvg(document.body);\n const img = await svgToImage(svgData, window.innerWidth, window.innerHeight);\n ctx.drawImage(img, 0, 0);\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null;\n }\n}\n\nasync function captureElementViaCanvas(\n element: HTMLElement\n): Promise<string | null> {\n const rect = element.getBoundingClientRect();\n const canvas = document.createElement(\"canvas\");\n const dpr = window.devicePixelRatio || 1;\n canvas.width = rect.width * dpr;\n canvas.height = rect.height * dpr;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.scale(dpr, dpr);\n\n try {\n const svgData = await elementToSvg(element);\n const img = await svgToImage(svgData, rect.width, rect.height);\n ctx.drawImage(img, 0, 0);\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null;\n }\n}\n\nfunction elementToSvg(element: HTMLElement): Promise<string> {\n return new Promise((resolve) => {\n const clone = element.cloneNode(true) as HTMLElement;\n\n // Inline computed styles on the clone\n inlineStyles(element, clone);\n\n const rect = element.getBoundingClientRect();\n const width = rect.width;\n const height = rect.height;\n\n const foreignObject = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n <foreignObject width=\"100%\" height=\"100%\">\n <div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"width:${width}px;height:${height}px;overflow:hidden;\">\n ${clone.outerHTML}\n </div>\n </foreignObject>\n </svg>`;\n\n resolve(foreignObject);\n });\n}\n\nfunction inlineStyles(source: HTMLElement, target: HTMLElement): void {\n const computed = window.getComputedStyle(source);\n let cssText = \"\";\n for (let i = 0; i < computed.length; i++) {\n const prop = computed[i];\n cssText += `${prop}:${computed.getPropertyValue(prop)};`;\n }\n target.style.cssText = cssText;\n\n const sourceChildren = source.children;\n const targetChildren = target.children;\n for (let i = 0; i < sourceChildren.length && i < targetChildren.length; i++) {\n inlineStyles(\n sourceChildren[i] as HTMLElement,\n targetChildren[i] as HTMLElement\n );\n }\n}\n\nfunction svgToImage(\n svgData: string,\n width: number,\n height: number\n): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const blob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error(\"Failed to load SVG image\"));\n };\n\n img.width = width;\n img.height = height;\n img.src = url;\n });\n}\n","import type { SelectedElement } from \"./dom-inspector.js\";\n\n// --- Network Log Capture ---\n\ninterface NetworkEntry {\n method: string;\n url: string;\n status?: number;\n duration?: number;\n timestamp: number;\n}\n\nconst networkLogs: NetworkEntry[] = [];\nconst MAX_NETWORK_LOGS = 50;\n\nlet networkCaptureInstalled = false;\n\nexport function installNetworkCapture(): void {\n if (networkCaptureInstalled) return;\n networkCaptureInstalled = true;\n\n // Intercept fetch\n const originalFetch = window.fetch;\n window.fetch = async function (...args) {\n const request = new Request(...args);\n const entry: NetworkEntry = {\n method: request.method,\n url: request.url,\n timestamp: Date.now(),\n };\n\n try {\n const response = await originalFetch.apply(this, args);\n entry.status = response.status;\n entry.duration = Date.now() - entry.timestamp;\n addNetworkEntry(entry);\n return response;\n } catch (e) {\n entry.status = 0;\n entry.duration = Date.now() - entry.timestamp;\n addNetworkEntry(entry);\n throw e;\n }\n };\n\n // Intercept XMLHttpRequest\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method: string, url: string, ...rest: any[]) {\n (this as any).__om_method = method;\n (this as any).__om_url = url;\n (this as any).__om_start = Date.now();\n return originalOpen.apply(this, [method, url, ...rest] as any);\n };\n\n XMLHttpRequest.prototype.send = function (...args) {\n this.addEventListener(\"loadend\", () => {\n addNetworkEntry({\n method: (this as any).__om_method || \"GET\",\n url: (this as any).__om_url || \"\",\n status: this.status,\n duration: Date.now() - ((this as any).__om_start || Date.now()),\n timestamp: (this as any).__om_start || Date.now(),\n });\n });\n return originalSend.apply(this, args);\n };\n}\n\nfunction addNetworkEntry(entry: NetworkEntry): void {\n // Filter out OpenMagic's own requests\n if (entry.url.includes(\"__openmagic__\")) return;\n networkLogs.push(entry);\n if (networkLogs.length > MAX_NETWORK_LOGS) {\n networkLogs.shift();\n }\n}\n\nexport function getNetworkLogs(): NetworkEntry[] {\n return [...networkLogs];\n}\n\nexport function clearNetworkLogs(): void {\n networkLogs.length = 0;\n}\n\n// --- Console Log Capture ---\n\ninterface ConsoleEntry {\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n args: string[];\n timestamp: number;\n}\n\nconst consoleLogs: ConsoleEntry[] = [];\nconst MAX_CONSOLE_LOGS = 100;\n\nlet consoleCaptureInstalled = false;\n\nexport function installConsoleCapture(): void {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n\n const levels: ConsoleEntry[\"level\"][] = [\"log\", \"warn\", \"error\", \"info\", \"debug\"];\n\n for (const level of levels) {\n const original = console[level];\n console[level] = function (...args: any[]) {\n consoleLogs.push({\n level,\n args: args.map((a) => {\n try {\n return typeof a === \"object\" ? JSON.stringify(a).slice(0, 500) : String(a);\n } catch {\n return String(a);\n }\n }),\n timestamp: Date.now(),\n });\n\n if (consoleLogs.length > MAX_CONSOLE_LOGS) {\n consoleLogs.shift();\n }\n\n original.apply(console, args);\n };\n }\n}\n\nexport function getConsoleLogs(): ConsoleEntry[] {\n return [...consoleLogs];\n}\n\nexport function clearConsoleLogs(): void {\n consoleLogs.length = 0;\n}\n\n// --- Context Builder ---\n\nexport function buildContext(\n selectedElement: SelectedElement | null,\n screenshot: string | null\n) {\n return {\n selectedElement: selectedElement\n ? {\n tagName: selectedElement.tagName,\n id: selectedElement.id,\n className: selectedElement.className,\n textContent: selectedElement.textContent,\n outerHTML: selectedElement.outerHTML,\n cssSelector: selectedElement.cssSelector,\n computedStyles: selectedElement.computedStyles,\n }\n : undefined,\n screenshot: screenshot || undefined,\n networkLogs: getNetworkLogs().map((l) => ({\n method: l.method,\n url: l.url,\n status: l.status,\n duration: l.duration,\n timestamp: l.timestamp,\n })),\n consoleLogs: getConsoleLogs().map((l) => ({\n level: l.level,\n args: l.args,\n timestamp: l.timestamp,\n })),\n };\n}\n","import { TOOLBAR_CSS } from \"./styles/toolbar.css.js\";\nimport * as ws from \"./services/ws-client.js\";\nimport {\n inspectElement,\n showHighlight,\n hideHighlight,\n removeHighlight,\n type SelectedElement,\n} from \"./services/dom-inspector.js\";\nimport { captureScreenshot } from \"./services/capture.js\";\nimport {\n installNetworkCapture,\n installConsoleCapture,\n buildContext,\n} from \"./services/context-builder.js\";\n\n// Inline model registry (bundled into toolbar IIFE)\nconst MODEL_REGISTRY: Record<string, { name: string; models: { id: string; name: string }[]; keyPlaceholder: string; local?: boolean }> = {\n openai: { name: \"OpenAI\", models: [\n { id: \"gpt-5.4\", name: \"GPT-5.4\" },\n { id: \"gpt-5.4-pro\", name: \"GPT-5.4 Pro\" },\n { id: \"gpt-5.4-mini\", name: \"GPT-5.4 Mini\" },\n { id: \"gpt-5.4-nano\", name: \"GPT-5.4 Nano\" },\n { id: \"gpt-5.2\", name: \"GPT-5.2 Thinking\" },\n { id: \"gpt-5.2-pro\", name: \"GPT-5.2 Pro\" },\n { id: \"o3\", name: \"o3 (Reasoning)\" },\n { id: \"o4-mini\", name: \"o4-mini (Reasoning)\" },\n { id: \"gpt-4.1\", name: \"GPT-4.1\" },\n { id: \"gpt-4.1-mini\", name: \"GPT-4.1 Mini\" },\n { id: \"codex-mini-latest\", name: \"Codex Mini\" },\n ], keyPlaceholder: \"sk-...\" },\n anthropic: { name: \"Anthropic\", models: [\n { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\" },\n { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\" },\n { id: \"claude-haiku-4-5-20251001\", name: \"Claude Haiku 4.5\" },\n { id: \"claude-sonnet-4-5-20250929\", name: \"Claude Sonnet 4.5\" },\n { id: \"claude-opus-4-5-20251101\", name: \"Claude Opus 4.5\" },\n { id: \"claude-sonnet-4-20250514\", name: \"Claude Sonnet 4\" },\n { id: \"claude-opus-4-20250514\", name: \"Claude Opus 4\" },\n ], keyPlaceholder: \"sk-ant-...\" },\n google: { name: \"Google Gemini\", models: [\n { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro\" },\n { id: \"gemini-3-flash-preview\", name: \"Gemini 3 Flash\" },\n { id: \"gemini-3.1-flash-lite-preview\", name: \"Gemini 3.1 Flash Lite\" },\n { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\" },\n { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\" },\n { id: \"gemini-2.5-flash-lite\", name: \"Gemini 2.5 Flash Lite\" },\n ], keyPlaceholder: \"AIza...\" },\n xai: { name: \"xAI (Grok)\", models: [\n { id: \"grok-4.20-0309-reasoning\", name: \"Grok 4.20 Reasoning\" },\n { id: \"grok-4.20-0309-non-reasoning\", name: \"Grok 4.20\" },\n { id: \"grok-4-1-fast-reasoning\", name: \"Grok 4.1 Fast Reasoning\" },\n { id: \"grok-4-1-fast-non-reasoning\", name: \"Grok 4.1 Fast\" },\n ], keyPlaceholder: \"xai-...\" },\n deepseek: { name: \"DeepSeek\", models: [\n { id: \"deepseek-chat\", name: \"DeepSeek V3.2\" },\n { id: \"deepseek-reasoner\", name: \"DeepSeek R1\" },\n ], keyPlaceholder: \"sk-...\" },\n mistral: { name: \"Mistral\", models: [\n { id: \"mistral-large-3-25-12\", name: \"Mistral Large 3\" },\n { id: \"mistral-small-4-0-26-03\", name: \"Mistral Small 4\" },\n { id: \"codestral-2508\", name: \"Codestral\" },\n { id: \"devstral-2-25-12\", name: \"Devstral 2\" },\n { id: \"magistral-medium-1-2-25-09\", name: \"Magistral Medium\" },\n ], keyPlaceholder: \"...\" },\n groq: { name: \"Groq\", models: [\n { id: \"meta-llama/llama-4-scout-17b-16e-instruct\", name: \"Llama 4 Scout 17B\" },\n { id: \"llama-3.3-70b-versatile\", name: \"Llama 3.3 70B\" },\n { id: \"llama-3.1-8b-instant\", name: \"Llama 3.1 8B Instant\" },\n { id: \"qwen/qwen3-32b\", name: \"Qwen 3 32B\" },\n ], keyPlaceholder: \"gsk_...\" },\n ollama: { name: \"Ollama (Local)\", models: [], keyPlaceholder: \"not required\", local: true },\n openrouter: { name: \"OpenRouter\", models: [], keyPlaceholder: \"sk-or-...\" },\n};\n\nconst CURRENT_VERSION = \"0.4.0\";\n\n// --- State ---\ninterface AppState {\n connected: boolean;\n panelOpen: boolean;\n activePanel: \"chat\" | \"settings\" | null;\n selecting: boolean;\n selectedElement: SelectedElement | null;\n screenshot: string | null;\n messages: Array<{ role: \"user\" | \"assistant\" | \"system\"; content: string }>;\n streaming: boolean;\n streamContent: string;\n provider: string;\n model: string;\n hasApiKey: boolean;\n roots: string[];\n updateAvailable: boolean;\n latestVersion: string;\n}\n\nconst state: AppState = {\n connected: false,\n panelOpen: false,\n activePanel: null,\n selecting: false,\n selectedElement: null,\n screenshot: null,\n messages: [],\n streaming: false,\n streamContent: \"\",\n provider: \"\",\n model: \"\",\n hasApiKey: false,\n roots: [],\n updateAvailable: false,\n latestVersion: \"\",\n};\n\n// --- DOM References ---\nlet shadow: ShadowRoot;\nlet container: HTMLDivElement;\n\n// --- Initialize ---\nfunction init() {\n // Don't initialize if already loaded\n if (document.querySelector(\"openmagic-toolbar\")) return;\n\n // Create custom element\n const host = document.createElement(\"openmagic-toolbar\");\n host.dataset.openmagic = \"true\";\n shadow = host.attachShadow({ mode: \"closed\" });\n\n // Inject styles\n const style = document.createElement(\"style\");\n style.textContent = TOOLBAR_CSS;\n shadow.appendChild(style);\n\n // Create container\n container = document.createElement(\"div\");\n shadow.appendChild(container);\n\n // Mount\n document.body.appendChild(host);\n\n // Install captures\n installNetworkCapture();\n installConsoleCapture();\n\n // Check for updates (non-blocking)\n checkForUpdates();\n\n // Connect to server\n const config = (window as any).__OPENMAGIC_CONFIG__;\n if (config) {\n ws.connect(config.wsPort, config.token)\n .then(() => {\n state.connected = true;\n // Fetch config\n ws.request(\"config.get\").then((msg: any) => {\n state.provider = msg.payload?.provider || \"\";\n state.model = msg.payload?.model || \"\";\n state.hasApiKey = msg.payload?.hasApiKey || false;\n state.roots = msg.payload?.roots || [];\n\n // If not configured, open settings\n if (!state.provider || !state.hasApiKey) {\n state.panelOpen = true;\n state.activePanel = \"settings\";\n }\n\n render();\n });\n })\n .catch((e: Error) => {\n console.error(\"[OpenMagic] Connection failed:\", e);\n state.connected = false;\n render();\n });\n }\n\n render();\n}\n\n// --- Render ---\nfunction render() {\n container.innerHTML = \"\";\n\n // Panel (if open)\n if (state.panelOpen && state.activePanel) {\n const panel = document.createElement(\"div\");\n panel.className = \"om-panel\";\n\n if (state.activePanel === \"settings\") {\n panel.innerHTML = renderSettings();\n } else if (state.activePanel === \"chat\") {\n panel.innerHTML = renderChat();\n }\n\n container.appendChild(panel);\n attachPanelEvents(panel);\n }\n\n // Floating pill\n const pill = document.createElement(\"div\");\n pill.className = \"om-pill\";\n pill.innerHTML = `\n <span class=\"om-pill-logo\">✨</span>\n <span class=\"om-pill-text\">Magic</span>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn ${state.selecting ? \"active\" : \"\"}\" data-action=\"select\" title=\"Select Element\">\n 🎯\n </button>\n <button class=\"om-pill-btn\" data-action=\"screenshot\" title=\"Screenshot\">\n 📸\n </button>\n <button class=\"om-pill-btn ${state.activePanel === \"chat\" ? \"active\" : \"\"}\" data-action=\"chat\" title=\"Chat\">\n 💬\n </button>\n <button class=\"om-pill-btn ${state.activePanel === \"settings\" ? \"active\" : \"\"}\" data-action=\"settings\" title=\"Settings\">\n ⚙️\n </button>\n `;\n\n // Connection indicator\n if (!state.connected) {\n const dot = document.createElement(\"span\");\n dot.style.cssText = \"width:8px;height:8px;border-radius:50%;background:#e94560;margin-left:4px;\";\n pill.appendChild(dot);\n }\n\n // Update indicator\n if (state.updateAvailable) {\n const updateDot = document.createElement(\"span\");\n updateDot.className = \"om-update-dot\";\n updateDot.title = `Update available: v${state.latestVersion}`;\n updateDot.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n state.panelOpen = true;\n state.activePanel = \"settings\";\n render();\n });\n pill.appendChild(updateDot);\n }\n\n container.appendChild(pill);\n\n // Draggable\n makeDraggable(pill);\n\n // Pill button events\n pill.querySelectorAll(\".om-pill-btn\").forEach((btn) => {\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n const action = (btn as HTMLElement).dataset.action;\n\n if (action === \"select\") {\n toggleSelectMode();\n } else if (action === \"screenshot\") {\n takeScreenshot();\n } else if (action === \"chat\") {\n togglePanel(\"chat\");\n } else if (action === \"settings\") {\n togglePanel(\"settings\");\n }\n });\n });\n}\n\n// --- Renderers ---\n\nfunction renderSettings(): string {\n const providerOptions = Object.entries(MODEL_REGISTRY)\n .map(([key, p]) => `<option value=\"${key}\" ${state.provider === key ? \"selected\" : \"\"}>${p.name}</option>`)\n .join(\"\");\n\n const currentProvider = MODEL_REGISTRY[state.provider];\n const modelOptions = currentProvider\n ? currentProvider.models.map((m) =>\n `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`\n ).join(\"\")\n : '<option value=\"\">Select a provider first</option>';\n\n const keyPlaceholder = currentProvider?.keyPlaceholder || \"Enter API key...\";\n const isLocal = currentProvider?.local || false;\n\n const updateBanner = state.updateAvailable\n ? `<div class=\"om-update-banner\">\n <span>🚀 v${state.latestVersion} available</span>\n <span class=\"om-update-current\">current: v${CURRENT_VERSION}</span>\n <code class=\"om-update-cmd\">npx openmagic@latest</code>\n </div>`\n : \"\";\n\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Settings</span>\n <span class=\"om-panel-version\">v${CURRENT_VERSION}</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n ${updateBanner}\n <div class=\"om-settings\">\n <div class=\"om-field\">\n <label class=\"om-label\">Provider</label>\n <select class=\"om-select\" data-field=\"provider\">\n <option value=\"\">Select Provider...</option>\n ${providerOptions}\n </select>\n </div>\n\n <div class=\"om-field\">\n <label class=\"om-label\">Model</label>\n <select class=\"om-select\" data-field=\"model\">\n <option value=\"\">Select Model...</option>\n ${modelOptions}\n </select>\n </div>\n\n <div class=\"om-field ${isLocal ? \"om-hidden\" : \"\"}\">\n <label class=\"om-label\">API Key</label>\n <input type=\"password\" class=\"om-input\" data-field=\"apiKey\"\n placeholder=\"${keyPlaceholder}\"\n value=\"\" />\n </div>\n\n <button class=\"om-btn\" data-action=\"save-settings\">Save Configuration</button>\n\n ${state.hasApiKey ? '<div class=\"om-status om-status-success\">API key configured</div>' : \"\"}\n </div>\n </div>\n `;\n}\n\nfunction renderChat(): string {\n if (!state.hasApiKey || !state.provider) {\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Chat</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n <div class=\"om-status om-status-error\">\n Configure your LLM provider in Settings first\n </div>\n </div>\n `;\n }\n\n const messagesHtml = state.messages\n .map((m) => `<div class=\"om-msg om-msg-${m.role}\">${escapeHtml(m.content)}</div>`)\n .join(\"\");\n\n const streamHtml = state.streaming\n ? `<div class=\"om-msg om-msg-assistant\"><div class=\"om-loading\"><div class=\"om-spinner\"></div> Thinking...</div>${escapeHtml(state.streamContent)}</div>`\n : \"\";\n\n const contextChips: string[] = [];\n if (state.selectedElement) {\n contextChips.push(`<span class=\"om-context-chip\">🎯 ${state.selectedElement.tagName}${state.selectedElement.id ? \"#\" + state.selectedElement.id : \"\"} <button class=\"om-context-chip-remove\" data-action=\"clear-element\">×</button></span>`);\n }\n if (state.screenshot) {\n contextChips.push(`<span class=\"om-context-chip\">📸 Screenshot <button class=\"om-context-chip-remove\" data-action=\"clear-screenshot\">×</button></span>`);\n }\n\n return `\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\">Chat — ${MODEL_REGISTRY[state.provider]?.name || state.provider} / ${state.model}</span>\n <button class=\"om-panel-close\" data-action=\"close\">×</button>\n </div>\n <div class=\"om-panel-body\">\n ${contextChips.length > 0 ? `<div class=\"om-context-bar\">${contextChips.join(\"\")}</div>` : \"\"}\n ${state.selectedElement ? `<div class=\"om-element-info\"><${state.selectedElement.tagName}${state.selectedElement.id ? ' id=\"' + state.selectedElement.id + '\"' : \"\"}${state.selectedElement.className ? ' class=\"' + state.selectedElement.className.toString().slice(0, 60) + '\"' : \"\"}></div>` : \"\"}\n <div class=\"om-chat-messages\">\n ${messagesHtml || '<div style=\"color:#555;text-align:center;padding:40px 0;font-size:13px;\">Select an element or describe what you want to change</div>'}\n ${streamHtml}\n </div>\n <div class=\"om-chat-input-wrap\">\n <textarea class=\"om-chat-input\" placeholder=\"Describe the change you want...\"\n rows=\"1\" ${state.streaming ? \"disabled\" : \"\"}></textarea>\n <button class=\"om-chat-send\" data-action=\"send\" ${state.streaming ? \"disabled\" : \"\"}>\n ${state.streaming ? \"...\" : \"Send\"}\n </button>\n </div>\n </div>\n `;\n}\n\n// --- Event Handlers ---\n\nfunction attachPanelEvents(panel: HTMLElement) {\n // Close button\n panel.querySelector('[data-action=\"close\"]')?.addEventListener(\"click\", () => {\n state.panelOpen = false;\n state.activePanel = null;\n render();\n });\n\n // Settings: provider change\n panel.querySelector('[data-field=\"provider\"]')?.addEventListener(\"change\", (e) => {\n state.provider = (e.target as HTMLSelectElement).value;\n state.model = \"\";\n render();\n });\n\n // Settings: model change\n panel.querySelector('[data-field=\"model\"]')?.addEventListener(\"change\", (e) => {\n state.model = (e.target as HTMLSelectElement).value;\n });\n\n // Settings: save\n panel.querySelector('[data-action=\"save-settings\"]')?.addEventListener(\"click\", () => {\n const apiKeyInput = panel.querySelector('[data-field=\"apiKey\"]') as HTMLInputElement;\n const apiKey = apiKeyInput?.value || \"\";\n\n const payload: any = {\n provider: state.provider,\n model: state.model,\n };\n if (apiKey) {\n payload.apiKey = apiKey;\n }\n\n ws.request(\"config.set\", payload).then(() => {\n state.hasApiKey = true;\n render();\n }).catch((e: Error) => {\n console.error(\"[OpenMagic] Failed to save config:\", e);\n });\n });\n\n // Chat: send\n panel.querySelector('[data-action=\"send\"]')?.addEventListener(\"click\", () => {\n sendMessage(panel);\n });\n\n // Chat: enter to send\n const input = panel.querySelector(\".om-chat-input\") as HTMLTextAreaElement;\n input?.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendMessage(panel);\n }\n });\n\n // Auto-resize textarea\n input?.addEventListener(\"input\", () => {\n input.style.height = \"auto\";\n input.style.height = Math.min(input.scrollHeight, 120) + \"px\";\n });\n\n // Clear context\n panel.querySelector('[data-action=\"clear-element\"]')?.addEventListener(\"click\", () => {\n state.selectedElement = null;\n render();\n });\n\n panel.querySelector('[data-action=\"clear-screenshot\"]')?.addEventListener(\"click\", () => {\n state.screenshot = null;\n render();\n });\n}\n\nasync function sendMessage(panel: HTMLElement) {\n const input = panel.querySelector(\".om-chat-input\") as HTMLTextAreaElement;\n if (!input) return;\n\n const text = input.value.trim();\n if (!text || state.streaming) return;\n\n // Add user message\n state.messages.push({ role: \"user\", content: text });\n state.streaming = true;\n state.streamContent = \"\";\n render();\n\n // Build context\n const context = buildContext(state.selectedElement, state.screenshot);\n\n try {\n const result = await ws.stream(\n \"llm.chat\",\n {\n provider: state.provider,\n model: state.model,\n messages: state.messages.map((m) => ({ role: m.role, content: m.content })),\n context,\n },\n (chunk: string) => {\n state.streamContent += chunk;\n // Update streaming message in place\n const msgContainer = shadow.querySelector(\".om-chat-messages\");\n const streamEl = msgContainer?.querySelector(\".om-msg-assistant:last-child\");\n if (streamEl) {\n streamEl.innerHTML = escapeHtml(state.streamContent);\n }\n }\n );\n\n // Add assistant message\n state.messages.push({ role: \"assistant\", content: state.streamContent || result?.content || \"\" });\n\n // Handle modifications\n if (result?.modifications && result.modifications.length > 0) {\n for (const mod of result.modifications) {\n if (mod.type === \"edit\" && mod.file && mod.search && mod.replace) {\n // Read the file first\n try {\n const fileResult = await ws.request(\"fs.read\", { path: resolveFilePath(mod.file) });\n const content = fileResult.payload?.content;\n if (content && content.includes(mod.search)) {\n const newContent = content.replace(mod.search, mod.replace);\n await ws.request(\"fs.write\", { path: resolveFilePath(mod.file), content: newContent });\n state.messages.push({\n role: \"system\",\n content: `Applied change to ${mod.file}`,\n });\n }\n } catch (e: any) {\n state.messages.push({\n role: \"system\",\n content: `Failed to apply change to ${mod.file}: ${e.message}`,\n });\n }\n }\n }\n }\n } catch (e: any) {\n state.messages.push({ role: \"system\", content: `Error: ${e.message}` });\n }\n\n state.streaming = false;\n state.streamContent = \"\";\n render();\n}\n\nfunction resolveFilePath(relativePath: string): string {\n // Resolve relative to first root\n if (state.roots.length > 0) {\n return state.roots[0] + \"/\" + relativePath;\n }\n return relativePath;\n}\n\n// --- Select Mode ---\n\nlet selectHandler: ((e: MouseEvent) => void) | null = null;\nlet hoverHandler: ((e: MouseEvent) => void) | null = null;\n\nfunction toggleSelectMode() {\n if (state.selecting) {\n exitSelectMode();\n } else {\n enterSelectMode();\n }\n}\n\nfunction enterSelectMode() {\n state.selecting = true;\n document.body.style.cursor = \"crosshair\";\n\n hoverHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (isOpenMagicElement(target)) return;\n const rect = target.getBoundingClientRect();\n showHighlight({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n };\n\n selectHandler = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const target = e.target as HTMLElement;\n if (isOpenMagicElement(target)) return;\n\n state.selectedElement = inspectElement(target);\n exitSelectMode();\n\n // Open chat if not open\n if (state.activePanel !== \"chat\") {\n state.panelOpen = true;\n state.activePanel = \"chat\";\n }\n\n render();\n };\n\n document.addEventListener(\"mousemove\", hoverHandler, true);\n document.addEventListener(\"click\", selectHandler, true);\n\n render();\n}\n\nfunction exitSelectMode() {\n state.selecting = false;\n document.body.style.cursor = \"\";\n hideHighlight();\n\n if (hoverHandler) {\n document.removeEventListener(\"mousemove\", hoverHandler, true);\n hoverHandler = null;\n }\n if (selectHandler) {\n document.removeEventListener(\"click\", selectHandler, true);\n selectHandler = null;\n }\n\n render();\n}\n\n// --- Screenshot ---\n\nasync function takeScreenshot() {\n const screenshot = await captureScreenshot();\n if (screenshot) {\n state.screenshot = screenshot;\n // Open chat\n state.panelOpen = true;\n state.activePanel = \"chat\";\n render();\n }\n}\n\n// --- Panel Toggle ---\n\nfunction togglePanel(panel: \"chat\" | \"settings\") {\n if (state.panelOpen && state.activePanel === panel) {\n state.panelOpen = false;\n state.activePanel = null;\n } else {\n state.panelOpen = true;\n state.activePanel = panel;\n }\n render();\n}\n\n// --- Draggable ---\n\nfunction makeDraggable(el: HTMLElement) {\n let isDragging = false;\n let startX = 0;\n let startY = 0;\n let origX = 0;\n let origY = 0;\n\n el.addEventListener(\"mousedown\", (e) => {\n // Only drag from the pill itself, not buttons\n if ((e.target as HTMLElement).closest(\".om-pill-btn\")) return;\n\n isDragging = true;\n startX = e.clientX;\n startY = e.clientY;\n const rect = el.getBoundingClientRect();\n origX = rect.left;\n origY = rect.top;\n e.preventDefault();\n });\n\n document.addEventListener(\"mousemove\", (e) => {\n if (!isDragging) return;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n el.style.position = \"fixed\";\n el.style.left = origX + dx + \"px\";\n el.style.top = origY + dy + \"px\";\n el.style.right = \"auto\";\n el.style.bottom = \"auto\";\n });\n\n document.addEventListener(\"mouseup\", () => {\n isDragging = false;\n });\n}\n\n// --- Helpers ---\n\nfunction isOpenMagicElement(el: HTMLElement): boolean {\n return !!el.closest(\"openmagic-toolbar\") || !!el.dataset?.openmagic;\n}\n\nfunction escapeHtml(text: string): string {\n const div = document.createElement(\"div\");\n div.textContent = text;\n return div.innerHTML;\n}\n\n// --- Update Check ---\n\nfunction checkForUpdates(): void {\n // Query npm registry for latest version (non-blocking, silent fail)\n fetch(\"https://registry.npmjs.org/openmagic/latest\", {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout(5000),\n })\n .then((res) => {\n if (!res.ok) return;\n return res.json();\n })\n .then((data) => {\n if (!data?.version) return;\n const latest = data.version;\n if (isNewerVersion(latest, CURRENT_VERSION)) {\n state.updateAvailable = true;\n state.latestVersion = latest;\n render();\n }\n })\n .catch(() => {\n // Silently ignore — update check is best-effort\n });\n}\n\nfunction isNewerVersion(latest: string, current: string): boolean {\n const l = latest.split(\".\").map(Number);\n const c = current.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n if ((l[i] || 0) > (c[i] || 0)) return true;\n if ((l[i] || 0) < (c[i] || 0)) return false;\n }\n return false;\n}\n\n// --- Boot ---\nif (typeof window !== \"undefined\") {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n}\n"],"mappings":";wCACO,IAAMA,EAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["TOOLBAR_CSS","ws","handlers","globalHandlers","messageQueue","connected","reconnectTimer","generateId","connect","port","token","resolve","reject","handshakeId","send","msg","queued","event","handler","e","data","request","type","payload","id","timeout","stream","onChunk","IMPORTANT_STYLES","inspectElement","el","computed","styles","prop","rect","getCleanOuterHTML","getCssSelector","getXPath","clone","s","html","tag","attrs","a","childSummary","c","parts","current","selector","classes","parent","siblings","index","element","sibling","highlightEl","showHighlight","hideHighlight","captureScreenshot","target","captureElementViaCanvas","captureViewport","e","canvas","dpr","ctx","svgData","elementToSvg","img","svgToImage","element","rect","resolve","clone","inlineStyles","width","height","foreignObject","source","computed","cssText","i","prop","sourceChildren","targetChildren","reject","blob","url","networkLogs","networkCaptureInstalled","installNetworkCapture","originalFetch","args","request","entry","response","addNetworkEntry","e","originalOpen","originalSend","method","url","rest","networkLogs","getNetworkLogs","consoleLogs","MAX_CONSOLE_LOGS","consoleCaptureInstalled","installConsoleCapture","levels","level","original","args","a","getConsoleLogs","buildContext","selectedElement","screenshot","getNetworkLogs","l","getConsoleLogs","MODEL_REGISTRY","CURRENT_VERSION","state","shadow","container","init","host","style","TOOLBAR_CSS","installNetworkCapture","installConsoleCapture","checkForUpdates","config","connect","request","msg","render","e","panel","renderSettings","renderChat","attachPanelEvents","pill","dot","updateDot","makeDraggable","btn","action","toggleSelectMode","takeScreenshot","togglePanel","providerOptions","key","p","currentProvider","modelOptions","m","keyPlaceholder","isLocal","updateBanner","messagesHtml","escapeHtml","streamHtml","contextChips","apiKey","payload","sendMessage","input","text","context","buildContext","result","stream","chunk","streamEl","mod","content","resolveFilePath","newContent","relativePath","selectHandler","hoverHandler","exitSelectMode","enterSelectMode","target","isOpenMagicElement","rect","showHighlight","inspectElement","hideHighlight","screenshot","captureScreenshot","el","isDragging","startX","startY","origX","origY","dx","dy","div","res","data","latest","isNewerVersion","current","l","c","i"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openmagic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "AI-powered coding toolbar for any web application. Select elements, capture context, and let AI modify your codebase in real-time.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,8 +34,16 @@
|
|
|
34
34
|
"element-selector",
|
|
35
35
|
"screenshot"
|
|
36
36
|
],
|
|
37
|
-
"author": "",
|
|
37
|
+
"author": "Khalid Almuraee <Khalid.s.almuraee@gmail.com> (https://github.com/kalmuraee)",
|
|
38
38
|
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/Kalmuraee/OpenMagic.git"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://kalmuraee.github.io/OpenMagic/",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/Kalmuraee/OpenMagic/issues"
|
|
46
|
+
},
|
|
39
47
|
"dependencies": {
|
|
40
48
|
"chalk": "^5.3.0",
|
|
41
49
|
"commander": "^12.1.0",
|