openmagic 0.41.1 → 0.42.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.
@@ -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":["export const TOOLBAR_CSS = `\n:host {\n all: initial;\n direction: ltr;\n unicode-bidi: isolate;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #e0e0e0;\n line-height: 1.5;\n text-align: left;\n}\n\n* { box-sizing: border-box; margin: 0; padding: 0; }\n.om-hidden { display: none !important; }\n\n/* ── Unified Toolbar Container ────────────────────────── */\n.om-toolbar {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n width: min(420px, calc(100vw - 40px));\n display: flex;\n flex-direction: column;\n background: #111125;\n border: 1px solid rgba(108, 92, 231, 0.18);\n border-radius: 14px;\n box-shadow: 0 6px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255,255,255,0.02);\n overflow: hidden;\n}\n\n/* Panel header */\n.om-panel-header {\n display: flex; align-items: center; gap: 6px;\n padding: 8px 12px;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n background: rgba(108, 92, 231, 0.03);\n flex-shrink: 0;\n}\n.om-panel-title { font-size: 11px; font-weight: 600; color: #a29bfe; }\n.om-panel-version { font-size: 10px; color: #444; margin-left: auto; }\n.om-panel-close {\n background: none; border: none; color: #555; cursor: pointer;\n padding: 2px 4px; border-radius: 4px; line-height: 1;\n display: flex; align-items: center;\n}\n.om-panel-close:hover { color: #ccc; background: rgba(255,255,255,0.05); }\n\n/* ── Header Bar (brand + tools) ───────────────────────── */\n.om-toolbar-header {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 6px 10px 6px 5px;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n background: rgba(108, 92, 231, 0.03);\n flex-shrink: 0;\n}\n\n.om-grab {\n display: flex; align-items: center; justify-content: center;\n width: 18px; height: 26px; color: #3a3a5a; cursor: grab;\n border-radius: 5px; transition: color 0.15s; flex-shrink: 0;\n}\n.om-grab:hover { color: #6c5ce7; }\n.om-grab:active { cursor: grabbing; color: #a29bfe; }\n\n.om-pill-brand {\n display: flex; align-items: center; gap: 5px;\n padding: 0 6px 0 4px; cursor: grab;\n}\n.om-pill-icon { color: #a29bfe; flex-shrink: 0; }\n.om-pill-text { font-size: 11px; font-weight: 700; color: #a29bfe; letter-spacing: 0.3px; white-space: nowrap; }\n\n.om-pill-divider { width: 1px; height: 18px; background: rgba(255,255,255,0.06); margin: 0 3px; flex-shrink: 0; }\n\n.om-pill-btn {\n background: none; border: none; color: #555; cursor: pointer;\n padding: 5px 6px; border-radius: 6px; line-height: 1;\n transition: background 0.15s, color 0.15s;\n display: flex; align-items: center; justify-content: center;\n}\n.om-pill-btn:hover { background: rgba(108, 92, 231, 0.15); color: #a29bfe; }\n.om-pill-btn:focus-visible { outline: 2px solid #6c5ce7; outline-offset: 2px; }\n.om-pill-btn.active { background: rgba(108, 92, 231, 0.25); color: #c4b5fd; }\n.om-panel-bug {\n background: none; border: none; color: #666; cursor: pointer; padding: 2px 4px;\n border-radius: 4px; line-height: 1; display: flex; align-items: center;\n}\n.om-panel-bug:hover { color: #e94560; background: rgba(233, 69, 96, 0.1); }\n\n.om-status-dot {\n width: 7px; height: 7px; border-radius: 50%; margin-left: auto; flex-shrink: 0;\n}\n.om-status-dot.connected { background: #00b894; }\n.om-status-dot.disconnected { background: #e94560; }\n.om-status-dot.outdated { background: #fdcb6e; animation: om-pulse 2s ease infinite; }\n@keyframes om-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(253,203,110,0.4); }\n 50% { box-shadow: 0 0 0 5px rgba(253,203,110,0); }\n}\n\n/* ── Panel (expandable area between header and prompt) ── */\n.om-panel {\n max-height: 420px;\n overflow: hidden;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n animation: om-expand 0.15s ease;\n}\n@keyframes om-expand {\n from { max-height: 0; opacity: 0; }\n to { max-height: 420px; opacity: 1; }\n}\n\n.om-panel-body {\n overflow-y: auto; padding: 12px;\n max-height: 420px;\n}\n.om-panel-body::-webkit-scrollbar { width: 5px; }\n.om-panel-body::-webkit-scrollbar-track { background: transparent; }\n.om-panel-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }\n\n/* ── Prompt Row (always visible at bottom) ────────────── */\n.om-prompt-row {\n display: flex;\n align-items: center;\n padding: 6px;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.om-prompt-context {\n display: flex; gap: 3px; flex-wrap: wrap; max-width: 200px; overflow: hidden;\n}\n.om-prompt-chip {\n display: flex; align-items: center; gap: 3px;\n padding: 3px 7px; background: rgba(108, 92, 231, 0.08);\n border: 1px solid rgba(108, 92, 231, 0.12);\n border-radius: 6px; font-size: 10px; color: #a29bfe;\n cursor: default; white-space: nowrap;\n}\n.om-prompt-chip-x {\n background: none; border: none; color: #a29bfe; cursor: pointer;\n font-size: 11px; line-height: 1; padding: 0 1px; opacity: 0.5;\n}\n.om-prompt-chip-x:hover { opacity: 1; }\n.om-prompt-chip-tokens { color: #888; background: transparent; border: 1px solid rgba(255,255,255,0.06); font-size: 9px; }\n\n.om-prompt-input {\n flex: 1;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.06);\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n padding: 7px 10px;\n outline: none;\n min-width: 0;\n transition: border-color 0.15s;\n}\n.om-prompt-input:focus { border-color: rgba(108, 92, 231, 0.4); }\n.om-prompt-input::placeholder { color: #3a3a5a; }\n\n.om-prompt-send {\n display: flex; align-items: center; justify-content: center;\n width: 30px; height: 30px; flex-shrink: 0;\n background: #6c5ce7; border: none; border-radius: 8px;\n color: white; cursor: pointer; transition: background 0.15s;\n}\n.om-prompt-send:hover { background: #7c6cf7; }\n.om-prompt-send:disabled { background: #2a2a4a; color: #444; cursor: not-allowed; }\n\n.om-prompt-attach {\n display: flex; align-items: center; justify-content: center;\n width: 28px; height: 28px; flex-shrink: 0;\n background: none; border: none; color: #555;\n cursor: pointer; border-radius: 6px; transition: color 0.15s, background 0.15s;\n}\n.om-prompt-attach:hover { color: #a29bfe; background: rgba(108, 92, 231, 0.1); }\n\n.om-model-switcher {\n background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08);\n color: #888; font-size: 10px; padding: 2px 4px; border-radius: 4px;\n max-width: 90px; flex-shrink: 0; cursor: pointer; outline: none;\n}\n.om-model-switcher:hover { border-color: rgba(108, 92, 231, 0.3); color: #a29bfe; }\n.om-model-switcher:focus { border-color: #6c5ce7; }\n\n/* ── Attachments ──────────────────────────────────────── */\n.om-prompt-attachments {\n display: flex; gap: 6px; padding: 4px 8px; flex-wrap: wrap;\n border-bottom: 1px solid rgba(255,255,255,0.03);\n}\n.om-attachment-thumb {\n position: relative; width: 48px; height: 48px;\n border-radius: 6px; overflow: hidden;\n border: 1px solid rgba(255,255,255,0.08);\n}\n.om-attachment-thumb img {\n width: 100%; height: 100%; object-fit: cover;\n}\n.om-attachment-remove {\n position: absolute; top: 1px; right: 1px;\n width: 16px; height: 16px; display: flex;\n align-items: center; justify-content: center;\n background: rgba(0,0,0,0.7); border: none; border-radius: 50%;\n color: #fff; cursor: pointer; padding: 0; line-height: 1;\n}\n.om-attachment-remove svg { width: 10px; height: 10px; }\n\n/* ── Settings ─────────────────────────────────────────── */\n.om-settings { display: flex; flex-direction: column; gap: 12px; }\n\n.om-field { display: flex; flex-direction: column; gap: 5px; }\n.om-label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: #555; }\n\n.om-select, .om-input {\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n padding: 8px 10px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n width: 100%;\n transition: border-color 0.15s;\n}\n.om-select:focus, .om-input:focus { border-color: rgba(108, 92, 231, 0.4); }\n.om-select option { background: #111125; color: #e0e0e0; }\n\n.om-key-row { display: flex; gap: 6px; align-items: stretch; }\n.om-key-input { flex: 1; min-width: 0; -webkit-text-security: disc; }\n\n.om-key-configured {\n display: flex; align-items: center; gap: 6px;\n padding: 8px 10px; background: rgba(0, 184, 148, 0.06);\n border: 1px solid rgba(0, 184, 148, 0.12);\n border-radius: 8px; font-size: 12px; color: #00b894;\n}\n.om-key-configured span { flex: 1; }\n.om-btn-change-key {\n background: none; border: 1px solid rgba(255,255,255,0.08);\n color: #888; cursor: pointer; padding: 3px 8px;\n border-radius: 5px; font-size: 10px; font-family: inherit;\n transition: all 0.15s;\n}\n.om-btn-change-key:hover { color: #ccc; border-color: rgba(255,255,255,0.15); }\n.om-key-change-row { margin-top: 6px; }\n\n.om-btn-get-key {\n display: flex; align-items: center; gap: 4px;\n padding: 6px 9px; background: rgba(108, 92, 231, 0.08);\n border: 1px solid rgba(108, 92, 231, 0.15); border-radius: 8px;\n color: #a29bfe; font-size: 11px; font-weight: 600;\n font-family: inherit; cursor: pointer; white-space: nowrap;\n transition: all 0.15s;\n}\n.om-btn-get-key:hover { background: rgba(108, 92, 231, 0.15); color: #c4b5fd; }\n\n.om-btn {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n background: #6c5ce7; border: none; color: white; cursor: pointer;\n padding: 8px 14px; border-radius: 8px;\n font-size: 13px; font-weight: 600; font-family: inherit;\n transition: background 0.15s;\n}\n.om-btn:hover { background: #7c6cf7; }\n.om-btn:disabled { background: #2a2a4a; color: #555; cursor: not-allowed; }\n.om-btn-saving { background: #4a3db0; }\n.om-btn-saved { background: #00b894; }\n\n.om-status { font-size: 11px; padding: 5px 8px; border-radius: 6px; text-align: center; display: flex; align-items: center; justify-content: center; gap: 4px; }\n.om-status-success { background: rgba(0, 184, 148, 0.06); color: #00b894; }\n.om-status-error { background: rgba(233, 69, 96, 0.06); color: #e94560; }\n\n.om-key-hint { font-size: 10px; color: #444; margin-top: 3px; }\n.om-key-hint a { color: #7c6cf7; cursor: pointer; text-decoration: none; }\n.om-key-hint a:hover { text-decoration: underline; }\n\n.om-update-banner {\n display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\n padding: 7px 10px; margin-bottom: 10px;\n background: rgba(253, 203, 110, 0.04); border: 1px solid rgba(253, 203, 110, 0.12);\n border-radius: 8px; font-size: 11px; color: #fdcb6e;\n}\n.om-update-cmd {\n display: block; width: 100%; margin-top: 2px;\n padding: 4px 7px; background: rgba(0, 0, 0, 0.12); border-radius: 4px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 11px; color: #fdcb6e; user-select: all;\n}\n\n/* ── Chat ─────────────────────────────────────────────── */\n.om-chat-messages {\n display: flex; flex-direction: column; gap: 8px;\n max-height: 380px;\n overflow-y: auto;\n}\n.om-chat-messages::-webkit-scrollbar { width: 4px; }\n.om-chat-messages::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.06); border-radius: 2px; }\n\n.om-msg {\n padding: 8px 11px; border-radius: 10px;\n font-size: 13px; line-height: 1.5;\n white-space: pre-wrap; word-break: break-word;\n}\n.om-msg-user { background: rgba(108, 92, 231, 0.08); color: #ccc; margin-left: 36px; border-bottom-right-radius: 3px; }\n.om-msg-assistant { background: rgba(255,255,255,0.02); color: #aaa; margin-right: 36px; border-bottom-left-radius: 3px; border: 1px solid rgba(255,255,255,0.03); }\n.om-msg-system { background: rgba(108, 92, 231, 0.05); color: #888; font-size: 11px; text-align: center; padding: 5px 8px; border-radius: 6px; }\n\n.om-chat-empty { color: #333; text-align: center; padding: 32px 16px; font-size: 12px; line-height: 1.6; }\n\n.om-spinner { width: 12px; height: 12px; border: 2px solid rgba(108,92,231,0.12); border-top-color: #6c5ce7; border-radius: 50%; animation: om-spin 0.6s linear infinite; display: inline-block; vertical-align: -1px; margin-right: 5px; }\n@keyframes om-spin { to { transform: rotate(360deg); } }\n\n.om-element-info {\n background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.03);\n border-radius: 6px; padding: 6px 8px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 10px; color: #555; max-height: 60px; overflow-y: auto; margin-bottom: 6px;\n}\n\n/* ── Diff Cards ──────────────────────────────────────── */\n.om-diff-card { background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.06); border-radius: 8px; padding: 8px 10px; margin: 4px 0; font-size: 12px; }\n.om-diff-file { color: #a29bfe; font-size: 11px; font-weight: 600; margin-bottom: 6px; font-family: 'SF Mono', Consolas, monospace; }\n.om-diff-removed { background: rgba(233,69,96,0.08); color: #fab1a0; padding: 4px 8px; border-radius: 4px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; margin-bottom: 4px; }\n.om-diff-added { background: rgba(0,184,148,0.08); color: #55efc4; padding: 4px 8px; border-radius: 4px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; margin-bottom: 6px; }\n.om-diff-lines { max-height: 300px; overflow-y: auto; border-radius: 6px; background: rgba(0,0,0,0.2); margin-bottom: 6px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; line-height: 1.5; }\n.om-diff-line { display: flex; white-space: pre; padding: 0 8px; }\n.om-diff-ln { color: #555; min-width: 28px; text-align: right; padding-right: 8px; user-select: none; flex-shrink: 0; }\n.om-diff-sign { min-width: 14px; flex-shrink: 0; font-weight: bold; user-select: none; }\n.om-diff-ctx { color: #888; }\n.om-diff-del { background: rgba(233,69,96,0.12); color: #fab1a0; }\n.om-diff-del .om-diff-sign { color: #e94560; }\n.om-diff-ins { background: rgba(0,184,148,0.12); color: #55efc4; }\n.om-diff-ins .om-diff-sign { color: #00b894; }\n.om-diff-actions { display: flex; gap: 6px; }\n.om-btn-sm { padding: 4px 10px; font-size: 11px; border-radius: 6px; }\n.om-btn-secondary { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.08); color: #888; cursor: pointer; font-family: inherit; }\n.om-btn-secondary:hover { background: rgba(255,255,255,0.08); color: #ccc; }\n.om-diff-applied { opacity: 0.5; }\n.om-diff-applied .om-diff-actions { display: none; }\n\n/* Sticky Apply All bar — between panel and prompt */\n.om-apply-bar {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 10px;\n background: rgba(108, 92, 231, 0.06);\n border-top: 1px solid rgba(108, 92, 231, 0.12);\n border-bottom: 1px solid rgba(108, 92, 231, 0.12);\n flex-shrink: 0;\n}\n.om-apply-bar-text { font-size: 12px; color: #a29bfe; font-weight: 600; }\n\n/* ── Undo Button ─────────────────────────────────────── */\n.om-undo-btn {\n background: none; border: 1px solid rgba(255,255,255,0.08);\n color: #888; cursor: pointer; padding: 2px 6px; margin-left: 6px;\n border-radius: 4px; font-size: 10px; font-family: inherit;\n}\n.om-undo-btn:hover { color: #e94560; border-color: rgba(233,69,96,0.2); }\n\n/* ── Clear Chat Button ───────────────────────────────── */\n.om-panel-clear {\n background: none; border: none; color: #444; cursor: pointer;\n padding: 2px 4px; border-radius: 4px; line-height: 1;\n display: flex; align-items: center; margin-right: 4px;\n}\n.om-panel-clear:hover { color: #e94560; background: rgba(233,69,96,0.08); }\n\n/* ── Code Blocks (Markdown) ─────────────────────────── */\n.om-code-block {\n background: rgba(0,0,0,0.2); border-radius: 6px; padding: 8px 10px;\n margin: 6px 0; overflow-x: auto; font-family: 'SF Mono', Consolas, monospace;\n font-size: 11px; line-height: 1.5; white-space: pre-wrap;\n}\n.om-inline-code {\n background: rgba(108,92,231,0.1); padding: 1px 4px; border-radius: 3px;\n font-family: 'SF Mono', Consolas, monospace; font-size: 12px;\n}\n\n/* ── Copy Button ─────────────────────────────────────── */\n.om-copy-btn {\n position: absolute; top: 4px; right: 4px;\n background: rgba(0,0,0,0.3); border: none; color: #888;\n cursor: pointer; padding: 3px; border-radius: 4px;\n opacity: 0; transition: opacity 0.15s;\n display: flex; align-items: center;\n}\n.om-msg:hover .om-copy-btn { opacity: 1; }\n.om-copy-btn:hover { color: #ccc; background: rgba(0,0,0,0.5); }\n.om-msg { position: relative; }\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 shouldReconnect = false;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet reconnectAttempt = 0;\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 shouldReconnect = true;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const handshakeTimeout = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject(new Error(\"Handshake timeout\"));\n ws?.close();\n }\n }, 10000);\n\n try {\n // Same-origin WebSocket — use page hostname and given port\n const wsHost = window.location.hostname || \"127.0.0.1\";\n const wsProto = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n ws = new WebSocket(`${wsProto}//${wsHost}:${port}/__openmagic__/ws`);\n\n ws.onopen = () => {\n // Send handshake directly (bypass send() which checks connected flag)\n const handshakeId = generateId();\n ws!.send(JSON.stringify({ id: handshakeId, type: \"handshake\", payload: { token } }));\n\n handlers.set(handshakeId, (msg) => {\n if (msg.type === \"handshake.ok\") {\n clearTimeout(handshakeTimeout);\n connected = true;\n reconnectAttempt = 0;\n // Flush queued messages\n for (const queued of messageQueue) {\n ws?.send(queued);\n }\n messageQueue = [];\n if (!settled) { settled = true; resolve(); }\n } else if (msg.type === \"error\") {\n clearTimeout(handshakeTimeout);\n if (!settled) { settled = true; 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 if (msg.id && handlers.has(msg.id)) {\n const handler = handlers.get(msg.id)!;\n handler(msg);\n if (msg.type === \"llm.done\" || msg.type === \"llm.error\" || !msg.type.startsWith(\"llm.\")) {\n handlers.delete(msg.id);\n }\n }\n for (const handler of globalHandlers) {\n handler(msg);\n }\n } catch {\n // Ignore parse errors\n }\n };\n\n ws.onclose = () => {\n const wasConnected = connected;\n connected = false;\n\n // Reject all pending handlers\n handlers.forEach((handler, id) => {\n handler({ type: \"error\", id, payload: { message: \"Connection lost\" } });\n });\n handlers.clear();\n\n if (!wasConnected && !settled) {\n // Connection closed before handshake completed\n clearTimeout(handshakeTimeout);\n settled = true;\n reject(new Error(\"WebSocket closed before handshake\"));\n return;\n }\n\n // Only reconnect if we were previously connected and should reconnect\n if (wasConnected && shouldReconnect && !reconnectTimer) {\n const delay = Math.min(2000 * Math.pow(1.5, reconnectAttempt), 30000);\n reconnectAttempt++;\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect(port, token).then(() => {\n // Notify toolbar of reconnection\n for (const handler of globalHandlers) {\n handler({ type: \"reconnected\", payload: {} });\n }\n }).catch(() => {});\n }, delay);\n }\n };\n\n ws.onerror = () => {\n if (!connected && !settled) {\n clearTimeout(handshakeTimeout);\n settled = true;\n reject(new Error(\"WebSocket connection failed\"));\n }\n };\n } catch (e) {\n clearTimeout(handshakeTimeout);\n if (!settled) { settled = true; 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 && ws.readyState === WebSocket.OPEN && 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\n // Idle timeout resets on every chunk — CLI agents (Claude Code, Codex, Gemini)\n // may pause for minutes while reading files or thinking between turns.\n // 5 min idle = generous enough for multi-turn agents.\n const IDLE_MS = 300000;\n let timeout = setTimeout(onTimeout, IDLE_MS);\n function onTimeout() {\n handlers.delete(id);\n reject(new Error(\"Stream timeout\"));\n }\n function resetTimeout() {\n clearTimeout(timeout);\n timeout = setTimeout(onTimeout, IDLE_MS);\n }\n\n handlers.set(id, (msg) => {\n if (msg.type === \"llm.chunk\") {\n resetTimeout();\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 shouldReconnect = false;\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 ancestry: string[];\n componentHint: string;\n rect: { x: number; y: number; width: number; height: number };\n // Enhanced context\n parentStyles: Record<string, string>;\n siblings: string[];\n matchedCssRules: string[];\n viewport: { width: number; height: number };\n ariaAttributes: Record<string, string>;\n eventHandlers: string[];\n reactProps: Record<string, unknown> | null;\n childrenLayout: {\n tag: string;\n className: string;\n rect: { x: number; y: number; width: number; height: number };\n gapToNext: { horizontal: number; vertical: number } | null;\n margin: string;\n padding: string;\n }[];\n resolvedClasses: { className: string; css: string }[];\n // Phase 3: Deep element intelligence (unique to OpenMagic)\n themeState: {\n darkMode: boolean;\n colorScheme: string;\n htmlDataAttributes: Record<string, string>;\n };\n cssVariables: Record<string, string>;\n stackingContext: { zIndex: string; createsContext: boolean; parentZIndex: string };\n visibilityState: {\n isVisible: boolean;\n isInViewport: boolean;\n scrollTop: number;\n scrollLeft: number;\n isScrollable: boolean;\n };\n activeBreakpoints: string[];\n pseudoElements: { before: string; after: string };\n formState: { disabled: boolean; readOnly: boolean; invalid: boolean } | null;\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 // Parent container styles (critical for layout context)\n const parentStyles: Record<string, string> = {};\n if (el.parentElement && el.parentElement !== document.body) {\n const parentComputed = window.getComputedStyle(el.parentElement);\n for (const prop of IMPORTANT_STYLES) {\n parentStyles[prop] = parentComputed.getPropertyValue(prop);\n }\n }\n\n // Sibling elements (layout context — ±3 siblings around the selected element)\n const siblings: string[] = [];\n if (el.parentElement) {\n const children = Array.from(el.parentElement.children);\n const selectedIdx = children.indexOf(el);\n const start = Math.max(0, selectedIdx - 3);\n const end = Math.min(children.length, selectedIdx + 4);\n if (start > 0) siblings.push(`... ${start} elements before ...`);\n for (let i = start; i < end; i++) {\n const sib = children[i];\n const tag = sib.tagName.toLowerCase();\n const cls = (sib.className || \"\").toString().slice(0, 60);\n if (sib === el) {\n siblings.push(`[SELECTED] <${tag} class=\"${cls}\">`);\n } else {\n siblings.push(`<${tag} class=\"${cls}\">`);\n }\n }\n if (end < children.length) siblings.push(`... ${children.length - end} elements after ...`);\n }\n\n // Children layout measurements (pixel-level spacing context)\n const childrenLayout: SelectedElement[\"childrenLayout\"] = [];\n const directChildren = Array.from(el.children).slice(0, 12);\n for (let i = 0; i < directChildren.length; i++) {\n const child = directChildren[i] as HTMLElement;\n const cRect = child.getBoundingClientRect();\n const cComputed = window.getComputedStyle(child);\n let gapToNext: { horizontal: number; vertical: number } | null = null;\n if (i < directChildren.length - 1) {\n const nextRect = (directChildren[i + 1] as HTMLElement).getBoundingClientRect();\n // Use absolute gap value to handle both LTR and RTL layouts\n gapToNext = {\n vertical: Math.round(nextRect.top - cRect.bottom),\n horizontal: Math.round(Math.abs(nextRect.left - cRect.right)),\n };\n }\n childrenLayout.push({\n tag: child.tagName.toLowerCase(),\n className: (child.className || \"\").toString().slice(0, 80),\n rect: { x: Math.round(cRect.x), y: Math.round(cRect.y), width: Math.round(cRect.width), height: Math.round(cRect.height) },\n gapToNext,\n margin: cComputed.margin,\n padding: cComputed.padding,\n });\n }\n\n // Matched CSS rules from stylesheets\n const matchedCssRules = getMatchedCssRules(el);\n\n // Resolve Tailwind/utility classes to their CSS values\n const resolvedClasses = resolveClasses(el, matchedCssRules);\n\n // ARIA / accessibility attributes\n const ariaAttributes: Record<string, string> = {};\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith(\"aria-\") || attr.name === \"role\" || attr.name === \"tabindex\") {\n ariaAttributes[attr.name] = attr.value;\n }\n }\n\n // Event handlers (from element attributes and React props)\n const eventHandlers: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith(\"on\")) eventHandlers.push(attr.name);\n }\n\n // React props extraction\n const reactProps = getReactProps(el);\n\n // ── Phase 3: Deep element intelligence ──\n\n // Theme / dark mode state\n const htmlEl = document.documentElement;\n const htmlComputed = window.getComputedStyle(htmlEl);\n const htmlDataAttributes: Record<string, string> = {};\n for (const key of Object.keys(htmlEl.dataset)) {\n htmlDataAttributes[key] = htmlEl.dataset[key] || \"\";\n }\n const themeState = {\n darkMode: htmlEl.classList.contains(\"dark\")\n || htmlEl.dataset.theme === \"dark\"\n || htmlEl.dataset.mode === \"dark\"\n || window.matchMedia(\"(prefers-color-scheme: dark)\").matches,\n colorScheme: htmlComputed.colorScheme || \"\",\n htmlDataAttributes,\n };\n\n // CSS custom properties used by this element\n const cssVariables: Record<string, string> = {};\n try {\n for (const rule of matchedCssRules) {\n const varMatches = rule.matchAll(/var\\((--[a-zA-Z0-9_-]+)/g);\n for (const vm of varMatches) {\n const varName = vm[1];\n if (!cssVariables[varName]) {\n cssVariables[varName] = computed.getPropertyValue(varName).trim() || \"(unset)\";\n }\n }\n }\n // Also check inline style\n const inlineVars = (el.getAttribute(\"style\") || \"\").matchAll(/var\\((--[a-zA-Z0-9_-]+)/g);\n for (const iv of inlineVars) {\n if (!cssVariables[iv[1]]) {\n cssVariables[iv[1]] = computed.getPropertyValue(iv[1]).trim() || \"(unset)\";\n }\n }\n } catch {}\n\n // z-index stacking context\n const zIndex = computed.zIndex;\n const position = computed.position;\n const createsContext = (position !== \"static\" && zIndex !== \"auto\") || computed.opacity !== \"1\"\n || computed.transform !== \"none\" || computed.filter !== \"none\";\n const parentZIndex = el.parentElement ? window.getComputedStyle(el.parentElement).zIndex : \"auto\";\n const stackingContext = { zIndex, createsContext, parentZIndex };\n\n // Visibility and scroll state\n const isInViewport = rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;\n let isVisible = true;\n try { isVisible = el.checkVisibility?.({ checkOpacity: true, checkVisibilityCSS: true }) ?? true; } catch { isVisible = computed.display !== \"none\" && computed.visibility !== \"hidden\"; }\n const isScrollable = el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;\n const visibilityState = { isVisible, isInViewport, scrollTop: el.scrollTop, scrollLeft: el.scrollLeft, isScrollable };\n\n // Active media queries / breakpoints\n const activeBreakpoints: string[] = [];\n const breakpointsToCheck = [\n \"(max-width: 639px)\", \"(min-width: 640px)\", \"(min-width: 768px)\",\n \"(min-width: 1024px)\", \"(min-width: 1280px)\", \"(min-width: 1536px)\",\n \"(prefers-color-scheme: dark)\", \"(prefers-reduced-motion: reduce)\",\n ];\n for (const bp of breakpointsToCheck) {\n try { if (window.matchMedia(bp).matches) activeBreakpoints.push(bp); } catch {}\n }\n\n // Pseudo-element content\n let beforeContent = \"\", afterContent = \"\";\n try { beforeContent = window.getComputedStyle(el, \"::before\").content || \"\"; } catch {}\n try { afterContent = window.getComputedStyle(el, \"::after\").content || \"\"; } catch {}\n const pseudoElements = { before: beforeContent, after: afterContent };\n\n // Form state (if applicable)\n let formState: { disabled: boolean; readOnly: boolean; invalid: boolean } | null = null;\n if (el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement || el instanceof HTMLButtonElement) {\n formState = {\n disabled: (el as any).disabled || false,\n readOnly: (el as any).readOnly || false,\n invalid: (el as any).checkValidity ? !(el as any).checkValidity() : false,\n };\n }\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 ancestry: getAncestry(el),\n componentHint: getComponentHint(el),\n rect: {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n },\n parentStyles,\n siblings,\n childrenLayout,\n matchedCssRules,\n resolvedClasses,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n ariaAttributes,\n eventHandlers,\n reactProps,\n themeState,\n cssVariables,\n stackingContext,\n visibilityState,\n activeBreakpoints,\n pseudoElements,\n formState,\n };\n}\n\nfunction getAncestry(el: HTMLElement, depth: number = 5): string[] {\n const result: string[] = [];\n let current = el.parentElement;\n while (current && current !== document.body && result.length < depth) {\n const tag = current.tagName.toLowerCase();\n const cls = (typeof current.className === \"string\" ? current.className : \"\")\n .split(/\\s+/).filter(c => c.length > 1 && !c.startsWith(\"_\")).slice(0, 3).join(\".\");\n result.push(cls ? `${tag}.${cls}` : tag);\n current = current.parentElement;\n }\n return result;\n}\n\nfunction getComponentHint(el: HTMLElement): string {\n // Try to find component name from data attributes or React fiber\n let current: HTMLElement | null = el;\n while (current && current !== document.body) {\n // Check common framework data attributes\n const dataComponent = current.getAttribute(\"data-component\")\n || current.getAttribute(\"data-testid\")\n || current.getAttribute(\"data-cy\");\n if (dataComponent) return dataComponent;\n\n // React: check __reactFiber or __reactInternalInstance\n const keys = Object.keys(current);\n for (const key of keys) {\n if (key.startsWith(\"__reactFiber\") || key.startsWith(\"__reactInternalInstance\")) {\n try {\n const fiber = (current as any)[key];\n const name = fiber?.type?.name || fiber?.type?.displayName\n || fiber?.return?.type?.name || fiber?.return?.type?.displayName;\n if (name && name !== \"div\" && name !== \"span\" && name.length > 1) return name;\n } catch {}\n }\n }\n\n current = current.parentElement;\n }\n return \"\";\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 `#${CSS.escape(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(`#${CSS.escape(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 .map((c) => CSS.escape(c));\n if (classes.length > 0) {\n selector += \".\" + classes.join(\".\");\n }\n }\n\n // Add nth-of-type 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-of-type(${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// --- Matched CSS Rules ---\n\nfunction getMatchedCssRules(el: HTMLElement): string[] {\n const rules: string[] = [];\n try {\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n const cssRules = sheet.cssRules || sheet.rules;\n if (!cssRules) continue;\n for (const rule of Array.from(cssRules)) {\n if (rule instanceof CSSStyleRule) {\n try {\n if (el.matches(rule.selectorText)) {\n // Only include rules with meaningful styles (skip resets/normalizers)\n const text = rule.cssText;\n if (text.length > 10 && text.length < 500) {\n rules.push(text);\n }\n }\n } catch { /* invalid selector */ }\n }\n }\n } catch { /* cross-origin stylesheet */ }\n }\n } catch { /* stylesheet access error */ }\n return rules.slice(0, 15); // Cap at 15 rules\n}\n\n// --- React Props Extraction ---\n\nfunction getReactProps(el: HTMLElement): Record<string, unknown> | null {\n try {\n const keys = Object.keys(el);\n for (const key of keys) {\n if (key.startsWith(\"__reactFiber\") || key.startsWith(\"__reactInternalInstance\")) {\n const fiber = (el as any)[key];\n if (!fiber?.memoizedProps) continue;\n const props = fiber.memoizedProps;\n // Extract safe, serializable props (skip functions, React elements, large objects)\n const safe: Record<string, unknown> = {};\n let count = 0;\n for (const [k, v] of Object.entries(props)) {\n if (count >= 10) break;\n if (k === \"children\") continue; // Skip children (too large)\n const t = typeof v;\n if (t === \"string\" || t === \"number\" || t === \"boolean\" || v === null) {\n safe[k] = v;\n count++;\n } else if (t === \"function\") {\n safe[k] = \"[function]\";\n count++;\n } else if (Array.isArray(v)) {\n safe[k] = `[Array(${v.length})]`;\n count++;\n }\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch { /* not React or access error */ }\n return null;\n}\n\n// --- Tailwind / Utility Class Resolution ---\n\nfunction resolveClasses(el: HTMLElement, matchedRules: string[]): { className: string; css: string }[] {\n const resolved: { className: string; css: string }[] = [];\n const classes = (el.className || \"\").toString().trim().split(/\\s+/).filter(Boolean);\n\n for (const cls of classes) {\n const escaped = CSS.escape(cls);\n for (const rule of matchedRules) {\n if (rule.includes(`.${escaped}`) && rule.length < 200) {\n resolved.push({ className: cls, css: rule });\n break;\n }\n }\n if (resolved.length >= 20) break;\n }\n return resolved;\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\n","// Screenshot capture with multiple approaches and error feedback\n\nexport async function captureScreenshot(\n target?: HTMLElement\n): Promise<string | null> {\n // Approach 1: Try the simple SVG foreignObject approach\n try {\n const el = target || document.body;\n const result = await captureViaSvg(el);\n if (result) return result;\n } catch (e) {\n console.warn(\"[OpenMagic] SVG screenshot failed:\", e);\n }\n\n // Approach 2: Try capturing just the visible area as a simple canvas\n try {\n const result = await captureSimple(target);\n if (result) return result;\n } catch (e) {\n console.warn(\"[OpenMagic] Simple screenshot failed:\", e);\n }\n\n console.warn(\"[OpenMagic] All screenshot methods failed\");\n return null;\n}\n\n// Error feedback version — returns error message if failed\nexport async function captureScreenshotWithFeedback(\n target?: HTMLElement\n): Promise<{ data: string | null; error?: string }> {\n try {\n const el = target || document.body;\n const result = await captureViaSvg(el);\n if (result) return { data: result };\n } catch (e: any) {\n // Fall through to simple\n }\n\n try {\n const result = await captureSimple(target);\n if (result) return { data: result };\n } catch (e: any) {\n return { data: null, error: `Screenshot failed: ${e.message || \"unknown error\"}. Try using the image attachment button instead.` };\n }\n\n return { data: null, error: \"Screenshot capture not available on this page. Try pasting or dragging an image instead.\" };\n}\n\nasync function captureViaSvg(element: HTMLElement): Promise<string | null> {\n const rect = element.getBoundingClientRect();\n const width = Math.min(rect.width || window.innerWidth, 1920);\n const height = Math.min(rect.height || window.innerHeight, 1080);\n\n // Clone and inline styles — but limit depth to avoid huge SVGs\n const clone = cloneWithStyles(element, 0, 4);\n if (!clone) return null;\n\n const svgData = `\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 const blob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n\n return new Promise<string | null>((resolve) => {\n const img = new Image();\n const canvas = document.createElement(\"canvas\");\n const dpr = Math.min(window.devicePixelRatio || 1, 2);\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) { resolve(null); return; }\n ctx.scale(dpr, dpr);\n ctx.drawImage(img, 0, 0);\n try {\n // Compress: resize to max 1280px wide, JPEG 80% quality\n const MAX_W = 1280;\n if (canvas.width > MAX_W) {\n const ratio = MAX_W / canvas.width;\n const small = document.createElement(\"canvas\");\n small.width = MAX_W;\n small.height = Math.round(canvas.height * ratio);\n const sCtx = small.getContext(\"2d\");\n if (sCtx) {\n sCtx.drawImage(canvas, 0, 0, small.width, small.height);\n resolve(small.toDataURL(\"image/jpeg\", 0.8));\n return;\n }\n }\n resolve(canvas.toDataURL(\"image/jpeg\", 0.8));\n } catch {\n resolve(null); // Tainted canvas\n }\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n\n // 5 second timeout\n setTimeout(() => { URL.revokeObjectURL(url); resolve(null); }, 5000);\n img.src = url;\n });\n}\n\n// Simpler approach: capture just text/layout info as a basic representation\nasync function captureSimple(target?: HTMLElement): Promise<string | null> {\n // Create a simple text-based capture showing element hierarchy\n // This works as fallback when SVG approach fails\n const el = target || document.documentElement;\n const rect = el.getBoundingClientRect();\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = 400;\n canvas.height = 300;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n\n // Dark background\n ctx.fillStyle = \"#1a1a2e\";\n ctx.fillRect(0, 0, 400, 300);\n\n // Draw element info\n ctx.fillStyle = \"#e0e0e0\";\n ctx.font = \"14px system-ui\";\n ctx.fillText(`Element: <${el.tagName.toLowerCase()}>`, 20, 30);\n ctx.fillStyle = \"#888\";\n ctx.font = \"12px system-ui\";\n ctx.fillText(`Size: ${Math.round(rect.width)}x${Math.round(rect.height)}`, 20, 55);\n ctx.fillText(`Classes: ${(el.className || \"\").toString().slice(0, 40)}`, 20, 75);\n ctx.fillText(`Page: ${window.location.pathname}`, 20, 95);\n ctx.fillStyle = \"#6c5ce7\";\n ctx.font = \"11px system-ui\";\n ctx.fillText(\"(Full screenshot unavailable — context sent as metadata)\", 20, 130);\n\n return canvas.toDataURL(\"image/png\");\n}\n\nfunction cloneWithStyles(source: HTMLElement, depth: number, maxDepth: number): HTMLElement | null {\n if (depth > maxDepth) return null;\n\n try {\n const clone = source.cloneNode(false) as HTMLElement;\n\n // Remove problematic elements\n if (clone.tagName === \"SCRIPT\" || clone.tagName === \"STYLE\" || clone.tagName === \"SVG\" ||\n clone.tagName === \"CANVAS\" || clone.tagName === \"VIDEO\" || clone.tagName === \"IFRAME\") {\n return null;\n }\n\n // Inline key styles only (not all — reduces size)\n const computed = window.getComputedStyle(source);\n const keyProps = [\"display\", \"position\", \"width\", \"height\", \"margin\", \"padding\",\n \"color\", \"background-color\", \"background\", \"font-size\", \"font-weight\", \"font-family\",\n \"border\", \"border-radius\", \"flex-direction\", \"justify-content\", \"align-items\", \"gap\",\n \"grid-template-columns\", \"text-align\", \"overflow\"];\n let css = \"\";\n for (const p of keyProps) {\n const v = computed.getPropertyValue(p);\n if (v && v !== \"normal\" && v !== \"none\" && v !== \"auto\" && v !== \"0px\") {\n css += `${p}:${v};`;\n }\n }\n clone.setAttribute(\"style\", css);\n\n // Clone children with depth limit\n for (let i = 0; i < source.children.length && i < 20; i++) {\n const child = cloneWithStyles(source.children[i] as HTMLElement, depth + 1, maxDepth);\n if (child) clone.appendChild(child);\n }\n\n return clone;\n } catch {\n return null;\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 { inspectElement, showHighlight, hideHighlight, type SelectedElement } from \"./services/dom-inspector.js\";\nimport { captureScreenshotWithFeedback } from \"./services/capture.js\";\nimport { installNetworkCapture, installConsoleCapture, buildContext, getNetworkLogs, getConsoleLogs } from \"./services/context-builder.js\";\n\n// ── SVG Icons (Lucide-style) ─────────────────────────────────────\nconst ICON = {\n sparkle: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.582a.5.5 0 0 1 0 .962L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"/></svg>`,\n crosshair: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"22\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"6\" y1=\"12\" x2=\"2\" y2=\"12\"/><line x1=\"12\" y1=\"6\" x2=\"12\" y2=\"2\"/><line x1=\"12\" y1=\"22\" x2=\"12\" y2=\"18\"/></svg>`,\n camera: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/></svg>`,\n chat: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>`,\n settings: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`,\n send: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/></svg>`,\n x: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`,\n externalLink: `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/><polyline points=\"15 3 21 3 21 9\"/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"/></svg>`,\n check: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"20 6 9 17 4 12\"/></svg>`,\n copy: `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg>`,\n grip: `<svg width=\"7\" height=\"14\" viewBox=\"0 0 8 14\" fill=\"currentColor\"><circle cx=\"2\" cy=\"2\" r=\"1.2\"/><circle cx=\"6\" cy=\"2\" r=\"1.2\"/><circle cx=\"2\" cy=\"7\" r=\"1.2\"/><circle cx=\"6\" cy=\"7\" r=\"1.2\"/><circle cx=\"2\" cy=\"12\" r=\"1.2\"/><circle cx=\"6\" cy=\"12\" r=\"1.2\"/></svg>`,\n network: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/></svg>`,\n activity: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"22 12 18 12 15 21 9 3 6 12 2 12\"/></svg>`,\n bug: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m8 2 1.88 1.88M14.12 3.88 16 2M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\"/><path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6\"/><path d=\"M12 20v-9\"/><path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\"/><path d=\"M6 13H2\"/><path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\"/><path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\"/><path d=\"M22 13h-4\"/><path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\"/></svg>`,\n paperclip: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48\"/></svg>`,\n image: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\"/><circle cx=\"9\" cy=\"9\" r=\"2\"/><path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\"/></svg>`,\n trash: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>`,\n minus: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>`,\n};\n\n// ── Model Registry (inline for browser bundle) ───────────────────\nconst MODEL_REGISTRY: Record<string, { name: string; models: { id: string; name: string }[]; keyPlaceholder: string; local?: boolean; keyUrl?: string }> = {\n \"claude-code\": { name: \"Claude Code (CLI)\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"claude-code\", name: \"Claude Code\" },\n ]},\n \"codex-cli\": { name: \"Codex CLI\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"codex-cli\", name: \"Codex CLI\" },\n ]},\n \"gemini-cli\": { name: \"Gemini CLI\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"gemini-cli\", name: \"Gemini CLI\" },\n ]},\n openai: { name: \"OpenAI\", keyUrl: \"https://platform.openai.com/api-keys\", keyPlaceholder: \"sk-...\", models: [\n { id: \"gpt-5.4\", name: \"GPT-5.4\" }, { id: \"gpt-5.4-mini\", name: \"GPT-5.4 Mini\" },\n { id: \"gpt-5.2\", name: \"GPT-5.2 Thinking\" }, { id: \"o3\", name: \"o3\" }, { id: \"o4-mini\", name: \"o4-mini\" },\n { id: \"gpt-4.1\", name: \"GPT-4.1\" }, { id: \"gpt-4.1-mini\", name: \"GPT-4.1 Mini\" },\n ]},\n anthropic: { name: \"Anthropic\", keyUrl: \"https://console.anthropic.com/settings/keys\", keyPlaceholder: \"sk-ant-...\", models: [\n { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\" }, { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\" },\n { id: \"claude-haiku-4-5-20251001\", name: \"Claude Haiku 4.5\" },\n ]},\n google: { name: \"Google Gemini\", keyUrl: \"https://aistudio.google.com/apikey\", keyPlaceholder: \"AIza...\", models: [\n { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro\" }, { id: \"gemini-3-flash-preview\", name: \"Gemini 3 Flash\" },\n { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\" }, { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\" },\n ]},\n xai: { name: \"xAI (Grok)\", keyUrl: \"https://console.x.ai/team/default/api-keys\", keyPlaceholder: \"xai-...\", models: [\n { id: \"grok-4.20-0309-reasoning\", name: \"Grok 4.20 Reasoning\" }, { id: \"grok-4-1-fast-non-reasoning\", name: \"Grok 4.1 Fast\" },\n ]},\n deepseek: { name: \"DeepSeek\", keyUrl: \"https://platform.deepseek.com/api_keys\", keyPlaceholder: \"sk-...\", models: [\n { id: \"deepseek-chat\", name: \"DeepSeek V3.2\" }, { id: \"deepseek-reasoner\", name: \"DeepSeek R1\" },\n ]},\n mistral: { name: \"Mistral\", keyUrl: \"https://console.mistral.ai/api-keys\", keyPlaceholder: \"...\", models: [\n { id: \"mistral-large-3-25-12\", name: \"Mistral Large 3\" }, { id: \"codestral-2508\", name: \"Codestral\" }, { id: \"devstral-2-25-12\", name: \"Devstral 2\" },\n ]},\n groq: { name: \"Groq\", keyUrl: \"https://console.groq.com/keys\", keyPlaceholder: \"gsk_...\", models: [\n { id: \"meta-llama/llama-4-scout-17b-16e-instruct\", name: \"Llama 4 Scout\" }, { id: \"llama-3.3-70b-versatile\", name: \"Llama 3.3 70B\" },\n ]},\n minimax: { name: \"MiniMax\", keyUrl: \"https://platform.minimax.chat/user-center/basic-information/interface-key\", keyPlaceholder: \"MiniMax key...\", models: [\n { id: \"MiniMax-M2.7\", name: \"MiniMax M2.7\" }, { id: \"MiniMax-M2.5\", name: \"MiniMax M2.5\" },\n ]},\n moonshot: { name: \"Kimi (Moonshot)\", keyUrl: \"https://platform.moonshot.cn/console/api-keys\", keyPlaceholder: \"Moonshot key...\", models: [\n { id: \"kimi-k2.5\", name: \"Kimi K2.5\" }, { id: \"kimi-k2-thinking\", name: \"Kimi K2 Thinking\" },\n ]},\n qwen: { name: \"Qwen (Alibaba)\", keyUrl: \"https://dashscope.console.aliyun.com/apiKey\", keyPlaceholder: \"DashScope key...\", models: [\n { id: \"qwen3.5-plus\", name: \"Qwen 3.5 Plus\" }, { id: \"qwen-max\", name: \"Qwen Max\" },\n ]},\n zhipu: { name: \"Zhipu AI (GLM)\", keyUrl: \"https://open.bigmodel.cn/usercenter/apikeys\", keyPlaceholder: \"Zhipu key...\", models: [\n { id: \"glm-5\", name: \"GLM-5\" }, { id: \"glm-4.7\", name: \"GLM-4.7\" },\n ]},\n doubao: { name: \"Doubao (ByteDance)\", keyUrl: \"https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey\", keyPlaceholder: \"Volcano key...\", models: [\n { id: \"doubao-seed-2-0-pro\", name: \"Doubao Seed 2.0 Pro\" }, { id: \"doubao-seed-2-0-code\", name: \"Doubao Seed 2.0 Code\" },\n ]},\n ollama: { name: \"Ollama (Local)\", keyPlaceholder: \"not required\", local: true, models: [] },\n openrouter: { name: \"OpenRouter\", keyUrl: \"https://openrouter.ai/settings/keys\", keyPlaceholder: \"sk-or-...\", models: [] },\n};\n\nfunction encodeBase64Utf8(value: string): string {\n const bytes = new TextEncoder().encode(value);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction decodeBase64Utf8(value: string): string {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n}\n\nconst CURRENT_VERSION = \"0.41.1\";\n\n// ── State ────────────────────────────────────────────────────────\nconst state = {\n connected: false,\n panelOpen: false,\n activePanel: \"\" as \"\" | \"chat\" | \"settings\",\n selecting: false,\n selectedElement: null as SelectedElement | null,\n screenshot: null as string | null,\n messages: [] as { role: \"user\" | \"assistant\" | \"system\"; content: string }[],\n streaming: false,\n streamContent: \"\",\n provider: \"\",\n model: \"\",\n hasApiKey: false,\n configuredProviders: {} as Record<string, boolean>, // which providers have keys\n detectedClis: [] as { id: string; name: string; installed: boolean; authenticated: boolean; version?: string }[],\n roots: [] as string[],\n updateAvailable: false,\n latestVersion: \"\",\n saveStatus: \"\" as \"\" | \"saving\" | \"saved\" | \"error\",\n networkCapture: false, // whether network panel is showing\n attachments: [] as string[], // base64 image data URLs attached to next message\n groundedFiles: [] as string[], // last grounded file paths for context chips\n minimized: false,\n};\n\n// ── DOM refs (created once) ──────────────────────────────────────\nlet shadow: ShadowRoot;\nlet $toolbar: HTMLDivElement;\nlet $promptInput: HTMLInputElement;\nlet $promptCtx: HTMLDivElement;\nlet $panel: HTMLDivElement;\nlet $panelBody: HTMLDivElement;\n\n// ── Initialize ───────────────────────────────────────────────────\n// ── State Persistence (survives HMR page reloads) ────────────────\nfunction saveState() {\n try {\n // Prune messages for storage: keep first 5 + last 45, strip large diff payloads\n let msgs = state.messages;\n if (msgs.length > 50) {\n msgs = [...msgs.slice(0, 5), ...msgs.slice(-45)];\n }\n const prunedMsgs = msgs.map(m => {\n if (m.content.startsWith(\"__DIFF__\") && m.content.length > 500) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n return { ...m, content: `Applied ${diff.type || \"edit\"} to ${diff.file || \"file\"}` };\n } catch { return m; }\n }\n return m;\n });\n sessionStorage.setItem(\"__om_state__\", JSON.stringify({\n messages: prunedMsgs,\n provider: state.provider,\n model: state.model,\n panelOpen: state.panelOpen,\n activePanel: state.activePanel,\n }));\n } catch { /* quota exceeded or unavailable */ }\n}\n\nfunction restoreState() {\n try {\n const saved = JSON.parse(sessionStorage.getItem(\"__om_state__\") || \"{}\");\n if (saved.messages?.length) state.messages = saved.messages;\n if (saved.provider) state.provider = saved.provider;\n if (saved.model) state.model = saved.model;\n if (saved.panelOpen) { state.panelOpen = saved.panelOpen; state.activePanel = saved.activePanel || \"\"; }\n } catch { /* parse error or unavailable */ }\n}\n\nfunction init() {\n if (document.querySelector(\"openmagic-toolbar\")) return;\n\n // Restore chat history and settings from session storage (survives HMR)\n restoreState();\n\n const host = document.createElement(\"openmagic-toolbar\");\n host.dataset.openmagic = \"true\";\n shadow = host.attachShadow({ mode: \"closed\" });\n\n const style = document.createElement(\"style\");\n style.textContent = TOOLBAR_CSS;\n shadow.appendChild(style);\n\n const root = document.createElement(\"div\");\n shadow.appendChild(root);\n\n // Build DOM structure ONCE\n root.innerHTML = buildStaticDOM();\n\n // Cache refs\n $toolbar = root.querySelector(\".om-toolbar\")!;\n $promptInput = root.querySelector(\".om-prompt-input\")!;\n $promptCtx = root.querySelector(\".om-prompt-context\")!;\n $panel = root.querySelector(\".om-panel\")!;\n $panelBody = root.querySelector(\".om-panel-body\")!;\n\n document.body.appendChild(host);\n\n // Attach event delegation ONCE\n attachGlobalEvents(root);\n setupDraggable();\n\n // Restore persisted toolbar position\n try {\n const pos = JSON.parse(localStorage.getItem(\"__om_pos__\") || \"\");\n if (pos?.left && pos?.top) {\n $toolbar.style.left = pos.left;\n $toolbar.style.top = pos.top;\n $toolbar.style.right = \"auto\";\n $toolbar.style.bottom = \"auto\";\n }\n } catch {}\n\n installNetworkCapture();\n installConsoleCapture();\n checkForUpdates();\n\n // Connect to server — same origin (single port)\n const currentScript = document.querySelector('script[data-openmagic-token]') as HTMLScriptElement | null;\n const token = currentScript?.dataset.openmagicToken || (window as any).__OPENMAGIC_TOKEN__;\n const wsPort = parseInt(window.location.port, 10) || (window.location.protocol === \"https:\" ? 443 : 80);\n if (token) {\n ws.connect(wsPort, token)\n .then(() => {\n state.connected = true;\n updateStatusDot();\n return ws.request(\"config.get\");\n })\n .then((msg: any) => {\n // Store detected CLI agents from server\n state.detectedClis = msg.payload?.detectedClis || [];\n\n // Merge server config with restored state (restored state takes precedence for provider/model)\n const serverProvider = msg.payload?.provider || \"\";\n const serverModel = msg.payload?.model || \"\";\n state.provider = state.provider || serverProvider;\n state.model = state.model || serverModel;\n state.configuredProviders = msg.payload?.apiKeys || {};\n\n // Local providers (CLI-based) are always \"configured\" — no API key needed\n // Also mark detected+authenticated CLIs as configured\n for (const cli of state.detectedClis) {\n if (cli.installed && cli.authenticated) {\n state.configuredProviders[cli.id] = true;\n }\n }\n const provMeta = MODEL_REGISTRY[state.provider];\n state.hasApiKey = !!(state.configuredProviders[state.provider] || provMeta?.local);\n state.roots = msg.payload?.roots || [];\n\n // Restore panel state if we had it open before refresh\n if (state.panelOpen && state.activePanel) {\n openPanel(state.activePanel as \"chat\" | \"settings\");\n } else if (!state.provider || (!state.hasApiKey && !Object.values(state.configuredProviders).some(Boolean) && !provMeta?.local)) {\n openPanel(\"settings\");\n }\n updatePillButtons();\n updateModelSwitcher();\n })\n .catch(() => {\n state.connected = false;\n updateStatusDot();\n });\n }\n}\n\nfunction buildStaticDOM(): string {\n return `\n <div class=\"om-toolbar\">\n <div class=\"om-toolbar-header\">\n <span class=\"om-grab\">${ICON.grip}</span>\n <span class=\"om-pill-brand\">\n <span class=\"om-pill-text\">✨OpenMagic🪄</span>\n </span>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn\" data-action=\"select\" title=\"Select element\">${ICON.crosshair}</button>\n <button class=\"om-pill-btn\" data-action=\"screenshot\" title=\"Screenshot\">${ICON.camera}</button>\n <button class=\"om-pill-btn\" data-action=\"network\" title=\"Network & Performance\">${ICON.activity}</button>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn\" data-action=\"chat\" title=\"Chat\">${ICON.chat}</button>\n <button class=\"om-pill-btn\" data-action=\"settings\" title=\"Settings\">${ICON.settings}</button>\n <button class=\"om-pill-btn\" data-action=\"minimize\" title=\"Minimize\">${ICON.minus}</button>\n <span class=\"om-status-dot disconnected\"></span>\n </div>\n <div class=\"om-panel om-hidden\">\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\"></span>\n <span class=\"om-panel-version\">v${CURRENT_VERSION}</span>\n <button class=\"om-panel-bug\" data-action=\"report-issue\" title=\"Report a bug on GitHub\">${ICON.bug}</button>\n <button class=\"om-panel-clear\" data-action=\"clear-chat\" title=\"Clear chat\">${ICON.trash}</button>\n <button class=\"om-panel-close\" data-action=\"close-panel\">${ICON.x}</button>\n </div>\n <div class=\"om-panel-body\"></div>\n </div>\n <div class=\"om-apply-bar om-hidden\">\n <span class=\"om-apply-bar-text\"></span>\n <div class=\"om-diff-actions\">\n <button class=\"om-btn om-btn-sm\" data-action=\"apply-all\">Apply All</button>\n <button class=\"om-btn-secondary om-btn-sm\" data-action=\"reject-all\">Reject All</button>\n </div>\n </div>\n <div class=\"om-prompt-attachments\"></div>\n <div class=\"om-prompt-row\">\n <div class=\"om-prompt-context\"></div>\n <select class=\"om-model-switcher\" data-field=\"quick-model\" title=\"Switch model\"></select>\n <button class=\"om-prompt-attach\" data-action=\"attach-image\" title=\"Attach image\">${ICON.paperclip}</button>\n <input class=\"om-prompt-input\" type=\"text\" placeholder=\"Describe what to change...\" autocomplete=\"off\" />\n <button class=\"om-prompt-send\" data-action=\"prompt-send\">${ICON.send}</button>\n <input type=\"file\" class=\"om-file-input om-hidden\" accept=\"image/*\" multiple />\n </div>\n </div>`;\n}\n\n// ── Event Delegation (attached ONCE) ─────────────────────────────\nfunction attachGlobalEvents(root: HTMLElement) {\n // Click delegation\n root.addEventListener(\"click\", (e) => {\n const target = (e.target as HTMLElement).closest(\"[data-action]\") as HTMLElement | null;\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n const action = target.dataset.action!;\n handleAction(action, target);\n });\n\n // Change delegation (dropdowns)\n root.addEventListener(\"change\", (e) => {\n const target = e.target as HTMLSelectElement;\n const field = target.dataset.field;\n if (!field) return;\n\n if (field === \"provider\") {\n state.provider = target.value;\n state.model = MODEL_REGISTRY[state.provider]?.models[0]?.id || \"\";\n state.hasApiKey = state.configuredProviders[state.provider] || MODEL_REGISTRY[state.provider]?.local || false;\n state.saveStatus = \"\";\n refreshPanelContent();\n } else if (field === \"model\") {\n state.model = target.value;\n } else if (field === \"quick-model\") {\n state.model = target.value;\n saveState(); // persist model switch\n }\n });\n\n // Prompt input: Enter to send\n $promptInput.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendPrompt();\n }\n });\n\n // File input change handler\n const fileInput = root.querySelector(\".om-file-input\") as HTMLInputElement;\n if (fileInput) {\n fileInput.addEventListener(\"change\", () => {\n handleFileSelect(fileInput.files);\n fileInput.value = \"\"; // Reset so same file can be selected again\n });\n }\n\n // Drag and drop on prompt area\n const promptRow = root.querySelector(\".om-prompt-row\");\n if (promptRow) {\n promptRow.addEventListener(\"dragover\", (e) => {\n e.preventDefault();\n (promptRow as HTMLElement).style.borderColor = \"rgba(108, 92, 231, 0.5)\";\n });\n promptRow.addEventListener(\"dragleave\", () => {\n (promptRow as HTMLElement).style.borderColor = \"\";\n });\n promptRow.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n (promptRow as HTMLElement).style.borderColor = \"\";\n const dt = (e as DragEvent).dataTransfer;\n if (dt?.files?.length) handleFileSelect(dt.files);\n });\n\n // Also handle paste with images\n $promptInput.addEventListener(\"paste\", (e) => {\n const items = (e as ClipboardEvent).clipboardData?.items;\n if (!items) return;\n for (let i = 0; i < items.length; i++) {\n if (items[i].type.startsWith(\"image/\")) {\n const file = items[i].getAsFile();\n if (file) {\n const dt = new DataTransfer();\n dt.items.add(file);\n handleFileSelect(dt.files);\n }\n }\n }\n });\n }\n\n // Listen for reconnection events\n ws.onMessage((msg: any) => {\n if (msg.type === \"reconnected\") {\n state.connected = true;\n updateStatusDot();\n }\n });\n\n // Global keyboard shortcuts (scoped to avoid stealing host app shortcuts)\n document.addEventListener(\"keydown\", (e) => {\n // Ctrl/Cmd + Shift + O: toggle toolbar — always works (unique combo)\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \"O\" || e.key === \"o\")) {\n e.preventDefault();\n if (state.minimized) {\n state.minimized = false;\n // Restore toolbar elements\n const headerBtns = $toolbar.querySelectorAll(\".om-pill-btn:not([data-action='minimize']), .om-pill-divider, .om-status-dot\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"\");\n const promptRow = shadow.querySelector(\".om-prompt-row\") as HTMLElement;\n if (promptRow) promptRow.classList.remove(\"om-hidden\");\n } else if (state.panelOpen) {\n closePanel();\n } else {\n openPanel(\"chat\");\n }\n return;\n }\n // Ctrl/Cmd + Shift + K: focus prompt input (Shift avoids stealing Cmd+K from host apps)\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \"k\" || e.key === \"K\")) {\n e.preventDefault();\n if (!state.panelOpen) openPanel(\"chat\");\n $promptInput.focus();\n return;\n }\n // Ctrl/Cmd + Z: undo last applied diff (only when toolbar is focused)\n if ((e.ctrlKey || e.metaKey) && (e.key === \"z\" || e.key === \"Z\") && !e.shiftKey) {\n if (shadow.activeElement) {\n const undoBtn = shadow.querySelector('[data-action=\"undo-diff\"]') as HTMLElement;\n if (undoBtn) { e.preventDefault(); undoDiff(undoBtn); return; }\n }\n }\n // Ctrl/Cmd + . : apply all pending diffs\n if ((e.ctrlKey || e.metaKey) && e.key === \".\") {\n const applyAllBtn = shadow.querySelector('[data-action=\"apply-all\"]') as HTMLElement;\n if (applyAllBtn && !shadow.querySelector(\".om-apply-bar.om-hidden\")) {\n e.preventDefault();\n handleAction(\"apply-all\", applyAllBtn);\n return;\n }\n }\n // Escape: only handle if the active element is inside the toolbar shadow DOM\n // or if we're in select mode. Don't steal from host app inputs.\n if (e.key === \"Escape\") {\n if (state.selecting) return; // select mode has its own ESC handler\n if (state.panelOpen) {\n closePanel();\n e.preventDefault();\n }\n }\n });\n\n // Ctrl/Cmd + Enter in prompt: send\n $promptInput.addEventListener(\"keydown\", (e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === \"Enter\") {\n e.preventDefault();\n sendPrompt();\n }\n });\n}\n\nfunction resolveFilePath(rel: string): string {\n return state.roots.length > 0 ? state.roots[0] + \"/\" + rel : rel;\n}\n\n// ── 4-Layer Diff Matching (Aider-style) ──────────────────────────\n// Layer 1: Exact trimmed-line match (current behavior)\n// Layer 2: Indentation-adjusted match (handles LLM indentation errors)\n// Layer 3: Similarity-based fuzzy match (0.8 threshold)\n\nfunction fuzzyLineMatch(content: string, search: string): { start: number; end: number; replace?: string } | null {\n const searchLines = search.split('\\n');\n const nonEmptySearch = searchLines.map(l => l.trim()).filter(l => l.length > 0);\n if (nonEmptySearch.length === 0) return null;\n const contentLines = content.split('\\n');\n\n // Layer 1: Trimmed line-by-line exact match\n for (let i = 0; i <= contentLines.length - nonEmptySearch.length; i++) {\n let allMatch = true;\n let matchLen = 0;\n let si = 0;\n for (let ci = i; ci < contentLines.length && si < nonEmptySearch.length; ci++) {\n if (contentLines[ci].trim() === \"\") { matchLen++; continue; } // skip blank lines in content\n if (contentLines[ci].trim() !== nonEmptySearch[si]) { allMatch = false; break; }\n si++; matchLen++;\n }\n if (allMatch && si === nonEmptySearch.length) {\n return lineRangeToOffsets(content, contentLines, i, matchLen);\n }\n }\n\n // Layer 2: Indentation-adjusted match\n // Strip leading whitespace from search lines, find match, compute indent delta\n const strippedSearch = searchLines.map(l => l.trimStart());\n for (let i = 0; i <= contentLines.length - strippedSearch.length; i++) {\n let allMatch = true;\n for (let j = 0; j < strippedSearch.length; j++) {\n if (strippedSearch[j] === \"\") continue; // skip blank search lines\n if (contentLines[i + j].trimStart() !== strippedSearch[j].trimEnd()) {\n allMatch = false; break;\n }\n }\n if (allMatch) {\n return lineRangeToOffsets(content, contentLines, i, strippedSearch.length);\n }\n }\n\n // Layer 3: Similarity-based fuzzy match (sliding window)\n const searchStr = nonEmptySearch.join(\"\\n\").toLowerCase();\n const searchLen = nonEmptySearch.length;\n let bestScore = 0;\n let bestStart = -1;\n let bestLen = 0;\n\n // Try windows of size searchLen ± 20%\n const minWin = Math.max(1, Math.floor(searchLen * 0.8));\n const maxWin = Math.min(contentLines.length, Math.ceil(searchLen * 1.2));\n\n for (let winSize = minWin; winSize <= maxWin; winSize++) {\n for (let i = 0; i <= contentLines.length - winSize; i++) {\n const windowStr = contentLines.slice(i, i + winSize)\n .map(l => l.trim()).filter(l => l).join(\"\\n\").toLowerCase();\n const score = similarity(searchStr, windowStr);\n if (score > bestScore) {\n bestScore = score; bestStart = i; bestLen = winSize;\n }\n }\n }\n\n if (bestScore >= 0.8 && bestStart >= 0) {\n return lineRangeToOffsets(content, contentLines, bestStart, bestLen);\n }\n\n return null;\n}\n\nfunction lineRangeToOffsets(content: string, lines: string[], start: number, count: number): { start: number; end: number } {\n let startOffset = 0;\n for (let k = 0; k < start; k++) startOffset += lines[k].length + 1;\n let endOffset = startOffset;\n for (let k = start; k < start + count; k++) endOffset += lines[k].length + 1;\n if (endOffset > 0 && endOffset <= content.length && content[endOffset - 1] === '\\n') endOffset--;\n return { start: startOffset, end: endOffset };\n}\n\n// Jaccard-ish similarity on character trigrams (fast, good enough for code)\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1;\n if (!a || !b) return 0;\n const trigramsA = new Set<string>();\n const trigramsB = new Set<string>();\n for (let i = 0; i <= a.length - 3; i++) trigramsA.add(a.slice(i, i + 3));\n for (let i = 0; i <= b.length - 3; i++) trigramsB.add(b.slice(i, i + 3));\n if (trigramsA.size === 0 || trigramsB.size === 0) return 0;\n let intersection = 0;\n for (const t of trigramsA) { if (trigramsB.has(t)) intersection++; }\n return intersection / (trigramsA.size + trigramsB.size - intersection);\n}\n\nasync function applyDiff(target: HTMLElement) {\n const file = target.dataset.file;\n const searchB64 = target.dataset.search;\n const replaceB64 = target.dataset.replace;\n if (!file || !searchB64 || !replaceB64) return;\n\n // Instant visual feedback — disable button and show spinner BEFORE any async work\n (target as HTMLButtonElement).disabled = true;\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n target.style.opacity = \"0.5\";\n target.style.pointerEvents = \"none\";\n\n const card = target.closest(\".om-diff-card\") as HTMLElement | null;\n if (card) {\n const actions = card.querySelector(\".om-diff-actions\");\n if (actions) actions.innerHTML = '<span class=\"om-spinner\"></span> Applying...';\n }\n\n // Force browser repaint before starting async work\n await new Promise(r => requestAnimationFrame(r));\n\n let search: string, replace: string;\n try {\n search = decodeBase64Utf8(searchB64);\n replace = decodeBase64Utf8(replaceB64);\n } catch {\n state.messages.push({ role: \"system\", content: `Failed to decode diff data for ${file}` });\n refreshPanelContent();\n return;\n }\n\n const filePath = resolveFilePath(file);\n\n try {\n // Handle create (empty search = write entire file)\n if (!search && replace) {\n const writeResult = await ws.request(\"fs.write\", { path: filePath, content: replace });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) state.messages[parseInt(idx)] = { role: \"system\", content: `Created ${file}` };\n else state.messages.push({ role: \"system\", content: `Created ${file}` });\n }\n refreshPanelContent();\n scrollChatToBottom();\n return;\n }\n\n // Try primary path, then fallbacks if it fails\n let content: string | undefined;\n let resolvedPath = filePath;\n\n // Try reading from multiple paths\n const pathsToTry = [filePath];\n if (file !== filePath) pathsToTry.push(file);\n const basename = file.split(\"/\").pop() || file;\n const root = state.roots[0] || \"\";\n const baseInRoot = root ? `${root}/${basename}` : basename;\n if (baseInRoot !== filePath && baseInRoot !== file) pathsToTry.push(baseInRoot);\n\n for (const tryPath of pathsToTry) {\n const r = await ws.request(\"fs.read\", { path: tryPath }).catch(() => null);\n const c = r?.payload?.content;\n if (c !== undefined && c !== null) {\n content = String(c);\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (!content) {\n state.messages.push({ role: \"system\", content: `Could not read ${file} — tried: ${pathsToTry.join(\", \")}` });\n } else {\n // Try exact match first\n const exactCount = content.split(search).length - 1;\n\n if (exactCount === 1) {\n // Exact match — apply directly\n const writeResult = await ws.request(\"fs.write\", { path: resolvedPath, content: content.replace(search, replace) });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file} - ${writeResult.payload?.error || \"unknown\"}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) {\n state.messages[parseInt(idx)] = { role: \"system\", content: `Applied change to ${file}. Reloading...` };\n } else {\n state.messages.push({ role: \"system\", content: `Applied change to ${file}. Reloading...` });\n }\n }\n } else if (exactCount > 1) {\n state.messages.push({ role: \"system\", content: `Found ${exactCount} exact matches in ${file} — expected 1. Edit not applied.` });\n } else {\n // No exact match — try fuzzy line-based matching\n const fuzzyResult = fuzzyLineMatch(content, search);\n if (fuzzyResult) {\n const newContent = content.slice(0, fuzzyResult.start) + replace + content.slice(fuzzyResult.end);\n const writeResult = await ws.request(\"fs.write\", { path: resolvedPath, content: newContent });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file} - ${writeResult.payload?.error || \"unknown\"}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) {\n state.messages[parseInt(idx)] = { role: \"system\", content: `Applied change to ${file} (fuzzy match). Reloading...` };\n } else {\n state.messages.push({ role: \"system\", content: `Applied change to ${file} (fuzzy match). Reloading...` });\n }\n }\n } else {\n state.messages.push({ role: \"system\", content: `No matching code found in ${file}. The file may have changed since the suggestion.` });\n }\n }\n }\n } catch (e: any) {\n state.messages.push({ role: \"system\", content: `Failed to apply: ${file} — ${e.message}` });\n }\n\n refreshPanelContent();\n scrollChatToBottom();\n\n // Auto-reload page after 1.5s so user sees the change\n // (HMR-based dev servers handle this automatically, but static servers don't)\n // Skip reload during batch apply-all (batchMode flag)\n if (!(applyDiff as any)._batchMode) {\n setTimeout(() => { window.location.reload(); }, 1500);\n }\n}\n\nfunction rejectDiff(target: HTMLElement) {\n // Instant feedback\n (target as HTMLButtonElement).disabled = true;\n target.style.opacity = \"0.5\";\n\n const idx = target.dataset.idx;\n if (idx !== undefined) {\n const i = parseInt(idx);\n try {\n const diff = JSON.parse(decodeBase64Utf8(state.messages[i]?.content.slice(8) || \"\"));\n // Feedback to LLM: include what was rejected so it can adjust on next turn\n const searchPreview = (diff.search || \"\").split(\"\\n\")[0].slice(0, 80);\n const replacePreview = (diff.replace || \"\").split(\"\\n\")[0].slice(0, 80);\n state.messages[i] = { role: \"system\", content: `Rejected change to ${diff.file || \"file\"}: \"${searchPreview}\" → \"${replacePreview}\"` };\n } catch {\n state.messages[i] = { role: \"system\", content: \"Change rejected\" };\n }\n }\n refreshPanelContent();\n scrollChatToBottom();\n}\n\nfunction updateApplyBar(count: number) {\n const bar = shadow.querySelector(\".om-apply-bar\") as HTMLElement;\n if (!bar) return;\n if (count > 0) {\n bar.classList.remove(\"om-hidden\");\n const text = bar.querySelector(\".om-apply-bar-text\");\n if (text) text.textContent = `${count} change${count > 1 ? \"s\" : \"\"} ready`;\n } else {\n bar.classList.add(\"om-hidden\");\n }\n}\n\nfunction hideApplyBar() {\n const bar = shadow.querySelector(\".om-apply-bar\") as HTMLElement;\n if (bar) bar.classList.add(\"om-hidden\");\n}\n\nasync function undoDiff(target: HTMLElement) {\n const file = target.dataset.file;\n if (!file) return;\n const filePath = resolveFilePath(file);\n try {\n const result = await ws.request(\"fs.undo\", { path: filePath });\n if (result?.payload?.ok) {\n state.messages.push({ role: \"system\", content: `Reverted change to ${file}` });\n } else {\n state.messages.push({ role: \"system\", content: `No backup found for ${file}` });\n }\n } catch {\n state.messages.push({ role: \"system\", content: `Could not revert ${file} — backup may not exist` });\n }\n refreshPanelContent();\n}\n\nasync function handleAction(action: string, target: HTMLElement) {\n switch (action) {\n case \"select\": toggleSelectMode(); break;\n case \"screenshot\": takeScreenshot(); break;\n case \"chat\": togglePanel(\"chat\"); break;\n case \"settings\": togglePanel(\"settings\"); break;\n case \"close-panel\": closePanel(); break;\n case \"prompt-send\": sendPrompt(); break;\n case \"save-settings\": saveSettings(); break;\n case \"get-key\": {\n const url = target.dataset.url;\n if (url) window.open(url, \"_blank\", \"noopener\");\n break;\n }\n case \"change-key\": {\n // Show the hidden key input field\n const changeRow = shadow.querySelector(\"[data-key-change]\");\n if (changeRow) changeRow.classList.remove(\"om-hidden\");\n target.style.display = \"none\";\n break;\n }\n case \"network\": togglePanel(\"chat\"); captureNetworkProfile(); break;\n case \"attach-image\": triggerFileAttach(); break;\n case \"remove-attachment\": {\n const idx = parseInt(target.dataset.idx || \"0\", 10);\n state.attachments.splice(idx, 1);\n renderAttachments();\n break;\n }\n case \"apply-diff\": applyDiff(target); break;\n case \"reject-diff\": rejectDiff(target); break;\n case \"apply-all\": {\n const buttons = Array.from(shadow.querySelectorAll(`[data-action=\"apply-diff\"]`));\n if (buttons.length === 0) break;\n // Snapshot files before batch for rollback\n const filesToSnapshot = new Set<string>();\n for (const btn of buttons) {\n const file = (btn as HTMLElement).dataset.file;\n if (file) filesToSnapshot.add(resolveFilePath(file));\n }\n const snapshots = new Map<string, string>();\n for (const fp of filesToSnapshot) {\n try {\n const r = await ws.request(\"fs.read\", { path: fp }).catch(() => null);\n if (r?.payload?.content) snapshots.set(fp, String(r.payload.content));\n } catch {}\n }\n // Apply diffs sequentially, suppress per-diff reload\n (applyDiff as any)._batchMode = true;\n let failed = false;\n for (const btn of buttons) {\n try {\n await applyDiff(btn as HTMLElement);\n } catch {\n failed = true;\n break;\n }\n }\n (applyDiff as any)._batchMode = false;\n // If any failed, rollback all\n if (failed && snapshots.size > 0) {\n for (const [fp, content] of snapshots) {\n try { await ws.request(\"fs.write\", { path: fp, content }); } catch {}\n }\n state.messages.push({ role: \"system\", content: \"Batch apply failed — all changes reverted.\" });\n refreshPanelContent();\n }\n hideApplyBar();\n // Single reload after batch completes (not per-diff)\n if (!failed) setTimeout(() => { window.location.reload(); }, 1500);\n break;\n }\n case \"reject-all\": {\n const buttons = shadow.querySelectorAll(`[data-action=\"reject-diff\"]`);\n for (const btn of Array.from(buttons)) {\n rejectDiff(btn as HTMLElement);\n }\n hideApplyBar();\n break;\n }\n case \"undo-diff\": undoDiff(target); break;\n case \"clear-chat\": {\n state.messages = [];\n try { sessionStorage.removeItem(\"__om_state__\"); } catch {}\n refreshPanelContent();\n break;\n }\n case \"copy-msg\": {\n const idx = parseInt(target.dataset.idx || \"0\", 10);\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n collectDebugInfo(idx).then(debugText => {\n try { navigator.clipboard.writeText(debugText); } catch {}\n target.innerHTML = ICON.check;\n setTimeout(() => { target.innerHTML = ICON.copy; }, 1500);\n });\n break;\n }\n case \"report-issue\": {\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n collectDebugInfo().then(debugInfo => {\n try { navigator.clipboard.writeText(debugInfo); } catch {}\n target.innerHTML = ICON.bug;\n window.open(\"https://github.com/Kalmuraee/OpenMagic/issues/new?template=bug_report.yml\", \"_blank\", \"noopener\");\n state.messages.push({ role: \"system\", content: \"Debug info copied to clipboard. Paste it in the Debug Info field on GitHub.\" });\n if (state.panelOpen) refreshPanelContent();\n });\n break;\n }\n case \"clear-element\": state.selectedElement = null; updatePromptContext(); break;\n case \"clear-screenshot\": state.screenshot = null; updatePromptContext(); break;\n case \"minimize\": {\n state.minimized = !state.minimized;\n const panel = shadow.querySelector(\".om-panel\") as HTMLElement;\n const promptRow = shadow.querySelector(\".om-prompt-row\") as HTMLElement;\n const promptAttach = shadow.querySelector(\".om-prompt-attachments\") as HTMLElement;\n const headerBtns = $toolbar.querySelectorAll(\".om-pill-btn:not([data-action='minimize']), .om-pill-divider, .om-status-dot\");\n\n if (state.minimized) {\n if (panel) panel.classList.add(\"om-hidden\");\n if (promptRow) promptRow.classList.add(\"om-hidden\");\n if (promptAttach) promptAttach.classList.add(\"om-hidden\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"none\");\n } else {\n if (promptRow) promptRow.classList.remove(\"om-hidden\");\n if (promptAttach) promptAttach.classList.remove(\"om-hidden\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"\");\n if (state.panelOpen && state.activePanel) {\n if (panel) panel.classList.remove(\"om-hidden\");\n }\n }\n break;\n }\n }\n}\n\n// ── Targeted UI Updates (no full DOM rebuild) ────────────────────\n\nfunction updateStatusDot() {\n const dot = shadow.querySelector(\".om-status-dot\");\n if (dot) {\n const cls = state.updateAvailable ? \"outdated\" : state.connected ? \"connected\" : \"disconnected\";\n dot.className = `om-status-dot ${cls}`;\n dot.setAttribute(\"title\", state.updateAvailable ? `v${state.latestVersion} available — run npx openmagic@latest` : state.connected ? \"Connected\" : \"Disconnected\");\n }\n}\n\nfunction updatePillButtons() {\n shadow.querySelectorAll(\".om-pill-btn\").forEach((btn) => {\n const action = (btn as HTMLElement).dataset.action;\n btn.classList.toggle(\"active\", action === state.activePanel || (action === \"select\" && state.selecting));\n });\n}\n\nfunction updateModelSwitcher() {\n const sel = shadow.querySelector(\".om-model-switcher\") as HTMLSelectElement | null;\n if (!sel) return;\n const prov = MODEL_REGISTRY[state.provider];\n if (!prov) { sel.innerHTML = \"\"; return; }\n const opts = prov.models.map(m =>\n `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`\n ).join(\"\");\n sel.innerHTML = opts;\n}\n\nfunction updatePromptContext() {\n const chips: string[] = [];\n if (state.selectedElement) {\n chips.push(`<span class=\"om-prompt-chip\">${state.selectedElement.tagName}${state.selectedElement.id ? \"#\" + state.selectedElement.id : \"\"} <button class=\"om-prompt-chip-x\" data-action=\"clear-element\">${ICON.x}</button></span>`);\n }\n if (state.screenshot) {\n chips.push(`<span class=\"om-prompt-chip\">Screenshot <button class=\"om-prompt-chip-x\" data-action=\"clear-screenshot\">${ICON.x}</button></span>`);\n }\n if (state.attachments.length) {\n chips.push(`<span class=\"om-prompt-chip\">${state.attachments.length} image${state.attachments.length > 1 ? \"s\" : \"\"}</span>`);\n }\n if (state.groundedFiles.length) {\n chips.push(`<span class=\"om-prompt-chip\">${state.groundedFiles.length} files grounded</span>`);\n }\n // Estimate tokens from context (rough: ~4 chars per token)\n const contextChars = (state.selectedElement?.outerHTML?.length || 0)\n + (state.screenshot ? 1000 : 0)\n + state.groundedFiles.length * 4000; // average file size\n if (contextChars > 2000) {\n const estTokens = Math.round(contextChars / 4);\n const label = estTokens > 10000 ? `~${Math.round(estTokens / 1000)}K tokens` : `~${estTokens} tokens`;\n chips.push(`<span class=\"om-prompt-chip om-prompt-chip-tokens\">${label}</span>`);\n }\n $promptCtx.innerHTML = chips.join(\"\");\n}\n\n// ── Panel Management ─────────────────────────────────────────────\n\nfunction openPanel(panel: \"chat\" | \"settings\") {\n state.panelOpen = true;\n state.activePanel = panel;\n $panel.classList.remove(\"om-hidden\");\n const title = shadow.querySelector(\".om-panel-title\");\n if (title) title.textContent = panel === \"settings\" ? \"Settings\" : \"Chat\";\n refreshPanelContent();\n updatePillButtons();\n}\n\nfunction closePanel() {\n state.panelOpen = false;\n state.activePanel = \"\";\n $panel.classList.add(\"om-hidden\");\n updatePillButtons();\n}\n\nfunction togglePanel(panel: \"chat\" | \"settings\") {\n if (state.panelOpen && state.activePanel === panel) {\n closePanel();\n } else {\n openPanel(panel);\n }\n}\n\nfunction refreshPanelContent() {\n if (state.activePanel === \"settings\") {\n $panelBody.innerHTML = renderSettingsHTML();\n } else if (state.activePanel === \"chat\") {\n $panelBody.innerHTML = renderChatHTML();\n scrollChatToBottom();\n }\n saveState();\n}\n\n// ── Settings Renderer ────────────────────────────────────────────\n\nfunction renderSettingsHTML(): string {\n const providerOpts = Object.entries(MODEL_REGISTRY)\n .map(([k, p]) => {\n // For CLI providers, show detailed detection status\n const cliInfo = state.detectedClis.find((c) => c.id === k);\n let indicator = \"\";\n if (cliInfo) {\n if (cliInfo.installed && cliInfo.authenticated) indicator = \" \\u2713 ready\";\n else if (cliInfo.installed) indicator = \" (not logged in)\";\n else indicator = \" (not installed)\";\n } else {\n const configured = state.configuredProviders[k] || p.local;\n indicator = configured ? \" \\u2713\" : \"\";\n }\n return `<option value=\"${k}\" ${state.provider === k ? \"selected\" : \"\"}>${p.name}${indicator}</option>`;\n }).join(\"\");\n\n const prov = MODEL_REGISTRY[state.provider];\n const modelOpts = prov\n ? prov.models.map(m => `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`).join(\"\")\n : '<option value=\"\">Select provider first</option>';\n\n const isLocal = prov?.local || false;\n const keyUrl = prov?.keyUrl || \"\";\n const keyPh = prov?.keyPlaceholder || \"Enter API key...\";\n const providerHasKey = state.configuredProviders[state.provider] || false;\n\n const updateBanner = state.updateAvailable\n ? `<div class=\"om-update-banner\">v${state.latestVersion} available <code class=\"om-update-cmd\">npx openmagic@latest</code></div>` : \"\";\n\n // Show connected status if current provider has a key\n const statusHtml = (providerHasKey || isLocal)\n ? `<div class=\"om-status om-status-success\">${ICON.check} ${prov?.name || \"Provider\"} connected</div>` : \"\";\n\n const saveBtnText = state.saveStatus === \"saving\" ? '<span class=\"om-spinner\"></span> Saving...'\n : state.saveStatus === \"saved\" ? `${ICON.check} Saved` : \"Save\";\n const saveBtnClass = state.saveStatus === \"saving\" ? \"om-btn om-btn-saving\"\n : state.saveStatus === \"saved\" ? \"om-btn om-btn-saved\" : \"om-btn\";\n const saveBtnDisabled = state.saveStatus === \"saving\" ? \"disabled\" : \"\";\n\n // API key section: show \"configured\" state if key exists, with option to change\n let keySection = \"\";\n if (!isLocal && state.provider) {\n if (providerHasKey) {\n keySection = `\n <div class=\"om-field\">\n <label class=\"om-label\">API Key</label>\n <div class=\"om-key-configured\">\n ${ICON.check} <span>Key configured</span>\n <button class=\"om-btn-change-key\" data-action=\"change-key\">Change</button>\n </div>\n <div class=\"om-key-change-row om-hidden\" data-key-change>\n <div class=\"om-key-row\">\n <input type=\"text\" class=\"om-input om-key-input\" data-field=\"apiKey\" placeholder=\"${keyPh}\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" data-lpignore=\"true\" data-1p-ignore=\"true\" data-form-type=\"other\" />\n ${keyUrl ? `<button class=\"om-btn-get-key\" data-action=\"get-key\" data-url=\"${keyUrl}\">${ICON.externalLink} Get key</button>` : \"\"}\n </div>\n </div>\n </div>`;\n } else {\n keySection = `\n <div class=\"om-field\">\n <label class=\"om-label\">API Key</label>\n <div class=\"om-key-row\">\n <input type=\"text\" class=\"om-input om-key-input\" data-field=\"apiKey\" placeholder=\"${keyPh}\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" data-lpignore=\"true\" data-1p-ignore=\"true\" data-form-type=\"other\" />\n ${keyUrl ? `<button class=\"om-btn-get-key\" data-action=\"get-key\" data-url=\"${keyUrl}\">${ICON.externalLink} Get key</button>` : \"\"}\n </div>\n ${keyUrl ? `<div class=\"om-key-hint\"><a data-action=\"get-key\" data-url=\"${keyUrl}\">Get your ${prov?.name || \"\"} API key here</a></div>` : \"\"}\n </div>`;\n }\n }\n\n return `\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\"><option value=\"\">Select Provider...</option>${providerOpts}</select>\n </div>\n <div class=\"om-field\">\n <label class=\"om-label\">Model</label>\n <select class=\"om-select\" data-field=\"model\"><option value=\"\">Select Model...</option>${modelOpts}</select>\n </div>\n ${keySection}\n <button class=\"${saveBtnClass}\" data-action=\"save-settings\" ${saveBtnDisabled}>${saveBtnText}</button>\n ${statusHtml}\n </div>`;\n}\n\n// ── Chat Renderer ────────────────────────────────────────────────\n\nfunction renderChatHTML(): string {\n if (!state.provider || (!state.hasApiKey && !MODEL_REGISTRY[state.provider]?.local)) {\n return `<div class=\"om-status om-status-error\">Configure your provider in Settings first</div>`;\n }\n\n const msgs = state.messages.map((m, i) => {\n // Skip legacy diff group messages\n if (m.content.startsWith(\"__DIFFGROUP__\")) return \"\";\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n const isCreate = diff.type === \"create\" || (!diff.search && diff.replace);\n const searchB64 = encodeBase64Utf8(diff.search || \"\");\n const replaceB64 = encodeBase64Utf8(diff.replace || \"\");\n const label = isCreate ? \"Create new file\" : \"Edit\";\n const diffHtml = renderLineDiff(diff.search || \"\", diff.replace || \"\");\n return `<div class=\"om-diff-card\" data-diff-idx=\"${i}\">\n <div class=\"om-diff-file\">${escapeHtml(label)}: ${escapeHtml(diff.file)}</div>\n <div class=\"om-diff-lines\">${diffHtml}</div>\n <div class=\"om-diff-actions\">\n <button class=\"om-btn om-btn-sm\" data-action=\"apply-diff\" data-file=\"${escapeHtml(diff.file)}\" data-search=\"${searchB64}\" data-replace=\"${replaceB64}\">Apply</button>\n <button class=\"om-btn-secondary om-btn-sm\" data-action=\"reject-diff\" data-idx=\"${i}\">Reject</button>\n </div>\n </div>`;\n } catch {\n return `<div class=\"om-msg om-msg-system\">Malformed diff data</div>`;\n }\n }\n if (m.content.startsWith(\"Applied change to \")) {\n const file = m.content.replace(\"Applied change to \", \"\").replace(/ \\(fuzzy match.*?\\)/g, \"\").replace(\". Reloading...\", \"\");\n return `<div class=\"om-msg om-msg-system\">${escapeHtml(m.content)} <button class=\"om-undo-btn\" data-action=\"undo-diff\" data-file=\"${escapeHtml(file)}\">Undo</button></div>`;\n }\n // Regular messages with copy button\n const copyBtn = (m.role === \"user\" || m.role === \"assistant\")\n ? `<button class=\"om-copy-btn\" data-action=\"copy-msg\" data-idx=\"${i}\" title=\"Copy\">${ICON.copy}</button>`\n : \"\";\n if (m.role === \"assistant\") {\n return `<div class=\"om-msg om-msg-assistant\" dir=\"auto\">${renderMarkdown(m.content)}${copyBtn}</div>`;\n }\n return `<div class=\"om-msg om-msg-${m.role}\" dir=\"auto\">${escapeHtml(m.content)}${copyBtn}</div>`;\n }).join(\"\");\n\n const streamHtml = state.streaming\n ? `<div class=\"om-msg om-msg-assistant\"><span class=\"om-spinner\"></span> Generating response...</div>` : \"\";\n\n const empty = !state.messages.length && !state.streaming\n ? `<div class=\"om-chat-empty\">Select an element or type below to start</div>` : \"\";\n\n return `<div class=\"om-chat-messages\">${empty}${msgs}${streamHtml}</div>`;\n}\n\nfunction scrollChatToBottom() {\n requestAnimationFrame(() => {\n const el = $panelBody.querySelector(\".om-chat-messages\");\n if (el) el.scrollTop = el.scrollHeight;\n });\n}\n\n// ── Save Settings ────────────────────────────────────────────────\n\nasync function saveSettings() {\n const apiKeyInput = $panelBody.querySelector('[data-field=\"apiKey\"]') as HTMLInputElement;\n const apiKey = apiKeyInput?.value || \"\";\n\n if (!state.provider) {\n state.saveStatus = \"error\";\n updateSaveButton();\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 2000);\n return;\n }\n\n // Check WebSocket connection\n if (!ws.isConnected()) {\n state.saveStatus = \"error\";\n updateSaveButton();\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n if (btn) btn.innerHTML = \"Not connected - check terminal\";\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 3000);\n return;\n }\n\n const payload: any = { provider: state.provider, model: state.model };\n if (apiKey) payload.apiKey = apiKey;\n\n state.saveStatus = \"saving\";\n updateSaveButton();\n\n try {\n // Race against a 8s local timeout (don't wait 30s)\n const result = await Promise.race([\n ws.request(\"config.set\", payload),\n new Promise((_, reject) => setTimeout(() => reject(new Error(\"Save timed out\")), 8000)),\n ]);\n // Mark this provider as configured\n if (apiKey && state.provider) {\n state.configuredProviders[state.provider] = true;\n }\n state.hasApiKey = !!(apiKey || state.configuredProviders[state.provider]);\n state.saveStatus = \"saved\";\n updateSaveButton();\n\n // Auto-transition to chat after 1.2s\n updateModelSwitcher();\n setTimeout(() => {\n state.saveStatus = \"\";\n if (state.activePanel === \"settings\") {\n openPanel(\"chat\");\n }\n }, 1200);\n } catch (e: any) {\n state.saveStatus = \"error\";\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n const msg = (e?.message || \"\").includes(\"timeout\") ? \"Connection timeout - is the CLI running?\"\n : (e?.message || \"\").includes(\"connected\") ? \"Not connected to OpenMagic server\"\n : `Save failed: ${e?.message || \"Unknown error\"}`;\n if (btn) {\n btn.innerHTML = msg;\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n }\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 4000);\n }\n}\n\nfunction updateSaveButton() {\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n if (!btn) return;\n if (state.saveStatus === \"saving\") {\n btn.innerHTML = '<span class=\"om-spinner\"></span> Saving...';\n btn.className = \"om-btn om-btn-saving\";\n (btn as HTMLButtonElement).disabled = true;\n } else if (state.saveStatus === \"saved\") {\n btn.innerHTML = `${ICON.check} Saved`;\n btn.className = \"om-btn om-btn-saved\";\n (btn as HTMLButtonElement).disabled = false;\n } else if (state.saveStatus === \"error\") {\n btn.innerHTML = \"Save failed - try again\";\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n } else {\n btn.innerHTML = \"Save\";\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n }\n}\n\n// ── Send Prompt ──────────────────────────────────────────────────\n\nasync function sendPrompt() {\n const text = $promptInput.value.trim();\n if (!text || state.streaming) return;\n\n if (!state.provider || (!state.hasApiKey && !MODEL_REGISTRY[state.provider]?.local)) {\n openPanel(\"settings\");\n return;\n }\n\n // Add user message\n state.messages.push({ role: \"user\", content: text });\n state.streaming = true;\n state.streamContent = \"\";\n $promptInput.value = \"\";\n\n // Open chat panel\n openPanel(\"chat\");\n\n // Build context — includes page info, selected element, screenshot, network/console logs\n const context: any = buildContext(state.selectedElement, state.screenshot);\n context.pageUrl = window.location.href;\n context.pageTitle = document.title;\n\n // Include image attachments (for vision-capable models)\n if (state.attachments.length > 0) {\n // Use the first attachment as the screenshot if none is captured\n if (!context.screenshot) {\n context.screenshot = state.attachments[0];\n }\n // Store all attachments for multi-image models\n context.attachments = [...state.attachments];\n }\n\n // Grounding: read project tree + score and read relevant source files\n const MAX_GROUNDED_FILES = 8;\n const MAX_GROUNDED_CHARS = 48000;\n const TEXT_RE = /\\.(?:[cm]?[jt]sx?|svelte|vue|astro|html?|css|scss|less|php|py)$/i;\n\n // Show grounding status\n const statusEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (statusEl) statusEl.innerHTML = '<span class=\"om-spinner\"></span> Reading project files...';\n\n try {\n const treeResult = await ws.request(\"fs.list\", {});\n if (treeResult?.payload?.projectTree) {\n context.projectTree = treeResult.payload.projectTree;\n }\n\n const allFiles = (treeResult?.payload?.files || []) as Array<{ path: string; type: string }>;\n const textFiles = allFiles.filter((f: { path: string; type: string }) => f.type === \"file\" && TEXT_RE.test(f.path));\n\n // Build search tokens from multiple sources\n const tokenSources: string[] = [text];\n\n // Add element metadata\n if (state.selectedElement) {\n if (state.selectedElement.id) tokenSources.push(state.selectedElement.id);\n if (state.selectedElement.className) tokenSources.push(state.selectedElement.className);\n if (state.selectedElement.textContent) tokenSources.push(state.selectedElement.textContent.slice(0, 100));\n if ((state.selectedElement as any).componentHint) tokenSources.push((state.selectedElement as any).componentHint);\n // Add ancestry class/component names\n if ((state.selectedElement as any).ancestry) {\n for (const a of (state.selectedElement as any).ancestry) {\n tokenSources.push(a);\n }\n }\n }\n\n const searchTokens = tokenSources\n .filter(Boolean).join(\" \").toLowerCase()\n .split(/[^a-z0-9_-]+/)\n .filter((t: string) => t.length >= 2 && ![\"the\", \"to\", \"in\", \"of\", \"and\", \"div\", \"span\", \"class\", \"style\"].includes(t));\n\n // Extract URL route segments (highest signal for finding the right page component)\n const pathname = window.location.pathname;\n const routeTokens = pathname.split(\"/\").filter((s: string) => s.length > 1 && !/^\\d+$/.test(s));\n\n // Monorepo detection: find which top-level directory likely contains the running app\n // by checking which subdir has files matching the component hint or route tokens\n let activeSubdir = \"\";\n if ((state.selectedElement as any)?.componentHint || routeTokens.length) {\n const hint = ((state.selectedElement as any)?.componentHint || \"\").toLowerCase();\n const subdirScores = new Map<string, number>();\n for (const tf of textFiles) {\n const topDir = tf.path.split(\"/\")[0];\n if (!topDir || topDir.includes(\".\")) continue;\n const l = tf.path.toLowerCase();\n let s = subdirScores.get(topDir) || 0;\n if (hint && l.includes(hint)) s += 10;\n for (const rt of routeTokens) { if (l.includes(rt.toLowerCase())) s += 5; }\n if (/(component|page|route|layout)/.test(l)) s += 1;\n subdirScores.set(topDir, s);\n }\n let best = 0;\n for (const [dir, s] of subdirScores) {\n if (s > best) { best = s; activeSubdir = dir; }\n }\n }\n\n const scored = textFiles.map((f: { path: string; type: string }) => {\n let score = 0;\n const lower = f.path.toLowerCase();\n // Strip Next.js route groups like (dashboard) from path for scoring\n const lowerNoGroups = lower.replace(/\\([^)]+\\)\\//g, \"\");\n\n // Monorepo: strongly boost files in the active sub-project, penalize others\n if (activeSubdir) {\n const topDir = f.path.split(\"/\")[0];\n if (topDir === activeSubdir) score += 20;\n else if (topDir !== activeSubdir && !f.path.includes(\"/\")) score += 0; // root files neutral\n else score -= 15; // files from other sub-projects\n }\n\n // Route match: files matching URL path get highest priority (+15)\n for (const rt of routeTokens) {\n if (lowerNoGroups.includes(rt.toLowerCase())) score += 15;\n }\n\n // Component hint match (+12)\n if ((state.selectedElement as any)?.componentHint) {\n const hint = (state.selectedElement as any).componentHint.toLowerCase();\n if (lower.includes(hint)) score += 12;\n }\n\n // Token match from prompt/element (+5)\n for (const token of searchTokens) {\n if (lower.includes(token)) score += 5;\n }\n\n // Framework patterns (+3)\n if (/(component|page|route|layout|template|view)/.test(lower)) score += 3;\n // Page/route files for current route get extra (+5)\n if (/page\\.[jt]sx?$|layout\\.[jt]sx?$|\\+page\\.svelte$/.test(lower)) score += 5;\n\n return { ...f, score };\n }).sort((a: { score: number }, b: { score: number }) => b.score - a.score);\n\n // Read top scored files + their co-located stylesheets\n const files: Array<{ path: string; content: string }> = [];\n const readPaths = new Set<string>();\n let totalChars = 0;\n\n // Parallel read of top scored files for faster grounding\n const topScored = scored.slice(0, MAX_GROUNDED_FILES).filter((f: any) => f.score > 0);\n const root = state.roots[0] || \"\";\n const readResults = await Promise.all(\n topScored.map((f: any) => {\n const fullPath = root ? `${root}/${f.path}` : f.path;\n return ws.request(\"fs.read\", { path: fullPath }).catch(() => null);\n })\n );\n\n for (let fi = 0; fi < topScored.length; fi++) {\n const f = topScored[fi];\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n try {\n const content = String(readResults[fi]?.payload?.content || \"\");\n if (!content) continue;\n const maxChars = Math.min(12000, MAX_GROUNDED_CHARS - totalChars);\n let trimmed = content.slice(0, maxChars);\n if (content.length > maxChars) {\n trimmed += `\\n// [FILE TRUNCATED — showing ${maxChars} of ${content.length} chars]`;\n }\n files.push({ path: f.path, content: trimmed });\n readPaths.add(f.path);\n totalChars += trimmed.length;\n\n // Auto-read co-located stylesheet (Component.module.css, Component.scss, etc.)\n const baseName = f.path.replace(/\\.[^.]+$/, \"\");\n const styleExts = [\".module.css\", \".module.scss\", \".css\", \".scss\", \".styles.ts\"];\n for (const ext of styleExts) {\n const stylePath = baseName + ext;\n if (readPaths.has(stylePath) || totalChars >= MAX_GROUNDED_CHARS) continue;\n const match = textFiles.find((tf: { path: string }) => tf.path === stylePath);\n if (match) {\n try {\n const sr = await ws.request(\"fs.read\", { path: root ? `${root}/${stylePath}` : stylePath });\n const sc = String(sr?.payload?.content || \"\");\n if (sc) {\n const stMax = Math.min(4000, MAX_GROUNDED_CHARS - totalChars);\n let st = sc.slice(0, stMax);\n if (sc.length > stMax) {\n st += `\\n// [FILE TRUNCATED — showing ${stMax} of ${sc.length} chars]`;\n }\n files.push({ path: stylePath, content: st });\n readPaths.add(stylePath);\n totalChars += st.length;\n }\n } catch {}\n break; // Only read the first matching style file\n }\n }\n // Auto-read layout files up the directory tree (for the first scored file only)\n if (files.length <= 2 && totalChars < MAX_GROUNDED_CHARS) {\n const LAYOUT_NAMES = [\"layout.tsx\", \"layout.jsx\", \"layout.js\", \"layout.ts\"];\n let layoutDir = f.path.replace(/\\/[^/]+$/, \"\");\n let layoutDepth = 0;\n while (layoutDir && layoutDepth < 4 && totalChars < MAX_GROUNDED_CHARS) {\n let foundLayout = false;\n for (const layoutName of LAYOUT_NAMES) {\n const layoutPath = `${layoutDir}/${layoutName}`;\n if (readPaths.has(layoutPath)) { foundLayout = true; break; }\n try {\n const lr = await ws.request(\"fs.read\", { path: root ? `${root}/${layoutPath}` : layoutPath }).catch(() => null);\n const lc = String(lr?.payload?.content || \"\");\n if (lc) {\n const lMax = Math.min(4000, MAX_GROUNDED_CHARS - totalChars);\n let lt = lc.slice(0, lMax);\n if (lc.length > lMax) lt += `\\n// [TRUNCATED]`;\n files.push({ path: layoutPath, content: lt });\n readPaths.add(layoutPath);\n totalChars += lt.length;\n foundLayout = true;\n break;\n }\n } catch {}\n }\n const parentDir = layoutDir.replace(/\\/[^/]+$/, \"\");\n if (parentDir === layoutDir || !parentDir) break;\n layoutDir = parentDir;\n layoutDepth++;\n }\n }\n\n // Follow imports: extract local imports and alias imports\n // Parse tsconfig paths for alias resolution (e.g., @/ → src/)\n let pathAliases: Record<string, string> = {};\n const tsconfigFile = files.find((fl: {path: string}) => fl.path === \"tsconfig.json\" || fl.path === \"tsconfig.app.json\");\n if (tsconfigFile) {\n try {\n const tsconfig = JSON.parse(tsconfigFile.content.replace(/\\/\\/.*$/gm, \"\").replace(/,\\s*([}\\]])/g, \"$1\"));\n const paths = tsconfig?.compilerOptions?.paths || {};\n const baseUrl = tsconfig?.compilerOptions?.baseUrl || \".\";\n for (const [alias, targets] of Object.entries(paths)) {\n const target = (targets as string[])?.[0];\n if (alias && target) {\n // Convert @/* → src/* style aliases\n const aliasPrefix = alias.replace(/\\/\\*$/, \"/\");\n const targetPrefix = target.replace(/\\/\\*$/, \"/\");\n const resolvedTarget = baseUrl === \".\" ? targetPrefix : `${baseUrl}/${targetPrefix}`;\n pathAliases[aliasPrefix] = resolvedTarget;\n }\n }\n } catch {}\n }\n\n // Follow relative imports\n const importMatches = content.matchAll(/(?:import|from)\\s+['\"]\\.?\\.\\/([\\w/.-]+)['\"]/g);\n for (const im of importMatches) {\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n const importPath = im[1];\n // Find matching file in the project (try with common extensions)\n const dir = f.path.replace(/\\/[^/]+$/, \"\");\n const candidates = [\n `${dir}/${importPath}`,\n `${dir}/${importPath}.tsx`,\n `${dir}/${importPath}.ts`,\n `${dir}/${importPath}.jsx`,\n `${dir}/${importPath}.js`,\n `${dir}/${importPath}/index.tsx`,\n `${dir}/${importPath}/index.ts`,\n ];\n for (const candidate of candidates) {\n if (readPaths.has(candidate)) break;\n const found = textFiles.find((tf: { path: string }) => tf.path === candidate);\n if (found) {\n try {\n const ir = await ws.request(\"fs.read\", { path: root ? `${root}/${candidate}` : candidate });\n const ic = String(ir?.payload?.content || \"\");\n if (ic) {\n const imMax = Math.min(8000, MAX_GROUNDED_CHARS - totalChars);\n let it = ic.slice(0, imMax);\n if (ic.length > imMax) it += `\\n// [FILE TRUNCATED — showing ${imMax} of ${ic.length} chars]`;\n files.push({ path: candidate, content: it });\n readPaths.add(candidate);\n totalChars += it.length;\n }\n } catch {}\n break;\n }\n }\n }\n\n // Follow alias imports (e.g., @/components/Button → src/components/Button)\n if (Object.keys(pathAliases).length > 0) {\n const aliasImports = content.matchAll(/(?:import|from)\\s+['\"]([^.'\"]\\S+)['\"]/g);\n for (const aim of aliasImports) {\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n const rawImport = aim[1];\n for (const [aliasPrefix, targetPrefix] of Object.entries(pathAliases)) {\n if (!rawImport.startsWith(aliasPrefix)) continue;\n const resolved = rawImport.replace(aliasPrefix, targetPrefix);\n const aliasCandidates = [\n resolved, `${resolved}.tsx`, `${resolved}.ts`, `${resolved}.jsx`, `${resolved}.js`,\n `${resolved}/index.tsx`, `${resolved}/index.ts`,\n ];\n for (const ac of aliasCandidates) {\n if (readPaths.has(ac)) break;\n const found = textFiles.find((tf: { path: string }) => tf.path === ac);\n if (found) {\n try {\n const ar = await ws.request(\"fs.read\", { path: root ? `${root}/${ac}` : ac });\n const acContent = String(ar?.payload?.content || \"\");\n if (acContent) {\n const aMax = Math.min(8000, MAX_GROUNDED_CHARS - totalChars);\n let at = acContent.slice(0, aMax);\n if (acContent.length > aMax) at += `\\n// [TRUNCATED]`;\n files.push({ path: ac, content: at });\n readPaths.add(ac);\n totalChars += at.length;\n }\n } catch {}\n break;\n }\n }\n break;\n }\n }\n }\n } catch { /* skip unreadable files */ }\n }\n\n // Also read package.json for dependency/framework awareness\n if (totalChars < MAX_GROUNDED_CHARS) {\n try {\n const root = state.roots[0] || \"\";\n const pkgResult = await ws.request(\"fs.read\", { path: root ? `${root}/package.json` : \"package.json\" });\n const pkgContent = String(pkgResult?.payload?.content || \"\");\n if (pkgContent) {\n // Extract just dependencies section (not the full package.json)\n try {\n const pkg = JSON.parse(pkgContent);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n const depsStr = JSON.stringify(deps, null, 2);\n files.push({ path: \"package.json (dependencies)\", content: depsStr.slice(0, 2000) });\n } catch {\n files.push({ path: \"package.json\", content: pkgContent.slice(0, 2000) });\n }\n }\n } catch {}\n }\n\n // Auto-ground config files (tailwind, global styles)\n if (totalChars < MAX_GROUNDED_CHARS) {\n const root = state.roots[0] || \"\";\n const CONFIG_CANDIDATES = [\n \"tailwind.config.ts\", \"tailwind.config.js\", \"tailwind.config.mjs\",\n \"src/app/globals.css\", \"src/styles/globals.css\", \"styles/globals.css\",\n \"app/globals.css\", \"src/index.css\", \"src/global.css\",\n \"tsconfig.json\", \"tsconfig.app.json\",\n \"next.config.js\", \"next.config.mjs\", \"next.config.ts\",\n \"vite.config.ts\", \"vite.config.js\",\n \"astro.config.mjs\", \"astro.config.ts\",\n ];\n for (const candidate of CONFIG_CANDIDATES) {\n if (totalChars >= MAX_GROUNDED_CHARS || readPaths.has(candidate)) continue;\n try {\n const cfgPath = root ? `${root}/${candidate}` : candidate;\n const cfgResult = await ws.request(\"fs.read\", { path: cfgPath }).catch(() => null);\n const cfgContent = String(cfgResult?.payload?.content || \"\");\n if (cfgContent) {\n const cap = Math.min(12000, MAX_GROUNDED_CHARS - totalChars);\n let trimmed = cfgContent.slice(0, cap);\n if (cfgContent.length > cap) trimmed += `\\n/* [TRUNCATED] */`;\n files.push({ path: candidate, content: trimmed });\n readPaths.add(candidate);\n totalChars += trimmed.length;\n }\n } catch {}\n }\n }\n\n if (files.length) {\n context.files = files;\n // Show grounded files in status\n const fileNames = files.map((f: {path: string}) => f.path.split(\"/\").pop()).join(\", \");\n if (statusEl) statusEl.innerHTML = `<span class=\"om-spinner\"></span> Thinking... (${files.length} files: ${fileNames})`;\n }\n state.groundedFiles = files.map((f: {path: string}) => f.path);\n } catch { /* grounding is best-effort */ }\n\n // Auto-retry loop: if LLM says \"NEED_FILE: path\" or \"SEARCH_FILES:\", read and retry\n const MAX_RETRIES = 4;\n let retryCount = 0;\n const retriedFiles = new Set<string>(); // prevent re-reading same file\n\n try {\n while (retryCount <= MAX_RETRIES) {\n state.streamContent = \"\";\n\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 // Don't show raw JSON chunks — just keep the spinner\n // The clean formatted response will appear after streaming completes\n }\n );\n\n const responseContent = state.streamContent || result?.content || \"\";\n\n // Decode JSON wrapper before pattern matching — LLM returns JSON with\n // escaped quotes (e.g. \\\"nav-group\\\") which breaks regex on raw content\n let decodedContent = responseContent;\n try {\n const p = JSON.parse(responseContent);\n if (p.explanation) decodedContent = p.explanation;\n } catch {\n const mdMatch = responseContent.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (mdMatch) {\n try { const p = JSON.parse(mdMatch[1]); if (p.explanation) decodedContent = p.explanation; } catch {}\n }\n }\n\n // If the LLM returned real modifications, apply them immediately — don't chase NEED_FILE\n const hasRealModifications = result?.modifications?.some((m: any) =>\n (m.type === \"edit\" && m.file && m.search && m.replace) ||\n (m.type === \"create\" && m.file && m.content)\n );\n\n // Check if LLM is requesting a file (NEED_FILE pattern)\n // Only retry if there are NO real modifications to apply\n const needFileMatch = !hasRealModifications && (\n decodedContent.match(/NEED_FILE:\\s*\"?([^\\s\"}\\]]+)\"?/)\n || decodedContent.match(/(?:need|provide|show|read|see|contents?\\s+of)\\s+(?:the\\s+)?(?:file\\s+)?[`\"']?([a-zA-Z0-9_/.@-]+\\.[a-z]{1,5})[`\"']?/i)\n || decodedContent.match(/(?:source\\s+(?:file|code)\\s+(?:for|of|at))\\s+[`\"']?([a-zA-Z0-9_/.@-]+\\.[a-z]{1,5})[`\"']?/i)\n || responseContent.match(/NEED_FILE:\\s*\\\\?\"?([^\\s\"\\\\}\\]]+)\"?/)\n );\n if (needFileMatch && retryCount < MAX_RETRIES && !retriedFiles.has(needFileMatch[1].trim())) {\n const neededFile = needFileMatch[1].trim();\n retriedFiles.add(neededFile);\n retryCount++;\n\n // Show transient status (update the spinner, don't add permanent messages)\n const spinnerEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (spinnerEl) spinnerEl.innerHTML = `<span class=\"om-spinner\"></span> Reading ${neededFile}...`;\n\n // Read the requested file — try primary path, then fallbacks\n try {\n const root = state.roots[0] || \"\";\n const primaryPath = root ? `${root}/${neededFile}` : neededFile;\n let fileContent: string | undefined;\n\n // Try multiple paths\n const pathsToTry = [primaryPath];\n if (neededFile !== primaryPath) pathsToTry.push(neededFile);\n const basename = neededFile.split(\"/\").pop() || neededFile;\n const baseInRoot = root ? `${root}/${basename}` : basename;\n if (baseInRoot !== primaryPath && baseInRoot !== neededFile) pathsToTry.push(baseInRoot);\n\n for (const p of pathsToTry) {\n const r = await ws.request(\"fs.read\", { path: p }).catch(() => null);\n if (r?.payload?.content) { fileContent = String(r.payload.content); break; }\n }\n\n if (fileContent) {\n if (!context.files) context.files = [];\n // Replace existing truncated entry if present, otherwise add new\n const existingIdx = context.files.findIndex((f: {path: string}) =>\n f.path === neededFile || f.path.endsWith(\"/\" + neededFile) || neededFile.endsWith(\"/\" + f.path)\n );\n const fullContent = fileContent.slice(0, 16000); // larger cap for explicitly requested files\n if (existingIdx >= 0) {\n context.files[existingIdx] = { path: neededFile, content: fullContent };\n } else {\n context.files.push({ path: neededFile, content: fullContent });\n }\n } else {\n state.messages.push({ role: \"system\", content: `Could not read ${neededFile}` });\n break;\n }\n } catch {\n state.messages.push({ role: \"system\", content: `File not found: ${neededFile}` });\n break;\n }\n continue; // Retry with the new file context\n }\n\n // Check if LLM is requesting a codebase search (SEARCH_FILES pattern)\n // Only retry if there are NO real modifications to apply\n const searchMatch = !hasRealModifications && (\n decodedContent.match(/SEARCH_FILES:\\s*\"([^\"]+)\"(?:\\s+in\\s+(\\S+))?/)\n || responseContent.match(/SEARCH_FILES:\\s*\\\\?\"([^\"\\\\]+)\\\\?\"(?:\\s+in\\s+(\\S+))?/)\n );\n // Prevent infinite loop: skip if we already searched for this pattern\n const alreadySearched = (context as any).searchResults?.some((s: any) => s.query === searchMatch?.[1]);\n if (searchMatch && retryCount < MAX_RETRIES && !alreadySearched) {\n const pattern = searchMatch[1];\n const searchPath = searchMatch[2] || \"\";\n retryCount++;\n\n const spinnerEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (spinnerEl) spinnerEl.innerHTML = `<span class=\"om-spinner\"></span> Searching: \"${pattern}\"...`;\n\n try {\n const grepResult = await Promise.race([\n ws.request(\"fs.grep\", { pattern, path: searchPath }),\n new Promise((_, rej) => setTimeout(() => rej(new Error(\"grep timeout\")), 5000)),\n ]) as any;\n const matches = grepResult?.payload?.results || [];\n if (matches.length) {\n if (!(context as any).searchResults) (context as any).searchResults = [];\n (context as any).searchResults.push({ query: pattern, matches });\n }\n } catch {}\n continue; // Retry with search results added\n }\n\n // Got a real response — strip any NEED_FILE/SEARCH_FILES lines from display\n let displayContent = decodedContent\n .replace(/^NEED_FILE:\\s*\\S+\\s*/gm, \"\")\n .replace(/^SEARCH_FILES:\\s*\"[^\"]*\"(?:\\s+in\\s+\\S+)?\\s*/gm, \"\")\n .trim();\n if (!displayContent) {\n displayContent = \"I couldn't determine the exact change from the available files. Try selecting a more specific element or giving more detail.\";\n }\n state.messages.push({ role: \"assistant\", content: displayContent });\n\n if (result?.modifications?.length) {\n const groupId = Math.random().toString(36).slice(2);\n const validMods = result.modifications.filter((m: any) =>\n (m.type === \"edit\" && m.file && m.search && m.replace) ||\n (m.type === \"create\" && m.file && m.content)\n );\n\n // Show sticky Apply All bar (for any number of diffs)\n updateApplyBar(validMods.length);\n\n for (const mod of result.modifications) {\n if (mod.type === \"edit\" && mod.file && mod.search && mod.replace) {\n const diffId = Math.random().toString(36).slice(2);\n const diffPayload = JSON.stringify({ id: diffId, file: mod.file, search: mod.search, replace: mod.replace, groupId });\n state.messages.push({\n role: \"system\",\n content: `__DIFF__${encodeBase64Utf8(diffPayload)}`,\n });\n } else if (mod.type === \"create\" && mod.file && (mod as any).content) {\n const diffId = Math.random().toString(36).slice(2);\n const diffPayload = JSON.stringify({ id: diffId, file: mod.file, search: \"\", replace: (mod as any).content, type: \"create\", groupId });\n state.messages.push({\n role: \"system\",\n content: `__DIFF__${encodeBase64Utf8(diffPayload)}`,\n });\n } else if (mod.type === \"delete\" && mod.file) {\n state.messages.push({\n role: \"system\",\n content: `LLM proposed deleting ${mod.file} — skipped (use edit with search/replace instead)`,\n });\n }\n }\n }\n break; // Done — no more retries needed\n }\n } catch (e: any) {\n // Stream disconnect recovery: if we have partial content, show it\n if (state.streamContent.trim().length > 20) {\n state.messages.push({ role: \"assistant\", content: state.streamContent.trim() });\n state.messages.push({ role: \"system\", content: `Response interrupted: ${e.message}. Partial response shown above.` });\n } else {\n state.messages.push({ role: \"system\", content: `Error: ${e.message}` });\n }\n }\n\n state.streaming = false;\n state.streamContent = \"\";\n state.attachments = [];\n renderAttachments();\n refreshPanelContent();\n scrollChatToBottom();\n}\n\n// ── Network & Profiling ──────────────────────────────────────────\n\nfunction captureNetworkProfile() {\n // Capture performance timing\n const perf = window.performance;\n const navEntry = perf.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n const paintEntries = perf.getEntriesByType(\"paint\");\n const resources = perf.getEntriesByType(\"resource\").slice(-20) as PerformanceResourceTiming[];\n\n const networkLogs = getNetworkLogs();\n const consoleLogs = getConsoleLogs();\n\n // Build a summary message\n const lines: string[] = [];\n lines.push(\"--- Network & Performance Capture ---\");\n\n if (navEntry) {\n lines.push(`Page load: ${Math.round(navEntry.loadEventEnd - navEntry.startTime)}ms`);\n lines.push(`DOM ready: ${Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime)}ms`);\n lines.push(`TTFB: ${Math.round(navEntry.responseStart - navEntry.startTime)}ms`);\n }\n\n const fcp = paintEntries.find(e => e.name === \"first-contentful-paint\");\n if (fcp) lines.push(`FCP: ${Math.round(fcp.startTime)}ms`);\n\n // ALL network requests from Performance API (includes page-load requests)\n if (resources.length) {\n const apiRequests = resources.filter(r =>\n r.initiatorType === \"fetch\" || r.initiatorType === \"xmlhttprequest\"\n );\n const allRequests = apiRequests.length > 0 ? apiRequests : resources;\n\n lines.push(`\\nAll network requests (${allRequests.length}):`);\n for (const r of allRequests.slice(-30)) {\n const url = r.name.length > 80 ? \"...\" + r.name.slice(-77) : r.name;\n const status = (r as any).responseStatus || \"\";\n lines.push(` ${Math.round(r.duration)}ms ${status ? `[${status}]` : \"\"} ${url}`);\n }\n }\n\n // Also include captured fetch/XHR logs (may have status codes)\n if (networkLogs.length) {\n lines.push(`\\nFetch/XHR requests (${networkLogs.length}):`);\n for (const log of networkLogs.slice(-20)) {\n lines.push(` ${log.method} ${log.url.slice(0, 80)} → ${log.status || \"pending\"} (${log.duration || \"?\"}ms)`);\n }\n }\n\n if (consoleLogs.length) {\n const errors = consoleLogs.filter(l => l.level === \"error\");\n const warns = consoleLogs.filter(l => l.level === \"warn\");\n if (errors.length) lines.push(`\\nConsole errors: ${errors.length}`);\n if (warns.length) lines.push(`Console warnings: ${warns.length}`);\n }\n\n // Slowest resources\n if (resources.length > 5) {\n const slowest = [...resources].sort((a, b) => b.duration - a.duration).slice(0, 5);\n lines.push(`\\nSlowest resources:`);\n for (const r of slowest) {\n lines.push(` ${Math.round(r.duration)}ms — ${r.name.split(\"/\").pop()?.slice(0, 60)}`);\n }\n }\n\n // Add as a system message in the chat\n state.messages.push({ role: \"system\", content: lines.join(\"\\n\") });\n refreshPanelContent();\n scrollChatToBottom();\n updatePromptContext();\n}\n\n// ── File Attachments ─────────────────────────────────────────────\n\nfunction triggerFileAttach() {\n const input = shadow.querySelector(\".om-file-input\") as HTMLInputElement;\n if (input) input.click();\n}\n\nfunction handleFileSelect(files: FileList | null) {\n if (!files) return;\n for (let i = 0; i < files.length && state.attachments.length < 5; i++) {\n const file = files[i];\n if (!file.type.startsWith(\"image/\")) continue;\n if (file.size > 10 * 1024 * 1024) continue; // 10MB max\n const reader = new FileReader();\n reader.onload = () => {\n if (typeof reader.result === \"string\") {\n state.attachments.push(reader.result);\n renderAttachments();\n }\n };\n reader.readAsDataURL(file);\n }\n}\n\nfunction renderAttachments() {\n const container = shadow.querySelector(\".om-prompt-attachments\");\n if (!container) return;\n if (!state.attachments.length) {\n container.innerHTML = \"\";\n container.classList.add(\"om-hidden\");\n return;\n }\n container.classList.remove(\"om-hidden\");\n container.innerHTML = state.attachments.map((a, i) =>\n `<div class=\"om-attachment-thumb\">\n <img src=\"${a}\" alt=\"attachment\" />\n <button class=\"om-attachment-remove\" data-action=\"remove-attachment\" data-idx=\"${i}\">${ICON.x}</button>\n </div>`\n ).join(\"\");\n}\n\n// ── Select Mode ──────────────────────────────────────────────────\n\nlet selectHandler: ((e: MouseEvent) => void) | null = null;\nlet hoverHandler: ((e: MouseEvent) => void) | null = null;\n\nfunction toggleSelectMode() {\n state.selecting ? exitSelectMode() : enterSelectMode();\n}\n\nfunction enterSelectMode() {\n state.selecting = true;\n document.body.style.cursor = \"crosshair\";\n updatePillButtons();\n\n hoverHandler = (e: MouseEvent) => {\n const t = e.target as HTMLElement;\n if (t.closest(\"openmagic-toolbar\") || t.dataset?.openmagic) return;\n const r = t.getBoundingClientRect();\n showHighlight({ x: r.x, y: r.y, width: r.width, height: r.height });\n };\n\n selectHandler = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const t = e.target as HTMLElement;\n if (t.closest(\"openmagic-toolbar\") || t.dataset?.openmagic) return;\n state.selectedElement = inspectElement(t);\n exitSelectMode();\n updatePromptContext();\n $promptInput.focus();\n };\n\n // ESC to cancel\n const escHandler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n exitSelectMode();\n }\n };\n\n document.addEventListener(\"mousemove\", hoverHandler, true);\n document.addEventListener(\"click\", selectHandler, true);\n document.addEventListener(\"keydown\", escHandler, true);\n\n // Store for cleanup\n (enterSelectMode as any)._escHandler = escHandler;\n}\n\nfunction exitSelectMode() {\n state.selecting = false;\n document.body.style.cursor = \"\";\n hideHighlight();\n if (hoverHandler) { document.removeEventListener(\"mousemove\", hoverHandler, true); hoverHandler = null; }\n if (selectHandler) { document.removeEventListener(\"click\", selectHandler, true); selectHandler = null; }\n const escH = (enterSelectMode as any)._escHandler;\n if (escH) { document.removeEventListener(\"keydown\", escH, true); (enterSelectMode as any)._escHandler = null; }\n updatePillButtons();\n}\n\nasync function takeScreenshot() {\n let target: HTMLElement | undefined;\n try {\n const sel = state.selectedElement?.cssSelector?.trim();\n if (sel) target = (document.querySelector(sel) as HTMLElement) || undefined;\n } catch { /* stale or invalid selector */ }\n\n // Try programmatic capture first\n const result = await captureScreenshotWithFeedback(target || undefined);\n\n // Check if we got a real screenshot (not just the fallback info card)\n const isRealScreenshot = result.data && result.data.length > 5000; // Real screenshots are >5KB\n\n if (isRealScreenshot) {\n state.screenshot = result.data;\n updatePromptContext();\n $promptInput.focus();\n } else {\n // Programmatic capture failed or only got metadata — guide user to paste\n state.messages.push({\n role: \"system\",\n content: \"Take a screenshot manually (Cmd+Shift+4 on Mac, Win+Shift+S on Windows), then paste it here (Ctrl+V) or drag it onto the prompt bar.\"\n });\n openPanel(\"chat\");\n refreshPanelContent();\n }\n}\n\n// ── Draggable (setup ONCE) ───────────────────────────────────────\n\nfunction setupDraggable() {\n let active = false, startX = 0, startY = 0, origX = 0, origY = 0;\n\n $toolbar.addEventListener(\"mousedown\", (e) => {\n const t = e.target as HTMLElement;\n if (t.closest(\"[data-action]\")) return;\n if (!t.closest(\".om-grab\") && !t.closest(\".om-pill-brand\")) return;\n active = true;\n startX = e.clientX; startY = e.clientY;\n const r = $toolbar.getBoundingClientRect();\n origX = r.left; origY = r.top;\n e.preventDefault();\n });\n\n document.addEventListener(\"mousemove\", (e) => {\n if (!active) return;\n $toolbar.style.left = (origX + e.clientX - startX) + \"px\";\n $toolbar.style.top = (origY + e.clientY - startY) + \"px\";\n $toolbar.style.right = \"auto\";\n $toolbar.style.bottom = \"auto\";\n });\n\n document.addEventListener(\"mouseup\", () => {\n if (active) {\n active = false;\n // Persist position\n try {\n localStorage.setItem(\"__om_pos__\", JSON.stringify({\n left: $toolbar.style.left,\n top: $toolbar.style.top,\n }));\n } catch {}\n }\n });\n}\n\n// ── Helpers ──────────────────────────────────────────────────────\n\nfunction escapeHtml(text: string): string {\n const d = document.createElement(\"div\");\n d.textContent = text;\n return d.innerHTML;\n}\n\nfunction renderLineDiff(search: string, replace: string): string {\n const searchLines = search.split(\"\\n\");\n const replaceLines = replace.split(\"\\n\");\n const lines: string[] = [];\n const maxLines = 30; // cap display\n\n // Simple LCS-based line diff\n const sLen = Math.min(searchLines.length, maxLines);\n const rLen = Math.min(replaceLines.length, maxLines);\n\n // Find common prefix and suffix\n let commonPrefix = 0;\n while (commonPrefix < sLen && commonPrefix < rLen && searchLines[commonPrefix] === replaceLines[commonPrefix]) commonPrefix++;\n let commonSuffix = 0;\n while (commonSuffix < sLen - commonPrefix && commonSuffix < rLen - commonPrefix\n && searchLines[sLen - 1 - commonSuffix] === replaceLines[rLen - 1 - commonSuffix]) commonSuffix++;\n\n // Render context (unchanged), removed, added\n for (let i = 0; i < commonPrefix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ctx\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\"> </span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n // Removed lines (from search)\n for (let i = commonPrefix; i < sLen - commonSuffix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-del\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\">-</span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n // Added lines (from replace)\n for (let i = commonPrefix; i < rLen - commonSuffix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ins\"><span class=\"om-diff-ln\"> </span><span class=\"om-diff-sign\">+</span>${escapeHtml(replaceLines[i])}</div>`);\n }\n\n // Common suffix\n for (let i = sLen - commonSuffix; i < sLen; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ctx\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\"> </span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n if (searchLines.length > maxLines) lines.push(`<div class=\"om-diff-line om-diff-ctx\">... ${searchLines.length - maxLines} more lines</div>`);\n\n return lines.join(\"\") || `<div class=\"om-diff-line om-diff-ins\">${escapeHtml(replace.slice(0, 500))}</div>`;\n}\n\nfunction renderMarkdown(text: string): string {\n // First: convert literal \\n strings to actual newlines (from JSON escaping)\n let clean = text.replace(/\\\\n/g, \"\\n\");\n let html = escapeHtml(clean);\n // Code blocks (``` ... ```)\n html = html.replace(/```(\\w*)\\n([\\s\\S]*?)```/g, '<pre class=\"om-code-block\"><code>$2</code></pre>');\n // Inline code (`...`)\n html = html.replace(/`([^`]+)`/g, '<code class=\"om-inline-code\">$1</code>');\n // Bold (**...**)\n html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n // Italic (*...*)\n // Italic: *text* but not **text** — avoid lookbehind for Safari compatibility\n html = html.replace(/([^*]|^)\\*([^*]+)\\*([^*]|$)/g, '$1<em>$2</em>$3');\n // Bullet lists (- item)\n html = html.replace(/^- (.+)$/gm, '&#8226; $1');\n // Line breaks\n html = html.replace(/\\n/g, '<br>');\n return html;\n}\n\nasync function collectDebugInfo(messageIdx?: number): Promise<string> {\n const lines: string[] = [];\n\n // ── Fetch server-side info ──\n let serverInfo: any = null;\n try {\n if (ws.isConnected()) {\n const res = await Promise.race([\n ws.request(\"debug.logs\"),\n new Promise((_, rej) => setTimeout(() => rej(new Error(\"timeout\")), 3000)),\n ]) as any;\n serverInfo = res?.payload || null;\n }\n } catch {}\n\n // ── Environment ──\n lines.push(\"## Environment\");\n lines.push(\"\");\n lines.push(`- **OpenMagic**: v${CURRENT_VERSION}${state.updateAvailable ? ` (v${state.latestVersion} available)` : \"\"}`);\n lines.push(`- **Browser**: ${navigator.userAgent}`);\n lines.push(`- **Platform**: ${navigator.platform}`);\n lines.push(`- **Viewport**: ${window.innerWidth}x${window.innerHeight} (devicePixelRatio: ${window.devicePixelRatio})`);\n lines.push(`- **Page URL**: ${window.location.href}`);\n lines.push(`- **Page Title**: ${document.title}`);\n if (serverInfo) {\n lines.push(`- **Node.js**: ${serverInfo.nodeVersion} (${serverInfo.platform}/${serverInfo.arch})`);\n lines.push(`- **Server PID**: ${serverInfo.pid}`);\n lines.push(`- **Server Uptime**: ${serverInfo.uptime}s`);\n lines.push(`- **Server Memory**: ${serverInfo.memoryMB}MB RSS`);\n lines.push(`- **Server CWD**: ${serverInfo.cwd}`);\n }\n\n // ── Connection & Config ──\n lines.push(\"\");\n lines.push(\"## Configuration\");\n lines.push(\"\");\n lines.push(`- **WebSocket**: ${state.connected ? \"connected\" : \"disconnected\"}`);\n lines.push(`- **Provider**: ${MODEL_REGISTRY[state.provider]?.name || state.provider || \"not set\"}`);\n lines.push(`- **Model**: ${state.model || \"not set\"}`);\n lines.push(`- **API Key Set**: ${state.hasApiKey ? \"yes\" : \"no\"}`);\n const configuredList = Object.entries(state.configuredProviders)\n .filter(([, v]) => v)\n .map(([k]) => MODEL_REGISTRY[k]?.name || k);\n if (configuredList.length) {\n lines.push(`- **Configured Providers**: ${configuredList.join(\", \")}`);\n }\n if (state.roots.length) {\n lines.push(`- **Project Roots**: ${state.roots.join(\", \")}`);\n }\n\n // ── Selected Element ──\n if (state.selectedElement) {\n const el = state.selectedElement;\n lines.push(\"\");\n lines.push(\"## Selected Element\");\n lines.push(\"\");\n lines.push(`- **Selector**: \\`${el.cssSelector || \"\"}\\``);\n lines.push(`- **Tag**: \\`${el.tagName}\\``);\n if (el.id) lines.push(`- **ID**: \\`${el.id}\\``);\n if (el.className) lines.push(`- **Class**: \\`${el.className}\\``);\n if ((el as any).componentHint) lines.push(`- **Component**: \\`${(el as any).componentHint}\\``);\n if ((el as any).ancestry?.length) lines.push(`- **Ancestry**: ${(el as any).ancestry.join(\" > \")}`);\n if (el.textContent) lines.push(`- **Text**: ${el.textContent.slice(0, 150)}`);\n }\n\n // ── Grounded Files (sent to LLM) ──\n if (state.groundedFiles.length) {\n lines.push(\"\");\n lines.push(\"## Files Sent to LLM\");\n lines.push(\"\");\n for (const f of state.groundedFiles) {\n lines.push(`- \\`${f}\\``);\n }\n }\n\n // ── Proposed Changes (diffs) ──\n const diffs: { file: string; type: string }[] = [];\n for (const m of state.messages) {\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n diffs.push({ file: diff.file, type: diff.type || \"edit\" });\n } catch {}\n }\n }\n if (diffs.length) {\n lines.push(\"\");\n lines.push(\"## Proposed Changes\");\n lines.push(\"\");\n for (const d of diffs) {\n lines.push(`- \\`${d.file}\\` (${d.type})`);\n }\n }\n\n // ── Applied / Rejected / Reverted ──\n const appliedMsgs = state.messages.filter(m =>\n m.role === \"system\" && (\n m.content.startsWith(\"Applied change to \") ||\n m.content.startsWith(\"Rejected change to \") ||\n m.content.startsWith(\"Reverted change to \") ||\n m.content.startsWith(\"Created \") ||\n m.content.startsWith(\"Change rejected\") ||\n m.content.startsWith(\"No matching code\") ||\n m.content.startsWith(\"Write failed\") ||\n m.content.startsWith(\"Could not read\")\n )\n );\n if (appliedMsgs.length) {\n lines.push(\"\");\n lines.push(\"## Applied/Rejected Changes\");\n lines.push(\"\");\n for (const m of appliedMsgs) {\n lines.push(`- ${m.content.slice(0, 200)}`);\n }\n }\n\n // ── Performance ──\n const perf = window.performance;\n const navEntry = perf.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n const paintEntries = perf.getEntriesByType(\"paint\");\n if (navEntry) {\n lines.push(\"\");\n lines.push(\"## Page Performance\");\n lines.push(\"\");\n lines.push(`- **Page Load**: ${Math.round(navEntry.loadEventEnd - navEntry.startTime)}ms`);\n lines.push(`- **DOM Ready**: ${Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime)}ms`);\n lines.push(`- **TTFB**: ${Math.round(navEntry.responseStart - navEntry.startTime)}ms`);\n const fcp = paintEntries.find(e => e.name === \"first-contentful-paint\");\n if (fcp) lines.push(`- **FCP**: ${Math.round(fcp.startTime)}ms`);\n }\n\n // ── Browser Console (all levels) ──\n const consoleLogs = getConsoleLogs();\n if (consoleLogs.length) {\n const errors = consoleLogs.filter(l => l.level === \"error\");\n const warnings = consoleLogs.filter(l => l.level === \"warn\");\n const infos = consoleLogs.filter(l => l.level === \"log\" || l.level === \"info\" || l.level === \"debug\");\n lines.push(\"\");\n lines.push(\"## Browser Console\");\n lines.push(\"\");\n lines.push(`Total: ${consoleLogs.length} entries (${errors.length} errors, ${warnings.length} warnings, ${infos.length} log/info/debug)`);\n if (errors.length) {\n lines.push(\"\");\n lines.push(`### Errors (${errors.length})`);\n lines.push(\"```\");\n for (const err of errors.slice(-15)) {\n lines.push(`[${new Date(err.timestamp).toISOString()}] ${err.args.map((a: any) => String(a)).join(\" \").slice(0, 300)}`);\n }\n lines.push(\"```\");\n }\n if (warnings.length) {\n lines.push(\"\");\n lines.push(`### Warnings (${warnings.length})`);\n lines.push(\"```\");\n for (const w of warnings.slice(-10)) {\n lines.push(`[${new Date(w.timestamp).toISOString()}] ${w.args.map((a: any) => String(a)).join(\" \").slice(0, 200)}`);\n }\n lines.push(\"```\");\n }\n if (infos.length) {\n lines.push(\"\");\n lines.push(\"<details><summary>Log/Info/Debug (\" + infos.length + \" entries)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const l of infos.slice(-30)) {\n lines.push(`[${new Date(l.timestamp).toISOString()}] [${l.level}] ${l.args.map((a: any) => String(a)).join(\" \").slice(0, 200)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n }\n\n // ── Network ──\n const networkLogs = getNetworkLogs();\n const failedRequests = networkLogs.filter(l => l.status && l.status >= 400);\n const slowRequests = networkLogs.filter(l => l.duration && l.duration > 2000);\n if (failedRequests.length || slowRequests.length) {\n lines.push(\"\");\n lines.push(\"## Network Issues\");\n lines.push(\"\");\n if (failedRequests.length) {\n lines.push(`### Failed Requests (${failedRequests.length})`);\n lines.push(\"```\");\n for (const req of failedRequests.slice(-15)) {\n lines.push(`${req.method} ${req.url.slice(0, 120)} → ${req.status} (${req.duration || \"?\"}ms)`);\n }\n lines.push(\"```\");\n }\n if (slowRequests.length) {\n lines.push(`### Slow Requests >2s (${slowRequests.length})`);\n lines.push(\"```\");\n for (const req of slowRequests.slice(-10)) {\n lines.push(`${req.method} ${req.url.slice(0, 120)} → ${req.status} (${req.duration}ms)`);\n }\n lines.push(\"```\");\n }\n }\n\n // ── Server-Side Logs (terminal) ──\n if (serverInfo?.logs?.length) {\n const sLogs = serverInfo.logs as { level: string; msg: string; ts: number }[];\n const sErrors = sLogs.filter(l => l.level === \"error\");\n const sWarnings = sLogs.filter(l => l.level === \"warn\");\n const sInfos = sLogs.filter(l => l.level === \"log\" || l.level === \"info\");\n lines.push(\"\");\n lines.push(\"## Server Logs (Terminal)\");\n lines.push(\"\");\n lines.push(`Total: ${sLogs.length} entries (${sErrors.length} errors, ${sWarnings.length} warnings, ${sInfos.length} log/info)`);\n if (sErrors.length) {\n lines.push(\"\");\n lines.push(`### Server Errors (${sErrors.length})`);\n lines.push(\"```\");\n for (const e of sErrors.slice(-15)) {\n lines.push(`[${new Date(e.ts).toISOString()}] ${e.msg.slice(0, 300)}`);\n }\n lines.push(\"```\");\n }\n if (sWarnings.length) {\n lines.push(\"\");\n lines.push(`### Server Warnings (${sWarnings.length})`);\n lines.push(\"```\");\n for (const w of sWarnings.slice(-10)) {\n lines.push(`[${new Date(w.ts).toISOString()}] ${w.msg.slice(0, 200)}`);\n }\n lines.push(\"```\");\n }\n lines.push(\"\");\n lines.push(\"<details><summary>All server logs (\" + sLogs.length + \" entries)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const l of sLogs.slice(-50)) {\n lines.push(`[${new Date(l.ts).toISOString()}] [${l.level}] ${l.msg.slice(0, 200)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n\n // ── Full Chat History ──\n if (state.messages.length) {\n lines.push(\"\");\n lines.push(\"## Chat History\");\n lines.push(\"\");\n lines.push(\"<details><summary>Full conversation (\" + state.messages.length + \" messages)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const m of state.messages) {\n if (m.content.startsWith(\"__DIFFGROUP__\")) continue;\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n lines.push(`[diff] ${diff.type || \"edit\"}: ${diff.file}`);\n if (diff.search) lines.push(` - search: ${diff.search.slice(0, 100)}...`);\n if (diff.replace) lines.push(` + replace: ${diff.replace.slice(0, 100)}...`);\n } catch {\n lines.push(`[diff] (parse error)`);\n }\n continue;\n }\n lines.push(`[${m.role}] ${m.content.slice(0, 500)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n\n // ── Specific message context (for copy button) ──\n if (messageIdx !== undefined) {\n const msg = state.messages[messageIdx];\n if (msg) {\n lines.push(\"\");\n lines.push(\"## Copied Message\");\n lines.push(\"\");\n lines.push(\"```\");\n lines.push(`[${msg.role}] ${msg.content.slice(0, 2000)}`);\n lines.push(\"```\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction checkForUpdates() {\n fetch(\"https://registry.npmjs.org/openmagic/latest\", {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout ? AbortSignal.timeout(5000) : undefined,\n }).then(r => r.ok ? r.json() : null).then(d => {\n if (!d || typeof d.version !== \"string\" || !/^\\d+\\.\\d+\\.\\d+/.test(d.version)) return;\n const l = d.version.split(\".\").map(Number), c = CURRENT_VERSION.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) { if ((l[i]||0) > (c[i]||0)) { state.updateAvailable = true; state.latestVersion = d.version; showUpdateDot(); return; } if ((l[i]||0) < (c[i]||0)) return; }\n }).catch(() => {});\n}\n\nfunction showUpdateDot() {\n updateStatusDot();\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":";wCAAO,IAAMA,GAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","shouldReconnect","reconnectTimer","reconnectAttempt","generateId","connect","port","token","resolve","reject","settled","handshakeTimeout","wsHost","wsProto","handshakeId","msg","queued","event","handler","wasConnected","id","delay","e","send","data","request","type","payload","timeout","stream","onChunk","IDLE_MS","onTimeout","resetTimeout","onMessage","h","isConnected","IMPORTANT_STYLES","inspectElement","el","computed","styles","prop","rect","parentStyles","parentComputed","siblings","children","selectedIdx","start","end","i","sib","tag","cls","childrenLayout","directChildren","child","cRect","cComputed","gapToNext","nextRect","matchedCssRules","getMatchedCssRules","resolvedClasses","resolveClasses","ariaAttributes","attr","eventHandlers","reactProps","getReactProps","htmlEl","htmlComputed","htmlDataAttributes","key","themeState","cssVariables","rule","varMatches","vm","varName","inlineVars","iv","zIndex","createsContext","parentZIndex","stackingContext","isInViewport","isVisible","isScrollable","visibilityState","activeBreakpoints","breakpointsToCheck","bp","beforeContent","afterContent","pseudoElements","formState","getCleanOuterHTML","getCssSelector","getXPath","getAncestry","getComponentHint","depth","result","current","c","dataComponent","keys","fiber","name","clone","s","html","attrs","a","childSummary","parts","selector","classes","parent","index","element","sibling","rules","sheet","cssRules","text","props","safe","count","k","v","t","matchedRules","resolved","escaped","highlightEl","showHighlight","hideHighlight","captureScreenshotWithFeedback","target","el","result","captureViaSvg","captureSimple","element","rect","width","height","clone","cloneWithStyles","svgData","blob","url","resolve","img","canvas","dpr","ctx","ratio","small","sCtx","source","depth","maxDepth","computed","keyProps","css","p","v","i","child","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","getConsoleLogs","buildContext","selectedElement","screenshot","getNetworkLogs","l","getConsoleLogs","ICON","MODEL_REGISTRY","encodeBase64Utf8","value","bytes","binary","i","decodeBase64Utf8","CURRENT_VERSION","state","shadow","$toolbar","$promptInput","$promptCtx","$panel","$panelBody","saveState","msgs","prunedMsgs","m","diff","restoreState","saved","init","host","style","TOOLBAR_CSS","root","buildStaticDOM","attachGlobalEvents","setupDraggable","pos","installNetworkCapture","installConsoleCapture","checkForUpdates","token","wsPort","connect","updateStatusDot","request","msg","serverProvider","serverModel","cli","provMeta","openPanel","updatePillButtons","updateModelSwitcher","e","target","action","handleAction","field","refreshPanelContent","sendPrompt","fileInput","handleFileSelect","promptRow","dt","items","file","onMessage","el","closePanel","undoBtn","undoDiff","applyAllBtn","resolveFilePath","rel","fuzzyLineMatch","content","search","searchLines","nonEmptySearch","contentLines","allMatch","matchLen","si","ci","lineRangeToOffsets","strippedSearch","j","searchStr","searchLen","bestScore","bestStart","bestLen","minWin","maxWin","winSize","windowStr","l","score","similarity","lines","start","count","startOffset","k","endOffset","a","b","trigramsA","trigramsB","intersection","t","applyDiff","searchB64","replaceB64","card","actions","r","replace","filePath","idx","scrollChatToBottom","resolvedPath","pathsToTry","basename","baseInRoot","tryPath","c","exactCount","writeResult","fuzzyResult","newContent","rejectDiff","searchPreview","replacePreview","updateApplyBar","bar","text","hideApplyBar","toggleSelectMode","takeScreenshot","togglePanel","saveSettings","url","changeRow","captureNetworkProfile","triggerFileAttach","renderAttachments","buttons","filesToSnapshot","btn","snapshots","fp","failed","collectDebugInfo","debugText","debugInfo","updatePromptContext","panel","promptAttach","headerBtns","dot","cls","sel","prov","opts","chips","contextChars","estTokens","label","title","renderSettingsHTML","renderChatHTML","providerOpts","p","cliInfo","indicator","modelOpts","isLocal","keyUrl","keyPh","providerHasKey","updateBanner","statusHtml","saveBtnText","saveBtnClass","saveBtnDisabled","keySection","isCreate","diffHtml","renderLineDiff","escapeHtml","copyBtn","renderMarkdown","streamHtml","apiKey","updateSaveButton","isConnected","payload","result","_","reject","context","buildContext","MAX_GROUNDED_FILES","MAX_GROUNDED_CHARS","TEXT_RE","statusEl","treeResult","textFiles","f","tokenSources","searchTokens","routeTokens","s","activeSubdir","hint","subdirScores","tf","topDir","rt","best","dir","scored","lower","lowerNoGroups","files","readPaths","totalChars","topScored","readResults","fullPath","fi","maxChars","trimmed","baseName","styleExts","ext","stylePath","sr","sc","stMax","st","LAYOUT_NAMES","layoutDir","layoutDepth","foundLayout","layoutName","layoutPath","lr","lc","lMax","lt","parentDir","pathAliases","tsconfigFile","fl","tsconfig","paths","baseUrl","alias","targets","aliasPrefix","targetPrefix","resolvedTarget","importMatches","im","importPath","candidates","candidate","ir","ic","imMax","it","aliasImports","aim","rawImport","resolved","aliasCandidates","ac","ar","acContent","aMax","at","pkgResult","pkgContent","pkg","deps","depsStr","CONFIG_CANDIDATES","cfgPath","cfgResult","cfgContent","cap","fileNames","MAX_RETRIES","retryCount","retriedFiles","stream","chunk","responseContent","decodedContent","mdMatch","hasRealModifications","needFileMatch","neededFile","spinnerEl","primaryPath","fileContent","existingIdx","fullContent","searchMatch","alreadySearched","pattern","searchPath","matches","rej","displayContent","groupId","validMods","mod","diffId","diffPayload","perf","navEntry","paintEntries","resources","networkLogs","getNetworkLogs","consoleLogs","getConsoleLogs","fcp","apiRequests","allRequests","status","log","errors","warns","slowest","input","reader","container","selectHandler","hoverHandler","exitSelectMode","enterSelectMode","showHighlight","inspectElement","escHandler","hideHighlight","escH","captureScreenshotWithFeedback","active","startX","startY","origX","origY","d","replaceLines","maxLines","sLen","rLen","commonPrefix","commonSuffix","clean","html","messageIdx","serverInfo","configuredList","v","diffs","appliedMsgs","warnings","infos","err","w","failedRequests","slowRequests","req","sLogs","sErrors","sWarnings","sInfos","showUpdateDot"]}
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":["export const TOOLBAR_CSS = `\n:host {\n all: initial;\n direction: ltr;\n unicode-bidi: isolate;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #e0e0e0;\n line-height: 1.5;\n text-align: left;\n}\n\n* { box-sizing: border-box; margin: 0; padding: 0; }\n.om-hidden { display: none !important; }\n\n/* ── Unified Toolbar Container ────────────────────────── */\n.om-toolbar {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n width: min(420px, calc(100vw - 40px));\n display: flex;\n flex-direction: column;\n background: #111125;\n border: 1px solid rgba(108, 92, 231, 0.18);\n border-radius: 14px;\n box-shadow: 0 6px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255,255,255,0.02);\n overflow: hidden;\n}\n\n/* Panel header */\n.om-panel-header {\n display: flex; align-items: center; gap: 6px;\n padding: 8px 12px;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n background: rgba(108, 92, 231, 0.03);\n flex-shrink: 0;\n}\n.om-panel-title { font-size: 11px; font-weight: 600; color: #a29bfe; }\n.om-panel-version { font-size: 10px; color: #444; margin-left: auto; }\n.om-panel-close {\n background: none; border: none; color: #555; cursor: pointer;\n padding: 2px 4px; border-radius: 4px; line-height: 1;\n display: flex; align-items: center;\n}\n.om-panel-close:hover { color: #ccc; background: rgba(255,255,255,0.05); }\n\n/* ── Header Bar (brand + tools) ───────────────────────── */\n.om-toolbar-header {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 6px 10px 6px 5px;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n background: rgba(108, 92, 231, 0.03);\n flex-shrink: 0;\n}\n\n.om-grab {\n display: flex; align-items: center; justify-content: center;\n width: 18px; height: 26px; color: #3a3a5a; cursor: grab;\n border-radius: 5px; transition: color 0.15s; flex-shrink: 0;\n}\n.om-grab:hover { color: #6c5ce7; }\n.om-grab:active { cursor: grabbing; color: #a29bfe; }\n\n.om-pill-brand {\n display: flex; align-items: center; gap: 5px;\n padding: 0 6px 0 4px; cursor: grab;\n}\n.om-pill-icon { color: #a29bfe; flex-shrink: 0; }\n.om-pill-text { font-size: 11px; font-weight: 700; color: #a29bfe; letter-spacing: 0.3px; white-space: nowrap; }\n\n.om-pill-divider { width: 1px; height: 18px; background: rgba(255,255,255,0.06); margin: 0 3px; flex-shrink: 0; }\n\n.om-pill-btn {\n background: none; border: none; color: #555; cursor: pointer;\n padding: 5px 6px; border-radius: 6px; line-height: 1;\n transition: background 0.15s, color 0.15s;\n display: flex; align-items: center; justify-content: center;\n}\n.om-pill-btn:hover { background: rgba(108, 92, 231, 0.15); color: #a29bfe; }\n.om-pill-btn:focus-visible { outline: 2px solid #6c5ce7; outline-offset: 2px; }\n.om-pill-btn.active { background: rgba(108, 92, 231, 0.25); color: #c4b5fd; }\n.om-panel-bug {\n background: none; border: none; color: #666; cursor: pointer; padding: 2px 4px;\n border-radius: 4px; line-height: 1; display: flex; align-items: center;\n}\n.om-panel-bug:hover { color: #e94560; background: rgba(233, 69, 96, 0.1); }\n\n.om-status-dot {\n width: 7px; height: 7px; border-radius: 50%; margin-left: auto; flex-shrink: 0;\n}\n.om-status-dot.connected { background: #00b894; }\n.om-status-dot.disconnected { background: #e94560; }\n.om-status-dot.outdated { background: #fdcb6e; animation: om-pulse 2s ease infinite; }\n@keyframes om-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(253,203,110,0.4); }\n 50% { box-shadow: 0 0 0 5px rgba(253,203,110,0); }\n}\n\n/* ── Panel (expandable area between header and prompt) ── */\n.om-panel {\n max-height: 420px;\n overflow: hidden;\n border-bottom: 1px solid rgba(255,255,255,0.04);\n animation: om-expand 0.15s ease;\n}\n@keyframes om-expand {\n from { max-height: 0; opacity: 0; }\n to { max-height: 420px; opacity: 1; }\n}\n\n.om-panel-body {\n overflow-y: auto; padding: 12px;\n max-height: 420px;\n}\n.om-panel-body::-webkit-scrollbar { width: 5px; }\n.om-panel-body::-webkit-scrollbar-track { background: transparent; }\n.om-panel-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }\n\n/* ── Prompt Row (always visible at bottom) ────────────── */\n.om-prompt-row {\n display: flex;\n align-items: center;\n padding: 6px;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.om-prompt-context {\n display: flex; gap: 3px; flex-wrap: wrap; max-width: 200px; overflow: hidden;\n}\n.om-prompt-chip {\n display: flex; align-items: center; gap: 3px;\n padding: 3px 7px; background: rgba(108, 92, 231, 0.08);\n border: 1px solid rgba(108, 92, 231, 0.12);\n border-radius: 6px; font-size: 10px; color: #a29bfe;\n cursor: default; white-space: nowrap;\n}\n.om-prompt-chip-x {\n background: none; border: none; color: #a29bfe; cursor: pointer;\n font-size: 11px; line-height: 1; padding: 0 1px; opacity: 0.5;\n}\n.om-prompt-chip-x:hover { opacity: 1; }\n.om-prompt-chip-tokens { color: #888; background: transparent; border: 1px solid rgba(255,255,255,0.06); font-size: 9px; }\n\n.om-prompt-input {\n flex: 1;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.06);\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n padding: 7px 10px;\n outline: none;\n min-width: 0;\n transition: border-color 0.15s;\n}\n.om-prompt-input:focus { border-color: rgba(108, 92, 231, 0.4); }\n.om-prompt-input::placeholder { color: #3a3a5a; }\n\n.om-prompt-send {\n display: flex; align-items: center; justify-content: center;\n width: 30px; height: 30px; flex-shrink: 0;\n background: #6c5ce7; border: none; border-radius: 8px;\n color: white; cursor: pointer; transition: background 0.15s;\n}\n.om-prompt-send:hover { background: #7c6cf7; }\n.om-prompt-send:disabled { background: #2a2a4a; color: #444; cursor: not-allowed; }\n\n.om-prompt-attach {\n display: flex; align-items: center; justify-content: center;\n width: 28px; height: 28px; flex-shrink: 0;\n background: none; border: none; color: #555;\n cursor: pointer; border-radius: 6px; transition: color 0.15s, background 0.15s;\n}\n.om-prompt-attach:hover { color: #a29bfe; background: rgba(108, 92, 231, 0.1); }\n\n.om-model-switcher {\n background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08);\n color: #888; font-size: 10px; padding: 2px 4px; border-radius: 4px;\n max-width: 90px; flex-shrink: 0; cursor: pointer; outline: none;\n}\n.om-model-switcher:hover { border-color: rgba(108, 92, 231, 0.3); color: #a29bfe; }\n.om-model-switcher:focus { border-color: #6c5ce7; }\n\n/* ── Attachments ──────────────────────────────────────── */\n.om-prompt-attachments {\n display: flex; gap: 6px; padding: 4px 8px; flex-wrap: wrap;\n border-bottom: 1px solid rgba(255,255,255,0.03);\n}\n.om-attachment-thumb {\n position: relative; width: 48px; height: 48px;\n border-radius: 6px; overflow: hidden;\n border: 1px solid rgba(255,255,255,0.08);\n}\n.om-attachment-thumb img {\n width: 100%; height: 100%; object-fit: cover;\n}\n.om-attachment-remove {\n position: absolute; top: 1px; right: 1px;\n width: 16px; height: 16px; display: flex;\n align-items: center; justify-content: center;\n background: rgba(0,0,0,0.7); border: none; border-radius: 50%;\n color: #fff; cursor: pointer; padding: 0; line-height: 1;\n}\n.om-attachment-remove svg { width: 10px; height: 10px; }\n\n/* ── Settings ─────────────────────────────────────────── */\n.om-settings { display: flex; flex-direction: column; gap: 12px; }\n\n.om-field { display: flex; flex-direction: column; gap: 5px; }\n.om-label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: #555; }\n\n.om-select, .om-input {\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n padding: 8px 10px;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n width: 100%;\n transition: border-color 0.15s;\n}\n.om-select:focus, .om-input:focus { border-color: rgba(108, 92, 231, 0.4); }\n.om-select option { background: #111125; color: #e0e0e0; }\n\n.om-key-row { display: flex; gap: 6px; align-items: stretch; }\n.om-key-input { flex: 1; min-width: 0; -webkit-text-security: disc; }\n\n.om-key-configured {\n display: flex; align-items: center; gap: 6px;\n padding: 8px 10px; background: rgba(0, 184, 148, 0.06);\n border: 1px solid rgba(0, 184, 148, 0.12);\n border-radius: 8px; font-size: 12px; color: #00b894;\n}\n.om-key-configured span { flex: 1; }\n.om-btn-change-key {\n background: none; border: 1px solid rgba(255,255,255,0.08);\n color: #888; cursor: pointer; padding: 3px 8px;\n border-radius: 5px; font-size: 10px; font-family: inherit;\n transition: all 0.15s;\n}\n.om-btn-change-key:hover { color: #ccc; border-color: rgba(255,255,255,0.15); }\n.om-key-change-row { margin-top: 6px; }\n\n.om-btn-get-key {\n display: flex; align-items: center; gap: 4px;\n padding: 6px 9px; background: rgba(108, 92, 231, 0.08);\n border: 1px solid rgba(108, 92, 231, 0.15); border-radius: 8px;\n color: #a29bfe; font-size: 11px; font-weight: 600;\n font-family: inherit; cursor: pointer; white-space: nowrap;\n transition: all 0.15s;\n}\n.om-btn-get-key:hover { background: rgba(108, 92, 231, 0.15); color: #c4b5fd; }\n\n.om-btn {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n background: #6c5ce7; border: none; color: white; cursor: pointer;\n padding: 8px 14px; border-radius: 8px;\n font-size: 13px; font-weight: 600; font-family: inherit;\n transition: background 0.15s;\n}\n.om-btn:hover { background: #7c6cf7; }\n.om-btn:disabled { background: #2a2a4a; color: #555; cursor: not-allowed; }\n.om-btn-saving { background: #4a3db0; }\n.om-btn-saved { background: #00b894; }\n\n.om-status { font-size: 11px; padding: 5px 8px; border-radius: 6px; text-align: center; display: flex; align-items: center; justify-content: center; gap: 4px; }\n.om-status-success { background: rgba(0, 184, 148, 0.06); color: #00b894; }\n.om-status-error { background: rgba(233, 69, 96, 0.06); color: #e94560; }\n\n.om-key-hint { font-size: 10px; color: #444; margin-top: 3px; }\n.om-key-hint a { color: #7c6cf7; cursor: pointer; text-decoration: none; }\n.om-key-hint a:hover { text-decoration: underline; }\n\n.om-update-banner {\n display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\n padding: 7px 10px; margin-bottom: 10px;\n background: rgba(253, 203, 110, 0.04); border: 1px solid rgba(253, 203, 110, 0.12);\n border-radius: 8px; font-size: 11px; color: #fdcb6e;\n}\n.om-update-cmd {\n display: block; width: 100%; margin-top: 2px;\n padding: 4px 7px; background: rgba(0, 0, 0, 0.12); border-radius: 4px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 11px; color: #fdcb6e; user-select: all;\n}\n\n/* ── Chat ─────────────────────────────────────────────── */\n.om-chat-messages {\n display: flex; flex-direction: column; gap: 8px;\n max-height: 380px;\n overflow-y: auto;\n}\n.om-chat-messages::-webkit-scrollbar { width: 4px; }\n.om-chat-messages::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.06); border-radius: 2px; }\n\n.om-msg {\n padding: 8px 11px; border-radius: 10px;\n font-size: 13px; line-height: 1.5;\n white-space: pre-wrap; word-break: break-word;\n}\n.om-msg-user { background: rgba(108, 92, 231, 0.08); color: #ccc; margin-left: 36px; border-bottom-right-radius: 3px; }\n.om-msg-assistant { background: rgba(255,255,255,0.02); color: #aaa; margin-right: 36px; border-bottom-left-radius: 3px; border: 1px solid rgba(255,255,255,0.03); }\n.om-msg-system { background: rgba(108, 92, 231, 0.05); color: #888; font-size: 11px; text-align: center; padding: 5px 8px; border-radius: 6px; }\n\n.om-chat-empty { color: #333; text-align: center; padding: 32px 16px; font-size: 12px; line-height: 1.6; }\n\n.om-spinner { width: 12px; height: 12px; border: 2px solid rgba(108,92,231,0.12); border-top-color: #6c5ce7; border-radius: 50%; animation: om-spin 0.6s linear infinite; display: inline-block; vertical-align: -1px; margin-right: 5px; }\n@keyframes om-spin { to { transform: rotate(360deg); } }\n\n.om-element-info {\n background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.03);\n border-radius: 6px; padding: 6px 8px;\n font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n font-size: 10px; color: #555; max-height: 60px; overflow-y: auto; margin-bottom: 6px;\n}\n\n/* ── Diff Cards ──────────────────────────────────────── */\n.om-diff-card { background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.06); border-radius: 8px; padding: 8px 10px; margin: 4px 0; font-size: 12px; }\n.om-diff-file { color: #a29bfe; font-size: 11px; font-weight: 600; margin-bottom: 6px; font-family: 'SF Mono', Consolas, monospace; }\n.om-diff-removed { background: rgba(233,69,96,0.08); color: #fab1a0; padding: 4px 8px; border-radius: 4px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; margin-bottom: 4px; }\n.om-diff-added { background: rgba(0,184,148,0.08); color: #55efc4; padding: 4px 8px; border-radius: 4px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; margin-bottom: 6px; }\n.om-diff-lines { max-height: 300px; overflow-y: auto; border-radius: 6px; background: rgba(0,0,0,0.2); margin-bottom: 6px; font-family: 'SF Mono', Consolas, monospace; font-size: 11px; line-height: 1.5; }\n.om-diff-line { display: flex; white-space: pre; padding: 0 8px; }\n.om-diff-ln { color: #555; min-width: 28px; text-align: right; padding-right: 8px; user-select: none; flex-shrink: 0; }\n.om-diff-sign { min-width: 14px; flex-shrink: 0; font-weight: bold; user-select: none; }\n.om-diff-ctx { color: #888; }\n.om-diff-del { background: rgba(233,69,96,0.12); color: #fab1a0; }\n.om-diff-del .om-diff-sign { color: #e94560; }\n.om-diff-ins { background: rgba(0,184,148,0.12); color: #55efc4; }\n.om-diff-ins .om-diff-sign { color: #00b894; }\n.om-diff-actions { display: flex; gap: 6px; }\n.om-btn-sm { padding: 4px 10px; font-size: 11px; border-radius: 6px; }\n.om-btn-secondary { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.08); color: #888; cursor: pointer; font-family: inherit; }\n.om-btn-secondary:hover { background: rgba(255,255,255,0.08); color: #ccc; }\n.om-diff-applied { opacity: 0.5; }\n.om-diff-applied .om-diff-actions { display: none; }\n\n/* Sticky Apply All bar — between panel and prompt */\n.om-apply-bar {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 10px;\n background: rgba(108, 92, 231, 0.06);\n border-top: 1px solid rgba(108, 92, 231, 0.12);\n border-bottom: 1px solid rgba(108, 92, 231, 0.12);\n flex-shrink: 0;\n}\n.om-apply-bar-text { font-size: 12px; color: #a29bfe; font-weight: 600; }\n\n/* ── Undo Button ─────────────────────────────────────── */\n.om-undo-btn {\n background: none; border: 1px solid rgba(255,255,255,0.08);\n color: #888; cursor: pointer; padding: 2px 6px; margin-left: 6px;\n border-radius: 4px; font-size: 10px; font-family: inherit;\n}\n.om-undo-btn:hover { color: #e94560; border-color: rgba(233,69,96,0.2); }\n\n/* ── Clear Chat Button ───────────────────────────────── */\n.om-panel-clear {\n background: none; border: none; color: #444; cursor: pointer;\n padding: 2px 4px; border-radius: 4px; line-height: 1;\n display: flex; align-items: center; margin-right: 4px;\n}\n.om-panel-clear:hover { color: #e94560; background: rgba(233,69,96,0.08); }\n\n/* ── Code Blocks (Markdown) ─────────────────────────── */\n.om-code-block {\n background: rgba(0,0,0,0.2); border-radius: 6px; padding: 8px 10px;\n margin: 6px 0; overflow-x: auto; font-family: 'SF Mono', Consolas, monospace;\n font-size: 11px; line-height: 1.5; white-space: pre-wrap;\n}\n.om-inline-code {\n background: rgba(108,92,231,0.1); padding: 1px 4px; border-radius: 3px;\n font-family: 'SF Mono', Consolas, monospace; font-size: 12px;\n}\n\n/* ── Copy Button ─────────────────────────────────────── */\n.om-copy-btn {\n position: absolute; top: 4px; right: 4px;\n background: rgba(0,0,0,0.3); border: none; color: #888;\n cursor: pointer; padding: 3px; border-radius: 4px;\n opacity: 0; transition: opacity 0.15s;\n display: flex; align-items: center;\n}\n.om-msg:hover .om-copy-btn { opacity: 1; }\n.om-copy-btn:hover { color: #ccc; background: rgba(0,0,0,0.5); }\n.om-msg { position: relative; }\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 shouldReconnect = false;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet reconnectAttempt = 0;\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 shouldReconnect = true;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const handshakeTimeout = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject(new Error(\"Handshake timeout\"));\n ws?.close();\n }\n }, 10000);\n\n try {\n // Same-origin WebSocket — use page hostname and given port\n const wsHost = window.location.hostname || \"127.0.0.1\";\n const wsProto = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n ws = new WebSocket(`${wsProto}//${wsHost}:${port}/__openmagic__/ws`);\n\n ws.onopen = () => {\n // Send handshake directly (bypass send() which checks connected flag)\n const handshakeId = generateId();\n ws!.send(JSON.stringify({ id: handshakeId, type: \"handshake\", payload: { token } }));\n\n handlers.set(handshakeId, (msg) => {\n if (msg.type === \"handshake.ok\") {\n clearTimeout(handshakeTimeout);\n connected = true;\n reconnectAttempt = 0;\n // Flush queued messages\n for (const queued of messageQueue) {\n ws?.send(queued);\n }\n messageQueue = [];\n if (!settled) { settled = true; resolve(); }\n } else if (msg.type === \"error\") {\n clearTimeout(handshakeTimeout);\n if (!settled) { settled = true; 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 if (msg.id && handlers.has(msg.id)) {\n const handler = handlers.get(msg.id)!;\n handler(msg);\n if (msg.type === \"llm.done\" || msg.type === \"llm.error\" || !msg.type.startsWith(\"llm.\")) {\n handlers.delete(msg.id);\n }\n }\n for (const handler of globalHandlers) {\n handler(msg);\n }\n } catch {\n // Ignore parse errors\n }\n };\n\n ws.onclose = () => {\n const wasConnected = connected;\n connected = false;\n\n // Reject all pending handlers\n handlers.forEach((handler, id) => {\n handler({ type: \"error\", id, payload: { message: \"Connection lost\" } });\n });\n handlers.clear();\n\n if (!wasConnected && !settled) {\n // Connection closed before handshake completed\n clearTimeout(handshakeTimeout);\n settled = true;\n reject(new Error(\"WebSocket closed before handshake\"));\n return;\n }\n\n // Only reconnect if we were previously connected and should reconnect\n if (wasConnected && shouldReconnect && !reconnectTimer) {\n const delay = Math.min(2000 * Math.pow(1.5, reconnectAttempt), 30000);\n reconnectAttempt++;\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect(port, token).then(() => {\n // Notify toolbar of reconnection\n for (const handler of globalHandlers) {\n handler({ type: \"reconnected\", payload: {} });\n }\n }).catch(() => {});\n }, delay);\n }\n };\n\n ws.onerror = () => {\n if (!connected && !settled) {\n clearTimeout(handshakeTimeout);\n settled = true;\n reject(new Error(\"WebSocket connection failed\"));\n }\n };\n } catch (e) {\n clearTimeout(handshakeTimeout);\n if (!settled) { settled = true; 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 && ws.readyState === WebSocket.OPEN && 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\n // Idle timeout resets on every chunk — CLI agents (Claude Code, Codex, Gemini)\n // may pause for minutes while reading files or thinking between turns.\n // 5 min idle = generous enough for multi-turn agents.\n const IDLE_MS = 300000;\n let timeout = setTimeout(onTimeout, IDLE_MS);\n function onTimeout() {\n handlers.delete(id);\n reject(new Error(\"Stream timeout\"));\n }\n function resetTimeout() {\n clearTimeout(timeout);\n timeout = setTimeout(onTimeout, IDLE_MS);\n }\n\n handlers.set(id, (msg) => {\n if (msg.type === \"llm.chunk\") {\n resetTimeout();\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 shouldReconnect = false;\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 ancestry: string[];\n componentHint: string;\n rect: { x: number; y: number; width: number; height: number };\n // Enhanced context\n parentStyles: Record<string, string>;\n siblings: string[];\n matchedCssRules: string[];\n viewport: { width: number; height: number };\n ariaAttributes: Record<string, string>;\n eventHandlers: string[];\n reactProps: Record<string, unknown> | null;\n childrenLayout: {\n tag: string;\n className: string;\n rect: { x: number; y: number; width: number; height: number };\n gapToNext: { horizontal: number; vertical: number } | null;\n margin: string;\n padding: string;\n }[];\n resolvedClasses: { className: string; css: string }[];\n // Phase 3: Deep element intelligence (unique to OpenMagic)\n themeState: {\n darkMode: boolean;\n colorScheme: string;\n htmlDataAttributes: Record<string, string>;\n };\n cssVariables: Record<string, string>;\n stackingContext: { zIndex: string; createsContext: boolean; parentZIndex: string };\n visibilityState: {\n isVisible: boolean;\n isInViewport: boolean;\n scrollTop: number;\n scrollLeft: number;\n isScrollable: boolean;\n };\n activeBreakpoints: string[];\n pseudoElements: { before: string; after: string };\n formState: { disabled: boolean; readOnly: boolean; invalid: boolean } | null;\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 // Parent container styles (critical for layout context)\n const parentStyles: Record<string, string> = {};\n if (el.parentElement && el.parentElement !== document.body) {\n const parentComputed = window.getComputedStyle(el.parentElement);\n for (const prop of IMPORTANT_STYLES) {\n parentStyles[prop] = parentComputed.getPropertyValue(prop);\n }\n }\n\n // Sibling elements (layout context — ±3 siblings around the selected element)\n const siblings: string[] = [];\n if (el.parentElement) {\n const children = Array.from(el.parentElement.children);\n const selectedIdx = children.indexOf(el);\n const start = Math.max(0, selectedIdx - 3);\n const end = Math.min(children.length, selectedIdx + 4);\n if (start > 0) siblings.push(`... ${start} elements before ...`);\n for (let i = start; i < end; i++) {\n const sib = children[i];\n const tag = sib.tagName.toLowerCase();\n const cls = (sib.className || \"\").toString().slice(0, 60);\n if (sib === el) {\n siblings.push(`[SELECTED] <${tag} class=\"${cls}\">`);\n } else {\n siblings.push(`<${tag} class=\"${cls}\">`);\n }\n }\n if (end < children.length) siblings.push(`... ${children.length - end} elements after ...`);\n }\n\n // Children layout measurements (pixel-level spacing context)\n const childrenLayout: SelectedElement[\"childrenLayout\"] = [];\n const directChildren = Array.from(el.children).slice(0, 12);\n for (let i = 0; i < directChildren.length; i++) {\n const child = directChildren[i] as HTMLElement;\n const cRect = child.getBoundingClientRect();\n const cComputed = window.getComputedStyle(child);\n let gapToNext: { horizontal: number; vertical: number } | null = null;\n if (i < directChildren.length - 1) {\n const nextRect = (directChildren[i + 1] as HTMLElement).getBoundingClientRect();\n // Use absolute gap value to handle both LTR and RTL layouts\n gapToNext = {\n vertical: Math.round(nextRect.top - cRect.bottom),\n horizontal: Math.round(Math.abs(nextRect.left - cRect.right)),\n };\n }\n childrenLayout.push({\n tag: child.tagName.toLowerCase(),\n className: (child.className || \"\").toString().slice(0, 80),\n rect: { x: Math.round(cRect.x), y: Math.round(cRect.y), width: Math.round(cRect.width), height: Math.round(cRect.height) },\n gapToNext,\n margin: cComputed.margin,\n padding: cComputed.padding,\n });\n }\n\n // Matched CSS rules from stylesheets\n const matchedCssRules = getMatchedCssRules(el);\n\n // Resolve Tailwind/utility classes to their CSS values\n const resolvedClasses = resolveClasses(el, matchedCssRules);\n\n // ARIA / accessibility attributes\n const ariaAttributes: Record<string, string> = {};\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith(\"aria-\") || attr.name === \"role\" || attr.name === \"tabindex\") {\n ariaAttributes[attr.name] = attr.value;\n }\n }\n\n // Event handlers (from element attributes and React props)\n const eventHandlers: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith(\"on\")) eventHandlers.push(attr.name);\n }\n\n // React props extraction\n const reactProps = getReactProps(el);\n\n // ── Phase 3: Deep element intelligence ──\n\n // Theme / dark mode state\n const htmlEl = document.documentElement;\n const htmlComputed = window.getComputedStyle(htmlEl);\n const htmlDataAttributes: Record<string, string> = {};\n for (const key of Object.keys(htmlEl.dataset)) {\n htmlDataAttributes[key] = htmlEl.dataset[key] || \"\";\n }\n const themeState = {\n darkMode: htmlEl.classList.contains(\"dark\")\n || htmlEl.dataset.theme === \"dark\"\n || htmlEl.dataset.mode === \"dark\"\n || window.matchMedia(\"(prefers-color-scheme: dark)\").matches,\n colorScheme: htmlComputed.colorScheme || \"\",\n htmlDataAttributes,\n };\n\n // CSS custom properties used by this element\n const cssVariables: Record<string, string> = {};\n try {\n for (const rule of matchedCssRules) {\n const varMatches = rule.matchAll(/var\\((--[a-zA-Z0-9_-]+)/g);\n for (const vm of varMatches) {\n const varName = vm[1];\n if (!cssVariables[varName]) {\n cssVariables[varName] = computed.getPropertyValue(varName).trim() || \"(unset)\";\n }\n }\n }\n // Also check inline style\n const inlineVars = (el.getAttribute(\"style\") || \"\").matchAll(/var\\((--[a-zA-Z0-9_-]+)/g);\n for (const iv of inlineVars) {\n if (!cssVariables[iv[1]]) {\n cssVariables[iv[1]] = computed.getPropertyValue(iv[1]).trim() || \"(unset)\";\n }\n }\n } catch {}\n\n // z-index stacking context\n const zIndex = computed.zIndex;\n const position = computed.position;\n const createsContext = (position !== \"static\" && zIndex !== \"auto\") || computed.opacity !== \"1\"\n || computed.transform !== \"none\" || computed.filter !== \"none\";\n const parentZIndex = el.parentElement ? window.getComputedStyle(el.parentElement).zIndex : \"auto\";\n const stackingContext = { zIndex, createsContext, parentZIndex };\n\n // Visibility and scroll state\n const isInViewport = rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;\n let isVisible = true;\n try { isVisible = el.checkVisibility?.({ checkOpacity: true, checkVisibilityCSS: true }) ?? true; } catch { isVisible = computed.display !== \"none\" && computed.visibility !== \"hidden\"; }\n const isScrollable = el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;\n const visibilityState = { isVisible, isInViewport, scrollTop: el.scrollTop, scrollLeft: el.scrollLeft, isScrollable };\n\n // Active media queries / breakpoints\n const activeBreakpoints: string[] = [];\n const breakpointsToCheck = [\n \"(max-width: 639px)\", \"(min-width: 640px)\", \"(min-width: 768px)\",\n \"(min-width: 1024px)\", \"(min-width: 1280px)\", \"(min-width: 1536px)\",\n \"(prefers-color-scheme: dark)\", \"(prefers-reduced-motion: reduce)\",\n ];\n for (const bp of breakpointsToCheck) {\n try { if (window.matchMedia(bp).matches) activeBreakpoints.push(bp); } catch {}\n }\n\n // Pseudo-element content\n let beforeContent = \"\", afterContent = \"\";\n try { beforeContent = window.getComputedStyle(el, \"::before\").content || \"\"; } catch {}\n try { afterContent = window.getComputedStyle(el, \"::after\").content || \"\"; } catch {}\n const pseudoElements = { before: beforeContent, after: afterContent };\n\n // Form state (if applicable)\n let formState: { disabled: boolean; readOnly: boolean; invalid: boolean } | null = null;\n if (el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement || el instanceof HTMLButtonElement) {\n formState = {\n disabled: (el as any).disabled || false,\n readOnly: (el as any).readOnly || false,\n invalid: (el as any).checkValidity ? !(el as any).checkValidity() : false,\n };\n }\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 ancestry: getAncestry(el),\n componentHint: getComponentHint(el),\n rect: {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n },\n parentStyles,\n siblings,\n childrenLayout,\n matchedCssRules,\n resolvedClasses,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n ariaAttributes,\n eventHandlers,\n reactProps,\n themeState,\n cssVariables,\n stackingContext,\n visibilityState,\n activeBreakpoints,\n pseudoElements,\n formState,\n };\n}\n\nfunction getAncestry(el: HTMLElement, depth: number = 5): string[] {\n const result: string[] = [];\n let current = el.parentElement;\n while (current && current !== document.body && result.length < depth) {\n const tag = current.tagName.toLowerCase();\n const cls = (typeof current.className === \"string\" ? current.className : \"\")\n .split(/\\s+/).filter(c => c.length > 1 && !c.startsWith(\"_\")).slice(0, 3).join(\".\");\n result.push(cls ? `${tag}.${cls}` : tag);\n current = current.parentElement;\n }\n return result;\n}\n\nfunction getComponentHint(el: HTMLElement): string {\n // Try to find component name from data attributes or React fiber\n let current: HTMLElement | null = el;\n while (current && current !== document.body) {\n // Check common framework data attributes\n const dataComponent = current.getAttribute(\"data-component\")\n || current.getAttribute(\"data-testid\")\n || current.getAttribute(\"data-cy\");\n if (dataComponent) return dataComponent;\n\n // React: check __reactFiber or __reactInternalInstance\n const keys = Object.keys(current);\n for (const key of keys) {\n if (key.startsWith(\"__reactFiber\") || key.startsWith(\"__reactInternalInstance\")) {\n try {\n const fiber = (current as any)[key];\n const name = fiber?.type?.name || fiber?.type?.displayName\n || fiber?.return?.type?.name || fiber?.return?.type?.displayName;\n if (name && name !== \"div\" && name !== \"span\" && name.length > 1) return name;\n } catch {}\n }\n }\n\n current = current.parentElement;\n }\n return \"\";\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 `#${CSS.escape(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(`#${CSS.escape(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 .map((c) => CSS.escape(c));\n if (classes.length > 0) {\n selector += \".\" + classes.join(\".\");\n }\n }\n\n // Add nth-of-type 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-of-type(${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// --- Matched CSS Rules ---\n\nfunction getMatchedCssRules(el: HTMLElement): string[] {\n const rules: string[] = [];\n try {\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n const cssRules = sheet.cssRules || sheet.rules;\n if (!cssRules) continue;\n for (const rule of Array.from(cssRules)) {\n if (rule instanceof CSSStyleRule) {\n try {\n if (el.matches(rule.selectorText)) {\n // Only include rules with meaningful styles (skip resets/normalizers)\n const text = rule.cssText;\n if (text.length > 10 && text.length < 500) {\n rules.push(text);\n }\n }\n } catch { /* invalid selector */ }\n }\n }\n } catch { /* cross-origin stylesheet */ }\n }\n } catch { /* stylesheet access error */ }\n return rules.slice(0, 15); // Cap at 15 rules\n}\n\n// --- React Props Extraction ---\n\nfunction getReactProps(el: HTMLElement): Record<string, unknown> | null {\n try {\n const keys = Object.keys(el);\n for (const key of keys) {\n if (key.startsWith(\"__reactFiber\") || key.startsWith(\"__reactInternalInstance\")) {\n const fiber = (el as any)[key];\n if (!fiber?.memoizedProps) continue;\n const props = fiber.memoizedProps;\n // Extract safe, serializable props (skip functions, React elements, large objects)\n const safe: Record<string, unknown> = {};\n let count = 0;\n for (const [k, v] of Object.entries(props)) {\n if (count >= 10) break;\n if (k === \"children\") continue; // Skip children (too large)\n const t = typeof v;\n if (t === \"string\" || t === \"number\" || t === \"boolean\" || v === null) {\n safe[k] = v;\n count++;\n } else if (t === \"function\") {\n safe[k] = \"[function]\";\n count++;\n } else if (Array.isArray(v)) {\n safe[k] = `[Array(${v.length})]`;\n count++;\n }\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch { /* not React or access error */ }\n return null;\n}\n\n// --- Tailwind / Utility Class Resolution ---\n\nfunction resolveClasses(el: HTMLElement, matchedRules: string[]): { className: string; css: string }[] {\n const resolved: { className: string; css: string }[] = [];\n const classes = (el.className || \"\").toString().trim().split(/\\s+/).filter(Boolean);\n\n for (const cls of classes) {\n const escaped = CSS.escape(cls);\n for (const rule of matchedRules) {\n if (rule.includes(`.${escaped}`) && rule.length < 200) {\n resolved.push({ className: cls, css: rule });\n break;\n }\n }\n if (resolved.length >= 20) break;\n }\n return resolved;\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\n","// Screenshot capture with multiple approaches and error feedback\n\nexport async function captureScreenshot(\n target?: HTMLElement\n): Promise<string | null> {\n // Approach 1: Try the simple SVG foreignObject approach\n try {\n const el = target || document.body;\n const result = await captureViaSvg(el);\n if (result) return result;\n } catch (e) {\n console.warn(\"[OpenMagic] SVG screenshot failed:\", e);\n }\n\n // Approach 2: Try capturing just the visible area as a simple canvas\n try {\n const result = await captureSimple(target);\n if (result) return result;\n } catch (e) {\n console.warn(\"[OpenMagic] Simple screenshot failed:\", e);\n }\n\n console.warn(\"[OpenMagic] All screenshot methods failed\");\n return null;\n}\n\n// Error feedback version — returns error message if failed\nexport async function captureScreenshotWithFeedback(\n target?: HTMLElement\n): Promise<{ data: string | null; error?: string }> {\n try {\n const el = target || document.body;\n const result = await captureViaSvg(el);\n if (result) return { data: result };\n } catch (e: any) {\n // Fall through to simple\n }\n\n try {\n const result = await captureSimple(target);\n if (result) return { data: result };\n } catch (e: any) {\n return { data: null, error: `Screenshot failed: ${e.message || \"unknown error\"}. Try using the image attachment button instead.` };\n }\n\n return { data: null, error: \"Screenshot capture not available on this page. Try pasting or dragging an image instead.\" };\n}\n\nasync function captureViaSvg(element: HTMLElement): Promise<string | null> {\n const rect = element.getBoundingClientRect();\n const width = Math.min(rect.width || window.innerWidth, 1920);\n const height = Math.min(rect.height || window.innerHeight, 1080);\n\n // Clone and inline styles — but limit depth to avoid huge SVGs\n const clone = cloneWithStyles(element, 0, 4);\n if (!clone) return null;\n\n const svgData = `\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 const blob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n\n return new Promise<string | null>((resolve) => {\n const img = new Image();\n const canvas = document.createElement(\"canvas\");\n const dpr = Math.min(window.devicePixelRatio || 1, 2);\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) { resolve(null); return; }\n ctx.scale(dpr, dpr);\n ctx.drawImage(img, 0, 0);\n try {\n // Compress: resize to max 1280px wide, JPEG 80% quality\n const MAX_W = 1280;\n if (canvas.width > MAX_W) {\n const ratio = MAX_W / canvas.width;\n const small = document.createElement(\"canvas\");\n small.width = MAX_W;\n small.height = Math.round(canvas.height * ratio);\n const sCtx = small.getContext(\"2d\");\n if (sCtx) {\n sCtx.drawImage(canvas, 0, 0, small.width, small.height);\n resolve(small.toDataURL(\"image/jpeg\", 0.8));\n return;\n }\n }\n resolve(canvas.toDataURL(\"image/jpeg\", 0.8));\n } catch {\n resolve(null); // Tainted canvas\n }\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n\n // 5 second timeout\n setTimeout(() => { URL.revokeObjectURL(url); resolve(null); }, 5000);\n img.src = url;\n });\n}\n\n// Simpler approach: capture just text/layout info as a basic representation\nasync function captureSimple(target?: HTMLElement): Promise<string | null> {\n // Create a simple text-based capture showing element hierarchy\n // This works as fallback when SVG approach fails\n const el = target || document.documentElement;\n const rect = el.getBoundingClientRect();\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = 400;\n canvas.height = 300;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n\n // Dark background\n ctx.fillStyle = \"#1a1a2e\";\n ctx.fillRect(0, 0, 400, 300);\n\n // Draw element info\n ctx.fillStyle = \"#e0e0e0\";\n ctx.font = \"14px system-ui\";\n ctx.fillText(`Element: <${el.tagName.toLowerCase()}>`, 20, 30);\n ctx.fillStyle = \"#888\";\n ctx.font = \"12px system-ui\";\n ctx.fillText(`Size: ${Math.round(rect.width)}x${Math.round(rect.height)}`, 20, 55);\n ctx.fillText(`Classes: ${(el.className || \"\").toString().slice(0, 40)}`, 20, 75);\n ctx.fillText(`Page: ${window.location.pathname}`, 20, 95);\n ctx.fillStyle = \"#6c5ce7\";\n ctx.font = \"11px system-ui\";\n ctx.fillText(\"(Full screenshot unavailable — context sent as metadata)\", 20, 130);\n\n return canvas.toDataURL(\"image/png\");\n}\n\nfunction cloneWithStyles(source: HTMLElement, depth: number, maxDepth: number): HTMLElement | null {\n if (depth > maxDepth) return null;\n\n try {\n const clone = source.cloneNode(false) as HTMLElement;\n\n // Remove problematic elements\n if (clone.tagName === \"SCRIPT\" || clone.tagName === \"STYLE\" || clone.tagName === \"SVG\" ||\n clone.tagName === \"CANVAS\" || clone.tagName === \"VIDEO\" || clone.tagName === \"IFRAME\") {\n return null;\n }\n\n // Inline key styles only (not all — reduces size)\n const computed = window.getComputedStyle(source);\n const keyProps = [\"display\", \"position\", \"width\", \"height\", \"margin\", \"padding\",\n \"color\", \"background-color\", \"background\", \"font-size\", \"font-weight\", \"font-family\",\n \"border\", \"border-radius\", \"flex-direction\", \"justify-content\", \"align-items\", \"gap\",\n \"grid-template-columns\", \"text-align\", \"overflow\"];\n let css = \"\";\n for (const p of keyProps) {\n const v = computed.getPropertyValue(p);\n if (v && v !== \"normal\" && v !== \"none\" && v !== \"auto\" && v !== \"0px\") {\n css += `${p}:${v};`;\n }\n }\n clone.setAttribute(\"style\", css);\n\n // Clone children with depth limit\n for (let i = 0; i < source.children.length && i < 20; i++) {\n const child = cloneWithStyles(source.children[i] as HTMLElement, depth + 1, maxDepth);\n if (child) clone.appendChild(child);\n }\n\n return clone;\n } catch {\n return null;\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 { inspectElement, showHighlight, hideHighlight, type SelectedElement } from \"./services/dom-inspector.js\";\nimport { captureScreenshotWithFeedback } from \"./services/capture.js\";\nimport { installNetworkCapture, installConsoleCapture, buildContext, getNetworkLogs, getConsoleLogs } from \"./services/context-builder.js\";\n\n// ── SVG Icons (Lucide-style) ─────────────────────────────────────\nconst ICON = {\n sparkle: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.582a.5.5 0 0 1 0 .962L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"/></svg>`,\n crosshair: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"22\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"6\" y1=\"12\" x2=\"2\" y2=\"12\"/><line x1=\"12\" y1=\"6\" x2=\"12\" y2=\"2\"/><line x1=\"12\" y1=\"22\" x2=\"12\" y2=\"18\"/></svg>`,\n camera: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/></svg>`,\n chat: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>`,\n settings: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`,\n send: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/></svg>`,\n x: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`,\n externalLink: `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/><polyline points=\"15 3 21 3 21 9\"/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"/></svg>`,\n check: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"20 6 9 17 4 12\"/></svg>`,\n copy: `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg>`,\n grip: `<svg width=\"7\" height=\"14\" viewBox=\"0 0 8 14\" fill=\"currentColor\"><circle cx=\"2\" cy=\"2\" r=\"1.2\"/><circle cx=\"6\" cy=\"2\" r=\"1.2\"/><circle cx=\"2\" cy=\"7\" r=\"1.2\"/><circle cx=\"6\" cy=\"7\" r=\"1.2\"/><circle cx=\"2\" cy=\"12\" r=\"1.2\"/><circle cx=\"6\" cy=\"12\" r=\"1.2\"/></svg>`,\n network: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/></svg>`,\n activity: `<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"22 12 18 12 15 21 9 3 6 12 2 12\"/></svg>`,\n bug: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m8 2 1.88 1.88M14.12 3.88 16 2M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\"/><path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6\"/><path d=\"M12 20v-9\"/><path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\"/><path d=\"M6 13H2\"/><path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\"/><path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\"/><path d=\"M22 13h-4\"/><path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\"/></svg>`,\n paperclip: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48\"/></svg>`,\n image: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\"/><circle cx=\"9\" cy=\"9\" r=\"2\"/><path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\"/></svg>`,\n trash: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>`,\n minus: `<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>`,\n};\n\n// ── Model Registry (inline for browser bundle) ───────────────────\nconst MODEL_REGISTRY: Record<string, { name: string; models: { id: string; name: string }[]; keyPlaceholder: string; local?: boolean; keyUrl?: string }> = {\n \"claude-code\": { name: \"Claude Code (CLI)\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"claude-code\", name: \"Claude Code\" },\n ]},\n \"codex-cli\": { name: \"Codex CLI\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"codex-cli\", name: \"Codex CLI\" },\n ]},\n \"gemini-cli\": { name: \"Gemini CLI\", keyPlaceholder: \"not required\", local: true, models: [\n { id: \"gemini-cli\", name: \"Gemini CLI\" },\n ]},\n openai: { name: \"OpenAI\", keyUrl: \"https://platform.openai.com/api-keys\", keyPlaceholder: \"sk-...\", models: [\n { id: \"gpt-5.4\", name: \"GPT-5.4\" }, { id: \"gpt-5.4-mini\", name: \"GPT-5.4 Mini\" },\n { id: \"gpt-5.2\", name: \"GPT-5.2 Thinking\" }, { id: \"o3\", name: \"o3\" }, { id: \"o4-mini\", name: \"o4-mini\" },\n { id: \"gpt-4.1\", name: \"GPT-4.1\" }, { id: \"gpt-4.1-mini\", name: \"GPT-4.1 Mini\" },\n ]},\n anthropic: { name: \"Anthropic\", keyUrl: \"https://console.anthropic.com/settings/keys\", keyPlaceholder: \"sk-ant-...\", models: [\n { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\" }, { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\" },\n { id: \"claude-haiku-4-5-20251001\", name: \"Claude Haiku 4.5\" },\n ]},\n google: { name: \"Google Gemini\", keyUrl: \"https://aistudio.google.com/apikey\", keyPlaceholder: \"AIza...\", models: [\n { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro\" }, { id: \"gemini-3-flash-preview\", name: \"Gemini 3 Flash\" },\n { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\" }, { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\" },\n ]},\n xai: { name: \"xAI (Grok)\", keyUrl: \"https://console.x.ai/team/default/api-keys\", keyPlaceholder: \"xai-...\", models: [\n { id: \"grok-4.20-0309-reasoning\", name: \"Grok 4.20 Reasoning\" }, { id: \"grok-4-1-fast-non-reasoning\", name: \"Grok 4.1 Fast\" },\n ]},\n deepseek: { name: \"DeepSeek\", keyUrl: \"https://platform.deepseek.com/api_keys\", keyPlaceholder: \"sk-...\", models: [\n { id: \"deepseek-chat\", name: \"DeepSeek V3.2\" }, { id: \"deepseek-reasoner\", name: \"DeepSeek R1\" },\n ]},\n mistral: { name: \"Mistral\", keyUrl: \"https://console.mistral.ai/api-keys\", keyPlaceholder: \"...\", models: [\n { id: \"mistral-large-3-25-12\", name: \"Mistral Large 3\" }, { id: \"codestral-2508\", name: \"Codestral\" }, { id: \"devstral-2-25-12\", name: \"Devstral 2\" },\n ]},\n groq: { name: \"Groq\", keyUrl: \"https://console.groq.com/keys\", keyPlaceholder: \"gsk_...\", models: [\n { id: \"meta-llama/llama-4-scout-17b-16e-instruct\", name: \"Llama 4 Scout\" }, { id: \"llama-3.3-70b-versatile\", name: \"Llama 3.3 70B\" },\n ]},\n minimax: { name: \"MiniMax\", keyUrl: \"https://platform.minimax.chat/user-center/basic-information/interface-key\", keyPlaceholder: \"MiniMax key...\", models: [\n { id: \"MiniMax-M2.7\", name: \"MiniMax M2.7\" }, { id: \"MiniMax-M2.5\", name: \"MiniMax M2.5\" },\n ]},\n moonshot: { name: \"Kimi (Moonshot)\", keyUrl: \"https://platform.moonshot.cn/console/api-keys\", keyPlaceholder: \"Moonshot key...\", models: [\n { id: \"kimi-k2.5\", name: \"Kimi K2.5\" }, { id: \"kimi-k2-thinking\", name: \"Kimi K2 Thinking\" },\n ]},\n qwen: { name: \"Qwen (Alibaba)\", keyUrl: \"https://dashscope.console.aliyun.com/apiKey\", keyPlaceholder: \"DashScope key...\", models: [\n { id: \"qwen3.5-plus\", name: \"Qwen 3.5 Plus\" }, { id: \"qwen-max\", name: \"Qwen Max\" },\n ]},\n zhipu: { name: \"Zhipu AI (GLM)\", keyUrl: \"https://open.bigmodel.cn/usercenter/apikeys\", keyPlaceholder: \"Zhipu key...\", models: [\n { id: \"glm-5\", name: \"GLM-5\" }, { id: \"glm-4.7\", name: \"GLM-4.7\" },\n ]},\n doubao: { name: \"Doubao (ByteDance)\", keyUrl: \"https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey\", keyPlaceholder: \"Volcano key...\", models: [\n { id: \"doubao-seed-2-0-pro\", name: \"Doubao Seed 2.0 Pro\" }, { id: \"doubao-seed-2-0-code\", name: \"Doubao Seed 2.0 Code\" },\n ]},\n ollama: { name: \"Ollama (Local)\", keyPlaceholder: \"not required\", local: true, models: [] },\n openrouter: { name: \"OpenRouter\", keyUrl: \"https://openrouter.ai/settings/keys\", keyPlaceholder: \"sk-or-...\", models: [] },\n};\n\nfunction encodeBase64Utf8(value: string): string {\n const bytes = new TextEncoder().encode(value);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction decodeBase64Utf8(value: string): string {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n}\n\nconst CURRENT_VERSION = \"0.42.0\";\n\n// ── State ────────────────────────────────────────────────────────\nconst state = {\n connected: false,\n panelOpen: false,\n activePanel: \"\" as \"\" | \"chat\" | \"settings\",\n selecting: false,\n selectedElement: null as SelectedElement | null,\n screenshot: null as string | null,\n messages: [] as { role: \"user\" | \"assistant\" | \"system\"; content: string }[],\n streaming: false,\n streamContent: \"\",\n provider: \"\",\n model: \"\",\n hasApiKey: false,\n configuredProviders: {} as Record<string, boolean>, // which providers have keys\n detectedClis: [] as { id: string; name: string; installed: boolean; authenticated: boolean; version?: string }[],\n roots: [] as string[],\n updateAvailable: false,\n latestVersion: \"\",\n saveStatus: \"\" as \"\" | \"saving\" | \"saved\" | \"error\",\n networkCapture: false, // whether network panel is showing\n attachments: [] as string[], // base64 image data URLs attached to next message\n groundedFiles: [] as string[], // last grounded file paths for context chips\n minimized: false,\n};\n\n// ── DOM refs (created once) ──────────────────────────────────────\nlet shadow: ShadowRoot;\nlet $toolbar: HTMLDivElement;\nlet $promptInput: HTMLInputElement;\nlet $promptCtx: HTMLDivElement;\nlet $panel: HTMLDivElement;\nlet $panelBody: HTMLDivElement;\n\n// ── Initialize ───────────────────────────────────────────────────\n// ── State Persistence (survives HMR page reloads) ────────────────\nfunction saveState() {\n try {\n // Prune messages for storage: keep first 5 + last 45, strip large diff payloads\n let msgs = state.messages;\n if (msgs.length > 50) {\n msgs = [...msgs.slice(0, 5), ...msgs.slice(-45)];\n }\n const prunedMsgs = msgs.map(m => {\n if (m.content.startsWith(\"__DIFF__\") && m.content.length > 500) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n return { ...m, content: `Applied ${diff.type || \"edit\"} to ${diff.file || \"file\"}` };\n } catch { return m; }\n }\n return m;\n });\n sessionStorage.setItem(\"__om_state__\", JSON.stringify({\n messages: prunedMsgs,\n provider: state.provider,\n model: state.model,\n panelOpen: state.panelOpen,\n activePanel: state.activePanel,\n }));\n } catch { /* quota exceeded or unavailable */ }\n}\n\nfunction restoreState() {\n try {\n const saved = JSON.parse(sessionStorage.getItem(\"__om_state__\") || \"{}\");\n if (saved.messages?.length) state.messages = saved.messages;\n if (saved.provider) state.provider = saved.provider;\n if (saved.model) state.model = saved.model;\n if (saved.panelOpen) { state.panelOpen = saved.panelOpen; state.activePanel = saved.activePanel || \"\"; }\n } catch { /* parse error or unavailable */ }\n}\n\nfunction init() {\n if (document.querySelector(\"openmagic-toolbar\")) return;\n\n // Restore chat history and settings from session storage (survives HMR)\n restoreState();\n\n const host = document.createElement(\"openmagic-toolbar\");\n host.dataset.openmagic = \"true\";\n shadow = host.attachShadow({ mode: \"closed\" });\n\n const style = document.createElement(\"style\");\n style.textContent = TOOLBAR_CSS;\n shadow.appendChild(style);\n\n const root = document.createElement(\"div\");\n shadow.appendChild(root);\n\n // Build DOM structure ONCE\n root.innerHTML = buildStaticDOM();\n\n // Cache refs\n $toolbar = root.querySelector(\".om-toolbar\")!;\n $promptInput = root.querySelector(\".om-prompt-input\")!;\n $promptCtx = root.querySelector(\".om-prompt-context\")!;\n $panel = root.querySelector(\".om-panel\")!;\n $panelBody = root.querySelector(\".om-panel-body\")!;\n\n document.body.appendChild(host);\n\n // Attach event delegation ONCE\n attachGlobalEvents(root);\n setupDraggable();\n\n // Restore persisted toolbar position\n try {\n const pos = JSON.parse(localStorage.getItem(\"__om_pos__\") || \"\");\n if (pos?.left && pos?.top) {\n $toolbar.style.left = pos.left;\n $toolbar.style.top = pos.top;\n $toolbar.style.right = \"auto\";\n $toolbar.style.bottom = \"auto\";\n }\n } catch {}\n\n installNetworkCapture();\n installConsoleCapture();\n checkForUpdates();\n\n // Connect to server — same origin (single port)\n const currentScript = document.querySelector('script[data-openmagic-token]') as HTMLScriptElement | null;\n const token = currentScript?.dataset.openmagicToken || (window as any).__OPENMAGIC_TOKEN__;\n const wsPort = parseInt(window.location.port, 10) || (window.location.protocol === \"https:\" ? 443 : 80);\n if (token) {\n ws.connect(wsPort, token)\n .then(() => {\n state.connected = true;\n updateStatusDot();\n return ws.request(\"config.get\");\n })\n .then((msg: any) => {\n // Store detected CLI agents from server\n state.detectedClis = msg.payload?.detectedClis || [];\n\n // Merge server config with restored state (restored state takes precedence for provider/model)\n const serverProvider = msg.payload?.provider || \"\";\n const serverModel = msg.payload?.model || \"\";\n state.provider = state.provider || serverProvider;\n state.model = state.model || serverModel;\n state.configuredProviders = msg.payload?.apiKeys || {};\n\n // Local providers (CLI-based) are always \"configured\" — no API key needed\n // Also mark detected+authenticated CLIs as configured\n for (const cli of state.detectedClis) {\n if (cli.installed && cli.authenticated) {\n state.configuredProviders[cli.id] = true;\n }\n }\n const provMeta = MODEL_REGISTRY[state.provider];\n state.hasApiKey = !!(state.configuredProviders[state.provider] || provMeta?.local);\n state.roots = msg.payload?.roots || [];\n\n // Restore panel state if we had it open before refresh\n if (state.panelOpen && state.activePanel) {\n openPanel(state.activePanel as \"chat\" | \"settings\");\n } else if (!state.provider || (!state.hasApiKey && !Object.values(state.configuredProviders).some(Boolean) && !provMeta?.local)) {\n openPanel(\"settings\");\n }\n updatePillButtons();\n updateModelSwitcher();\n })\n .catch(() => {\n state.connected = false;\n updateStatusDot();\n });\n }\n}\n\nfunction buildStaticDOM(): string {\n return `\n <div class=\"om-toolbar\">\n <div class=\"om-toolbar-header\">\n <span class=\"om-grab\">${ICON.grip}</span>\n <span class=\"om-pill-brand\">\n <span class=\"om-pill-text\">✨OpenMagic🪄</span>\n </span>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn\" data-action=\"select\" title=\"Select element\">${ICON.crosshair}</button>\n <button class=\"om-pill-btn\" data-action=\"screenshot\" title=\"Screenshot\">${ICON.camera}</button>\n <button class=\"om-pill-btn\" data-action=\"network\" title=\"Network & Performance\">${ICON.activity}</button>\n <span class=\"om-pill-divider\"></span>\n <button class=\"om-pill-btn\" data-action=\"chat\" title=\"Chat\">${ICON.chat}</button>\n <button class=\"om-pill-btn\" data-action=\"settings\" title=\"Settings\">${ICON.settings}</button>\n <button class=\"om-pill-btn\" data-action=\"minimize\" title=\"Minimize\">${ICON.minus}</button>\n <span class=\"om-status-dot disconnected\"></span>\n </div>\n <div class=\"om-panel om-hidden\">\n <div class=\"om-panel-header\">\n <span class=\"om-panel-title\"></span>\n <span class=\"om-panel-version\">v${CURRENT_VERSION}</span>\n <button class=\"om-panel-bug\" data-action=\"report-issue\" title=\"Report a bug on GitHub\">${ICON.bug}</button>\n <button class=\"om-panel-clear\" data-action=\"clear-chat\" title=\"Clear chat\">${ICON.trash}</button>\n <button class=\"om-panel-close\" data-action=\"close-panel\">${ICON.x}</button>\n </div>\n <div class=\"om-panel-body\"></div>\n </div>\n <div class=\"om-apply-bar om-hidden\">\n <span class=\"om-apply-bar-text\"></span>\n <div class=\"om-diff-actions\">\n <button class=\"om-btn om-btn-sm\" data-action=\"apply-all\">Apply All</button>\n <button class=\"om-btn-secondary om-btn-sm\" data-action=\"reject-all\">Reject All</button>\n </div>\n </div>\n <div class=\"om-prompt-attachments\"></div>\n <div class=\"om-prompt-row\">\n <div class=\"om-prompt-context\"></div>\n <select class=\"om-model-switcher\" data-field=\"quick-model\" title=\"Switch model\"></select>\n <button class=\"om-prompt-attach\" data-action=\"attach-image\" title=\"Attach image\">${ICON.paperclip}</button>\n <input class=\"om-prompt-input\" type=\"text\" placeholder=\"Describe what to change...\" autocomplete=\"off\" />\n <button class=\"om-prompt-send\" data-action=\"prompt-send\">${ICON.send}</button>\n <input type=\"file\" class=\"om-file-input om-hidden\" accept=\"image/*\" multiple />\n </div>\n </div>`;\n}\n\n// ── Event Delegation (attached ONCE) ─────────────────────────────\nfunction attachGlobalEvents(root: HTMLElement) {\n // Click delegation\n root.addEventListener(\"click\", (e) => {\n const target = (e.target as HTMLElement).closest(\"[data-action]\") as HTMLElement | null;\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n const action = target.dataset.action!;\n handleAction(action, target);\n });\n\n // Change delegation (dropdowns)\n root.addEventListener(\"change\", (e) => {\n const target = e.target as HTMLSelectElement;\n const field = target.dataset.field;\n if (!field) return;\n\n if (field === \"provider\") {\n state.provider = target.value;\n state.model = MODEL_REGISTRY[state.provider]?.models[0]?.id || \"\";\n state.hasApiKey = state.configuredProviders[state.provider] || MODEL_REGISTRY[state.provider]?.local || false;\n state.saveStatus = \"\";\n refreshPanelContent();\n } else if (field === \"model\") {\n state.model = target.value;\n } else if (field === \"quick-model\") {\n state.model = target.value;\n saveState(); // persist model switch\n }\n });\n\n // Prompt input: Enter to send\n $promptInput.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendPrompt();\n }\n });\n\n // File input change handler\n const fileInput = root.querySelector(\".om-file-input\") as HTMLInputElement;\n if (fileInput) {\n fileInput.addEventListener(\"change\", () => {\n handleFileSelect(fileInput.files);\n fileInput.value = \"\"; // Reset so same file can be selected again\n });\n }\n\n // Drag and drop on prompt area\n const promptRow = root.querySelector(\".om-prompt-row\");\n if (promptRow) {\n promptRow.addEventListener(\"dragover\", (e) => {\n e.preventDefault();\n (promptRow as HTMLElement).style.borderColor = \"rgba(108, 92, 231, 0.5)\";\n });\n promptRow.addEventListener(\"dragleave\", () => {\n (promptRow as HTMLElement).style.borderColor = \"\";\n });\n promptRow.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n (promptRow as HTMLElement).style.borderColor = \"\";\n const dt = (e as DragEvent).dataTransfer;\n if (dt?.files?.length) handleFileSelect(dt.files);\n });\n\n // Also handle paste with images\n $promptInput.addEventListener(\"paste\", (e) => {\n const items = (e as ClipboardEvent).clipboardData?.items;\n if (!items) return;\n for (let i = 0; i < items.length; i++) {\n if (items[i].type.startsWith(\"image/\")) {\n const file = items[i].getAsFile();\n if (file) {\n const dt = new DataTransfer();\n dt.items.add(file);\n handleFileSelect(dt.files);\n }\n }\n }\n });\n }\n\n // Listen for reconnection events\n ws.onMessage((msg: any) => {\n if (msg.type === \"reconnected\") {\n state.connected = true;\n updateStatusDot();\n }\n });\n\n // Global keyboard shortcuts (scoped to avoid stealing host app shortcuts)\n document.addEventListener(\"keydown\", (e) => {\n // Ctrl/Cmd + Shift + O: toggle toolbar — always works (unique combo)\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \"O\" || e.key === \"o\")) {\n e.preventDefault();\n if (state.minimized) {\n state.minimized = false;\n // Restore toolbar elements\n const headerBtns = $toolbar.querySelectorAll(\".om-pill-btn:not([data-action='minimize']), .om-pill-divider, .om-status-dot\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"\");\n const promptRow = shadow.querySelector(\".om-prompt-row\") as HTMLElement;\n if (promptRow) promptRow.classList.remove(\"om-hidden\");\n } else if (state.panelOpen) {\n closePanel();\n } else {\n openPanel(\"chat\");\n }\n return;\n }\n // Ctrl/Cmd + Shift + K: focus prompt input (Shift avoids stealing Cmd+K from host apps)\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \"k\" || e.key === \"K\")) {\n e.preventDefault();\n if (!state.panelOpen) openPanel(\"chat\");\n $promptInput.focus();\n return;\n }\n // Ctrl/Cmd + Z: undo last applied diff (only when toolbar is focused)\n if ((e.ctrlKey || e.metaKey) && (e.key === \"z\" || e.key === \"Z\") && !e.shiftKey) {\n if (shadow.activeElement) {\n const undoBtn = shadow.querySelector('[data-action=\"undo-diff\"]') as HTMLElement;\n if (undoBtn) { e.preventDefault(); undoDiff(undoBtn); return; }\n }\n }\n // Ctrl/Cmd + . : apply all pending diffs\n if ((e.ctrlKey || e.metaKey) && e.key === \".\") {\n const applyAllBtn = shadow.querySelector('[data-action=\"apply-all\"]') as HTMLElement;\n if (applyAllBtn && !shadow.querySelector(\".om-apply-bar.om-hidden\")) {\n e.preventDefault();\n handleAction(\"apply-all\", applyAllBtn);\n return;\n }\n }\n // Escape: only handle if the active element is inside the toolbar shadow DOM\n // or if we're in select mode. Don't steal from host app inputs.\n if (e.key === \"Escape\") {\n if (state.selecting) return; // select mode has its own ESC handler\n if (state.panelOpen) {\n closePanel();\n e.preventDefault();\n }\n }\n });\n\n // Ctrl/Cmd + Enter in prompt: send\n $promptInput.addEventListener(\"keydown\", (e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === \"Enter\") {\n e.preventDefault();\n sendPrompt();\n }\n });\n}\n\nfunction resolveFilePath(rel: string): string {\n return state.roots.length > 0 ? state.roots[0] + \"/\" + rel : rel;\n}\n\n// ── 4-Layer Diff Matching (Aider-style) ──────────────────────────\n// Layer 1: Exact trimmed-line match (current behavior)\n// Layer 2: Indentation-adjusted match (handles LLM indentation errors)\n// Layer 3: Similarity-based fuzzy match (0.8 threshold)\n\nfunction fuzzyLineMatch(content: string, search: string): { start: number; end: number; replace?: string } | null {\n const searchLines = search.split('\\n');\n const nonEmptySearch = searchLines.map(l => l.trim()).filter(l => l.length > 0);\n if (nonEmptySearch.length === 0) return null;\n const contentLines = content.split('\\n');\n\n // Layer 1: Trimmed line-by-line exact match\n for (let i = 0; i <= contentLines.length - nonEmptySearch.length; i++) {\n let allMatch = true;\n let matchLen = 0;\n let si = 0;\n for (let ci = i; ci < contentLines.length && si < nonEmptySearch.length; ci++) {\n if (contentLines[ci].trim() === \"\") { matchLen++; continue; } // skip blank lines in content\n if (contentLines[ci].trim() !== nonEmptySearch[si]) { allMatch = false; break; }\n si++; matchLen++;\n }\n if (allMatch && si === nonEmptySearch.length) {\n return lineRangeToOffsets(content, contentLines, i, matchLen);\n }\n }\n\n // Layer 2: Indentation-adjusted match\n // Strip leading whitespace from search lines, find match, compute indent delta\n const strippedSearch = searchLines.map(l => l.trimStart());\n for (let i = 0; i <= contentLines.length - strippedSearch.length; i++) {\n let allMatch = true;\n for (let j = 0; j < strippedSearch.length; j++) {\n if (strippedSearch[j] === \"\") continue; // skip blank search lines\n if (contentLines[i + j].trimStart() !== strippedSearch[j].trimEnd()) {\n allMatch = false; break;\n }\n }\n if (allMatch) {\n return lineRangeToOffsets(content, contentLines, i, strippedSearch.length);\n }\n }\n\n // Layer 3: Similarity-based fuzzy match (sliding window)\n const searchStr = nonEmptySearch.join(\"\\n\").toLowerCase();\n const searchLen = nonEmptySearch.length;\n let bestScore = 0;\n let bestStart = -1;\n let bestLen = 0;\n\n // Try windows of size searchLen ± 20%\n const minWin = Math.max(1, Math.floor(searchLen * 0.8));\n const maxWin = Math.min(contentLines.length, Math.ceil(searchLen * 1.2));\n\n for (let winSize = minWin; winSize <= maxWin; winSize++) {\n for (let i = 0; i <= contentLines.length - winSize; i++) {\n const windowStr = contentLines.slice(i, i + winSize)\n .map(l => l.trim()).filter(l => l).join(\"\\n\").toLowerCase();\n const score = similarity(searchStr, windowStr);\n if (score > bestScore) {\n bestScore = score; bestStart = i; bestLen = winSize;\n }\n }\n }\n\n if (bestScore >= 0.8 && bestStart >= 0) {\n return lineRangeToOffsets(content, contentLines, bestStart, bestLen);\n }\n\n return null;\n}\n\nfunction lineRangeToOffsets(content: string, lines: string[], start: number, count: number): { start: number; end: number } {\n let startOffset = 0;\n for (let k = 0; k < start; k++) startOffset += lines[k].length + 1;\n let endOffset = startOffset;\n for (let k = start; k < start + count; k++) endOffset += lines[k].length + 1;\n if (endOffset > 0 && endOffset <= content.length && content[endOffset - 1] === '\\n') endOffset--;\n return { start: startOffset, end: endOffset };\n}\n\n// Jaccard-ish similarity on character trigrams (fast, good enough for code)\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1;\n if (!a || !b) return 0;\n const trigramsA = new Set<string>();\n const trigramsB = new Set<string>();\n for (let i = 0; i <= a.length - 3; i++) trigramsA.add(a.slice(i, i + 3));\n for (let i = 0; i <= b.length - 3; i++) trigramsB.add(b.slice(i, i + 3));\n if (trigramsA.size === 0 || trigramsB.size === 0) return 0;\n let intersection = 0;\n for (const t of trigramsA) { if (trigramsB.has(t)) intersection++; }\n return intersection / (trigramsA.size + trigramsB.size - intersection);\n}\n\nasync function applyDiff(target: HTMLElement) {\n const file = target.dataset.file;\n const searchB64 = target.dataset.search;\n const replaceB64 = target.dataset.replace;\n if (!file || !searchB64 || !replaceB64) return;\n\n // Instant visual feedback — disable button and show spinner BEFORE any async work\n (target as HTMLButtonElement).disabled = true;\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n target.style.opacity = \"0.5\";\n target.style.pointerEvents = \"none\";\n\n const card = target.closest(\".om-diff-card\") as HTMLElement | null;\n if (card) {\n const actions = card.querySelector(\".om-diff-actions\");\n if (actions) actions.innerHTML = '<span class=\"om-spinner\"></span> Applying...';\n }\n\n // Force browser repaint before starting async work\n await new Promise(r => requestAnimationFrame(r));\n\n let search: string, replace: string;\n try {\n search = decodeBase64Utf8(searchB64);\n replace = decodeBase64Utf8(replaceB64);\n } catch {\n state.messages.push({ role: \"system\", content: `Failed to decode diff data for ${file}` });\n refreshPanelContent();\n return;\n }\n\n const filePath = resolveFilePath(file);\n\n try {\n // Handle create (empty search = write entire file)\n if (!search && replace) {\n const writeResult = await ws.request(\"fs.write\", { path: filePath, content: replace });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) state.messages[parseInt(idx)] = { role: \"system\", content: `Created ${file}` };\n else state.messages.push({ role: \"system\", content: `Created ${file}` });\n }\n refreshPanelContent();\n scrollChatToBottom();\n return;\n }\n\n // Try primary path, then fallbacks if it fails\n let content: string | undefined;\n let resolvedPath = filePath;\n\n // Try reading from multiple paths\n const pathsToTry = [filePath];\n if (file !== filePath) pathsToTry.push(file);\n const basename = file.split(\"/\").pop() || file;\n const root = state.roots[0] || \"\";\n const baseInRoot = root ? `${root}/${basename}` : basename;\n if (baseInRoot !== filePath && baseInRoot !== file) pathsToTry.push(baseInRoot);\n\n for (const tryPath of pathsToTry) {\n const r = await ws.request(\"fs.read\", { path: tryPath }).catch(() => null);\n const c = r?.payload?.content;\n if (c !== undefined && c !== null) {\n content = String(c);\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (!content) {\n state.messages.push({ role: \"system\", content: `Could not read ${file} — tried: ${pathsToTry.join(\", \")}` });\n } else {\n // Try exact match first\n const exactCount = content.split(search).length - 1;\n\n if (exactCount === 1) {\n // Exact match — apply directly\n const writeResult = await ws.request(\"fs.write\", { path: resolvedPath, content: content.replace(search, replace) });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file} - ${writeResult.payload?.error || \"unknown\"}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) {\n state.messages[parseInt(idx)] = { role: \"system\", content: `Applied change to ${file}. Reloading...` };\n } else {\n state.messages.push({ role: \"system\", content: `Applied change to ${file}. Reloading...` });\n }\n }\n } else if (exactCount > 1) {\n state.messages.push({ role: \"system\", content: `Found ${exactCount} exact matches in ${file} — expected 1. Edit not applied.` });\n } else {\n // No exact match — try fuzzy line-based matching\n const fuzzyResult = fuzzyLineMatch(content, search);\n if (fuzzyResult) {\n const newContent = content.slice(0, fuzzyResult.start) + replace + content.slice(fuzzyResult.end);\n const writeResult = await ws.request(\"fs.write\", { path: resolvedPath, content: newContent });\n if (writeResult?.payload?.ok === false) {\n state.messages.push({ role: \"system\", content: `Write failed: ${file} - ${writeResult.payload?.error || \"unknown\"}` });\n } else {\n const idx = card?.dataset.diffIdx;\n if (idx !== undefined) {\n state.messages[parseInt(idx)] = { role: \"system\", content: `Applied change to ${file} (fuzzy match). Reloading...` };\n } else {\n state.messages.push({ role: \"system\", content: `Applied change to ${file} (fuzzy match). Reloading...` });\n }\n }\n } else {\n state.messages.push({ role: \"system\", content: `No matching code found in ${file}. The file may have changed since the suggestion.` });\n }\n }\n }\n } catch (e: any) {\n state.messages.push({ role: \"system\", content: `Failed to apply: ${file} — ${e.message}` });\n }\n\n refreshPanelContent();\n scrollChatToBottom();\n\n // Auto-reload page after 1.5s so user sees the change\n // (HMR-based dev servers handle this automatically, but static servers don't)\n // Skip reload during batch apply-all (batchMode flag)\n if (!(applyDiff as any)._batchMode) {\n setTimeout(() => { window.location.reload(); }, 1500);\n }\n}\n\nfunction rejectDiff(target: HTMLElement) {\n // Instant feedback\n (target as HTMLButtonElement).disabled = true;\n target.style.opacity = \"0.5\";\n\n const idx = target.dataset.idx;\n if (idx !== undefined) {\n const i = parseInt(idx);\n try {\n const diff = JSON.parse(decodeBase64Utf8(state.messages[i]?.content.slice(8) || \"\"));\n // Feedback to LLM: include what was rejected so it can adjust on next turn\n const searchPreview = (diff.search || \"\").split(\"\\n\")[0].slice(0, 80);\n const replacePreview = (diff.replace || \"\").split(\"\\n\")[0].slice(0, 80);\n state.messages[i] = { role: \"system\", content: `Rejected change to ${diff.file || \"file\"}: \"${searchPreview}\" → \"${replacePreview}\"` };\n } catch {\n state.messages[i] = { role: \"system\", content: \"Change rejected\" };\n }\n }\n refreshPanelContent();\n scrollChatToBottom();\n}\n\nfunction updateApplyBar(count: number) {\n const bar = shadow.querySelector(\".om-apply-bar\") as HTMLElement;\n if (!bar) return;\n if (count > 0) {\n bar.classList.remove(\"om-hidden\");\n const text = bar.querySelector(\".om-apply-bar-text\");\n if (text) text.textContent = `${count} change${count > 1 ? \"s\" : \"\"} ready`;\n } else {\n bar.classList.add(\"om-hidden\");\n }\n}\n\nfunction hideApplyBar() {\n const bar = shadow.querySelector(\".om-apply-bar\") as HTMLElement;\n if (bar) bar.classList.add(\"om-hidden\");\n}\n\nasync function undoDiff(target: HTMLElement) {\n const file = target.dataset.file;\n if (!file) return;\n const filePath = resolveFilePath(file);\n try {\n const result = await ws.request(\"fs.undo\", { path: filePath });\n if (result?.payload?.ok) {\n state.messages.push({ role: \"system\", content: `Reverted change to ${file}` });\n } else {\n state.messages.push({ role: \"system\", content: `No backup found for ${file}` });\n }\n } catch {\n state.messages.push({ role: \"system\", content: `Could not revert ${file} — backup may not exist` });\n }\n refreshPanelContent();\n}\n\nasync function handleAction(action: string, target: HTMLElement) {\n switch (action) {\n case \"select\": toggleSelectMode(); break;\n case \"screenshot\": takeScreenshot(); break;\n case \"chat\": togglePanel(\"chat\"); break;\n case \"settings\": togglePanel(\"settings\"); break;\n case \"close-panel\": closePanel(); break;\n case \"prompt-send\": sendPrompt(); break;\n case \"save-settings\": saveSettings(); break;\n case \"get-key\": {\n const url = target.dataset.url;\n if (url) window.open(url, \"_blank\", \"noopener\");\n break;\n }\n case \"change-key\": {\n // Show the hidden key input field\n const changeRow = shadow.querySelector(\"[data-key-change]\");\n if (changeRow) changeRow.classList.remove(\"om-hidden\");\n target.style.display = \"none\";\n break;\n }\n case \"network\": togglePanel(\"chat\"); captureNetworkProfile(); break;\n case \"attach-image\": triggerFileAttach(); break;\n case \"remove-attachment\": {\n const idx = parseInt(target.dataset.idx || \"0\", 10);\n state.attachments.splice(idx, 1);\n renderAttachments();\n break;\n }\n case \"apply-diff\": applyDiff(target); break;\n case \"reject-diff\": rejectDiff(target); break;\n case \"apply-all\": {\n const buttons = Array.from(shadow.querySelectorAll(`[data-action=\"apply-diff\"]`));\n if (buttons.length === 0) break;\n // Snapshot files before batch for rollback\n const filesToSnapshot = new Set<string>();\n for (const btn of buttons) {\n const file = (btn as HTMLElement).dataset.file;\n if (file) filesToSnapshot.add(resolveFilePath(file));\n }\n const snapshots = new Map<string, string>();\n for (const fp of filesToSnapshot) {\n try {\n const r = await ws.request(\"fs.read\", { path: fp }).catch(() => null);\n if (r?.payload?.content) snapshots.set(fp, String(r.payload.content));\n } catch {}\n }\n // Apply diffs sequentially, suppress per-diff reload\n (applyDiff as any)._batchMode = true;\n let failed = false;\n for (const btn of buttons) {\n try {\n await applyDiff(btn as HTMLElement);\n } catch {\n failed = true;\n break;\n }\n }\n (applyDiff as any)._batchMode = false;\n // If any failed, rollback all\n if (failed && snapshots.size > 0) {\n for (const [fp, content] of snapshots) {\n try { await ws.request(\"fs.write\", { path: fp, content }); } catch {}\n }\n state.messages.push({ role: \"system\", content: \"Batch apply failed — all changes reverted.\" });\n refreshPanelContent();\n }\n hideApplyBar();\n // Single reload after batch completes (not per-diff)\n if (!failed) setTimeout(() => { window.location.reload(); }, 1500);\n break;\n }\n case \"reject-all\": {\n const buttons = shadow.querySelectorAll(`[data-action=\"reject-diff\"]`);\n for (const btn of Array.from(buttons)) {\n rejectDiff(btn as HTMLElement);\n }\n hideApplyBar();\n break;\n }\n case \"undo-diff\": undoDiff(target); break;\n case \"clear-chat\": {\n state.messages = [];\n try { sessionStorage.removeItem(\"__om_state__\"); } catch {}\n refreshPanelContent();\n break;\n }\n case \"copy-msg\": {\n const idx = parseInt(target.dataset.idx || \"0\", 10);\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n collectDebugInfo(idx).then(debugText => {\n try { navigator.clipboard.writeText(debugText); } catch {}\n target.innerHTML = ICON.check;\n setTimeout(() => { target.innerHTML = ICON.copy; }, 1500);\n });\n break;\n }\n case \"report-issue\": {\n target.innerHTML = '<span class=\"om-spinner\"></span>';\n collectDebugInfo().then(debugInfo => {\n try { navigator.clipboard.writeText(debugInfo); } catch {}\n target.innerHTML = ICON.bug;\n window.open(\"https://github.com/Kalmuraee/OpenMagic/issues/new?template=bug_report.yml\", \"_blank\", \"noopener\");\n state.messages.push({ role: \"system\", content: \"Debug info copied to clipboard. Paste it in the Debug Info field on GitHub.\" });\n if (state.panelOpen) refreshPanelContent();\n });\n break;\n }\n case \"clear-element\": state.selectedElement = null; updatePromptContext(); break;\n case \"clear-screenshot\": state.screenshot = null; updatePromptContext(); break;\n case \"minimize\": {\n state.minimized = !state.minimized;\n const panel = shadow.querySelector(\".om-panel\") as HTMLElement;\n const promptRow = shadow.querySelector(\".om-prompt-row\") as HTMLElement;\n const promptAttach = shadow.querySelector(\".om-prompt-attachments\") as HTMLElement;\n const headerBtns = $toolbar.querySelectorAll(\".om-pill-btn:not([data-action='minimize']), .om-pill-divider, .om-status-dot\");\n\n if (state.minimized) {\n if (panel) panel.classList.add(\"om-hidden\");\n if (promptRow) promptRow.classList.add(\"om-hidden\");\n if (promptAttach) promptAttach.classList.add(\"om-hidden\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"none\");\n } else {\n if (promptRow) promptRow.classList.remove(\"om-hidden\");\n if (promptAttach) promptAttach.classList.remove(\"om-hidden\");\n headerBtns.forEach(el => (el as HTMLElement).style.display = \"\");\n if (state.panelOpen && state.activePanel) {\n if (panel) panel.classList.remove(\"om-hidden\");\n }\n }\n break;\n }\n }\n}\n\n// ── Targeted UI Updates (no full DOM rebuild) ────────────────────\n\nfunction updateStatusDot() {\n const dot = shadow.querySelector(\".om-status-dot\");\n if (dot) {\n const cls = state.updateAvailable ? \"outdated\" : state.connected ? \"connected\" : \"disconnected\";\n dot.className = `om-status-dot ${cls}`;\n dot.setAttribute(\"title\", state.updateAvailable ? `v${state.latestVersion} available — run npx openmagic@latest` : state.connected ? \"Connected\" : \"Disconnected\");\n }\n}\n\nfunction updatePillButtons() {\n shadow.querySelectorAll(\".om-pill-btn\").forEach((btn) => {\n const action = (btn as HTMLElement).dataset.action;\n btn.classList.toggle(\"active\", action === state.activePanel || (action === \"select\" && state.selecting));\n });\n}\n\nfunction updateModelSwitcher() {\n const sel = shadow.querySelector(\".om-model-switcher\") as HTMLSelectElement | null;\n if (!sel) return;\n const prov = MODEL_REGISTRY[state.provider];\n if (!prov) { sel.innerHTML = \"\"; return; }\n const opts = prov.models.map(m =>\n `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`\n ).join(\"\");\n sel.innerHTML = opts;\n}\n\nfunction updatePromptContext() {\n const chips: string[] = [];\n if (state.selectedElement) {\n chips.push(`<span class=\"om-prompt-chip\">${state.selectedElement.tagName}${state.selectedElement.id ? \"#\" + state.selectedElement.id : \"\"} <button class=\"om-prompt-chip-x\" data-action=\"clear-element\">${ICON.x}</button></span>`);\n }\n if (state.screenshot) {\n chips.push(`<span class=\"om-prompt-chip\">Screenshot <button class=\"om-prompt-chip-x\" data-action=\"clear-screenshot\">${ICON.x}</button></span>`);\n }\n if (state.attachments.length) {\n chips.push(`<span class=\"om-prompt-chip\">${state.attachments.length} image${state.attachments.length > 1 ? \"s\" : \"\"}</span>`);\n }\n if (state.groundedFiles.length) {\n chips.push(`<span class=\"om-prompt-chip\">${state.groundedFiles.length} files grounded</span>`);\n }\n // Estimate tokens from context (rough: ~4 chars per token)\n const contextChars = (state.selectedElement?.outerHTML?.length || 0)\n + (state.screenshot ? 1000 : 0)\n + state.groundedFiles.length * 4000; // average file size\n if (contextChars > 2000) {\n const estTokens = Math.round(contextChars / 4);\n const label = estTokens > 10000 ? `~${Math.round(estTokens / 1000)}K tokens` : `~${estTokens} tokens`;\n chips.push(`<span class=\"om-prompt-chip om-prompt-chip-tokens\">${label}</span>`);\n }\n $promptCtx.innerHTML = chips.join(\"\");\n}\n\n// ── Panel Management ─────────────────────────────────────────────\n\nfunction openPanel(panel: \"chat\" | \"settings\") {\n state.panelOpen = true;\n state.activePanel = panel;\n $panel.classList.remove(\"om-hidden\");\n const title = shadow.querySelector(\".om-panel-title\");\n if (title) title.textContent = panel === \"settings\" ? \"Settings\" : \"Chat\";\n refreshPanelContent();\n updatePillButtons();\n}\n\nfunction closePanel() {\n state.panelOpen = false;\n state.activePanel = \"\";\n $panel.classList.add(\"om-hidden\");\n updatePillButtons();\n}\n\nfunction togglePanel(panel: \"chat\" | \"settings\") {\n if (state.panelOpen && state.activePanel === panel) {\n closePanel();\n } else {\n openPanel(panel);\n }\n}\n\nfunction refreshPanelContent() {\n if (state.activePanel === \"settings\") {\n $panelBody.innerHTML = renderSettingsHTML();\n } else if (state.activePanel === \"chat\") {\n $panelBody.innerHTML = renderChatHTML();\n scrollChatToBottom();\n }\n saveState();\n}\n\n// ── Settings Renderer ────────────────────────────────────────────\n\nfunction renderSettingsHTML(): string {\n const providerOpts = Object.entries(MODEL_REGISTRY)\n .map(([k, p]) => {\n // For CLI providers, show detailed detection status\n const cliInfo = state.detectedClis.find((c) => c.id === k);\n let indicator = \"\";\n if (cliInfo) {\n if (cliInfo.installed && cliInfo.authenticated) indicator = \" \\u2713 ready\";\n else if (cliInfo.installed) indicator = \" (not logged in)\";\n else indicator = \" (not installed)\";\n } else {\n const configured = state.configuredProviders[k] || p.local;\n indicator = configured ? \" \\u2713\" : \"\";\n }\n return `<option value=\"${k}\" ${state.provider === k ? \"selected\" : \"\"}>${p.name}${indicator}</option>`;\n }).join(\"\");\n\n const prov = MODEL_REGISTRY[state.provider];\n const modelOpts = prov\n ? prov.models.map(m => `<option value=\"${m.id}\" ${state.model === m.id ? \"selected\" : \"\"}>${m.name}</option>`).join(\"\")\n : '<option value=\"\">Select provider first</option>';\n\n const isLocal = prov?.local || false;\n const keyUrl = prov?.keyUrl || \"\";\n const keyPh = prov?.keyPlaceholder || \"Enter API key...\";\n const providerHasKey = state.configuredProviders[state.provider] || false;\n\n const updateBanner = state.updateAvailable\n ? `<div class=\"om-update-banner\">v${state.latestVersion} available <code class=\"om-update-cmd\">npx openmagic@latest</code></div>` : \"\";\n\n // Show connected status if current provider has a key\n const statusHtml = (providerHasKey || isLocal)\n ? `<div class=\"om-status om-status-success\">${ICON.check} ${prov?.name || \"Provider\"} connected</div>` : \"\";\n\n const saveBtnText = state.saveStatus === \"saving\" ? '<span class=\"om-spinner\"></span> Saving...'\n : state.saveStatus === \"saved\" ? `${ICON.check} Saved` : \"Save\";\n const saveBtnClass = state.saveStatus === \"saving\" ? \"om-btn om-btn-saving\"\n : state.saveStatus === \"saved\" ? \"om-btn om-btn-saved\" : \"om-btn\";\n const saveBtnDisabled = state.saveStatus === \"saving\" ? \"disabled\" : \"\";\n\n // API key section: show \"configured\" state if key exists, with option to change\n let keySection = \"\";\n if (!isLocal && state.provider) {\n if (providerHasKey) {\n keySection = `\n <div class=\"om-field\">\n <label class=\"om-label\">API Key</label>\n <div class=\"om-key-configured\">\n ${ICON.check} <span>Key configured</span>\n <button class=\"om-btn-change-key\" data-action=\"change-key\">Change</button>\n </div>\n <div class=\"om-key-change-row om-hidden\" data-key-change>\n <div class=\"om-key-row\">\n <input type=\"text\" class=\"om-input om-key-input\" data-field=\"apiKey\" placeholder=\"${keyPh}\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" data-lpignore=\"true\" data-1p-ignore=\"true\" data-form-type=\"other\" />\n ${keyUrl ? `<button class=\"om-btn-get-key\" data-action=\"get-key\" data-url=\"${keyUrl}\">${ICON.externalLink} Get key</button>` : \"\"}\n </div>\n </div>\n </div>`;\n } else {\n keySection = `\n <div class=\"om-field\">\n <label class=\"om-label\">API Key</label>\n <div class=\"om-key-row\">\n <input type=\"text\" class=\"om-input om-key-input\" data-field=\"apiKey\" placeholder=\"${keyPh}\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" data-lpignore=\"true\" data-1p-ignore=\"true\" data-form-type=\"other\" />\n ${keyUrl ? `<button class=\"om-btn-get-key\" data-action=\"get-key\" data-url=\"${keyUrl}\">${ICON.externalLink} Get key</button>` : \"\"}\n </div>\n ${keyUrl ? `<div class=\"om-key-hint\"><a data-action=\"get-key\" data-url=\"${keyUrl}\">Get your ${prov?.name || \"\"} API key here</a></div>` : \"\"}\n </div>`;\n }\n }\n\n return `\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\"><option value=\"\">Select Provider...</option>${providerOpts}</select>\n </div>\n <div class=\"om-field\">\n <label class=\"om-label\">Model</label>\n <select class=\"om-select\" data-field=\"model\"><option value=\"\">Select Model...</option>${modelOpts}</select>\n </div>\n ${keySection}\n <button class=\"${saveBtnClass}\" data-action=\"save-settings\" ${saveBtnDisabled}>${saveBtnText}</button>\n ${statusHtml}\n </div>`;\n}\n\n// ── Chat Renderer ────────────────────────────────────────────────\n\nfunction renderChatHTML(): string {\n if (!state.provider || (!state.hasApiKey && !MODEL_REGISTRY[state.provider]?.local)) {\n return `<div class=\"om-status om-status-error\">Configure your provider in Settings first</div>`;\n }\n\n const msgs = state.messages.map((m, i) => {\n // Skip legacy diff group messages\n if (m.content.startsWith(\"__DIFFGROUP__\")) return \"\";\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n const isCreate = diff.type === \"create\" || (!diff.search && diff.replace);\n const searchB64 = encodeBase64Utf8(diff.search || \"\");\n const replaceB64 = encodeBase64Utf8(diff.replace || \"\");\n const label = isCreate ? \"Create new file\" : \"Edit\";\n const diffHtml = renderLineDiff(diff.search || \"\", diff.replace || \"\");\n return `<div class=\"om-diff-card\" data-diff-idx=\"${i}\">\n <div class=\"om-diff-file\">${escapeHtml(label)}: ${escapeHtml(diff.file)}</div>\n <div class=\"om-diff-lines\">${diffHtml}</div>\n <div class=\"om-diff-actions\">\n <button class=\"om-btn om-btn-sm\" data-action=\"apply-diff\" data-file=\"${escapeHtml(diff.file)}\" data-search=\"${searchB64}\" data-replace=\"${replaceB64}\">Apply</button>\n <button class=\"om-btn-secondary om-btn-sm\" data-action=\"reject-diff\" data-idx=\"${i}\">Reject</button>\n </div>\n </div>`;\n } catch {\n return `<div class=\"om-msg om-msg-system\">Malformed diff data</div>`;\n }\n }\n if (m.content.startsWith(\"Applied change to \")) {\n const file = m.content.replace(\"Applied change to \", \"\").replace(/ \\(fuzzy match.*?\\)/g, \"\").replace(\". Reloading...\", \"\");\n return `<div class=\"om-msg om-msg-system\">${escapeHtml(m.content)} <button class=\"om-undo-btn\" data-action=\"undo-diff\" data-file=\"${escapeHtml(file)}\">Undo</button></div>`;\n }\n // Regular messages with copy button\n const copyBtn = (m.role === \"user\" || m.role === \"assistant\")\n ? `<button class=\"om-copy-btn\" data-action=\"copy-msg\" data-idx=\"${i}\" title=\"Copy\">${ICON.copy}</button>`\n : \"\";\n if (m.role === \"assistant\") {\n return `<div class=\"om-msg om-msg-assistant\" dir=\"auto\">${renderMarkdown(m.content)}${copyBtn}</div>`;\n }\n return `<div class=\"om-msg om-msg-${m.role}\" dir=\"auto\">${escapeHtml(m.content)}${copyBtn}</div>`;\n }).join(\"\");\n\n const streamHtml = state.streaming\n ? `<div class=\"om-msg om-msg-assistant\"><span class=\"om-spinner\"></span> Generating response...</div>` : \"\";\n\n const empty = !state.messages.length && !state.streaming\n ? `<div class=\"om-chat-empty\">Select an element or type below to start</div>` : \"\";\n\n return `<div class=\"om-chat-messages\">${empty}${msgs}${streamHtml}</div>`;\n}\n\nfunction scrollChatToBottom() {\n requestAnimationFrame(() => {\n const el = $panelBody.querySelector(\".om-chat-messages\");\n if (el) el.scrollTop = el.scrollHeight;\n });\n}\n\n// ── Save Settings ────────────────────────────────────────────────\n\nasync function saveSettings() {\n const apiKeyInput = $panelBody.querySelector('[data-field=\"apiKey\"]') as HTMLInputElement;\n const apiKey = apiKeyInput?.value || \"\";\n\n if (!state.provider) {\n state.saveStatus = \"error\";\n updateSaveButton();\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 2000);\n return;\n }\n\n // Check WebSocket connection\n if (!ws.isConnected()) {\n state.saveStatus = \"error\";\n updateSaveButton();\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n if (btn) btn.innerHTML = \"Not connected - check terminal\";\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 3000);\n return;\n }\n\n const payload: any = { provider: state.provider, model: state.model };\n if (apiKey) payload.apiKey = apiKey;\n\n state.saveStatus = \"saving\";\n updateSaveButton();\n\n try {\n // Race against a 8s local timeout (don't wait 30s)\n const result = await Promise.race([\n ws.request(\"config.set\", payload),\n new Promise((_, reject) => setTimeout(() => reject(new Error(\"Save timed out\")), 8000)),\n ]);\n // Mark this provider as configured\n if (apiKey && state.provider) {\n state.configuredProviders[state.provider] = true;\n }\n state.hasApiKey = !!(apiKey || state.configuredProviders[state.provider]);\n state.saveStatus = \"saved\";\n updateSaveButton();\n\n // Auto-transition to chat after 1.2s\n updateModelSwitcher();\n setTimeout(() => {\n state.saveStatus = \"\";\n if (state.activePanel === \"settings\") {\n openPanel(\"chat\");\n }\n }, 1200);\n } catch (e: any) {\n state.saveStatus = \"error\";\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n const msg = (e?.message || \"\").includes(\"timeout\") ? \"Connection timeout - is the CLI running?\"\n : (e?.message || \"\").includes(\"connected\") ? \"Not connected to OpenMagic server\"\n : `Save failed: ${e?.message || \"Unknown error\"}`;\n if (btn) {\n btn.innerHTML = msg;\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n }\n setTimeout(() => { state.saveStatus = \"\"; refreshPanelContent(); }, 4000);\n }\n}\n\nfunction updateSaveButton() {\n const btn = $panelBody.querySelector('[data-action=\"save-settings\"]');\n if (!btn) return;\n if (state.saveStatus === \"saving\") {\n btn.innerHTML = '<span class=\"om-spinner\"></span> Saving...';\n btn.className = \"om-btn om-btn-saving\";\n (btn as HTMLButtonElement).disabled = true;\n } else if (state.saveStatus === \"saved\") {\n btn.innerHTML = `${ICON.check} Saved`;\n btn.className = \"om-btn om-btn-saved\";\n (btn as HTMLButtonElement).disabled = false;\n } else if (state.saveStatus === \"error\") {\n btn.innerHTML = \"Save failed - try again\";\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n } else {\n btn.innerHTML = \"Save\";\n btn.className = \"om-btn\";\n (btn as HTMLButtonElement).disabled = false;\n }\n}\n\n// ── Send Prompt ──────────────────────────────────────────────────\n\nasync function sendPrompt() {\n const text = $promptInput.value.trim();\n if (!text || state.streaming) return;\n\n if (!state.provider || (!state.hasApiKey && !MODEL_REGISTRY[state.provider]?.local)) {\n openPanel(\"settings\");\n return;\n }\n\n // Add user message\n state.messages.push({ role: \"user\", content: text });\n state.streaming = true;\n state.streamContent = \"\";\n $promptInput.value = \"\";\n\n // Open chat panel\n openPanel(\"chat\");\n\n // Build context — includes page info, selected element, screenshot, network/console logs\n const context: any = buildContext(state.selectedElement, state.screenshot);\n context.pageUrl = window.location.href;\n context.pageTitle = document.title;\n\n // Include image attachments (for vision-capable models)\n if (state.attachments.length > 0) {\n // Use the first attachment as the screenshot if none is captured\n if (!context.screenshot) {\n context.screenshot = state.attachments[0];\n }\n // Store all attachments for multi-image models\n context.attachments = [...state.attachments];\n }\n\n // Grounding: read project tree + score and read relevant source files\n const MAX_GROUNDED_FILES = 8;\n const MAX_GROUNDED_CHARS = 48000;\n const TEXT_RE = /\\.(?:[cm]?[jt]sx?|svelte|vue|astro|html?|css|scss|less|php|py)$/i;\n\n // Show grounding status\n const statusEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (statusEl) statusEl.innerHTML = '<span class=\"om-spinner\"></span> Reading project files...';\n\n try {\n const treeResult = await ws.request(\"fs.list\", {});\n if (treeResult?.payload?.projectTree) {\n context.projectTree = treeResult.payload.projectTree;\n }\n\n const allFiles = (treeResult?.payload?.files || []) as Array<{ path: string; type: string }>;\n const textFiles = allFiles.filter((f: { path: string; type: string }) => f.type === \"file\" && TEXT_RE.test(f.path));\n\n // Build search tokens from multiple sources\n const tokenSources: string[] = [text];\n\n // Add element metadata\n if (state.selectedElement) {\n if (state.selectedElement.id) tokenSources.push(state.selectedElement.id);\n if (state.selectedElement.className) tokenSources.push(state.selectedElement.className);\n if (state.selectedElement.textContent) tokenSources.push(state.selectedElement.textContent.slice(0, 100));\n if ((state.selectedElement as any).componentHint) tokenSources.push((state.selectedElement as any).componentHint);\n // Add ancestry class/component names\n if ((state.selectedElement as any).ancestry) {\n for (const a of (state.selectedElement as any).ancestry) {\n tokenSources.push(a);\n }\n }\n }\n\n const searchTokens = tokenSources\n .filter(Boolean).join(\" \").toLowerCase()\n .split(/[^a-z0-9_-]+/)\n .filter((t: string) => t.length >= 2 && ![\"the\", \"to\", \"in\", \"of\", \"and\", \"div\", \"span\", \"class\", \"style\"].includes(t));\n\n // Extract URL route segments (highest signal for finding the right page component)\n const pathname = window.location.pathname;\n const routeTokens = pathname.split(\"/\").filter((s: string) => s.length > 1 && !/^\\d+$/.test(s));\n\n // Monorepo detection: find which top-level directory likely contains the running app\n // by checking which subdir has files matching the component hint or route tokens\n let activeSubdir = \"\";\n if ((state.selectedElement as any)?.componentHint || routeTokens.length) {\n const hint = ((state.selectedElement as any)?.componentHint || \"\").toLowerCase();\n const subdirScores = new Map<string, number>();\n for (const tf of textFiles) {\n const topDir = tf.path.split(\"/\")[0];\n if (!topDir || topDir.includes(\".\")) continue;\n const l = tf.path.toLowerCase();\n let s = subdirScores.get(topDir) || 0;\n if (hint && l.includes(hint)) s += 10;\n for (const rt of routeTokens) { if (l.includes(rt.toLowerCase())) s += 5; }\n if (/(component|page|route|layout)/.test(l)) s += 1;\n subdirScores.set(topDir, s);\n }\n let best = 0;\n for (const [dir, s] of subdirScores) {\n if (s > best) { best = s; activeSubdir = dir; }\n }\n }\n\n const scored = textFiles.map((f: { path: string; type: string }) => {\n let score = 0;\n const lower = f.path.toLowerCase();\n // Strip Next.js route groups like (dashboard) from path for scoring\n const lowerNoGroups = lower.replace(/\\([^)]+\\)\\//g, \"\");\n\n // Monorepo: strongly boost files in the active sub-project, penalize others\n if (activeSubdir) {\n const topDir = f.path.split(\"/\")[0];\n if (topDir === activeSubdir) score += 20;\n else if (topDir !== activeSubdir && !f.path.includes(\"/\")) score += 0; // root files neutral\n else score -= 15; // files from other sub-projects\n }\n\n // Route match: files matching URL path get highest priority (+15)\n for (const rt of routeTokens) {\n if (lowerNoGroups.includes(rt.toLowerCase())) score += 15;\n }\n\n // Component hint match (+12)\n if ((state.selectedElement as any)?.componentHint) {\n const hint = (state.selectedElement as any).componentHint.toLowerCase();\n if (lower.includes(hint)) score += 12;\n }\n\n // Token match from prompt/element (+5)\n for (const token of searchTokens) {\n if (lower.includes(token)) score += 5;\n }\n\n // Framework patterns (+3)\n if (/(component|page|route|layout|template|view)/.test(lower)) score += 3;\n // Page/route files for current route get extra (+5)\n if (/page\\.[jt]sx?$|layout\\.[jt]sx?$|\\+page\\.svelte$/.test(lower)) score += 5;\n\n return { ...f, score };\n }).sort((a: { score: number }, b: { score: number }) => b.score - a.score);\n\n // Read top scored files + their co-located stylesheets\n const files: Array<{ path: string; content: string }> = [];\n const readPaths = new Set<string>();\n let totalChars = 0;\n\n // Parallel read of top scored files for faster grounding\n const topScored = scored.slice(0, MAX_GROUNDED_FILES).filter((f: any) => f.score > 0);\n const root = state.roots[0] || \"\";\n const readResults = await Promise.all(\n topScored.map((f: any) => {\n const fullPath = root ? `${root}/${f.path}` : f.path;\n return ws.request(\"fs.read\", { path: fullPath }).catch(() => null);\n })\n );\n\n for (let fi = 0; fi < topScored.length; fi++) {\n const f = topScored[fi];\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n try {\n const content = String(readResults[fi]?.payload?.content || \"\");\n if (!content) continue;\n const maxChars = Math.min(12000, MAX_GROUNDED_CHARS - totalChars);\n let trimmed = content.slice(0, maxChars);\n if (content.length > maxChars) {\n trimmed += `\\n// [FILE TRUNCATED — showing ${maxChars} of ${content.length} chars]`;\n }\n files.push({ path: f.path, content: trimmed });\n readPaths.add(f.path);\n totalChars += trimmed.length;\n\n // Auto-read co-located stylesheet (Component.module.css, Component.scss, etc.)\n const baseName = f.path.replace(/\\.[^.]+$/, \"\");\n const styleExts = [\".module.css\", \".module.scss\", \".css\", \".scss\", \".styles.ts\"];\n for (const ext of styleExts) {\n const stylePath = baseName + ext;\n if (readPaths.has(stylePath) || totalChars >= MAX_GROUNDED_CHARS) continue;\n const match = textFiles.find((tf: { path: string }) => tf.path === stylePath);\n if (match) {\n try {\n const sr = await ws.request(\"fs.read\", { path: root ? `${root}/${stylePath}` : stylePath });\n const sc = String(sr?.payload?.content || \"\");\n if (sc) {\n const stMax = Math.min(4000, MAX_GROUNDED_CHARS - totalChars);\n let st = sc.slice(0, stMax);\n if (sc.length > stMax) {\n st += `\\n// [FILE TRUNCATED — showing ${stMax} of ${sc.length} chars]`;\n }\n files.push({ path: stylePath, content: st });\n readPaths.add(stylePath);\n totalChars += st.length;\n }\n } catch {}\n break; // Only read the first matching style file\n }\n }\n // Auto-read layout files up the directory tree (for the first scored file only)\n if (files.length <= 2 && totalChars < MAX_GROUNDED_CHARS) {\n const LAYOUT_NAMES = [\"layout.tsx\", \"layout.jsx\", \"layout.js\", \"layout.ts\"];\n let layoutDir = f.path.replace(/\\/[^/]+$/, \"\");\n let layoutDepth = 0;\n while (layoutDir && layoutDepth < 4 && totalChars < MAX_GROUNDED_CHARS) {\n let foundLayout = false;\n for (const layoutName of LAYOUT_NAMES) {\n const layoutPath = `${layoutDir}/${layoutName}`;\n if (readPaths.has(layoutPath)) { foundLayout = true; break; }\n try {\n const lr = await ws.request(\"fs.read\", { path: root ? `${root}/${layoutPath}` : layoutPath }).catch(() => null);\n const lc = String(lr?.payload?.content || \"\");\n if (lc) {\n const lMax = Math.min(4000, MAX_GROUNDED_CHARS - totalChars);\n let lt = lc.slice(0, lMax);\n if (lc.length > lMax) lt += `\\n// [TRUNCATED]`;\n files.push({ path: layoutPath, content: lt });\n readPaths.add(layoutPath);\n totalChars += lt.length;\n foundLayout = true;\n break;\n }\n } catch {}\n }\n const parentDir = layoutDir.replace(/\\/[^/]+$/, \"\");\n if (parentDir === layoutDir || !parentDir) break;\n layoutDir = parentDir;\n layoutDepth++;\n }\n }\n\n // Follow imports: extract local imports and alias imports\n // Parse tsconfig paths for alias resolution (e.g., @/ → src/)\n let pathAliases: Record<string, string> = {};\n const tsconfigFile = files.find((fl: {path: string}) => fl.path === \"tsconfig.json\" || fl.path === \"tsconfig.app.json\");\n if (tsconfigFile) {\n try {\n const tsconfig = JSON.parse(tsconfigFile.content.replace(/\\/\\/.*$/gm, \"\").replace(/,\\s*([}\\]])/g, \"$1\"));\n const paths = tsconfig?.compilerOptions?.paths || {};\n const baseUrl = tsconfig?.compilerOptions?.baseUrl || \".\";\n for (const [alias, targets] of Object.entries(paths)) {\n const target = (targets as string[])?.[0];\n if (alias && target) {\n // Convert @/* → src/* style aliases\n const aliasPrefix = alias.replace(/\\/\\*$/, \"/\");\n const targetPrefix = target.replace(/\\/\\*$/, \"/\");\n const resolvedTarget = baseUrl === \".\" ? targetPrefix : `${baseUrl}/${targetPrefix}`;\n pathAliases[aliasPrefix] = resolvedTarget;\n }\n }\n } catch {}\n }\n\n // Follow relative imports\n const importMatches = content.matchAll(/(?:import|from)\\s+['\"]\\.?\\.\\/([\\w/.-]+)['\"]/g);\n for (const im of importMatches) {\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n const importPath = im[1];\n // Find matching file in the project (try with common extensions)\n const dir = f.path.replace(/\\/[^/]+$/, \"\");\n const candidates = [\n `${dir}/${importPath}`,\n `${dir}/${importPath}.tsx`,\n `${dir}/${importPath}.ts`,\n `${dir}/${importPath}.jsx`,\n `${dir}/${importPath}.js`,\n `${dir}/${importPath}/index.tsx`,\n `${dir}/${importPath}/index.ts`,\n ];\n for (const candidate of candidates) {\n if (readPaths.has(candidate)) break;\n const found = textFiles.find((tf: { path: string }) => tf.path === candidate);\n if (found) {\n try {\n const ir = await ws.request(\"fs.read\", { path: root ? `${root}/${candidate}` : candidate });\n const ic = String(ir?.payload?.content || \"\");\n if (ic) {\n const imMax = Math.min(8000, MAX_GROUNDED_CHARS - totalChars);\n let it = ic.slice(0, imMax);\n if (ic.length > imMax) it += `\\n// [FILE TRUNCATED — showing ${imMax} of ${ic.length} chars]`;\n files.push({ path: candidate, content: it });\n readPaths.add(candidate);\n totalChars += it.length;\n }\n } catch {}\n break;\n }\n }\n }\n\n // Follow alias imports (e.g., @/components/Button → src/components/Button)\n if (Object.keys(pathAliases).length > 0) {\n const aliasImports = content.matchAll(/(?:import|from)\\s+['\"]([^.'\"]\\S+)['\"]/g);\n for (const aim of aliasImports) {\n if (totalChars >= MAX_GROUNDED_CHARS) break;\n const rawImport = aim[1];\n for (const [aliasPrefix, targetPrefix] of Object.entries(pathAliases)) {\n if (!rawImport.startsWith(aliasPrefix)) continue;\n const resolved = rawImport.replace(aliasPrefix, targetPrefix);\n const aliasCandidates = [\n resolved, `${resolved}.tsx`, `${resolved}.ts`, `${resolved}.jsx`, `${resolved}.js`,\n `${resolved}/index.tsx`, `${resolved}/index.ts`,\n ];\n for (const ac of aliasCandidates) {\n if (readPaths.has(ac)) break;\n const found = textFiles.find((tf: { path: string }) => tf.path === ac);\n if (found) {\n try {\n const ar = await ws.request(\"fs.read\", { path: root ? `${root}/${ac}` : ac });\n const acContent = String(ar?.payload?.content || \"\");\n if (acContent) {\n const aMax = Math.min(8000, MAX_GROUNDED_CHARS - totalChars);\n let at = acContent.slice(0, aMax);\n if (acContent.length > aMax) at += `\\n// [TRUNCATED]`;\n files.push({ path: ac, content: at });\n readPaths.add(ac);\n totalChars += at.length;\n }\n } catch {}\n break;\n }\n }\n break;\n }\n }\n }\n } catch { /* skip unreadable files */ }\n }\n\n // Also read package.json for dependency/framework awareness\n if (totalChars < MAX_GROUNDED_CHARS) {\n try {\n const root = state.roots[0] || \"\";\n const pkgResult = await ws.request(\"fs.read\", { path: root ? `${root}/package.json` : \"package.json\" });\n const pkgContent = String(pkgResult?.payload?.content || \"\");\n if (pkgContent) {\n // Extract just dependencies section (not the full package.json)\n try {\n const pkg = JSON.parse(pkgContent);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n const depsStr = JSON.stringify(deps, null, 2);\n files.push({ path: \"package.json (dependencies)\", content: depsStr.slice(0, 2000) });\n } catch {\n files.push({ path: \"package.json\", content: pkgContent.slice(0, 2000) });\n }\n }\n } catch {}\n }\n\n // Auto-ground config files (tailwind, global styles)\n if (totalChars < MAX_GROUNDED_CHARS) {\n const root = state.roots[0] || \"\";\n const CONFIG_CANDIDATES = [\n \"tailwind.config.ts\", \"tailwind.config.js\", \"tailwind.config.mjs\",\n \"src/app/globals.css\", \"src/styles/globals.css\", \"styles/globals.css\",\n \"app/globals.css\", \"src/index.css\", \"src/global.css\",\n \"tsconfig.json\", \"tsconfig.app.json\",\n \"next.config.js\", \"next.config.mjs\", \"next.config.ts\",\n \"vite.config.ts\", \"vite.config.js\",\n \"astro.config.mjs\", \"astro.config.ts\",\n ];\n for (const candidate of CONFIG_CANDIDATES) {\n if (totalChars >= MAX_GROUNDED_CHARS || readPaths.has(candidate)) continue;\n try {\n const cfgPath = root ? `${root}/${candidate}` : candidate;\n const cfgResult = await ws.request(\"fs.read\", { path: cfgPath }).catch(() => null);\n const cfgContent = String(cfgResult?.payload?.content || \"\");\n if (cfgContent) {\n const cap = Math.min(12000, MAX_GROUNDED_CHARS - totalChars);\n let trimmed = cfgContent.slice(0, cap);\n if (cfgContent.length > cap) trimmed += `\\n/* [TRUNCATED] */`;\n files.push({ path: candidate, content: trimmed });\n readPaths.add(candidate);\n totalChars += trimmed.length;\n }\n } catch {}\n }\n }\n\n if (files.length) {\n context.files = files;\n // Show grounded files in status\n const fileNames = files.map((f: {path: string}) => f.path.split(\"/\").pop()).join(\", \");\n if (statusEl) statusEl.innerHTML = `<span class=\"om-spinner\"></span> Thinking... (${files.length} files: ${fileNames})`;\n }\n state.groundedFiles = files.map((f: {path: string}) => f.path);\n } catch { /* grounding is best-effort */ }\n\n // Auto-retry loop: if LLM says \"NEED_FILE: path\" or \"SEARCH_FILES:\", read and retry\n const MAX_RETRIES = 4;\n let retryCount = 0;\n const retriedFiles = new Set<string>(); // prevent re-reading same file\n\n try {\n while (retryCount <= MAX_RETRIES) {\n state.streamContent = \"\";\n\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 // Don't show raw JSON chunks — just keep the spinner\n // The clean formatted response will appear after streaming completes\n }\n );\n\n const responseContent = state.streamContent || result?.content || \"\";\n\n // Decode JSON wrapper before pattern matching — LLM returns JSON with\n // escaped quotes (e.g. \\\"nav-group\\\") which breaks regex on raw content\n let decodedContent = responseContent;\n try {\n const p = JSON.parse(responseContent);\n if (p.explanation) decodedContent = p.explanation;\n } catch {\n const mdMatch = responseContent.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (mdMatch) {\n try { const p = JSON.parse(mdMatch[1]); if (p.explanation) decodedContent = p.explanation; } catch {}\n }\n }\n\n // If the LLM returned real modifications, apply them immediately — don't chase NEED_FILE\n const hasRealModifications = result?.modifications?.some((m: any) =>\n (m.type === \"edit\" && m.file && m.search && m.replace) ||\n (m.type === \"create\" && m.file && m.content)\n );\n\n // Check if LLM is requesting a file (NEED_FILE pattern)\n // Only retry if there are NO real modifications to apply\n const needFileMatch = !hasRealModifications && (\n decodedContent.match(/NEED_FILE:\\s*\"?([^\\s\"}\\]]+)\"?/)\n || decodedContent.match(/(?:need|provide|show|read|see|contents?\\s+of)\\s+(?:the\\s+)?(?:file\\s+)?[`\"']?([a-zA-Z0-9_/.@-]+\\.[a-z]{1,5})[`\"']?/i)\n || decodedContent.match(/(?:source\\s+(?:file|code)\\s+(?:for|of|at))\\s+[`\"']?([a-zA-Z0-9_/.@-]+\\.[a-z]{1,5})[`\"']?/i)\n || responseContent.match(/NEED_FILE:\\s*\\\\?\"?([^\\s\"\\\\}\\]]+)\"?/)\n );\n if (needFileMatch && retryCount < MAX_RETRIES && !retriedFiles.has(needFileMatch[1].trim())) {\n const neededFile = needFileMatch[1].trim();\n retriedFiles.add(neededFile);\n retryCount++;\n\n // Show transient status (update the spinner, don't add permanent messages)\n const spinnerEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (spinnerEl) spinnerEl.innerHTML = `<span class=\"om-spinner\"></span> Reading ${neededFile}...`;\n\n // Read the requested file — try primary path, then fallbacks\n try {\n const root = state.roots[0] || \"\";\n const primaryPath = root ? `${root}/${neededFile}` : neededFile;\n let fileContent: string | undefined;\n\n // Try multiple paths\n const pathsToTry = [primaryPath];\n if (neededFile !== primaryPath) pathsToTry.push(neededFile);\n const basename = neededFile.split(\"/\").pop() || neededFile;\n const baseInRoot = root ? `${root}/${basename}` : basename;\n if (baseInRoot !== primaryPath && baseInRoot !== neededFile) pathsToTry.push(baseInRoot);\n\n for (const p of pathsToTry) {\n const r = await ws.request(\"fs.read\", { path: p }).catch(() => null);\n if (r?.payload?.content) { fileContent = String(r.payload.content); break; }\n }\n\n if (fileContent) {\n if (!context.files) context.files = [];\n // Replace existing truncated entry if present, otherwise add new\n const existingIdx = context.files.findIndex((f: {path: string}) =>\n f.path === neededFile || f.path.endsWith(\"/\" + neededFile) || neededFile.endsWith(\"/\" + f.path)\n );\n const fullContent = fileContent.slice(0, 16000); // larger cap for explicitly requested files\n if (existingIdx >= 0) {\n context.files[existingIdx] = { path: neededFile, content: fullContent };\n } else {\n context.files.push({ path: neededFile, content: fullContent });\n }\n } else {\n state.messages.push({ role: \"system\", content: `Could not read ${neededFile}` });\n break;\n }\n } catch {\n state.messages.push({ role: \"system\", content: `File not found: ${neededFile}` });\n break;\n }\n continue; // Retry with the new file context\n }\n\n // Check if LLM is requesting a codebase search (SEARCH_FILES pattern)\n // Only retry if there are NO real modifications to apply\n const searchMatch = !hasRealModifications && (\n decodedContent.match(/SEARCH_FILES:\\s*\"([^\"]+)\"(?:\\s+in\\s+(\\S+))?/)\n || responseContent.match(/SEARCH_FILES:\\s*\\\\?\"([^\"\\\\]+)\\\\?\"(?:\\s+in\\s+(\\S+))?/)\n );\n // Prevent infinite loop: skip if we already searched for this pattern\n const alreadySearched = (context as any).searchResults?.some((s: any) => s.query === searchMatch?.[1]);\n if (searchMatch && retryCount < MAX_RETRIES && !alreadySearched) {\n const pattern = searchMatch[1];\n const searchPath = searchMatch[2] || \"\";\n retryCount++;\n\n const spinnerEl = $panelBody.querySelector(\".om-msg-assistant:last-child\");\n if (spinnerEl) spinnerEl.innerHTML = `<span class=\"om-spinner\"></span> Searching: \"${pattern}\"...`;\n\n try {\n const grepResult = await Promise.race([\n ws.request(\"fs.grep\", { pattern, path: searchPath }),\n new Promise((_, rej) => setTimeout(() => rej(new Error(\"grep timeout\")), 5000)),\n ]) as any;\n const matches = grepResult?.payload?.results || [];\n if (matches.length) {\n if (!(context as any).searchResults) (context as any).searchResults = [];\n (context as any).searchResults.push({ query: pattern, matches });\n }\n } catch {}\n continue; // Retry with search results added\n }\n\n // Got a real response — strip any NEED_FILE/SEARCH_FILES lines from display\n let displayContent = decodedContent\n .replace(/^NEED_FILE:\\s*\\S+\\s*/gm, \"\")\n .replace(/^SEARCH_FILES:\\s*\"[^\"]*\"(?:\\s+in\\s+\\S+)?\\s*/gm, \"\")\n .trim();\n if (!displayContent) {\n displayContent = \"I couldn't determine the exact change from the available files. Try selecting a more specific element or giving more detail.\";\n }\n state.messages.push({ role: \"assistant\", content: displayContent });\n\n if (result?.modifications?.length) {\n const groupId = Math.random().toString(36).slice(2);\n const validMods = result.modifications.filter((m: any) =>\n (m.type === \"edit\" && m.file && m.search && m.replace) ||\n (m.type === \"create\" && m.file && m.content)\n );\n\n // Show sticky Apply All bar (for any number of diffs)\n updateApplyBar(validMods.length);\n\n for (const mod of result.modifications) {\n if (mod.type === \"edit\" && mod.file && mod.search && mod.replace) {\n const diffId = Math.random().toString(36).slice(2);\n const diffPayload = JSON.stringify({ id: diffId, file: mod.file, search: mod.search, replace: mod.replace, groupId });\n state.messages.push({\n role: \"system\",\n content: `__DIFF__${encodeBase64Utf8(diffPayload)}`,\n });\n } else if (mod.type === \"create\" && mod.file && (mod as any).content) {\n const diffId = Math.random().toString(36).slice(2);\n const diffPayload = JSON.stringify({ id: diffId, file: mod.file, search: \"\", replace: (mod as any).content, type: \"create\", groupId });\n state.messages.push({\n role: \"system\",\n content: `__DIFF__${encodeBase64Utf8(diffPayload)}`,\n });\n } else if (mod.type === \"delete\" && mod.file) {\n state.messages.push({\n role: \"system\",\n content: `LLM proposed deleting ${mod.file} — skipped (use edit with search/replace instead)`,\n });\n }\n }\n }\n break; // Done — no more retries needed\n }\n } catch (e: any) {\n // Stream disconnect recovery: if we have partial content, show it\n if (state.streamContent.trim().length > 20) {\n state.messages.push({ role: \"assistant\", content: state.streamContent.trim() });\n state.messages.push({ role: \"system\", content: `Response interrupted: ${e.message}. Partial response shown above.` });\n } else {\n state.messages.push({ role: \"system\", content: `Error: ${e.message}` });\n }\n }\n\n state.streaming = false;\n state.streamContent = \"\";\n state.attachments = [];\n renderAttachments();\n refreshPanelContent();\n scrollChatToBottom();\n}\n\n// ── Network & Profiling ──────────────────────────────────────────\n\nfunction captureNetworkProfile() {\n // Capture performance timing\n const perf = window.performance;\n const navEntry = perf.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n const paintEntries = perf.getEntriesByType(\"paint\");\n const resources = perf.getEntriesByType(\"resource\").slice(-20) as PerformanceResourceTiming[];\n\n const networkLogs = getNetworkLogs();\n const consoleLogs = getConsoleLogs();\n\n // Build a summary message\n const lines: string[] = [];\n lines.push(\"--- Network & Performance Capture ---\");\n\n if (navEntry) {\n lines.push(`Page load: ${Math.round(navEntry.loadEventEnd - navEntry.startTime)}ms`);\n lines.push(`DOM ready: ${Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime)}ms`);\n lines.push(`TTFB: ${Math.round(navEntry.responseStart - navEntry.startTime)}ms`);\n }\n\n const fcp = paintEntries.find(e => e.name === \"first-contentful-paint\");\n if (fcp) lines.push(`FCP: ${Math.round(fcp.startTime)}ms`);\n\n // ALL network requests from Performance API (includes page-load requests)\n if (resources.length) {\n const apiRequests = resources.filter(r =>\n r.initiatorType === \"fetch\" || r.initiatorType === \"xmlhttprequest\"\n );\n const allRequests = apiRequests.length > 0 ? apiRequests : resources;\n\n lines.push(`\\nAll network requests (${allRequests.length}):`);\n for (const r of allRequests.slice(-30)) {\n const url = r.name.length > 80 ? \"...\" + r.name.slice(-77) : r.name;\n const status = (r as any).responseStatus || \"\";\n lines.push(` ${Math.round(r.duration)}ms ${status ? `[${status}]` : \"\"} ${url}`);\n }\n }\n\n // Also include captured fetch/XHR logs (may have status codes)\n if (networkLogs.length) {\n lines.push(`\\nFetch/XHR requests (${networkLogs.length}):`);\n for (const log of networkLogs.slice(-20)) {\n lines.push(` ${log.method} ${log.url.slice(0, 80)} → ${log.status || \"pending\"} (${log.duration || \"?\"}ms)`);\n }\n }\n\n if (consoleLogs.length) {\n const errors = consoleLogs.filter(l => l.level === \"error\");\n const warns = consoleLogs.filter(l => l.level === \"warn\");\n if (errors.length) lines.push(`\\nConsole errors: ${errors.length}`);\n if (warns.length) lines.push(`Console warnings: ${warns.length}`);\n }\n\n // Slowest resources\n if (resources.length > 5) {\n const slowest = [...resources].sort((a, b) => b.duration - a.duration).slice(0, 5);\n lines.push(`\\nSlowest resources:`);\n for (const r of slowest) {\n lines.push(` ${Math.round(r.duration)}ms — ${r.name.split(\"/\").pop()?.slice(0, 60)}`);\n }\n }\n\n // Add as a system message in the chat\n state.messages.push({ role: \"system\", content: lines.join(\"\\n\") });\n refreshPanelContent();\n scrollChatToBottom();\n updatePromptContext();\n}\n\n// ── File Attachments ─────────────────────────────────────────────\n\nfunction triggerFileAttach() {\n const input = shadow.querySelector(\".om-file-input\") as HTMLInputElement;\n if (input) input.click();\n}\n\nfunction handleFileSelect(files: FileList | null) {\n if (!files) return;\n for (let i = 0; i < files.length && state.attachments.length < 5; i++) {\n const file = files[i];\n if (!file.type.startsWith(\"image/\")) continue;\n if (file.size > 10 * 1024 * 1024) continue; // 10MB max\n const reader = new FileReader();\n reader.onload = () => {\n if (typeof reader.result === \"string\") {\n state.attachments.push(reader.result);\n renderAttachments();\n }\n };\n reader.readAsDataURL(file);\n }\n}\n\nfunction renderAttachments() {\n const container = shadow.querySelector(\".om-prompt-attachments\");\n if (!container) return;\n if (!state.attachments.length) {\n container.innerHTML = \"\";\n container.classList.add(\"om-hidden\");\n return;\n }\n container.classList.remove(\"om-hidden\");\n container.innerHTML = state.attachments.map((a, i) =>\n `<div class=\"om-attachment-thumb\">\n <img src=\"${a}\" alt=\"attachment\" />\n <button class=\"om-attachment-remove\" data-action=\"remove-attachment\" data-idx=\"${i}\">${ICON.x}</button>\n </div>`\n ).join(\"\");\n}\n\n// ── Select Mode ──────────────────────────────────────────────────\n\nlet selectHandler: ((e: MouseEvent) => void) | null = null;\nlet hoverHandler: ((e: MouseEvent) => void) | null = null;\n\nfunction toggleSelectMode() {\n state.selecting ? exitSelectMode() : enterSelectMode();\n}\n\nfunction enterSelectMode() {\n state.selecting = true;\n document.body.style.cursor = \"crosshair\";\n updatePillButtons();\n\n hoverHandler = (e: MouseEvent) => {\n const t = e.target as HTMLElement;\n if (t.closest(\"openmagic-toolbar\") || t.dataset?.openmagic) return;\n const r = t.getBoundingClientRect();\n showHighlight({ x: r.x, y: r.y, width: r.width, height: r.height });\n };\n\n selectHandler = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const t = e.target as HTMLElement;\n if (t.closest(\"openmagic-toolbar\") || t.dataset?.openmagic) return;\n state.selectedElement = inspectElement(t);\n exitSelectMode();\n updatePromptContext();\n $promptInput.focus();\n };\n\n // ESC to cancel\n const escHandler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n exitSelectMode();\n }\n };\n\n document.addEventListener(\"mousemove\", hoverHandler, true);\n document.addEventListener(\"click\", selectHandler, true);\n document.addEventListener(\"keydown\", escHandler, true);\n\n // Store for cleanup\n (enterSelectMode as any)._escHandler = escHandler;\n}\n\nfunction exitSelectMode() {\n state.selecting = false;\n document.body.style.cursor = \"\";\n hideHighlight();\n if (hoverHandler) { document.removeEventListener(\"mousemove\", hoverHandler, true); hoverHandler = null; }\n if (selectHandler) { document.removeEventListener(\"click\", selectHandler, true); selectHandler = null; }\n const escH = (enterSelectMode as any)._escHandler;\n if (escH) { document.removeEventListener(\"keydown\", escH, true); (enterSelectMode as any)._escHandler = null; }\n updatePillButtons();\n}\n\nasync function takeScreenshot() {\n let target: HTMLElement | undefined;\n try {\n const sel = state.selectedElement?.cssSelector?.trim();\n if (sel) target = (document.querySelector(sel) as HTMLElement) || undefined;\n } catch { /* stale or invalid selector */ }\n\n // Try programmatic capture first\n const result = await captureScreenshotWithFeedback(target || undefined);\n\n // Check if we got a real screenshot (not just the fallback info card)\n const isRealScreenshot = result.data && result.data.length > 5000; // Real screenshots are >5KB\n\n if (isRealScreenshot) {\n state.screenshot = result.data;\n updatePromptContext();\n $promptInput.focus();\n } else {\n // Programmatic capture failed or only got metadata — guide user to paste\n state.messages.push({\n role: \"system\",\n content: \"Take a screenshot manually (Cmd+Shift+4 on Mac, Win+Shift+S on Windows), then paste it here (Ctrl+V) or drag it onto the prompt bar.\"\n });\n openPanel(\"chat\");\n refreshPanelContent();\n }\n}\n\n// ── Draggable (setup ONCE) ───────────────────────────────────────\n\nfunction setupDraggable() {\n let active = false, startX = 0, startY = 0, origX = 0, origY = 0;\n\n $toolbar.addEventListener(\"mousedown\", (e) => {\n const t = e.target as HTMLElement;\n if (t.closest(\"[data-action]\")) return;\n if (!t.closest(\".om-grab\") && !t.closest(\".om-pill-brand\")) return;\n active = true;\n startX = e.clientX; startY = e.clientY;\n const r = $toolbar.getBoundingClientRect();\n origX = r.left; origY = r.top;\n e.preventDefault();\n });\n\n document.addEventListener(\"mousemove\", (e) => {\n if (!active) return;\n $toolbar.style.left = (origX + e.clientX - startX) + \"px\";\n $toolbar.style.top = (origY + e.clientY - startY) + \"px\";\n $toolbar.style.right = \"auto\";\n $toolbar.style.bottom = \"auto\";\n });\n\n document.addEventListener(\"mouseup\", () => {\n if (active) {\n active = false;\n // Persist position\n try {\n localStorage.setItem(\"__om_pos__\", JSON.stringify({\n left: $toolbar.style.left,\n top: $toolbar.style.top,\n }));\n } catch {}\n }\n });\n}\n\n// ── Helpers ──────────────────────────────────────────────────────\n\nfunction escapeHtml(text: string): string {\n const d = document.createElement(\"div\");\n d.textContent = text;\n return d.innerHTML;\n}\n\nfunction renderLineDiff(search: string, replace: string): string {\n const searchLines = search.split(\"\\n\");\n const replaceLines = replace.split(\"\\n\");\n const lines: string[] = [];\n const maxLines = 30; // cap display\n\n // Simple LCS-based line diff\n const sLen = Math.min(searchLines.length, maxLines);\n const rLen = Math.min(replaceLines.length, maxLines);\n\n // Find common prefix and suffix\n let commonPrefix = 0;\n while (commonPrefix < sLen && commonPrefix < rLen && searchLines[commonPrefix] === replaceLines[commonPrefix]) commonPrefix++;\n let commonSuffix = 0;\n while (commonSuffix < sLen - commonPrefix && commonSuffix < rLen - commonPrefix\n && searchLines[sLen - 1 - commonSuffix] === replaceLines[rLen - 1 - commonSuffix]) commonSuffix++;\n\n // Render context (unchanged), removed, added\n for (let i = 0; i < commonPrefix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ctx\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\"> </span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n // Removed lines (from search)\n for (let i = commonPrefix; i < sLen - commonSuffix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-del\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\">-</span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n // Added lines (from replace)\n for (let i = commonPrefix; i < rLen - commonSuffix; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ins\"><span class=\"om-diff-ln\"> </span><span class=\"om-diff-sign\">+</span>${escapeHtml(replaceLines[i])}</div>`);\n }\n\n // Common suffix\n for (let i = sLen - commonSuffix; i < sLen; i++) {\n lines.push(`<div class=\"om-diff-line om-diff-ctx\"><span class=\"om-diff-ln\">${i + 1}</span><span class=\"om-diff-sign\"> </span>${escapeHtml(searchLines[i])}</div>`);\n }\n\n if (searchLines.length > maxLines) lines.push(`<div class=\"om-diff-line om-diff-ctx\">... ${searchLines.length - maxLines} more lines</div>`);\n\n return lines.join(\"\") || `<div class=\"om-diff-line om-diff-ins\">${escapeHtml(replace.slice(0, 500))}</div>`;\n}\n\nfunction renderMarkdown(text: string): string {\n // First: convert literal \\n strings to actual newlines (from JSON escaping)\n let clean = text.replace(/\\\\n/g, \"\\n\");\n let html = escapeHtml(clean);\n // Code blocks (``` ... ```)\n html = html.replace(/```(\\w*)\\n([\\s\\S]*?)```/g, '<pre class=\"om-code-block\"><code>$2</code></pre>');\n // Inline code (`...`)\n html = html.replace(/`([^`]+)`/g, '<code class=\"om-inline-code\">$1</code>');\n // Bold (**...**)\n html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n // Italic (*...*)\n // Italic: *text* but not **text** — avoid lookbehind for Safari compatibility\n html = html.replace(/([^*]|^)\\*([^*]+)\\*([^*]|$)/g, '$1<em>$2</em>$3');\n // Bullet lists (- item)\n html = html.replace(/^- (.+)$/gm, '&#8226; $1');\n // Line breaks\n html = html.replace(/\\n/g, '<br>');\n return html;\n}\n\nasync function collectDebugInfo(messageIdx?: number): Promise<string> {\n const lines: string[] = [];\n\n // ── Fetch server-side info ──\n let serverInfo: any = null;\n try {\n if (ws.isConnected()) {\n const res = await Promise.race([\n ws.request(\"debug.logs\"),\n new Promise((_, rej) => setTimeout(() => rej(new Error(\"timeout\")), 3000)),\n ]) as any;\n serverInfo = res?.payload || null;\n }\n } catch {}\n\n // ── Environment ──\n lines.push(\"## Environment\");\n lines.push(\"\");\n lines.push(`- **OpenMagic**: v${CURRENT_VERSION}${state.updateAvailable ? ` (v${state.latestVersion} available)` : \"\"}`);\n lines.push(`- **Browser**: ${navigator.userAgent}`);\n lines.push(`- **Platform**: ${navigator.platform}`);\n lines.push(`- **Viewport**: ${window.innerWidth}x${window.innerHeight} (devicePixelRatio: ${window.devicePixelRatio})`);\n lines.push(`- **Page URL**: ${window.location.href}`);\n lines.push(`- **Page Title**: ${document.title}`);\n if (serverInfo) {\n lines.push(`- **Node.js**: ${serverInfo.nodeVersion} (${serverInfo.platform}/${serverInfo.arch})`);\n lines.push(`- **Server PID**: ${serverInfo.pid}`);\n lines.push(`- **Server Uptime**: ${serverInfo.uptime}s`);\n lines.push(`- **Server Memory**: ${serverInfo.memoryMB}MB RSS`);\n lines.push(`- **Server CWD**: ${serverInfo.cwd}`);\n }\n\n // ── Connection & Config ──\n lines.push(\"\");\n lines.push(\"## Configuration\");\n lines.push(\"\");\n lines.push(`- **WebSocket**: ${state.connected ? \"connected\" : \"disconnected\"}`);\n lines.push(`- **Provider**: ${MODEL_REGISTRY[state.provider]?.name || state.provider || \"not set\"}`);\n lines.push(`- **Model**: ${state.model || \"not set\"}`);\n lines.push(`- **API Key Set**: ${state.hasApiKey ? \"yes\" : \"no\"}`);\n const configuredList = Object.entries(state.configuredProviders)\n .filter(([, v]) => v)\n .map(([k]) => MODEL_REGISTRY[k]?.name || k);\n if (configuredList.length) {\n lines.push(`- **Configured Providers**: ${configuredList.join(\", \")}`);\n }\n if (state.roots.length) {\n lines.push(`- **Project Roots**: ${state.roots.join(\", \")}`);\n }\n\n // ── Selected Element ──\n if (state.selectedElement) {\n const el = state.selectedElement;\n lines.push(\"\");\n lines.push(\"## Selected Element\");\n lines.push(\"\");\n lines.push(`- **Selector**: \\`${el.cssSelector || \"\"}\\``);\n lines.push(`- **Tag**: \\`${el.tagName}\\``);\n if (el.id) lines.push(`- **ID**: \\`${el.id}\\``);\n if (el.className) lines.push(`- **Class**: \\`${el.className}\\``);\n if ((el as any).componentHint) lines.push(`- **Component**: \\`${(el as any).componentHint}\\``);\n if ((el as any).ancestry?.length) lines.push(`- **Ancestry**: ${(el as any).ancestry.join(\" > \")}`);\n if (el.textContent) lines.push(`- **Text**: ${el.textContent.slice(0, 150)}`);\n }\n\n // ── Grounded Files (sent to LLM) ──\n if (state.groundedFiles.length) {\n lines.push(\"\");\n lines.push(\"## Files Sent to LLM\");\n lines.push(\"\");\n for (const f of state.groundedFiles) {\n lines.push(`- \\`${f}\\``);\n }\n }\n\n // ── Proposed Changes (diffs) ──\n const diffs: { file: string; type: string }[] = [];\n for (const m of state.messages) {\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n diffs.push({ file: diff.file, type: diff.type || \"edit\" });\n } catch {}\n }\n }\n if (diffs.length) {\n lines.push(\"\");\n lines.push(\"## Proposed Changes\");\n lines.push(\"\");\n for (const d of diffs) {\n lines.push(`- \\`${d.file}\\` (${d.type})`);\n }\n }\n\n // ── Applied / Rejected / Reverted ──\n const appliedMsgs = state.messages.filter(m =>\n m.role === \"system\" && (\n m.content.startsWith(\"Applied change to \") ||\n m.content.startsWith(\"Rejected change to \") ||\n m.content.startsWith(\"Reverted change to \") ||\n m.content.startsWith(\"Created \") ||\n m.content.startsWith(\"Change rejected\") ||\n m.content.startsWith(\"No matching code\") ||\n m.content.startsWith(\"Write failed\") ||\n m.content.startsWith(\"Could not read\")\n )\n );\n if (appliedMsgs.length) {\n lines.push(\"\");\n lines.push(\"## Applied/Rejected Changes\");\n lines.push(\"\");\n for (const m of appliedMsgs) {\n lines.push(`- ${m.content.slice(0, 200)}`);\n }\n }\n\n // ── Performance ──\n const perf = window.performance;\n const navEntry = perf.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n const paintEntries = perf.getEntriesByType(\"paint\");\n if (navEntry) {\n lines.push(\"\");\n lines.push(\"## Page Performance\");\n lines.push(\"\");\n lines.push(`- **Page Load**: ${Math.round(navEntry.loadEventEnd - navEntry.startTime)}ms`);\n lines.push(`- **DOM Ready**: ${Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime)}ms`);\n lines.push(`- **TTFB**: ${Math.round(navEntry.responseStart - navEntry.startTime)}ms`);\n const fcp = paintEntries.find(e => e.name === \"first-contentful-paint\");\n if (fcp) lines.push(`- **FCP**: ${Math.round(fcp.startTime)}ms`);\n }\n\n // ── Browser Console (all levels) ──\n const consoleLogs = getConsoleLogs();\n if (consoleLogs.length) {\n const errors = consoleLogs.filter(l => l.level === \"error\");\n const warnings = consoleLogs.filter(l => l.level === \"warn\");\n const infos = consoleLogs.filter(l => l.level === \"log\" || l.level === \"info\" || l.level === \"debug\");\n lines.push(\"\");\n lines.push(\"## Browser Console\");\n lines.push(\"\");\n lines.push(`Total: ${consoleLogs.length} entries (${errors.length} errors, ${warnings.length} warnings, ${infos.length} log/info/debug)`);\n if (errors.length) {\n lines.push(\"\");\n lines.push(`### Errors (${errors.length})`);\n lines.push(\"```\");\n for (const err of errors.slice(-15)) {\n lines.push(`[${new Date(err.timestamp).toISOString()}] ${err.args.map((a: any) => String(a)).join(\" \").slice(0, 300)}`);\n }\n lines.push(\"```\");\n }\n if (warnings.length) {\n lines.push(\"\");\n lines.push(`### Warnings (${warnings.length})`);\n lines.push(\"```\");\n for (const w of warnings.slice(-10)) {\n lines.push(`[${new Date(w.timestamp).toISOString()}] ${w.args.map((a: any) => String(a)).join(\" \").slice(0, 200)}`);\n }\n lines.push(\"```\");\n }\n if (infos.length) {\n lines.push(\"\");\n lines.push(\"<details><summary>Log/Info/Debug (\" + infos.length + \" entries)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const l of infos.slice(-30)) {\n lines.push(`[${new Date(l.timestamp).toISOString()}] [${l.level}] ${l.args.map((a: any) => String(a)).join(\" \").slice(0, 200)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n }\n\n // ── Network ──\n const networkLogs = getNetworkLogs();\n const failedRequests = networkLogs.filter(l => l.status && l.status >= 400);\n const slowRequests = networkLogs.filter(l => l.duration && l.duration > 2000);\n if (failedRequests.length || slowRequests.length) {\n lines.push(\"\");\n lines.push(\"## Network Issues\");\n lines.push(\"\");\n if (failedRequests.length) {\n lines.push(`### Failed Requests (${failedRequests.length})`);\n lines.push(\"```\");\n for (const req of failedRequests.slice(-15)) {\n lines.push(`${req.method} ${req.url.slice(0, 120)} → ${req.status} (${req.duration || \"?\"}ms)`);\n }\n lines.push(\"```\");\n }\n if (slowRequests.length) {\n lines.push(`### Slow Requests >2s (${slowRequests.length})`);\n lines.push(\"```\");\n for (const req of slowRequests.slice(-10)) {\n lines.push(`${req.method} ${req.url.slice(0, 120)} → ${req.status} (${req.duration}ms)`);\n }\n lines.push(\"```\");\n }\n }\n\n // ── Server-Side Logs (terminal) ──\n if (serverInfo?.logs?.length) {\n const sLogs = serverInfo.logs as { level: string; msg: string; ts: number }[];\n const sErrors = sLogs.filter(l => l.level === \"error\");\n const sWarnings = sLogs.filter(l => l.level === \"warn\");\n const sInfos = sLogs.filter(l => l.level === \"log\" || l.level === \"info\");\n lines.push(\"\");\n lines.push(\"## Server Logs (Terminal)\");\n lines.push(\"\");\n lines.push(`Total: ${sLogs.length} entries (${sErrors.length} errors, ${sWarnings.length} warnings, ${sInfos.length} log/info)`);\n if (sErrors.length) {\n lines.push(\"\");\n lines.push(`### Server Errors (${sErrors.length})`);\n lines.push(\"```\");\n for (const e of sErrors.slice(-15)) {\n lines.push(`[${new Date(e.ts).toISOString()}] ${e.msg.slice(0, 300)}`);\n }\n lines.push(\"```\");\n }\n if (sWarnings.length) {\n lines.push(\"\");\n lines.push(`### Server Warnings (${sWarnings.length})`);\n lines.push(\"```\");\n for (const w of sWarnings.slice(-10)) {\n lines.push(`[${new Date(w.ts).toISOString()}] ${w.msg.slice(0, 200)}`);\n }\n lines.push(\"```\");\n }\n lines.push(\"\");\n lines.push(\"<details><summary>All server logs (\" + sLogs.length + \" entries)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const l of sLogs.slice(-50)) {\n lines.push(`[${new Date(l.ts).toISOString()}] [${l.level}] ${l.msg.slice(0, 200)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n\n // ── Full Chat History ──\n if (state.messages.length) {\n lines.push(\"\");\n lines.push(\"## Chat History\");\n lines.push(\"\");\n lines.push(\"<details><summary>Full conversation (\" + state.messages.length + \" messages)</summary>\");\n lines.push(\"\");\n lines.push(\"```\");\n for (const m of state.messages) {\n if (m.content.startsWith(\"__DIFFGROUP__\")) continue;\n if (m.content.startsWith(\"__DIFF__\")) {\n try {\n const diff = JSON.parse(decodeBase64Utf8(m.content.slice(8)));\n lines.push(`[diff] ${diff.type || \"edit\"}: ${diff.file}`);\n if (diff.search) lines.push(` - search: ${diff.search.slice(0, 100)}...`);\n if (diff.replace) lines.push(` + replace: ${diff.replace.slice(0, 100)}...`);\n } catch {\n lines.push(`[diff] (parse error)`);\n }\n continue;\n }\n lines.push(`[${m.role}] ${m.content.slice(0, 500)}`);\n }\n lines.push(\"```\");\n lines.push(\"</details>\");\n }\n\n // ── Specific message context (for copy button) ──\n if (messageIdx !== undefined) {\n const msg = state.messages[messageIdx];\n if (msg) {\n lines.push(\"\");\n lines.push(\"## Copied Message\");\n lines.push(\"\");\n lines.push(\"```\");\n lines.push(`[${msg.role}] ${msg.content.slice(0, 2000)}`);\n lines.push(\"```\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction checkForUpdates() {\n fetch(\"https://registry.npmjs.org/openmagic/latest\", {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout ? AbortSignal.timeout(5000) : undefined,\n }).then(r => r.ok ? r.json() : null).then(d => {\n if (!d || typeof d.version !== \"string\" || !/^\\d+\\.\\d+\\.\\d+/.test(d.version)) return;\n const l = d.version.split(\".\").map(Number), c = CURRENT_VERSION.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) { if ((l[i]||0) > (c[i]||0)) { state.updateAvailable = true; state.latestVersion = d.version; showUpdateDot(); return; } if ((l[i]||0) < (c[i]||0)) return; }\n }).catch(() => {});\n}\n\nfunction showUpdateDot() {\n updateStatusDot();\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":";wCAAO,IAAMA,GAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","shouldReconnect","reconnectTimer","reconnectAttempt","generateId","connect","port","token","resolve","reject","settled","handshakeTimeout","wsHost","wsProto","handshakeId","msg","queued","event","handler","wasConnected","id","delay","e","send","data","request","type","payload","timeout","stream","onChunk","IDLE_MS","onTimeout","resetTimeout","onMessage","h","isConnected","IMPORTANT_STYLES","inspectElement","el","computed","styles","prop","rect","parentStyles","parentComputed","siblings","children","selectedIdx","start","end","i","sib","tag","cls","childrenLayout","directChildren","child","cRect","cComputed","gapToNext","nextRect","matchedCssRules","getMatchedCssRules","resolvedClasses","resolveClasses","ariaAttributes","attr","eventHandlers","reactProps","getReactProps","htmlEl","htmlComputed","htmlDataAttributes","key","themeState","cssVariables","rule","varMatches","vm","varName","inlineVars","iv","zIndex","createsContext","parentZIndex","stackingContext","isInViewport","isVisible","isScrollable","visibilityState","activeBreakpoints","breakpointsToCheck","bp","beforeContent","afterContent","pseudoElements","formState","getCleanOuterHTML","getCssSelector","getXPath","getAncestry","getComponentHint","depth","result","current","c","dataComponent","keys","fiber","name","clone","s","html","attrs","a","childSummary","parts","selector","classes","parent","index","element","sibling","rules","sheet","cssRules","text","props","safe","count","k","v","t","matchedRules","resolved","escaped","highlightEl","showHighlight","hideHighlight","captureScreenshotWithFeedback","target","el","result","captureViaSvg","captureSimple","element","rect","width","height","clone","cloneWithStyles","svgData","blob","url","resolve","img","canvas","dpr","ctx","ratio","small","sCtx","source","depth","maxDepth","computed","keyProps","css","p","v","i","child","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","getConsoleLogs","buildContext","selectedElement","screenshot","getNetworkLogs","l","getConsoleLogs","ICON","MODEL_REGISTRY","encodeBase64Utf8","value","bytes","binary","i","decodeBase64Utf8","CURRENT_VERSION","state","shadow","$toolbar","$promptInput","$promptCtx","$panel","$panelBody","saveState","msgs","prunedMsgs","m","diff","restoreState","saved","init","host","style","TOOLBAR_CSS","root","buildStaticDOM","attachGlobalEvents","setupDraggable","pos","installNetworkCapture","installConsoleCapture","checkForUpdates","token","wsPort","connect","updateStatusDot","request","msg","serverProvider","serverModel","cli","provMeta","openPanel","updatePillButtons","updateModelSwitcher","e","target","action","handleAction","field","refreshPanelContent","sendPrompt","fileInput","handleFileSelect","promptRow","dt","items","file","onMessage","el","closePanel","undoBtn","undoDiff","applyAllBtn","resolveFilePath","rel","fuzzyLineMatch","content","search","searchLines","nonEmptySearch","contentLines","allMatch","matchLen","si","ci","lineRangeToOffsets","strippedSearch","j","searchStr","searchLen","bestScore","bestStart","bestLen","minWin","maxWin","winSize","windowStr","l","score","similarity","lines","start","count","startOffset","k","endOffset","a","b","trigramsA","trigramsB","intersection","t","applyDiff","searchB64","replaceB64","card","actions","r","replace","filePath","idx","scrollChatToBottom","resolvedPath","pathsToTry","basename","baseInRoot","tryPath","c","exactCount","writeResult","fuzzyResult","newContent","rejectDiff","searchPreview","replacePreview","updateApplyBar","bar","text","hideApplyBar","toggleSelectMode","takeScreenshot","togglePanel","saveSettings","url","changeRow","captureNetworkProfile","triggerFileAttach","renderAttachments","buttons","filesToSnapshot","btn","snapshots","fp","failed","collectDebugInfo","debugText","debugInfo","updatePromptContext","panel","promptAttach","headerBtns","dot","cls","sel","prov","opts","chips","contextChars","estTokens","label","title","renderSettingsHTML","renderChatHTML","providerOpts","p","cliInfo","indicator","modelOpts","isLocal","keyUrl","keyPh","providerHasKey","updateBanner","statusHtml","saveBtnText","saveBtnClass","saveBtnDisabled","keySection","isCreate","diffHtml","renderLineDiff","escapeHtml","copyBtn","renderMarkdown","streamHtml","apiKey","updateSaveButton","isConnected","payload","result","_","reject","context","buildContext","MAX_GROUNDED_FILES","MAX_GROUNDED_CHARS","TEXT_RE","statusEl","treeResult","textFiles","f","tokenSources","searchTokens","routeTokens","s","activeSubdir","hint","subdirScores","tf","topDir","rt","best","dir","scored","lower","lowerNoGroups","files","readPaths","totalChars","topScored","readResults","fullPath","fi","maxChars","trimmed","baseName","styleExts","ext","stylePath","sr","sc","stMax","st","LAYOUT_NAMES","layoutDir","layoutDepth","foundLayout","layoutName","layoutPath","lr","lc","lMax","lt","parentDir","pathAliases","tsconfigFile","fl","tsconfig","paths","baseUrl","alias","targets","aliasPrefix","targetPrefix","resolvedTarget","importMatches","im","importPath","candidates","candidate","ir","ic","imMax","it","aliasImports","aim","rawImport","resolved","aliasCandidates","ac","ar","acContent","aMax","at","pkgResult","pkgContent","pkg","deps","depsStr","CONFIG_CANDIDATES","cfgPath","cfgResult","cfgContent","cap","fileNames","MAX_RETRIES","retryCount","retriedFiles","stream","chunk","responseContent","decodedContent","mdMatch","hasRealModifications","needFileMatch","neededFile","spinnerEl","primaryPath","fileContent","existingIdx","fullContent","searchMatch","alreadySearched","pattern","searchPath","matches","rej","displayContent","groupId","validMods","mod","diffId","diffPayload","perf","navEntry","paintEntries","resources","networkLogs","getNetworkLogs","consoleLogs","getConsoleLogs","fcp","apiRequests","allRequests","status","log","errors","warns","slowest","input","reader","container","selectHandler","hoverHandler","exitSelectMode","enterSelectMode","showHighlight","inspectElement","escHandler","hideHighlight","escH","captureScreenshotWithFeedback","active","startX","startY","origX","origY","d","replaceLines","maxLines","sLen","rLen","commonPrefix","commonSuffix","clean","html","messageIdx","serverInfo","configuredList","v","diffs","appliedMsgs","warnings","infos","err","w","failedRequests","slowRequests","req","sLogs","sErrors","sWarnings","sInfos","showUpdateDot"]}