@mp-consulting/homebridge-ui-kit 1.2.1 → 1.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/js/env.js","../src/js/util.js","../src/js/core.js","../src/js/ai.js","../src/js/theme.js","../src/js/tabs.js","../src/js/toast.js","../src/js/dialog.js","../src/js/form.js","../src/js/delegates.js","../src/js/devices.js","../src/js/log.js","../src/js/pairing.js","../src/js/index.js","../src/js/global.js"],"sourcesContent":["// Runtime environment: the global object, the document and the Homebridge\n// plugin UI client (`window.homebridge` from @homebridge/plugin-ui-utils).\n// Everything is looked up lazily so the modules can be imported in Node.\n\n/* global homebridge */\n\nexport const root = typeof window !== 'undefined' ? window : globalThis;\n\nexport function doc() {\n return typeof document !== 'undefined' ? document : root.document;\n}\n\nexport function hbClient() {\n return root.homebridge || (typeof homebridge !== 'undefined' ? homebridge : undefined);\n}\n\n/** True when the Homebridge client exposes `method` as a function. */\nexport function hbHas(method) {\n const hb = hbClient();\n return !!hb && typeof hb[method] === 'function';\n}\n","import { doc } from './env.js';\n\nconst ESCAPES = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', '\\'': '&#39;' };\n\n/** Escapes a value for safe use in HTML text and quoted attributes. */\nexport function escapeHtml(value) {\n return String(value == null ? '' : value).replace(/[&<>\"']/g, c => ESCAPES[c]);\n}\n\n/** Returns the URL if it uses http(s), otherwise null (blocks javascript:, data:, …). */\nexport function safeUrl(url) {\n if (typeof url !== 'string') { return null; }\n return /^https?:\\/\\//i.test(url.trim()) ? url.trim() : null;\n}\n\nlet uidSeq = 0;\n\n/** Returns a unique id with the given prefix (for label/aria wiring). */\nexport function uid(prefix) {\n uidSeq += 1;\n return (prefix || 'mp') + '-' + uidSeq;\n}\n\n/** Resolves a selector or element to an element (or null). */\nexport function toElement(target) {\n if (!target) { return null; }\n if (typeof target === 'string') {\n const d = doc();\n return d ? d.querySelector(target) : null;\n }\n return target;\n}\n\nexport function errorMessage(err, fallback) {\n if (typeof err === 'string' && err) { return err; }\n return (err && err.message) || fallback;\n}\n\nlet liveRegion = null;\n\n/**\n * Announces a message to screen readers through a shared, visually hidden\n * live region (polite by default; 'assertive' for urgent messages).\n */\nexport function announce(message, politeness) {\n const d = doc();\n if (!d || !d.body || typeof d.createElement !== 'function') { return; }\n if (!liveRegion || !liveRegion.isConnected) {\n liveRegion = d.createElement('div');\n liveRegion.className = 'mp-sr-only';\n liveRegion.setAttribute('data-mp-live', '');\n liveRegion.setAttribute('aria-atomic', 'true');\n d.body.appendChild(liveRegion);\n }\n liveRegion.setAttribute('aria-live', politeness === 'assertive' ? 'assertive' : 'polite');\n // Clear first so repeating the same message is announced again.\n liveRegion.textContent = '';\n const text = String(message == null ? '' : message);\n setTimeout(() => { liveRegion.textContent = text; }, 30);\n}\n\nconst FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), '\n + 'select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\n/** Focusable descendants of el, in DOM order (visible ones only when layout is known). */\nexport function focusables(el) {\n return Array.from(el.querySelectorAll(FOCUSABLE)).filter(n => !n.hidden && !n.closest('[hidden]'));\n}\n\n/** Focuses el without scrolling, making it programmatically focusable if needed. */\nexport function focusElement(el) {\n if (!el || typeof el.focus !== 'function') { return; }\n if (!el.matches(FOCUSABLE) && !el.hasAttribute('tabindex')) {\n el.setAttribute('tabindex', '-1');\n el.classList.add('mp-focus-target');\n }\n try { el.focus({ preventScroll: true }); } catch { el.focus(); }\n}\n\n/** Visible text of an element, collapsed. */\nexport function textOf(el) {\n return el ? String(el.textContent || '').replace(/\\s+/g, ' ').trim() : '';\n}\n","// Core helpers: status badges, empty/loading states, view switching, footer.\n\nimport { doc } from './env.js';\nimport {\n announce, escapeHtml, focusElement, safeUrl, textOf, toElement,\n} from './util.js';\n\nfunction badge(badgeClass, dotClass, label) {\n return '<span class=\"badge ' + badgeClass + '\">'\n + (dotClass ? '<span class=\"mp-status ' + dotClass + '\" aria-hidden=\"true\"></span>' : '')\n + escapeHtml(label) + '</span>';\n}\n\n// Icon paths from Bootstrap Icons 1.11.3 (MIT), inlined so the footer\n// works whether or not the plugin loads the icon font.\nconst FOOTER_LINKS = [\n {\n key: 'github',\n text: 'GitHub',\n paths: [\n 'M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8',\n ],\n },\n {\n key: 'npm',\n text: 'npm',\n paths: [\n 'M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z',\n ],\n },\n {\n key: 'changelog',\n text: 'Changelog',\n paths: [\n 'M8.515 1.019A7 7 0 0 0 8 1V0a8 8 0 0 1 .589.022zm2.004.45a7 7 0 0 0-.985-.299l.219-.976q.576.129 1.126.342zm1.37.71a7 7 0 0 0-.439-.27l.493-.87a8 8 0 0 1 .979.654l-.615.789a7 7 0 0 0-.418-.302zm1.834 1.79a7 7 0 0 0-.653-.796l.724-.69q.406.429.747.91zm.744 1.352a7 7 0 0 0-.214-.468l.893-.45a8 8 0 0 1 .45 1.088l-.95.313a7 7 0 0 0-.179-.483m.53 2.507a7 7 0 0 0-.1-1.025l.985-.17q.1.58.116 1.17zm-.131 1.538q.05-.254.081-.51l.993.123a8 8 0 0 1-.23 1.155l-.964-.267q.069-.247.12-.501m-.952 2.379q.276-.436.486-.908l.914.405q-.24.54-.555 1.038zm-.964 1.205q.183-.183.35-.378l.758.653a8 8 0 0 1-.401.432z',\n 'M8 1a7 7 0 1 0 4.95 11.95l.707.707A8.001 8.001 0 1 1 8 0z',\n 'M7.5 3a.5.5 0 0 1 .5.5v5.21l3.248 1.856a.5.5 0 0 1-.496.868l-3.5-2A.5.5 0 0 1 7 9V3.5a.5.5 0 0 1 .5-.5',\n ],\n },\n];\n\nfunction icon(paths) {\n return '<svg class=\"mp-footer-icon\" viewBox=\"0 0 16 16\" aria-hidden=\"true\" focusable=\"false\">'\n + paths.map(d => '<path d=\"' + d + '\"/>').join('')\n + '</svg>';\n}\n\n/**\n * StatusBadge — returns inline HTML for device status badges.\n * Labels are HTML-escaped.\n */\nexport const StatusBadge = {\n online: label => badge('bg-success-subtle text-success-emphasis', 'mp-status-online', label || 'Online'),\n offline: label => badge('bg-danger-subtle text-danger-emphasis', 'mp-status-offline', label || 'Offline'),\n checking: label => badge('bg-secondary-subtle text-secondary-emphasis', 'mp-status-checking', label || 'Checking…'),\n disabled: label => badge('bg-secondary', null, label || 'Disabled'),\n};\n\n/** EmptyState — returns HTML for an empty list placeholder (all options escaped). */\nexport const EmptyState = {\n render(opts) {\n opts = opts || {};\n const iconClass = opts.iconClass || 'bi bi-inbox';\n const title = opts.title || 'No items';\n const hint = opts.hint || '';\n return '<div class=\"mp-empty-state\">'\n + '<i class=\"' + escapeHtml(iconClass) + ' mp-empty-state-icon\" aria-hidden=\"true\"></i>'\n + '<p class=\"mp-empty-state-title\">' + escapeHtml(title) + '</p>'\n + (hint ? '<p class=\"mp-empty-state-hint\">' + escapeHtml(hint) + '</p>' : '')\n + '</div>';\n },\n};\n\n/** Loading — returns HTML for a centred spinner with an announced message. */\nexport const Loading = {\n render(message) {\n message = message || 'Loading…';\n return '<div class=\"mp-loading\" role=\"status\" aria-live=\"polite\">'\n + '<div class=\"spinner-border spinner-border-sm text-secondary\" aria-hidden=\"true\"></div>'\n + '<span>' + escapeHtml(message) + '</span>'\n + '</div>';\n },\n};\n\nconst HEADING = 'h1, h2, h3, h4, h5, h6, [data-mp-focus]';\n\n/**\n * View — shows one .mp-view element and hides the others. When it switches\n * from another view, focus moves to the new view's heading (or its\n * [data-mp-focus] element, or the view itself) and its name is announced\n * through a polite live region. The first show (no view was active) does\n * neither, so page load does not steal focus.\n * opts: { focus, announce (true/false, or a custom message for announce) }\n */\nexport const View = {\n show(id, opts) {\n opts = opts || {};\n let shown = null;\n let changed = false;\n let previous = false;\n doc().querySelectorAll('.mp-view').forEach(v => {\n const active = v.id === id;\n const was = v.classList.contains('active');\n if (active) {\n shown = v;\n changed = !was;\n } else if (was) {\n previous = true;\n }\n v.classList.toggle('active', active);\n });\n if (!shown || !changed || typeof shown.querySelector !== 'function') { return shown; }\n const heading = shown.querySelector(HEADING);\n if (opts.focus === undefined ? previous : opts.focus) { focusElement(heading || shown); }\n if (opts.announce === undefined ? previous : opts.announce) {\n const label = typeof opts.announce === 'string' ? opts.announce\n : (shown.getAttribute('aria-label') || textOf(heading));\n if (label) { announce(label); }\n }\n return shown;\n },\n};\n\n/** Footer — renders http(s) support links into a .mp-footer element. */\nexport const Footer = {\n render(opts) {\n opts = opts || {};\n const el = toElement(opts.target || '.mp-footer');\n if (!el) { return; }\n const links = [];\n FOOTER_LINKS.forEach(link => {\n const url = safeUrl(opts[link.key]);\n if (!url) { return; }\n links.push('<a href=\"' + escapeHtml(url) + '\" target=\"_blank\" rel=\"noopener noreferrer\">'\n + icon(link.paths) + link.text + '</a>');\n });\n el.innerHTML = links.join('<span class=\"mp-footer-sep\" aria-hidden=\"true\">|</span>');\n },\n};\n","import { doc, hbClient } from './env.js';\nimport { errorMessage, escapeHtml, uid } from './util.js';\n\n// ── Assistant (AI) ─────────────────────────────────────────────────────────\n// Talks to the plugin's server-side routes registered by\n// @mp-consulting/homebridge-ai-core/plugin (`registerAiRoutes`) through the global\n// `homebridge` object from @homebridge/plugin-ui-utils.\n\n// Generic four-point sparkle (not a product logo).\nvar SPARKLE = '<svg class=\"mp-ai-icon\" viewBox=\"0 0 16 16\" aria-hidden=\"true\" focusable=\"false\">'\n + '<path d=\"M8 0c.4 3.9 2.1 5.6 6 6-3.9.4-5.6 2.1-6 6-.4-3.9-2.1-5.6-6-6 3.9-.4 5.6-2.1 6-6z\"/>'\n + '<path d=\"M13.5 10.5c.15 1.5.85 2.2 2.5 2.5-1.65.3-2.35 1-2.5 2.5-.15-1.5-.85-2.2-2.5-2.5 1.65-.3 2.35-1 2.5-2.5z\"/>'\n + '</svg>';\nvar CARET = '<span class=\"mp-ai-caret\" aria-hidden=\"true\"></span>';\nvar DEFAULT_NOTE = 'Generated by the Assistant. Check it before acting on it.';\nvar DEFAULT_ERROR = 'The Assistant could not answer. Please try again.';\nvar LCS_LIMIT = 4000000; // cells; larger diffs fall back to remove-all/add-all\n\nvar aiSeq = 0;\n\nfunction newRequestId() {\n aiSeq += 1;\n return 'mpai-' + Date.now().toString(36) + '-' + aiSeq.toString(36) + '-'\n + Math.random().toString(36).slice(2, 8);\n}\n\nfunction eventData(ev) {\n if (ev && ev.data !== undefined) { return ev.data; }\n if (ev && ev.detail !== undefined) { return ev.detail; }\n return ev;\n}\n\nfunction abortError(reason) {\n if (reason != null) { return reason; }\n var message = 'The Assistant request was cancelled';\n if (typeof DOMException === 'function') {\n try { return new DOMException(message, 'AbortError'); } catch (e) { /* old engines */ }\n }\n var err = new Error(message);\n err.name = 'AbortError';\n return err;\n}\n\n/** Tells the server to stop generating; best effort, failures are ignored. */\nfunction notifyCancel(hb, requestId) {\n try {\n Promise.resolve(hb.request('/ai/cancel', { requestId: requestId })).catch(function () {});\n } catch (e) { /* ignore */ }\n}\n\n/**\n * Sends a request to an /ai/* route with a generated requestId and, while it\n * runs, forwards matching `ai:chunk` / `ai:done` / `ai:error` events to the\n * onChunk / onDone / onError callbacks. Resolves with the route's result.\n *\n * Cancellation: pass `opts.signal` (an AbortSignal) or call `.cancel()` on the\n * returned promise. Either rejects it with an AbortError (or the signal's\n * reason), removes the event listeners and, unless `opts.notifyServer` is\n * false, sends a best-effort `/ai/cancel` request with the requestId.\n * The promise also carries `.requestId`.\n */\nfunction aiRequest(path, body, opts) {\n opts = opts || {};\n var hb = hbClient();\n if (!hb || typeof hb.request !== 'function') {\n return withCancel(Promise.reject(new Error('MpKit.ai needs the Homebridge plugin UI (window.homebridge)')));\n }\n var signal = opts.signal;\n if (signal && signal.aborted) {\n return withCancel(Promise.reject(abortError(signal.reason)));\n }\n var requestId = newRequestId();\n var payload = {};\n Object.keys(body || {}).forEach(function (k) { payload[k] = body[k]; });\n payload.requestId = requestId;\n\n var settled = false;\n var listeners = [];\n if (typeof hb.addEventListener === 'function') {\n var on = function (type, fn) {\n var handler = function (ev) {\n var data = eventData(ev);\n if (!settled && data && data.requestId === requestId) { fn(data); }\n };\n hb.addEventListener(type, handler);\n listeners.push([type, handler]);\n };\n if (typeof opts.onChunk === 'function') {\n on('ai:chunk', function (d) {\n if (typeof d.delta === 'string' && d.delta) { opts.onChunk(d.delta, d); }\n });\n }\n if (typeof opts.onDone === 'function') {\n on('ai:done', function (d) { opts.onDone(d); });\n }\n if (typeof opts.onError === 'function') {\n on('ai:error', function (d) { opts.onError(d.message || DEFAULT_ERROR, d); });\n }\n }\n\n var rejectCancelled;\n var cancelled = new Promise(function (resolve, reject) { rejectCancelled = reject; });\n // Avoid an unhandled rejection when nobody awaits a cancelled request.\n cancelled.catch(function () {});\n\n function onAbort() { cancel(signal.reason); }\n\n function cleanup() {\n settled = true;\n if (signal && typeof signal.removeEventListener === 'function') {\n signal.removeEventListener('abort', onAbort);\n }\n if (typeof hb.removeEventListener !== 'function') { return; }\n listeners.forEach(function (l) { hb.removeEventListener(l[0], l[1]); });\n listeners = [];\n }\n\n function cancel(reason) {\n if (settled) { return false; }\n cleanup();\n if (opts.notifyServer !== false) { notifyCancel(hb, requestId); }\n rejectCancelled(abortError(reason));\n return true;\n }\n\n if (signal && typeof signal.addEventListener === 'function') {\n signal.addEventListener('abort', onAbort);\n }\n\n var pending;\n try {\n pending = Promise.resolve(hb.request(path, payload));\n } catch (err) {\n pending = Promise.reject(err);\n }\n var result = Promise.race([pending, cancelled]).then(function (value) {\n cleanup();\n return value;\n }, function (err) {\n cleanup();\n throw err;\n });\n return withCancel(result, cancel, requestId);\n}\n\nfunction withCancel(promise, cancel, requestId) {\n promise.cancel = cancel || function () { return false; };\n promise.requestId = requestId || null;\n return promise;\n}\n\n// ── Safe markdown subset ──\n// Paragraphs, **bold**, `inline code`, fenced code blocks, bullet and\n// numbered lists, and #-headings (rendered as bold paragraphs). Every piece of\n// text is HTML-escaped before any tag is added, so model output can never\n// inject markup. Links are left as plain text.\n\nfunction inlineMarkdown(text) {\n return String(text).split(/(`[^`\\n]+`)/).map(function (part, i) {\n if (i % 2 === 1) { return '<code>' + escapeHtml(part.slice(1, -1)) + '</code>'; }\n return escapeHtml(part).replace(/\\*\\*([^*\\n]+?)\\*\\*|__([^_\\n]+?)__/g, function (m, a, b) {\n return '<strong>' + (a || b) + '</strong>';\n });\n }).join('');\n}\n\nvar UL_ITEM = /^\\s*[-*+]\\s+(.*)$/;\nvar OL_ITEM = /^\\s*\\d+[.)]\\s+(.*)$/;\nvar HEADING = /^\\s*#{1,6}\\s+(.*)$/;\nvar FENCE = /^\\s*(```|~~~)/;\n\nexport function markdown(text) {\n var lines = String(text == null ? '' : text).replace(/\\r\\n?/g, '\\n').split('\\n');\n var out = [];\n var para = [];\n var i = 0;\n function flush() {\n if (para.length) {\n out.push('<p>' + para.map(inlineMarkdown).join('<br>') + '</p>');\n para = [];\n }\n }\n while (i < lines.length) {\n var line = lines[i];\n var fence = FENCE.exec(line);\n if (fence) {\n flush();\n var code = [];\n i += 1;\n while (i < lines.length && lines[i].trim().indexOf(fence[1]) !== 0) {\n code.push(lines[i]);\n i += 1;\n }\n i += 1; // closing fence (absent while a block is still streaming)\n out.push('<pre><code>' + escapeHtml(code.join('\\n')) + '</code></pre>');\n continue;\n }\n var listRe = UL_ITEM.test(line) ? UL_ITEM : (OL_ITEM.test(line) ? OL_ITEM : null);\n if (listRe) {\n flush();\n var tag = listRe === UL_ITEM ? 'ul' : 'ol';\n var items = [];\n while (i < lines.length && listRe.test(lines[i])) {\n items.push('<li>' + inlineMarkdown(listRe.exec(lines[i])[1]) + '</li>');\n i += 1;\n }\n out.push('<' + tag + '>' + items.join('') + '</' + tag + '>');\n continue;\n }\n var heading = HEADING.exec(line);\n if (heading) {\n flush();\n out.push('<p><strong>' + inlineMarkdown(heading[1]) + '</strong></p>');\n } else if (!line.trim()) {\n flush();\n } else {\n para.push(line);\n }\n i += 1;\n }\n flush();\n return out.join('');\n}\n\n/** Puts the streaming caret at the end of the last paragraph or list item. */\nfunction withCaret(html) {\n if (/<\\/p>$/.test(html)) { return html.slice(0, -4) + CARET + '</p>'; }\n if (/<\\/li><\\/[ou]l>$/.test(html)) { return html.slice(0, -10) + CARET + html.slice(-10); }\n return html + CARET;\n}\n\n// ── Line diff (longest common subsequence) ──\n\nfunction toLines(value) {\n if (value == null) { return []; }\n var text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);\n text = text.replace(/\\r\\n?/g, '\\n');\n if (text === '') { return []; }\n if (text.charAt(text.length - 1) === '\\n') { text = text.slice(0, -1); }\n return text.split('\\n');\n}\n\nexport function diffLines(before, after) {\n var a = toLines(before);\n var b = toLines(after);\n var out = [];\n var start = 0;\n while (start < a.length && start < b.length && a[start] === b[start]) {\n out.push({ type: 'same', text: a[start] });\n start += 1;\n }\n var endA = a.length;\n var endB = b.length;\n while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {\n endA -= 1;\n endB -= 1;\n }\n var x = a.slice(start, endA);\n var y = b.slice(start, endB);\n var n = x.length;\n var m = y.length;\n var i;\n var j;\n if (n * m > LCS_LIMIT) {\n x.forEach(function (t) { out.push({ type: 'del', text: t }); });\n y.forEach(function (t) { out.push({ type: 'add', text: t }); });\n } else {\n var w = m + 1;\n var dp = new Int32Array((n + 1) * w);\n for (i = n - 1; i >= 0; i -= 1) {\n for (j = m - 1; j >= 0; j -= 1) {\n dp[i * w + j] = x[i] === y[j]\n ? dp[(i + 1) * w + j + 1] + 1\n : Math.max(dp[(i + 1) * w + j], dp[i * w + j + 1]);\n }\n }\n i = 0;\n j = 0;\n while (i < n && j < m) {\n if (x[i] === y[j]) {\n out.push({ type: 'same', text: x[i] });\n i += 1;\n j += 1;\n } else if (dp[(i + 1) * w + j] >= dp[i * w + j + 1]) {\n out.push({ type: 'del', text: x[i] });\n i += 1;\n } else {\n out.push({ type: 'add', text: y[j] });\n j += 1;\n }\n }\n for (; i < n; i += 1) { out.push({ type: 'del', text: x[i] }); }\n for (; j < m; j += 1) { out.push({ type: 'add', text: y[j] }); }\n }\n for (i = endA; i < a.length; i += 1) { out.push({ type: 'same', text: a[i] }); }\n return out;\n}\n\nvar DIFF_SIGN = { add: '+', del: '−', same: ' ' };\nvar DIFF_SR = { add: 'Added: ', del: 'Removed: ', same: '' };\n\nfunction diffLineHtml(line) {\n return '<span class=\"mp-ai-diff-line is-' + line.type + '\">'\n + '<span class=\"mp-ai-diff-sign\" aria-hidden=\"true\">' + DIFF_SIGN[line.type] + '</span>'\n + (DIFF_SR[line.type] ? '<span class=\"mp-ai-sr-only\">' + DIFF_SR[line.type] + '</span>' : '')\n + escapeHtml(line.text) + '</span>';\n}\n\n/** Replaces a previous listener of the same kind that MpKit.ai bound to el. */\nfunction bind(el, type, fn) {\n var store = el.__mpAiListeners || (el.__mpAiListeners = {});\n if (store[type]) { el.removeEventListener(type, store[type]); }\n store[type] = fn;\n el.addEventListener(type, fn);\n}\n\nfunction actionTarget(ev) {\n var t = ev && ev.target;\n return t && typeof t.closest === 'function' ? t.closest('[data-mp-ai-action]') : null;\n}\n\nfunction badgeHtml(label) {\n return '<span class=\"mp-ai-badge\">' + SPARKLE + escapeHtml(label || 'Assistant') + '</span>';\n}\n\nfunction thinkingHtml(label) {\n return '<span class=\"mp-ai-thinking\" role=\"status\">' + escapeHtml(label || 'Thinking…') + '</span>';\n}\n\nvar edgeEl = null;\n\nexport const ai = {\n\n /** GET-style status of the Assistant: { enabled, provider, model, capabilities }. */\n status: function () {\n var hb = hbClient();\n if (!hb || typeof hb.request !== 'function') {\n return Promise.reject(new Error('MpKit.ai needs the Homebridge plugin UI (window.homebridge)'));\n }\n return Promise.resolve(hb.request('/ai/status'));\n },\n\n /**\n * Explains a device/plugin error. body: { error, context?, device? } → { text, usage }\n * opts: { onChunk, onDone, onError, signal, notifyServer = true }; the\n * returned promise has .cancel() and .requestId.\n */\n explain: function (body, opts) { return aiRequest('/ai/explain', body, opts); },\n\n /** Free-form question. body: { prompt, context? } → { text, usage } */\n ask: function (body, opts) { return aiRequest('/ai/ask', body, opts); },\n\n /** Generates plugin config. body: { schema, request, current? } → { config, explanation, usage } */\n config: function (body, opts) { return aiRequest('/ai/config', body, opts); },\n\n markdown: markdown,\n diffLines: diffLines,\n\n /**\n * Returns HTML for an Assistant button (sparkle icon + escaped label).\n * opts: { label = 'Ask Assistant', id, className, size: 'sm' | 'lg', title }\n */\n renderButton: function (opts) {\n opts = opts || {};\n var cls = 'mp-ai-button'\n + (opts.size === 'sm' || opts.size === 'lg' ? ' mp-ai-button-' + opts.size : '')\n + (opts.className ? ' ' + escapeHtml(opts.className) : '');\n return '<button type=\"button\" class=\"' + cls + '\"'\n + (opts.id ? ' id=\"' + escapeHtml(opts.id) + '\"' : '')\n + (opts.title ? ' title=\"' + escapeHtml(opts.title) + '\"' : '')\n + '>' + SPARKLE + '<span>' + escapeHtml(opts.label || 'Ask Assistant') + '</span></button>';\n },\n\n /** Returns HTML for a small \"Assistant\" badge. */\n renderBadge: badgeHtml,\n\n /** Returns HTML for a pulsing \"Thinking…\" indicator (a status live region). */\n renderThinking: thinkingHtml,\n\n /**\n * Renders an answer panel into el and returns a controller for streaming:\n * const answer = MpKit.ai.renderAnswer(el);\n * const res = await MpKit.ai.ask({ prompt }, { onChunk: answer.append });\n * answer.done(res.text);\n * opts: { label = 'Assistant', title, text, streaming = true, note }\n * The text is rendered as escaped, safe markdown.\n */\n renderAnswer: function (el, opts) {\n opts = opts || {};\n var note = opts.note === undefined ? DEFAULT_NOTE : opts.note;\n el.innerHTML = '<section class=\"mp-ai-panel\" aria-label=\"' + escapeHtml(opts.label || 'Assistant') + ' answer\">'\n + '<div class=\"mp-ai-panel-header\">' + badgeHtml(opts.label)\n + (opts.title ? '<p class=\"mp-ai-panel-title\">' + escapeHtml(opts.title) + '</p>' : '')\n + '</div>'\n + '<div class=\"mp-ai-panel-body mp-ai-prose\"></div>'\n + '<p class=\"mp-ai-error\" role=\"alert\" hidden></p>'\n + (note ? '<p class=\"mp-ai-panel-note\">' + escapeHtml(note) + '</p>' : '')\n + '</section>';\n var panel = el.querySelector('.mp-ai-panel');\n var body = el.querySelector('.mp-ai-panel-body');\n var errorEl = el.querySelector('.mp-ai-error');\n var text = opts.text == null ? '' : String(opts.text);\n var streaming = opts.streaming !== false;\n\n function paint() {\n var html = markdown(text);\n if (streaming) { html = text ? withCaret(html) : thinkingHtml(); }\n body.innerHTML = html;\n panel.classList.toggle('is-streaming', streaming);\n panel.setAttribute('aria-busy', streaming ? 'true' : 'false');\n }\n\n var controller = {\n append: function (delta) {\n text += delta == null ? '' : String(delta);\n paint();\n return controller;\n },\n setText: function (value) {\n text = value == null ? '' : String(value);\n paint();\n return controller;\n },\n done: function (result) {\n var final = result && typeof result === 'object' ? result.text : result;\n if (typeof final === 'string' && final) { text = final; }\n streaming = false;\n paint();\n return controller;\n },\n error: function (err) {\n streaming = false;\n paint();\n errorEl.textContent = errorMessage(err, DEFAULT_ERROR);\n errorEl.hidden = false;\n return controller;\n },\n getText: function () { return text; },\n };\n paint();\n return controller;\n },\n\n /**\n * Renders a line diff with Apply / Reject buttons into el.\n * before/after may be strings or JSON-serialisable values (pretty-printed).\n * onApply / onReject receive { before, after, lines }; they may return a\n * promise — if it rejects, the buttons are re-enabled and the error shown.\n * opts: { before, after, onApply, onReject, title, applyLabel, rejectLabel }\n * Returns { lines, added, removed }.\n */\n renderDiff: function (el, opts) {\n opts = opts || {};\n var lines = diffLines(opts.before, opts.after);\n var added = lines.filter(function (l) { return l.type === 'add'; }).length;\n var removed = lines.filter(function (l) { return l.type === 'del'; }).length;\n var hasActions = typeof opts.onApply === 'function' || typeof opts.onReject === 'function';\n var title = opts.title || 'Suggested changes';\n\n el.innerHTML = '<div class=\"mp-ai-diff\">'\n + '<div class=\"mp-ai-diff-header\">' + badgeHtml(opts.label)\n + '<span class=\"mp-ai-diff-title\">' + escapeHtml(title) + '</span>'\n + '<span class=\"mp-ai-diff-stats\">'\n + '<span class=\"mp-ai-diff-stat-add\">+' + added + '<span class=\"mp-ai-sr-only\"> added</span></span>'\n + '<span class=\"mp-ai-diff-stat-del\">−' + removed + '<span class=\"mp-ai-sr-only\"> removed</span></span>'\n + '</span></div>'\n + '<pre class=\"mp-ai-diff-body\" tabindex=\"0\" aria-label=\"' + escapeHtml(title) + '\"><code>'\n + (added || removed ? lines.map(diffLineHtml).join('') : '<span class=\"mp-ai-diff-line\">No changes</span>')\n + '</code></pre>'\n + (hasActions\n ? '<div class=\"mp-ai-diff-actions\">'\n + '<span class=\"mp-ai-diff-status\" role=\"status\"></span>'\n + '<button type=\"button\" class=\"mp-ai-action\" data-mp-ai-action=\"reject\">'\n + escapeHtml(opts.rejectLabel || 'Reject') + '</button>'\n + '<button type=\"button\" class=\"mp-ai-action mp-ai-action-primary\" data-mp-ai-action=\"apply\">'\n + escapeHtml(opts.applyLabel || 'Apply') + '</button>'\n + '</div>'\n : '')\n + '</div>';\n\n var result = { lines: lines, added: added, removed: removed };\n if (!hasActions) { return result; }\n\n var root = el.querySelector('.mp-ai-diff');\n var statusEl = el.querySelector('.mp-ai-diff-status');\n var applyBtn = el.querySelector('[data-mp-ai-action=\"apply\"]');\n var rejectBtn = el.querySelector('[data-mp-ai-action=\"reject\"]');\n var settled = false;\n var busy = false;\n\n function setDisabled(disabled) {\n applyBtn.disabled = disabled;\n rejectBtn.disabled = disabled;\n }\n\n bind(el, 'click', function (ev) {\n var btn = actionTarget(ev);\n if (!btn || settled || busy) { return; }\n var action = btn.getAttribute('data-mp-ai-action');\n if (action !== 'apply' && action !== 'reject') { return; }\n var cb = action === 'apply' ? opts.onApply : opts.onReject;\n busy = true;\n setDisabled(true);\n statusEl.textContent = '';\n Promise.resolve()\n .then(function () {\n return typeof cb === 'function'\n ? cb({ before: opts.before, after: opts.after, lines: lines })\n : undefined;\n })\n .then(function () {\n busy = false;\n settled = true;\n root.classList.add(action === 'apply' ? 'is-applied' : 'is-rejected');\n statusEl.textContent = action === 'apply' ? 'Applied' : 'Rejected';\n }, function (err) {\n busy = false;\n setDisabled(false);\n statusEl.textContent = errorMessage(err, 'Something went wrong');\n });\n });\n return result;\n },\n\n /**\n * Renders a chat (log + input) into el. Each message is sent with\n * MpKit.ai.ask({ prompt, context }) and streamed into the log; the context is\n * opts.context plus the recent conversation. Pass opts.onSend(prompt,\n * { onChunk, history }) to use another transport; it may resolve with a\n * string or { text }.\n * opts: { label = 'Assistant', context, placeholder, emptyText, onSend }\n * onSend also receives ctx.signal (an AbortSignal) for chat.cancel().\n * Returns { send(text?), cancel(), clear(), messages() }.\n */\n renderChat: function (el, opts) {\n opts = opts || {};\n var inputId = uid('mp-ai-chat-input');\n el.innerHTML = '<div class=\"mp-ai-chat\">'\n + '<div class=\"mp-ai-chat-header\">' + badgeHtml(opts.label) + '</div>'\n + '<div class=\"mp-ai-chat-log\" role=\"log\" aria-live=\"polite\" aria-label=\"'\n + escapeHtml(opts.label || 'Assistant') + ' conversation\"></div>'\n + '<form class=\"mp-ai-chat-form\">'\n + '<label class=\"mp-ai-sr-only\" for=\"' + inputId + '\">Message</label>'\n + '<textarea class=\"mp-ai-chat-input\" id=\"' + inputId + '\" rows=\"1\" placeholder=\"'\n + escapeHtml(opts.placeholder || 'Ask the Assistant…') + '\"></textarea>'\n + '<button type=\"submit\" class=\"mp-ai-button\">' + SPARKLE + '<span>Send</span></button>'\n + '</form></div>';\n\n var log = el.querySelector('.mp-ai-chat-log');\n var input = el.querySelector('.mp-ai-chat-input');\n var sendBtn = el.querySelector('.mp-ai-chat-form .mp-ai-button');\n var messages = [];\n var busy = false;\n\n function messageHtml(m) {\n if (m.role === 'user') {\n return '<div class=\"mp-ai-chat-msg is-user\"><div class=\"mp-ai-chat-bubble\">'\n + '<span class=\"mp-ai-sr-only\">You: </span>'\n + escapeHtml(m.text).replace(/\\n/g, '<br>') + '</div></div>';\n }\n var html = markdown(m.text);\n if (m.streaming) { html = m.text ? withCaret(html) : thinkingHtml(); }\n if (m.error) { html += '<p class=\"mp-ai-error\" role=\"alert\">' + escapeHtml(m.error) + '</p>'; }\n if (m.stopped) { html += '<p class=\"mp-ai-panel-note\">Stopped</p>'; }\n return '<div class=\"mp-ai-chat-msg is-assistant\"><div class=\"mp-ai-chat-bubble mp-ai-prose\">'\n + '<span class=\"mp-ai-sr-only\">' + escapeHtml(opts.label || 'Assistant') + ': </span>'\n + html + '</div></div>';\n }\n\n function paint() {\n log.innerHTML = messages.length\n ? messages.map(messageHtml).join('')\n : '<p class=\"mp-ai-chat-empty\">' + escapeHtml(opts.emptyText || 'Ask the Assistant a question.') + '</p>';\n log.setAttribute('aria-busy', busy ? 'true' : 'false');\n log.scrollTop = log.scrollHeight;\n sendBtn.disabled = busy;\n sendBtn.setAttribute('aria-busy', busy ? 'true' : 'false');\n }\n\n function defaultSend(prompt, ctx) {\n var transcript = ctx.history.slice(-10).map(function (m) {\n return (m.role === 'user' ? 'User' : 'Assistant') + ': ' + m.text;\n }).join('\\n');\n var context = [opts.context, transcript ? 'Conversation so far:\\n' + transcript : '']\n .filter(Boolean).join('\\n\\n');\n var body = { prompt: prompt };\n if (context) { body.context = context; }\n return ai.ask(body, { onChunk: ctx.onChunk, signal: ctx.signal });\n }\n\n var controller = null;\n\n function send(text) {\n var prompt = String(text == null ? input.value : text).trim();\n if (!prompt || busy) { return Promise.resolve(null); }\n if (text == null) { input.value = ''; }\n var history = messages.filter(function (m) { return !m.error && !m.stopped; }).map(function (m) {\n return { role: m.role, text: m.text };\n });\n var reply = { role: 'assistant', text: '', streaming: true };\n messages.push({ role: 'user', text: prompt }, reply);\n busy = true;\n paint();\n var handler = typeof opts.onSend === 'function' ? opts.onSend : defaultSend;\n controller = typeof AbortController === 'function' ? new AbortController() : null;\n var signal = controller ? controller.signal : undefined;\n return Promise.resolve()\n .then(function () {\n return handler(prompt, {\n history: history,\n signal: signal,\n onChunk: function (delta) {\n reply.text += delta == null ? '' : String(delta);\n paint();\n },\n });\n })\n .then(function (res) {\n var final = res && typeof res === 'object' ? res.text : res;\n if (typeof final === 'string' && final) { reply.text = final; }\n }, function (err) {\n if ((err && err.name === 'AbortError') || (signal && signal.aborted)) {\n reply.stopped = true;\n } else {\n reply.error = errorMessage(err, DEFAULT_ERROR);\n }\n })\n .then(function () {\n reply.streaming = false;\n busy = false;\n controller = null;\n paint();\n return reply.error || reply.stopped ? null : reply.text;\n });\n }\n\n bind(el, 'submit', function (ev) {\n ev.preventDefault();\n send();\n });\n bind(el, 'keydown', function (ev) {\n var t = ev.target;\n if (ev.key === 'Enter' && !ev.shiftKey && !ev.isComposing && t === input) {\n ev.preventDefault();\n send();\n }\n });\n paint();\n\n return {\n send: send,\n /** Stops the reply in progress (aborts the signal passed to onSend / ask). */\n cancel: function () {\n if (!controller) { return false; }\n controller.abort();\n return true;\n },\n clear: function () {\n messages = [];\n paint();\n },\n messages: function () {\n return messages.map(function (m) {\n return { role: m.role, text: m.text, error: m.error };\n });\n },\n };\n },\n\n /**\n * Shows (default) or hides a fixed glow around the page edges, e.g. while\n * the Assistant works. Returns the element.\n */\n edgeGlow: function (show) {\n if (show === false) {\n if (edgeEl) { edgeEl.hidden = true; }\n return edgeEl;\n }\n if (!edgeEl) {\n edgeEl = doc().createElement('div');\n edgeEl.className = 'mp-ai-edge-glow';\n edgeEl.setAttribute('aria-hidden', 'true');\n doc().body.appendChild(edgeEl);\n }\n edgeEl.hidden = false;\n return edgeEl;\n },\n\n};\n","// Theme — light/dark handling for plugin UIs. Combines the system preference,\n// the Homebridge user's setting (homebridge.getUserSettings(), including\n// \"auto\") and a live prefers-color-scheme listener, and remembers the\n// preference so dist/theme-boot.js can apply it before first paint.\n\nimport { root, doc, hbClient } from './env.js';\n\nexport const THEME_STORAGE_KEY = 'mp-kit-theme';\nconst QUERY = '(prefers-color-scheme: dark)';\n\n/** Maps the many spellings hosts use to 'light' | 'dark' | 'auto' (or null). */\nexport function normalizeTheme(value) {\n if (typeof value !== 'string') { return null; }\n const v = value.trim().toLowerCase();\n if (v === 'dark' || v === 'dark-mode') { return 'dark'; }\n if (v === 'light' || v === 'light-mode') { return 'light'; }\n if (v === 'auto' || v === 'system') { return 'auto'; }\n return null;\n}\n\n/** Resolves a preference to 'light' | 'dark' given whether the system is dark. */\nexport function resolveTheme(preference, systemDark) {\n return preference === 'dark' || (preference !== 'light' && !!systemDark) ? 'dark' : 'light';\n}\n\n/** Reads the preference from a homebridge.getUserSettings() result. */\nexport function themeFromSettings(settings) {\n if (!settings || typeof settings !== 'object') { return null; }\n return normalizeTheme(settings.colorScheme) || normalizeTheme(settings.theme)\n || normalizeTheme(settings.lightingMode);\n}\n\nfunction mediaQuery() {\n try {\n return typeof root.matchMedia === 'function' ? root.matchMedia(QUERY) : null;\n } catch {\n return null;\n }\n}\n\nfunction store(key, value) {\n if (!key) { return; }\n try { root.localStorage.setItem(key, value); } catch { /* storage blocked */ }\n}\n\nfunction stored(key) {\n if (!key) { return null; }\n try { return normalizeTheme(root.localStorage.getItem(key)); } catch { return null; }\n}\n\n/** Asks Homebridge for the user's theme: getUserSettings(), then userCurrentLightingMode(). */\nexport async function homebridgeTheme() {\n const hb = hbClient();\n if (!hb) { return null; }\n if (typeof hb.getUserSettings === 'function') {\n try {\n const pref = themeFromSettings(await hb.getUserSettings());\n if (pref) { return pref; }\n } catch { /* older Homebridge UI */ }\n }\n if (typeof hb.userCurrentLightingMode === 'function') {\n try {\n const pref = normalizeTheme(await hb.userCurrentLightingMode());\n if (pref) { return pref; }\n } catch { /* not available */ }\n }\n return null;\n}\n\n/** Applies a resolved theme to an element (data-bs-theme and .mp-theme-dark). */\nexport function applyTheme(resolved, opts) {\n opts = opts || {};\n const d = doc();\n const target = opts.target || (d && d.documentElement);\n if (!target) { return; }\n const dark = resolved === 'dark';\n if (opts.attribute !== false) { target.setAttribute('data-bs-theme', dark ? 'dark' : 'light'); }\n if (opts.className !== false) { target.classList.toggle('mp-theme-dark', dark); }\n}\n\nexport const Theme = {\n /**\n * Applies the theme now (stored/system preference), then the Homebridge\n * user's setting once it arrives, and follows system changes while the\n * preference is 'auto'.\n * opts: { target = <html>, theme ('light'|'dark'|'auto': skip Homebridge),\n * homebridge = true, storageKey = 'mp-kit-theme' (false: none),\n * attribute = true, className = true, onChange(resolved, preference) }\n */\n init(opts) {\n opts = opts || {};\n const key = opts.storageKey === undefined ? THEME_STORAGE_KEY : opts.storageKey;\n const explicit = normalizeTheme(opts.theme);\n let preference = explicit || stored(key) || 'auto';\n let current = null;\n let pinned = !!explicit;\n let destroyed = false;\n const media = mediaQuery();\n\n function update() {\n const resolved = resolveTheme(preference, media && media.matches);\n applyTheme(resolved, opts);\n store(key, preference);\n if (resolved !== current) {\n const first = current === null;\n current = resolved;\n if (!first && typeof opts.onChange === 'function') { opts.onChange(resolved, preference); }\n }\n }\n\n function onMedia() {\n if (!destroyed && preference === 'auto') { update(); }\n }\n\n if (media) {\n if (typeof media.addEventListener === 'function') { media.addEventListener('change', onMedia); }\n else if (typeof media.addListener === 'function') { media.addListener(onMedia); }\n }\n update();\n\n const controller = {\n /** Resolves with the resolved theme once the Homebridge setting was applied. */\n ready: null,\n preference: () => preference,\n resolved: () => current,\n /** Overrides the preference ('light' | 'dark' | 'auto'). */\n set(mode) {\n preference = normalizeTheme(mode) || 'auto';\n pinned = true;\n update();\n return current;\n },\n destroy() {\n destroyed = true;\n if (!media) { return; }\n if (typeof media.removeEventListener === 'function') { media.removeEventListener('change', onMedia); }\n else if (typeof media.removeListener === 'function') { media.removeListener(onMedia); }\n },\n };\n\n controller.ready = (pinned || opts.homebridge === false ? Promise.resolve(null) : homebridgeTheme())\n .then(pref => {\n if (pref && !pinned && !destroyed) {\n preference = pref;\n update();\n }\n return current;\n });\n return controller;\n },\n\n apply: applyTheme,\n resolve: resolveTheme,\n normalize: normalizeTheme,\n fromSettings: themeFromSettings,\n};\n","// Tabs — accessible behaviour for .mp-tabs (Bootstrap .nav markup):\n// role=\"tablist\"/\"tab\"/\"tabpanel\", aria-selected, roving tabindex and\n// arrow-key / Home / End navigation (mirrored on RTL pages).\n\nimport { doc } from './env.js';\nimport { uid } from './util.js';\nimport { View } from './core.js';\n\nfunction panelId(tab) {\n const ref = tab.getAttribute('data-mp-view') || tab.getAttribute('aria-controls')\n || tab.getAttribute('data-bs-target') || tab.getAttribute('href') || '';\n const id = ref.charAt(0) === '#' ? ref.slice(1) : ref;\n return /^[A-Za-z][\\w:.-]*$/.test(id) ? id : null;\n}\n\nfunction isRtl(el) {\n const holder = el.closest('[dir]');\n if (holder) { return holder.getAttribute('dir').toLowerCase() === 'rtl'; }\n try {\n const view = el.ownerDocument.defaultView;\n return view.getComputedStyle(el).direction === 'rtl';\n } catch {\n return false;\n }\n}\n\nexport const Tabs = {\n /**\n * Enhances a tab bar. el: .mp-tabs element or selector.\n * opts: { activation: 'auto' | 'manual', onChange(tab, index, panel) }\n * Tabs reference their panel with data-mp-view (an .mp-view id, shown with\n * MpKit.View.show), aria-controls, data-bs-target or href=\"#id\".\n * Returns { select(indexOrTab), selected(), tabs(), destroy() }.\n */\n init(el, opts) {\n opts = opts || {};\n const root = typeof el === 'string' ? doc().querySelector(el) : el;\n if (!root) { return null; }\n const tabs = Array.from(root.querySelectorAll('.nav-link, [role=\"tab\"]'));\n const vertical = root.getAttribute('aria-orientation') === 'vertical';\n root.setAttribute('role', 'tablist');\n\n tabs.forEach(tab => {\n if (tab.parentElement !== root && tab.parentElement.tagName === 'LI') {\n tab.parentElement.setAttribute('role', 'presentation');\n }\n tab.setAttribute('role', 'tab');\n if (!tab.id) { tab.id = uid('mp-tab'); }\n const id = panelId(tab);\n const panel = id && root.ownerDocument.getElementById(id);\n if (panel) {\n tab.setAttribute('aria-controls', id);\n panel.setAttribute('role', 'tabpanel');\n if (!panel.hasAttribute('aria-labelledby')) { panel.setAttribute('aria-labelledby', tab.id); }\n }\n });\n\n let current = -1;\n\n function panelOf(tab) {\n const id = tab.getAttribute('aria-controls');\n return id ? root.ownerDocument.getElementById(id) : null;\n }\n\n function select(target, fromUser) {\n const index = typeof target === 'number' ? target : tabs.indexOf(target);\n if (index < 0 || index >= tabs.length) { return; }\n const changed = index !== current;\n tabs.forEach((tab, i) => {\n const on = i === index;\n tab.setAttribute('aria-selected', on ? 'true' : 'false');\n tab.setAttribute('tabindex', on ? '0' : '-1');\n tab.classList.toggle('active', on);\n const panel = panelOf(tab);\n if (!panel || panel.classList.contains('mp-view')) { return; }\n if (panel.classList.contains('tab-pane')) {\n panel.classList.toggle('active', on);\n panel.classList.toggle('show', on);\n } else {\n panel.hidden = !on;\n }\n });\n const panel = panelOf(tabs[index]);\n if (panel && panel.classList.contains('mp-view')) {\n View.show(panel.id, { focus: false, announce: false });\n }\n current = index;\n if (changed && fromUser && typeof opts.onChange === 'function') {\n opts.onChange(tabs[index], index, panel);\n }\n }\n\n function onClick(ev) {\n const tab = ev.target.closest('[role=\"tab\"]');\n if (!tab || !root.contains(tab)) { return; }\n if (tab.tagName === 'A') { ev.preventDefault(); }\n select(tab, true);\n }\n\n function onKeydown(ev) {\n const tab = ev.target.closest('[role=\"tab\"]');\n if (!tab || !root.contains(tab)) { return; }\n const enabled = tabs.filter(t => !t.disabled && t.getAttribute('aria-disabled') !== 'true');\n const pos = enabled.indexOf(tab);\n const rtl = !vertical && isRtl(root);\n const next = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');\n const prev = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');\n let to = null;\n if (ev.key === next) { to = enabled[(pos + 1) % enabled.length]; }\n else if (ev.key === prev) { to = enabled[(pos - 1 + enabled.length) % enabled.length]; }\n else if (ev.key === 'Home') { to = enabled[0]; }\n else if (ev.key === 'End') { to = enabled[enabled.length - 1]; }\n else if ((ev.key === 'Enter' || ev.key === ' ') && opts.activation === 'manual') {\n ev.preventDefault();\n select(tab, true);\n return;\n }\n if (!to) { return; }\n ev.preventDefault();\n if (opts.activation === 'manual') {\n tabs.forEach(t => t.setAttribute('tabindex', t === to ? '0' : '-1'));\n } else {\n select(to, true);\n }\n to.focus();\n }\n\n root.addEventListener('click', onClick);\n root.addEventListener('keydown', onKeydown);\n\n const initial = tabs.findIndex(t => t.classList.contains('active') || t.getAttribute('aria-selected') === 'true');\n select(initial < 0 ? 0 : initial, false);\n\n return {\n select: target => select(target, true),\n selected: () => current,\n tabs: () => tabs.slice(),\n destroy() {\n root.removeEventListener('click', onClick);\n root.removeEventListener('keydown', onKeydown);\n },\n };\n },\n};\n","// Toast — notifications. Inside Homebridge they use the UI's own toasts\n// (homebridge.toast.*); elsewhere (or with { local: true }) a Bootstrap-style\n// toast is shown in a fixed .mp-toast-container.\n\nimport { doc, hbClient } from './env.js';\nimport { escapeHtml } from './util.js';\n\nconst TYPES = ['success', 'error', 'warning', 'info'];\nconst DURATION = { success: 5000, info: 5000, warning: 7000, error: 8000 };\nconst ICON = { success: '✓', info: 'i', warning: '!', error: '✕' };\n\nlet container = null;\n\nfunction ensureContainer(d) {\n if (!container || !container.isConnected) {\n container = d.createElement('div');\n container.className = 'mp-toast-container';\n d.body.appendChild(container);\n }\n return container;\n}\n\n/**\n * Shows a toast. type: 'success' | 'error' | 'warning' | 'info'.\n * opts (or a title string): { title, duration (ms, 0 = until closed), local }\n * Returns { close(), element, native } — native is true when Homebridge showed it.\n */\nfunction show(type, message, opts) {\n if (TYPES.indexOf(type) < 0) { type = 'info'; }\n opts = typeof opts === 'string' ? { title: opts } : (opts || {});\n const text = String(message == null ? '' : message);\n const hb = hbClient();\n if (!opts.local && hb && hb.toast && typeof hb.toast[type] === 'function') {\n hb.toast[type](text, opts.title);\n return { close() {}, element: null, native: true };\n }\n const d = doc();\n if (!d || !d.body) { return { close() {}, element: null, native: false }; }\n\n const el = d.createElement('div');\n el.className = 'mp-toast mp-toast-' + type;\n // Errors and warnings interrupt; the rest wait for a pause.\n el.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status');\n el.setAttribute('aria-atomic', 'true');\n el.innerHTML = '<span class=\"mp-toast-icon\" aria-hidden=\"true\">' + ICON[type] + '</span>'\n + '<div class=\"mp-toast-body\">'\n + (opts.title ? '<p class=\"mp-toast-title\">' + escapeHtml(opts.title) + '</p>' : '')\n + '<p class=\"mp-toast-message\">' + escapeHtml(text) + '</p>'\n + '</div>'\n + '<button type=\"button\" class=\"mp-toast-close\" aria-label=\"Close\">×</button>';\n ensureContainer(d).appendChild(el);\n\n let timer = null;\n let closed = false;\n const duration = opts.duration === undefined ? DURATION[type] : Number(opts.duration) || 0;\n\n function close() {\n if (closed) { return; }\n closed = true;\n clearTimeout(timer);\n el.remove();\n }\n function arm() {\n clearTimeout(timer);\n if (duration > 0) { timer = setTimeout(close, duration); }\n }\n // Pause while the pointer or focus is on the toast, so it can be read.\n el.addEventListener('mouseenter', () => clearTimeout(timer));\n el.addEventListener('mouseleave', arm);\n el.addEventListener('focusin', () => clearTimeout(timer));\n el.addEventListener('focusout', arm);\n el.querySelector('.mp-toast-close').addEventListener('click', close);\n arm();\n return { close, element: el, native: false };\n}\n\nexport const Toast = {\n show,\n success: (message, opts) => show('success', message, opts),\n error: (message, opts) => show('error', message, opts),\n warning: (message, opts) => show('warning', message, opts),\n info: (message, opts) => show('info', message, opts),\n};\n","// confirm() — an accessible modal confirmation dialog returning a promise.\n\nimport { doc } from './env.js';\nimport { escapeHtml, focusables, uid } from './util.js';\n\n/**\n * Opens a modal dialog and resolves with true (confirmed) or false\n * (cancelled, Escape, or a click on the backdrop).\n * opts (or a message string): { title = 'Are you sure?', message,\n * confirmLabel = 'Confirm', cancelLabel = 'Cancel', danger = false }\n * The danger variant uses a red confirm button and focuses Cancel first.\n */\nexport function confirm(opts) {\n opts = typeof opts === 'string' ? { message: opts } : (opts || {});\n const d = doc();\n if (!d || !d.body) { return Promise.resolve(false); }\n const titleId = uid('mp-dialog-title');\n const messageId = uid('mp-dialog-message');\n const danger = !!opts.danger;\n\n const backdrop = d.createElement('div');\n backdrop.className = 'mp-dialog-backdrop';\n backdrop.innerHTML = '<div class=\"mp-dialog' + (danger ? ' mp-dialog-danger' : '') + '\" role=\"alertdialog\"'\n + ' aria-modal=\"true\" aria-labelledby=\"' + titleId + '\"'\n + (opts.message ? ' aria-describedby=\"' + messageId + '\"' : '') + '>'\n + '<h2 class=\"mp-dialog-title\" id=\"' + titleId + '\">' + escapeHtml(opts.title || 'Are you sure?') + '</h2>'\n + (opts.message ? '<p class=\"mp-dialog-message\" id=\"' + messageId + '\">' + escapeHtml(opts.message) + '</p>' : '')\n + '<div class=\"mp-dialog-actions\">'\n + '<button type=\"button\" class=\"btn btn-outline-secondary\" data-mp-dialog=\"cancel\">'\n + escapeHtml(opts.cancelLabel || 'Cancel') + '</button>'\n + '<button type=\"button\" class=\"btn ' + (danger ? 'btn-danger' : 'btn-primary') + '\" data-mp-dialog=\"confirm\">'\n + escapeHtml(opts.confirmLabel || 'Confirm') + '</button>'\n + '</div></div>';\n\n const dialog = backdrop.firstChild;\n const previous = d.activeElement;\n // Make the rest of the page inert while the dialog is open.\n const inerted = Array.from(d.body.children).filter(n => !n.hasAttribute('inert')\n && !n.hasAttribute('data-mp-live') && !n.classList.contains('mp-toast-container'));\n inerted.forEach(n => n.setAttribute('inert', ''));\n d.body.appendChild(backdrop);\n d.body.classList.add('mp-dialog-open');\n\n return new Promise(resolve => {\n function finish(result) {\n d.removeEventListener('keydown', onKey, true);\n backdrop.remove();\n inerted.forEach(n => n.removeAttribute('inert'));\n if (!d.querySelector('.mp-dialog-backdrop')) { d.body.classList.remove('mp-dialog-open'); }\n if (previous && typeof previous.focus === 'function' && previous.isConnected) {\n try { previous.focus({ preventScroll: true }); } catch { previous.focus(); }\n }\n resolve(result);\n }\n function onKey(ev) {\n if (ev.key === 'Escape') {\n ev.preventDefault();\n ev.stopPropagation();\n finish(false);\n } else if (ev.key === 'Tab') {\n const items = focusables(dialog);\n if (!items.length) { return; }\n const first = items[0];\n const last = items[items.length - 1];\n const active = d.activeElement;\n if (ev.shiftKey && (active === first || !dialog.contains(active))) {\n ev.preventDefault();\n last.focus();\n } else if (!ev.shiftKey && (active === last || !dialog.contains(active))) {\n ev.preventDefault();\n first.focus();\n }\n }\n }\n backdrop.addEventListener('click', ev => {\n const action = ev.target.closest && ev.target.closest('[data-mp-dialog]');\n if (action) { finish(action.getAttribute('data-mp-dialog') === 'confirm'); }\n else if (ev.target === backdrop) { finish(false); }\n });\n d.addEventListener('keydown', onKey, true);\n dialog.querySelector('[data-mp-dialog=\"' + (danger ? 'cancel' : 'confirm') + '\"]').focus();\n });\n}\n","// Form helpers: Bootstrap field markup, secret inputs (reveal + copy), copy\n// buttons, value (de)serialisation, and dirty-state tracking with a sticky\n// Save bar wired to homebridge.updatePluginConfig / savePluginConfig.\n\nimport { root, doc, hbClient } from './env.js';\nimport { announce, errorMessage, escapeHtml, toElement, uid } from './util.js';\nimport { Toast } from './toast.js';\n\n// ── Clipboard ──\n\n/** Copies text to the clipboard. Resolves true on success, false otherwise. */\nexport function copyText(text) {\n const value = String(text == null ? '' : text);\n const nav = root.navigator;\n if (nav && nav.clipboard && typeof nav.clipboard.writeText === 'function') {\n return nav.clipboard.writeText(value).then(() => true, () => legacyCopy(value));\n }\n return Promise.resolve(legacyCopy(value));\n}\n\nfunction legacyCopy(value) {\n const d = doc();\n if (!d || !d.body || typeof d.execCommand !== 'function') { return false; }\n const area = d.createElement('textarea');\n area.value = value;\n area.setAttribute('readonly', '');\n area.className = 'mp-sr-only';\n d.body.appendChild(area);\n area.select();\n let ok = false;\n try { ok = d.execCommand('copy'); } catch { ok = false; }\n area.remove();\n return !!ok;\n}\n\nfunction attrs(map) {\n return Object.keys(map).map(k => {\n const v = map[k];\n if (v === undefined || v === null || v === false) { return ''; }\n return v === true ? ' ' + k : ' ' + k + '=\"' + escapeHtml(v) + '\"';\n }).join('');\n}\n\n/** CopyButton — HTML for a button that copies `text` or the value/text of `target`. */\nexport const CopyButton = {\n /** opts: { text, target (selector), label = 'Copy', copiedLabel = 'Copied', className, size: 'sm' } */\n render(opts) {\n opts = opts || {};\n const cls = 'btn btn-outline-secondary mp-copy-btn' + (opts.size === 'sm' ? ' btn-sm' : '')\n + (opts.className ? ' ' + opts.className : '');\n return '<button type=\"button\"' + attrs({\n class: cls,\n 'data-mp-copy': opts.target ? undefined : String(opts.text == null ? '' : opts.text),\n 'data-mp-copy-target': opts.target,\n 'data-mp-copied-label': opts.copiedLabel || 'Copied',\n 'aria-label': opts.ariaLabel,\n }) + '>' + escapeHtml(opts.label || 'Copy') + '</button>';\n },\n};\n\n/** Copies for a [data-mp-copy] / [data-mp-copy-target] button and shows feedback. */\nexport function copyFromButton(btn) {\n let text = btn.getAttribute('data-mp-copy');\n const targetSel = btn.getAttribute('data-mp-copy-target');\n if (targetSel) {\n const target = toElement(targetSel);\n if (!target) { return Promise.resolve(false); }\n text = 'value' in target && target.tagName !== 'BUTTON' ? target.value : target.textContent;\n }\n return copyText(text).then(ok => {\n const label = btn.getAttribute('data-mp-copied-label') || 'Copied';\n if (!btn.__mpLabel) { btn.__mpLabel = btn.textContent; }\n btn.textContent = ok ? label : 'Copy failed';\n btn.classList.toggle('is-copied', ok);\n announce(ok ? 'Copied to clipboard' : 'Could not copy');\n clearTimeout(btn.__mpCopyTimer);\n btn.__mpCopyTimer = setTimeout(() => {\n btn.textContent = btn.__mpLabel;\n btn.classList.remove('is-copied');\n }, 2000);\n return ok;\n });\n}\n\n/** Toggles a [data-mp-reveal=\"inputId\"] button's password field. */\nexport function toggleReveal(btn) {\n const input = doc().getElementById(btn.getAttribute('data-mp-reveal'));\n if (!input) { return; }\n const show = input.type === 'password';\n input.type = show ? 'text' : 'password';\n btn.setAttribute('aria-pressed', show ? 'true' : 'false');\n btn.textContent = show ? (btn.getAttribute('data-mp-hide-label') || 'Hide')\n : (btn.getAttribute('data-mp-show-label') || 'Show');\n}\n\n// ── Fields ──\n\nfunction normaliseOptions(options) {\n return (options || []).map(o => (o && typeof o === 'object' ? o : { value: o, label: String(o) }));\n}\n\nfunction fieldParts(opts, kind) {\n const id = opts.id || uid('mp-field');\n const helpId = opts.help ? id + '-help' : null;\n const errorId = opts.error ? id + '-error' : null;\n const describedBy = [helpId, errorId].filter(Boolean).join(' ') || undefined;\n const label = '<label class=\"' + (kind === 'check' ? 'form-check-label' : 'form-label') + '\" for=\"' + escapeHtml(id) + '\">'\n + escapeHtml(opts.label || opts.name || '')\n + (opts.required ? '<span class=\"mp-required\" aria-hidden=\"true\"> *</span>' : '') + '</label>';\n const help = opts.help ? '<div class=\"form-text\" id=\"' + escapeHtml(helpId) + '\">' + escapeHtml(opts.help) + '</div>' : '';\n const error = opts.error ? '<div class=\"invalid-feedback d-block\" id=\"' + escapeHtml(errorId) + '\">' + escapeHtml(opts.error) + '</div>' : '';\n return { id, describedBy, label, help, error };\n}\n\n/**\n * Form.field(opts) → HTML for a labelled Bootstrap form control.\n * opts: { name, label, type = 'text' (any input type, 'textarea', 'select',\n * 'checkbox', 'switch'), id, value, placeholder, help, error, required,\n * disabled, readonly, min, max, step, pattern, autocomplete, rows,\n * options: [{ value, label }] | ['a', 'b'] (select), checked (checkbox) }\n * All values are escaped; help and error are wired with aria-describedby.\n */\nfunction field(opts) {\n opts = opts || {};\n const type = opts.type || 'text';\n const check = type === 'checkbox' || type === 'switch';\n const p = fieldParts(opts, check ? 'check' : 'field');\n const common = {\n id: p.id,\n name: opts.name,\n required: !!opts.required,\n disabled: !!opts.disabled,\n 'aria-describedby': p.describedBy,\n 'aria-invalid': opts.error ? 'true' : undefined,\n };\n const invalid = opts.error ? ' is-invalid' : '';\n\n if (check) {\n return '<div class=\"form-check' + (type === 'switch' ? ' form-switch' : '') + ' mb-3 mp-field\">'\n + '<input' + attrs(Object.assign({\n class: 'form-check-input' + invalid,\n type: 'checkbox',\n role: type === 'switch' ? 'switch' : undefined,\n checked: !!(opts.checked !== undefined ? opts.checked : opts.value),\n }, common)) + '>' + p.label + p.help + p.error + '</div>';\n }\n\n let control;\n if (type === 'select') {\n control = '<select' + attrs(Object.assign({ class: 'form-select' + invalid, multiple: !!opts.multiple }, common)) + '>'\n + normaliseOptions(opts.options).map(o => {\n const selected = Array.isArray(opts.value) ? opts.value.map(String).indexOf(String(o.value)) >= 0\n : String(opts.value) === String(o.value);\n return '<option' + attrs({ value: String(o.value), selected, disabled: !!o.disabled }) + '>'\n + escapeHtml(o.label) + '</option>';\n }).join('') + '</select>';\n } else if (type === 'textarea') {\n control = '<textarea' + attrs(Object.assign({\n class: 'form-control' + invalid, rows: opts.rows || 3, placeholder: opts.placeholder, readonly: !!opts.readonly,\n }, common)) + '>' + escapeHtml(opts.value == null ? '' : opts.value) + '</textarea>';\n } else {\n control = '<input' + attrs(Object.assign({\n class: 'form-control' + invalid,\n type,\n value: opts.value == null ? undefined : String(opts.value),\n placeholder: opts.placeholder,\n readonly: !!opts.readonly,\n min: opts.min,\n max: opts.max,\n step: opts.step,\n pattern: opts.pattern,\n autocomplete: opts.autocomplete,\n inputmode: opts.inputmode,\n }, common)) + '>';\n }\n return '<div class=\"mb-3 mp-field\">' + p.label + control + p.help + p.error + '</div>';\n}\n\n/**\n * Form.secret(opts) → HTML for a password-style field with Show/Hide and\n * Copy buttons (handled by the kit's delegated listeners).\n * opts: field options plus { copy = true, reveal = true }\n */\nfunction secret(opts) {\n opts = opts || {};\n const p = fieldParts(opts, 'field');\n const input = '<input' + attrs({\n class: 'form-control mp-secret-input' + (opts.error ? ' is-invalid' : ''),\n type: 'password',\n id: p.id,\n name: opts.name,\n value: opts.value == null ? undefined : String(opts.value),\n placeholder: opts.placeholder,\n required: !!opts.required,\n disabled: !!opts.disabled,\n readonly: !!opts.readonly,\n autocomplete: opts.autocomplete || 'off',\n spellcheck: 'false',\n autocapitalize: 'off',\n 'aria-describedby': p.describedBy,\n 'aria-invalid': opts.error ? 'true' : undefined,\n }) + '>';\n const label = escapeHtml(opts.label || opts.name || 'value');\n const reveal = opts.reveal === false ? '' : '<button type=\"button\" class=\"btn btn-outline-secondary mp-reveal-btn\"'\n + ' data-mp-reveal=\"' + escapeHtml(p.id) + '\" aria-controls=\"' + escapeHtml(p.id) + '\" aria-pressed=\"false\"'\n + ' aria-label=\"Show ' + label + '\">Show</button>';\n const copy = opts.copy === false ? '' : CopyButton.render({ target: '#' + p.id, ariaLabel: 'Copy ' + label });\n return '<div class=\"mb-3 mp-field\">' + p.label\n + '<div class=\"input-group' + (opts.error ? ' has-validation' : '') + '\">' + input + reveal + copy + '</div>'\n + p.help + p.error + '</div>';\n}\n\n// ── Values ──\n\nfunction setPath(obj, path, value) {\n const keys = path.split('.');\n let node = obj;\n keys.slice(0, -1).forEach(k => {\n if (!node[k] || typeof node[k] !== 'object') { node[k] = {}; }\n node = node[k];\n });\n node[keys[keys.length - 1]] = value;\n}\n\nfunction getPath(obj, path) {\n return path.split('.').reduce((node, k) => (node == null ? undefined : node[k]), obj);\n}\n\nfunction controls(form) {\n return Array.from(form.querySelectorAll('input[name], select[name], textarea[name]'))\n .filter(el => !el.disabled && !el.hasAttribute('data-mp-ignore')\n && ['button', 'submit', 'reset', 'file', 'image'].indexOf(el.type) < 0);\n}\n\n/**\n * Form.values(form) → plain object from the named controls. Dotted names\n * nest (\"auth.token\"), checkboxes give booleans (or arrays of values when\n * several share a name), number/range inputs give numbers (null when empty),\n * radio groups their checked value, multiple selects arrays.\n */\nfunction values(form) {\n form = toElement(form);\n const out = {};\n const els = controls(form);\n const counts = {};\n els.forEach(el => { if (el.type === 'checkbox') { counts[el.name] = (counts[el.name] || 0) + 1; } });\n els.forEach(el => {\n const name = el.name;\n if (el.type === 'checkbox') {\n if (counts[name] > 1) {\n const list = getPath(out, name) || [];\n if (el.checked) { list.push(el.value); }\n setPath(out, name, list);\n } else {\n setPath(out, name, el.checked);\n }\n } else if (el.type === 'radio') {\n if (el.checked) { setPath(out, name, el.value); }\n else if (getPath(out, name) === undefined) { setPath(out, name, null); }\n } else if (el.type === 'number' || el.type === 'range') {\n setPath(out, name, el.value === '' ? null : Number(el.value));\n } else if (el.tagName === 'SELECT' && el.multiple) {\n setPath(out, name, Array.from(el.selectedOptions).map(o => o.value));\n } else {\n setPath(out, name, el.value);\n }\n });\n return out;\n}\n\n/** Form.fill(form, data) — sets named controls from a (nested) object. */\nfunction fill(form, data) {\n form = toElement(form);\n data = data || {};\n controls(form).forEach(el => {\n const v = getPath(data, el.name);\n if (v === undefined) { return; }\n if (el.type === 'checkbox') {\n el.checked = Array.isArray(v) ? v.map(String).indexOf(el.value) >= 0 : !!v;\n } else if (el.type === 'radio') {\n el.checked = String(v) === el.value;\n } else if (el.tagName === 'SELECT' && el.multiple) {\n const list = (Array.isArray(v) ? v : [v]).map(String);\n Array.from(el.options).forEach(o => { o.selected = list.indexOf(o.value) >= 0; });\n } else {\n el.value = v == null ? '' : String(v);\n }\n });\n return form;\n}\n\nfunction isPlainObject(v) {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\n/** Deep merge of plain objects (arrays and scalars from `patch` replace). */\nexport function mergeConfig(base, patch) {\n const out = Object.assign({}, base);\n Object.keys(patch || {}).forEach(k => {\n out[k] = isPlainObject(out[k]) && isPlainObject(patch[k]) ? mergeConfig(out[k], patch[k]) : patch[k];\n });\n return out;\n}\n\n// ── Dirty tracking + Save bar ──\n\n/**\n * Form.track(form, opts) — tracks unsaved changes and shows a sticky Save bar.\n * Saving calls homebridge.updatePluginConfig(blocks) then savePluginConfig().\n * opts: {\n * toConfig(values, blocks) → block or array of blocks (default: values\n * merged into the first existing block),\n * save(values) — replaces the Homebridge calls entirely,\n * persist = true (false: only updatePluginConfig, the user saves in Homebridge),\n * bar = true | element (where to render the bar; default after the form),\n * message, saveLabel, discardLabel, savedMessage, toast = true,\n * onDirtyChange(dirty), onSaved(config), onError(err)\n * }\n * Outside Homebridge (no opts.save) saving only resets the dirty state and\n * resolves false. Returns { isDirty(), values(), save(), discard(), reset(), destroy(), bar }.\n */\nfunction track(form, opts) {\n opts = opts || {};\n form = toElement(form);\n const d = form.ownerDocument;\n let baseline = JSON.stringify(values(form));\n let baselineValues = values(form);\n let dirty = false;\n let busy = false;\n\n let bar = null;\n if (opts.bar !== false) {\n bar = d.createElement('div');\n bar.className = 'mp-savebar';\n bar.setAttribute('role', 'region');\n bar.setAttribute('aria-label', 'Unsaved changes');\n bar.hidden = true;\n bar.innerHTML = '<span class=\"mp-savebar-message\" role=\"status\">'\n + escapeHtml(opts.message || 'You have unsaved changes') + '</span>'\n + '<span class=\"mp-savebar-actions\">'\n + '<button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" data-mp-save=\"discard\">'\n + escapeHtml(opts.discardLabel || 'Discard') + '</button>'\n + '<button type=\"button\" class=\"btn btn-sm btn-primary\" data-mp-save=\"save\">'\n + escapeHtml(opts.saveLabel || 'Save') + '</button></span>';\n const host = opts.bar && opts.bar !== true ? toElement(opts.bar) : null;\n if (host) { host.appendChild(bar); } else { form.insertAdjacentElement('afterend', bar); }\n }\n\n function setDirty(next) {\n if (next === dirty) { return; }\n dirty = next;\n if (bar) { bar.hidden = !dirty; }\n form.classList.toggle('is-dirty', dirty);\n if (typeof opts.onDirtyChange === 'function') { opts.onDirtyChange(dirty); }\n }\n\n function check() {\n setDirty(JSON.stringify(values(form)) !== baseline);\n }\n\n function reset() {\n baselineValues = values(form);\n baseline = JSON.stringify(baselineValues);\n setDirty(false);\n }\n\n function setBusy(next) {\n busy = next;\n if (!bar) { return; }\n bar.setAttribute('aria-busy', next ? 'true' : 'false');\n bar.querySelectorAll('button').forEach(b => { b.disabled = next; });\n }\n\n async function defaultSave(vals) {\n const hb = hbClient();\n if (!hb || typeof hb.updatePluginConfig !== 'function') { return null; }\n const blocks = typeof hb.getPluginConfig === 'function' ? (await hb.getPluginConfig()) || [] : [];\n let config = typeof opts.toConfig === 'function'\n ? await opts.toConfig(vals, blocks)\n : [mergeConfig(blocks[0] || {}, vals)].concat(blocks.slice(1));\n if (!Array.isArray(config)) { config = [config]; }\n await hb.updatePluginConfig(config);\n if (opts.persist !== false && typeof hb.savePluginConfig === 'function') { await hb.savePluginConfig(); }\n return config;\n }\n\n async function save() {\n if (busy) { return false; }\n const vals = values(form);\n setBusy(true);\n try {\n const custom = typeof opts.save === 'function';\n const result = custom ? await opts.save(vals) : await defaultSave(vals);\n const saved = custom || result !== null;\n reset();\n if (saved) {\n if (opts.toast !== false) { Toast.success(opts.savedMessage || 'Settings saved'); }\n if (typeof opts.onSaved === 'function') { opts.onSaved(result); }\n }\n return saved;\n } catch (err) {\n if (opts.toast !== false) { Toast.error(errorMessage(err, 'Could not save the settings')); }\n if (typeof opts.onError === 'function') { opts.onError(err); }\n throw err;\n } finally {\n setBusy(false);\n }\n }\n\n function discard() {\n fill(form, baselineValues);\n check();\n }\n\n function onBarClick(ev) {\n const btn = ev.target.closest('[data-mp-save]');\n if (!btn) { return; }\n if (btn.getAttribute('data-mp-save') === 'save') { save().catch(() => {}); } else { discard(); }\n }\n\n function onSubmit(ev) {\n ev.preventDefault();\n save().catch(() => {});\n }\n\n form.addEventListener('input', check);\n form.addEventListener('change', check);\n if (opts.submit !== false) { form.addEventListener('submit', onSubmit); }\n if (bar) { bar.addEventListener('click', onBarClick); }\n\n return {\n bar,\n isDirty: () => dirty,\n values: () => values(form),\n save,\n discard,\n /** Takes the current values as the new saved state. */\n reset,\n /** Re-checks after programmatic changes. */\n check,\n destroy() {\n form.removeEventListener('input', check);\n form.removeEventListener('change', check);\n form.removeEventListener('submit', onSubmit);\n if (bar) { bar.remove(); }\n },\n };\n}\n\nexport const Form = { field, secret, values, fill, track };\n","// Document-level delegated listeners, installed once when the kit loads, so\n// HTML returned by the render helpers works without extra wiring:\n// [data-mp-copy] / [data-mp-copy-target] copy buttons\n// [data-mp-reveal] show/hide a secret input\n// .mp-device-card[role=\"button\"] Enter / Space activate (click)\n\nimport { doc } from './env.js';\nimport { copyFromButton, toggleReveal } from './form.js';\n\nconst ACTIVATABLE = '.mp-device-card[role=\"button\"], [data-mp-activate][role=\"button\"]';\n\nfunction onClick(ev) {\n const t = ev.target;\n if (!t || typeof t.closest !== 'function') { return; }\n const copy = t.closest('[data-mp-copy], [data-mp-copy-target]');\n if (copy) {\n copyFromButton(copy);\n return;\n }\n const reveal = t.closest('[data-mp-reveal]');\n if (reveal) { toggleReveal(reveal); }\n}\n\nfunction onKeydown(ev) {\n if (ev.defaultPrevented || (ev.key !== 'Enter' && ev.key !== ' ')) { return; }\n const t = ev.target;\n if (!t || typeof t.matches !== 'function' || !t.matches(ACTIVATABLE)) { return; }\n ev.preventDefault(); // Space would scroll the page\n t.click();\n}\n\nexport function installDelegates() {\n const d = doc();\n if (!d || typeof d.addEventListener !== 'function' || d.__mpKitDelegates) { return; }\n d.__mpKitDelegates = true;\n d.addEventListener('click', onClick);\n d.addEventListener('keydown', onKeydown);\n}\n","// DeviceList — a searchable list of .mp-device-card items with loading\n// (skeleton), empty and no-results states and keyboard activation.\n// Skeleton — shimmer placeholders.\n\nimport { escapeHtml, textOf, toElement, uid } from './util.js';\nimport { EmptyState, StatusBadge } from './core.js';\n\n/** Skeleton.render(opts) → HTML for shimmer placeholder lines (hidden from AT). */\nexport const Skeleton = {\n /** opts: { lines = 3, avatar = false, className } */\n render(opts) {\n opts = opts || {};\n const lines = Math.max(1, opts.lines || 3);\n let html = '';\n for (let i = 0; i < lines; i += 1) {\n html += '<span class=\"mp-skeleton mp-skeleton-text\"' + (i === lines - 1 && lines > 1 ? ' style=\"width:60%\"' : '') + '></span>';\n }\n return '<div class=\"mp-skeleton-group' + (opts.className ? ' ' + escapeHtml(opts.className) : '') + '\" aria-hidden=\"true\">'\n + (opts.avatar ? '<span class=\"mp-skeleton mp-skeleton-circle\"></span>' : '')\n + '<span class=\"mp-skeleton-lines\">' + html + '</span></div>';\n },\n};\n\nconst STATUS = {\n online: StatusBadge.online,\n offline: StatusBadge.offline,\n checking: StatusBadge.checking,\n disabled: StatusBadge.disabled,\n};\n\nfunction defaultItem(item, index, interactive) {\n const name = item.name || item.displayName || item.id || 'Device ' + (index + 1);\n const status = STATUS[item.status] ? STATUS[item.status](item.statusLabel) : '';\n return '<div class=\"card mp-device-card\"' + (interactive ? ' role=\"button\" tabindex=\"0\"' : '') + '>'\n + '<div class=\"card-body mp-device-card-body\">'\n + (item.iconClass ? '<i class=\"' + escapeHtml(item.iconClass) + ' mp-device-card-icon\" aria-hidden=\"true\"></i>' : '')\n + '<div class=\"mp-device-card-text\"><div class=\"mp-device-card-name\">' + escapeHtml(name) + '</div>'\n + (item.subtitle ? '<div class=\"mp-device-card-subtitle\">' + escapeHtml(item.subtitle) + '</div>' : '')\n + '</div>' + status + '</div></div>';\n}\n\nfunction defaultFilter(keys) {\n return (item, query) => keys.some(k => {\n const v = item && item[k];\n return v != null && String(v).toLowerCase().indexOf(query) >= 0;\n });\n}\n\nexport const DeviceList = {\n /**\n * Renders a device list into el and returns a controller.\n * opts: { items = [], loading = false, label = 'Devices',\n * renderItem(item, index) → HTML (default: an .mp-device-card with\n * name/displayName, subtitle, iconClass and status badge),\n * search = true | { placeholder, label }, keys = ['name', 'subtitle', 'id'],\n * filter(item, query), onActivate(item, index, event),\n * empty: { iconClass, title, hint }, noResults: { title, hint },\n * skeletonCount = 3 }\n * With onActivate the default cards are role=\"button\" (Enter / Space work).\n * Returns { setItems(items), setLoading(bool), setQuery(q), items(), visible(), destroy() }.\n */\n render(el, opts) {\n opts = opts || {};\n el = toElement(el);\n const label = opts.label || 'Devices';\n const searchOpts = opts.search === false ? null : (typeof opts.search === 'object' ? opts.search : {});\n const searchId = uid('mp-device-search');\n const filter = typeof opts.filter === 'function' ? opts.filter : defaultFilter(opts.keys || ['name', 'displayName', 'subtitle', 'id']);\n const interactive = typeof opts.onActivate === 'function';\n let items = Array.isArray(opts.items) ? opts.items.slice() : [];\n let loading = !!opts.loading;\n let query = '';\n let visible = [];\n\n el.innerHTML = '<div class=\"mp-device-list\">'\n + (searchOpts ? '<div class=\"mp-device-list-search\">'\n + '<label class=\"mp-sr-only\" for=\"' + searchId + '\">' + escapeHtml(searchOpts.label || 'Search ' + label.toLowerCase()) + '</label>'\n + '<input type=\"search\" class=\"form-control\" id=\"' + searchId + '\" autocomplete=\"off\" placeholder=\"'\n + escapeHtml(searchOpts.placeholder || 'Search…') + '\">'\n + '</div>' : '')\n + '<p class=\"mp-sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\"></p>'\n + '<div class=\"mp-device-list-items\" role=\"list\" aria-label=\"' + escapeHtml(label) + '\"></div>'\n + '</div>';\n const list = el.querySelector('.mp-device-list-items');\n const status = el.querySelector('.mp-device-list [role=\"status\"]');\n const input = searchOpts ? el.querySelector('input[type=\"search\"]') : null;\n\n function announce(text) {\n if (status.textContent !== text) { status.textContent = text; }\n }\n\n function paint() {\n list.setAttribute('aria-busy', loading ? 'true' : 'false');\n if (input) { input.disabled = loading && !items.length; }\n if (loading && !items.length) {\n const n = opts.skeletonCount || 3;\n let html = '';\n for (let i = 0; i < n; i += 1) {\n html += '<div class=\"card mp-device-card mp-device-card-skeleton\" role=\"listitem\"><div class=\"card-body\">'\n + Skeleton.render({ lines: 2, avatar: true }) + '</div></div>';\n }\n list.innerHTML = html;\n announce('Loading ' + label.toLowerCase() + '…');\n visible = [];\n return;\n }\n visible = query ? items.filter(item => filter(item, query)) : items.slice();\n if (!items.length) {\n list.innerHTML = '<div role=\"listitem\">' + EmptyState.render(Object.assign({ title: 'No ' + label.toLowerCase() + ' found' }, opts.empty)) + '</div>';\n announce('No ' + label.toLowerCase());\n return;\n }\n if (!visible.length) {\n const nr = opts.noResults || {};\n list.innerHTML = '<div role=\"listitem\">' + EmptyState.render({\n iconClass: nr.iconClass || 'bi bi-search',\n title: nr.title || 'No matches for “' + query + '”',\n hint: nr.hint || 'Try a different search',\n }) + '</div>';\n announce('No matches');\n return;\n }\n list.innerHTML = visible.map(item => {\n const index = items.indexOf(item);\n const html = typeof opts.renderItem === 'function' ? opts.renderItem(item, index) : defaultItem(item, index, interactive);\n return '<div role=\"listitem\" class=\"mp-device-list-item\" data-mp-index=\"' + index + '\">' + html + '</div>';\n }).join('');\n announce(query ? visible.length + ' of ' + items.length + ' ' + label.toLowerCase() : '');\n }\n\n function onInput() {\n query = input.value.trim().toLowerCase();\n paint();\n }\n\n function onClick(ev) {\n if (!interactive) { return; }\n const row = ev.target.closest('[data-mp-index]');\n if (!row || !list.contains(row)) { return; }\n // Let nested controls (buttons, links, inputs) do their own thing.\n const control = ev.target.closest('a, button, input, select, textarea, label, [role=\"button\"]');\n if (control && row.contains(control) && !control.classList.contains('mp-device-card')) { return; }\n const index = Number(row.getAttribute('data-mp-index'));\n opts.onActivate(items[index], index, ev);\n }\n\n if (input) { input.addEventListener('input', onInput); }\n list.addEventListener('click', onClick);\n paint();\n\n return {\n setItems(next) {\n items = Array.isArray(next) ? next.slice() : [];\n loading = false;\n paint();\n },\n setLoading(next) {\n loading = !!next;\n paint();\n },\n setQuery(q) {\n query = String(q == null ? '' : q).trim().toLowerCase();\n if (input) { input.value = q == null ? '' : String(q); }\n paint();\n },\n items: () => items.slice(),\n visible: () => visible.slice(),\n /** Text announced to screen readers for the current state. */\n status: () => textOf(status),\n destroy() {\n if (input) { input.removeEventListener('input', onInput); }\n list.removeEventListener('click', onClick);\n el.innerHTML = '';\n },\n };\n },\n};\n","// LogViewer — a scrolling, plain-text log: ANSI escape codes are stripped,\n// lines are capped, and it auto-scrolls unless the user scrolled up.\n\nimport { toElement } from './util.js';\n\n// Matches ANSI/VT100 escape sequences (colours, cursor moves, OSC titles).\nconst ANSI = /[\\u001b\\u009b][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))/g;\n\n/** Removes ANSI escape codes from text. */\nexport function stripAnsi(text) {\n return String(text == null ? '' : text).replace(ANSI, '');\n}\n\nconst NEAR_BOTTOM = 8; // px\n\nexport const LogViewer = {\n /**\n * Creates a log viewer in el.\n * opts: { maxLines = 1000, label = 'Log', live = 'off' | 'polite',\n * autoscroll = true, wrap = false, lineClass(line) → extra class,\n * jumpLabel = 'Jump to latest' }\n * Returns { append(textOrLines), clear(), lines(), scrollToBottom(), isFollowing(), destroy(), element }.\n */\n create(el, opts) {\n opts = opts || {};\n el = toElement(el);\n const d = el.ownerDocument;\n const maxLines = opts.maxLines > 0 ? opts.maxLines : 1000;\n el.innerHTML = '<div class=\"mp-log' + (opts.wrap ? ' mp-log-wrap' : '') + '\">'\n + '<div class=\"mp-log-body\" role=\"log\" tabindex=\"0\"></div>'\n + '<button type=\"button\" class=\"btn btn-sm btn-primary mp-log-jump\" hidden></button>'\n + '</div>';\n const body = el.querySelector('.mp-log-body');\n const jump = el.querySelector('.mp-log-jump');\n body.setAttribute('aria-label', opts.label || 'Log');\n // A busy log would flood screen readers; it is still reachable with Tab.\n body.setAttribute('aria-live', opts.live === 'polite' ? 'polite' : 'off');\n jump.textContent = opts.jumpLabel || 'Jump to latest';\n let follow = opts.autoscroll !== false;\n let lines = [];\n\n function atBottom() {\n return body.scrollHeight - body.scrollTop - body.clientHeight <= NEAR_BOTTOM;\n }\n\n function scrollToBottom() {\n body.scrollTop = body.scrollHeight;\n follow = opts.autoscroll !== false;\n jump.hidden = true;\n }\n\n function onScroll() {\n if (opts.autoscroll === false) { return; }\n follow = atBottom();\n if (follow) { jump.hidden = true; }\n }\n\n function append(input) {\n const incoming = (Array.isArray(input) ? input : String(input == null ? '' : input).split(/\\r?\\n/))\n .map(stripAnsi);\n if (!Array.isArray(input) && incoming.length > 1 && incoming[incoming.length - 1] === '') { incoming.pop(); }\n if (!incoming.length) { return; }\n const stick = follow && (opts.autoscroll !== false);\n const frag = d.createDocumentFragment();\n incoming.forEach(line => {\n const row = d.createElement('div');\n const extra = typeof opts.lineClass === 'function' ? opts.lineClass(line) : '';\n row.className = 'mp-log-line' + (extra ? ' ' + extra : '');\n row.textContent = line;\n frag.appendChild(row);\n });\n body.appendChild(frag);\n lines = lines.concat(incoming);\n const excess = lines.length - maxLines;\n if (excess > 0) {\n lines = lines.slice(excess);\n for (let i = 0; i < excess && body.firstChild; i += 1) { body.removeChild(body.firstChild); }\n }\n if (stick) { body.scrollTop = body.scrollHeight; } else if (opts.autoscroll !== false) { jump.hidden = false; }\n }\n\n body.addEventListener('scroll', onScroll);\n jump.addEventListener('click', () => {\n scrollToBottom();\n body.focus();\n });\n\n return {\n element: body,\n append,\n clear() {\n lines = [];\n body.textContent = '';\n jump.hidden = true;\n },\n lines: () => lines.slice(),\n scrollToBottom,\n isFollowing: () => follow,\n destroy() {\n body.removeEventListener('scroll', onScroll);\n el.innerHTML = '';\n },\n };\n },\n stripAnsi,\n};\n","// Pairing and sign-in components: HomeKit setup-code block, OAuth /\n// device-code step card, and a multi-step wizard.\n\nimport {\n announce, escapeHtml, focusElement, safeUrl, toElement, uid,\n} from './util.js';\nimport { CopyButton } from './form.js';\n\n// ── HomeKit setup code ──\n\n/** Formats an 8-digit HomeKit setup code as XXX-XX-XXX ('' when it is not 8 digits). */\nexport function formatPin(code) {\n const digits = String(code == null ? '' : code).replace(/\\D/g, '');\n return digits.length === 8 ? digits.slice(0, 3) + '-' + digits.slice(3, 5) + '-' + digits.slice(5) : '';\n}\n\n/** Image sources allowed for the QR code: http(s), same-origin paths, data:image/*. */\nexport function safeImageSrc(src) {\n if (typeof src !== 'string') { return null; }\n const s = src.trim();\n if (safeUrl(s)) { return s; }\n if (/^data:image\\/(png|gif|jpeg|webp|svg\\+xml)[;,]/i.test(s)) { return s; }\n if (/^(\\.{0,2}\\/|[\\w-]+(\\/|\\.))/.test(s) && !/^[a-z][\\w+.-]*:/i.test(s)) { return s; }\n return null;\n}\n\nfunction pinHtml(opts) {\n opts = opts || {};\n const formatted = formatPin(opts.pin) || escapeHtml(opts.pin || '');\n const spoken = String(opts.pin == null ? '' : opts.pin).replace(/\\D/g, '').split('').join(' ');\n const id = uid('mp-pin');\n const src = safeImageSrc(opts.qrSrc);\n const label = opts.label || 'HomeKit setup code';\n return '<figure class=\"mp-pin\" aria-labelledby=\"' + id + '\">'\n + '<div class=\"mp-pin-label-box\">'\n + '<span class=\"mp-pin-label\" id=\"' + id + '\">' + escapeHtml(label) + '</span>'\n + '<span class=\"mp-pin-code\" aria-hidden=\"true\">' + formatted + '</span>'\n + '<span class=\"mp-sr-only\">' + escapeHtml(spoken || formatted) + '</span>'\n + '</div>'\n + (src ? '<img class=\"mp-pin-qr\" src=\"' + escapeHtml(src) + '\" alt=\"' + escapeHtml(opts.qrAlt || 'QR code for ' + label) + '\">' : '')\n + '<span class=\"mp-pin-qr-slot\"></span>'\n + (opts.copy === false ? '' : '<figcaption class=\"mp-pin-actions\">'\n + CopyButton.render({ text: formatted, label: opts.copyLabel || 'Copy code', size: 'sm' }) + '</figcaption>')\n + '</figure>';\n}\n\nexport const Pairing = {\n formatPin,\n /**\n * HTML for a HomeKit setup-code block (XXX-XX-XXX, read digit by digit by\n * screen readers) with an optional QR image and a Copy button.\n * opts: { pin, label = 'HomeKit setup code', qrSrc (http(s), path or\n * data:image/*), qrAlt, copy = true, copyLabel }\n * The kit does not generate QR codes: pass an image, or an SVG element to renderPin().\n */\n pin: pinHtml,\n /** Renders pin() into el; opts.qr may be an SVG/IMG element (appended) or an image URL. */\n renderPin(el, opts) {\n opts = opts || {};\n el = toElement(el);\n const qr = opts.qr;\n el.innerHTML = pinHtml(Object.assign({}, opts, { qrSrc: typeof qr === 'string' ? qr : opts.qrSrc }));\n if (qr && typeof qr === 'object' && qr.nodeType === 1) {\n const slot = el.querySelector('.mp-pin-qr-slot');\n if (qr.tagName.toLowerCase() === 'svg') {\n qr.setAttribute('role', 'img');\n if (!qr.getAttribute('aria-label')) { qr.setAttribute('aria-label', opts.qrAlt || 'QR code for ' + (opts.label || 'HomeKit setup code')); }\n }\n qr.classList.add('mp-pin-qr');\n slot.appendChild(qr);\n }\n return el.querySelector('.mp-pin');\n },\n};\n\n// ── OAuth / device-code sign-in ──\n\nconst STATE_TEXT = {\n waiting: 'Waiting for you to sign in…',\n polling: 'Waiting for authorization…',\n success: 'Signed in.',\n error: 'Sign-in failed.',\n expired: 'The code expired. Start again to get a new one.',\n};\n\nexport const Auth = {\n /**\n * Renders a device-code / OAuth step card into el:\n * 1. open the sign-in URL, 2. enter the code (with Copy), then a status\n * line that follows the polling state.\n * opts: { title = 'Sign in', url, code, instructions, openLabel,\n * poll() → true | { done, error, interval } (called every `interval` ms\n * until done; a rejection or { error } shows the error),\n * interval = 5000, expiresIn (seconds), onSuccess(result), onError(err),\n * onRetry() (shows a Try again button on error/expiry), successMessage }\n * Returns { setState(state, message), state(), start(), stop(), destroy(), element }.\n */\n deviceCode(el, opts) {\n opts = opts || {};\n el = toElement(el);\n const titleId = uid('mp-auth-title');\n const url = safeUrl(opts.url);\n el.innerHTML = '<section class=\"card mp-auth-card\" aria-labelledby=\"' + titleId + '\"><div class=\"card-body\">'\n + '<h3 class=\"mp-auth-title\" id=\"' + titleId + '\">' + escapeHtml(opts.title || 'Sign in') + '</h3>'\n + (opts.instructions ? '<p class=\"mp-auth-instructions\">' + escapeHtml(opts.instructions) + '</p>' : '')\n + '<ol class=\"mp-auth-steps\">'\n + (url ? '<li><span class=\"mp-auth-step-text\">Open the sign-in page</span>'\n + '<a class=\"btn btn-primary btn-sm mp-auth-open\" href=\"' + escapeHtml(url) + '\" target=\"_blank\" rel=\"noopener noreferrer\">'\n + escapeHtml(opts.openLabel || 'Open sign-in page') + '<span class=\"mp-sr-only\"> (opens in a new tab)</span></a></li>' : '')\n + (opts.code ? '<li><span class=\"mp-auth-step-text\">Enter this code</span>'\n + '<span class=\"mp-auth-code-row\"><code class=\"mp-auth-code\">' + escapeHtml(opts.code) + '</code>'\n + CopyButton.render({ text: opts.code, label: 'Copy', size: 'sm', ariaLabel: 'Copy code' }) + '</span></li>' : '')\n + '</ol>'\n + '<p class=\"mp-auth-status\" role=\"status\" aria-live=\"polite\"><span class=\"mp-auth-status-icon\" aria-hidden=\"true\"></span>'\n + '<span class=\"mp-auth-status-text\"></span></p>'\n + '<button type=\"button\" class=\"btn btn-outline-secondary btn-sm mp-auth-retry\" hidden>Try again</button>'\n + '</div></section>';\n const card = el.querySelector('.mp-auth-card');\n const statusEl = el.querySelector('.mp-auth-status');\n const statusText = el.querySelector('.mp-auth-status-text');\n const retry = el.querySelector('.mp-auth-retry');\n let state = null;\n let timer = null;\n let expiry = null;\n let running = false;\n let interval = opts.interval > 0 ? opts.interval : 5000;\n\n function setState(next, message) {\n state = STATE_TEXT[next] ? next : 'waiting';\n ['waiting', 'polling', 'success', 'error', 'expired'].forEach(s => card.classList.toggle('is-' + s, s === state));\n statusText.textContent = message || (state === 'success' && opts.successMessage) || STATE_TEXT[state];\n statusEl.setAttribute('role', state === 'error' || state === 'expired' ? 'alert' : 'status');\n retry.hidden = !((state === 'error' || state === 'expired') && typeof opts.onRetry === 'function');\n if (state === 'success' || state === 'error' || state === 'expired') { stop(); }\n return controller;\n }\n\n function stop() {\n running = false;\n clearTimeout(timer);\n clearTimeout(expiry);\n }\n\n function schedule() {\n if (!running) { return; }\n timer = setTimeout(tick, interval);\n }\n\n function tick() {\n if (!running) { return; }\n Promise.resolve().then(() => opts.poll()).then(res => {\n if (!running) { return; }\n if (res && typeof res === 'object' && res.error) { throw res.error; }\n if (res && typeof res === 'object' && res.interval > 0) { interval = res.interval; }\n if (res === true || (res && typeof res === 'object' && res.done)) {\n setState('success');\n if (typeof opts.onSuccess === 'function') { opts.onSuccess(res); }\n } else {\n schedule();\n }\n }).catch(err => {\n if (!running) { return; }\n setState('error', (err && err.message) || (typeof err === 'string' ? err : ''));\n if (typeof opts.onError === 'function') { opts.onError(err); }\n });\n }\n\n function start() {\n if (typeof opts.poll !== 'function') { return controller; }\n stop();\n running = true;\n setState('polling');\n if (opts.expiresIn > 0) {\n expiry = setTimeout(() => setState('expired'), opts.expiresIn * 1000);\n }\n schedule();\n return controller;\n }\n\n retry.addEventListener('click', () => {\n setState('waiting');\n opts.onRetry();\n });\n\n const controller = {\n element: card,\n setState,\n state: () => state,\n start,\n stop,\n destroy() {\n stop();\n el.innerHTML = '';\n },\n };\n setState('waiting');\n if (typeof opts.poll === 'function' && opts.autoStart !== false) { start(); }\n return controller;\n },\n};\n\n// ── Multi-step wizard ──\n\nexport const Steps = {\n /**\n * Renders an .mp-steps progress list into el and shows one panel at a time.\n * opts: { steps: [{ title, panel (selector/element) }], current = 0,\n * label = 'Progress', onChange(index, step), focus = true }\n * Returns { go(index), next(), prev(), current(), destroy() }.\n */\n create(el, opts) {\n opts = opts || {};\n el = toElement(el);\n const steps = (opts.steps || []).map(s => (typeof s === 'string' ? { title: s } : s));\n let current = -1;\n\n function paint() {\n el.innerHTML = '<ol class=\"mp-steps\" aria-label=\"' + escapeHtml(opts.label || 'Progress') + '\">'\n + steps.map((s, i) => {\n const st = i < current ? 'complete' : (i === current ? 'current' : 'upcoming');\n return '<li class=\"mp-step is-' + st + '\"' + (st === 'current' ? ' aria-current=\"step\"' : '') + '>'\n + '<span class=\"mp-step-marker\" aria-hidden=\"true\">' + (st === 'complete' ? '✓' : i + 1) + '</span>'\n + '<span class=\"mp-step-title\">' + escapeHtml(s.title) + '</span>'\n + (st === 'complete' ? '<span class=\"mp-sr-only\"> (completed)</span>' : '')\n + '</li>';\n }).join('') + '</ol>';\n }\n\n function go(index, initial) {\n if (index < 0 || index >= steps.length || index === current) { return current; }\n current = index;\n paint();\n steps.forEach((s, i) => {\n const panel = toElement(s.panel);\n if (panel) { panel.hidden = i !== index; }\n });\n if (!initial) {\n const panel = toElement(steps[index].panel);\n if (panel && opts.focus !== false) {\n focusElement(panel.querySelector('h1, h2, h3, h4, h5, h6, [data-mp-focus]') || panel);\n }\n announce('Step ' + (index + 1) + ' of ' + steps.length + ': ' + steps[index].title);\n if (typeof opts.onChange === 'function') { opts.onChange(index, steps[index]); }\n }\n return current;\n }\n\n go(Math.min(Math.max(opts.current || 0, 0), Math.max(steps.length - 1, 0)), true);\n\n return {\n go: i => go(i),\n next: () => go(current + 1),\n prev: () => go(current - 1),\n current: () => current,\n destroy() { el.innerHTML = ''; },\n };\n },\n};\n","// ESM entry (dist/kit.mjs): named exports for bundlers and <script type=\"module\">.\n// The classic-script build (dist/kit.js) exposes the same object as window.MpKit.\n\nimport { announce, escapeHtml, safeUrl } from './util.js';\nimport { StatusBadge, EmptyState, Loading, View, Footer } from './core.js';\nimport { ai, markdown, diffLines } from './ai.js';\nimport { Theme } from './theme.js';\nimport { Tabs } from './tabs.js';\nimport { Toast } from './toast.js';\nimport { confirm } from './dialog.js';\nimport { Form, CopyButton, copyText } from './form.js';\nimport { installDelegates } from './delegates.js';\nimport { DeviceList, Skeleton } from './devices.js';\nimport { LogViewer, stripAnsi } from './log.js';\nimport { Pairing, Auth, Steps, formatPin } from './pairing.js';\n\nexport const version = __VERSION__;\n\nexport const MpKit = {\n version,\n escapeHtml,\n announce,\n StatusBadge,\n EmptyState,\n Loading,\n View,\n Footer,\n Tabs,\n Theme,\n Toast,\n confirm,\n Form,\n CopyButton,\n copy: copyText,\n DeviceList,\n Skeleton,\n LogViewer,\n stripAnsi,\n Pairing,\n Auth,\n Steps,\n ai,\n};\n\ninstallDelegates();\n\nexport {\n escapeHtml, safeUrl, announce, StatusBadge, EmptyState, Loading, View, Footer, Tabs, Theme, Toast, confirm,\n Form, CopyButton, copyText as copy, DeviceList, Skeleton, LogViewer, stripAnsi,\n Pairing, Auth, Steps, formatPin, ai, markdown, diffLines,\n};\n\nexport default MpKit;\n","// Classic-script entry (dist/kit.js): exposes window.MpKit.\nimport { root } from './env.js';\nimport { MpKit } from './index.js';\n\nroot.MpKit = MpKit;\n"],"mappings":"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","names":["root","doc","hbClient","ESCAPES","escapeHtml","value","c","safeUrl","url","uidSeq","uid","prefix","toElement","target","d","doc","errorMessage","err","fallback","liveRegion","announce","message","politeness","text","FOCUSABLE","focusables","el","n","focusElement","textOf","badge","badgeClass","dotClass","label","escapeHtml","FOOTER_LINKS","icon","paths","d","StatusBadge","EmptyState","opts","iconClass","title","hint","Loading","message","HEADING","View","id","shown","changed","previous","doc","v","active","was","heading","focusElement","textOf","announce","Footer","el","toElement","links","link","url","safeUrl","SPARKLE","CARET","DEFAULT_NOTE","DEFAULT_ERROR","LCS_LIMIT","aiSeq","newRequestId","eventData","ev","abortError","reason","message","err","notifyCancel","hb","requestId","aiRequest","path","body","opts","hbClient","withCancel","signal","payload","k","settled","listeners","on","type","fn","handler","data","d","rejectCancelled","cancelled","resolve","reject","onAbort","cancel","cleanup","l","pending","result","value","promise","inlineMarkdown","text","part","i","escapeHtml","m","a","b","UL_ITEM","OL_ITEM","HEADING","FENCE","markdown","lines","out","para","flush","line","fence","code","listRe","tag","items","heading","withCaret","html","toLines","diffLines","before","after","start","endA","endB","x","y","n","j","t","w","dp","DIFF_SIGN","DIFF_SR","diffLineHtml","bind","el","store","actionTarget","badgeHtml","label","thinkingHtml","edgeEl","ai","cls","note","panel","errorEl","streaming","paint","controller","delta","final","errorMessage","added","removed","hasActions","title","root","statusEl","applyBtn","rejectBtn","busy","setDisabled","disabled","btn","action","cb","inputId","uid","log","input","sendBtn","messages","messageHtml","defaultSend","prompt","ctx","transcript","context","send","history","reply","res","show","doc","THEME_STORAGE_KEY","QUERY","normalizeTheme","value","v","resolveTheme","preference","systemDark","themeFromSettings","settings","mediaQuery","root","store","key","stored","homebridgeTheme","hb","hbClient","pref","applyTheme","resolved","opts","d","doc","target","dark","Theme","explicit","current","pinned","destroyed","media","update","first","onMedia","controller","mode","panelId","tab","ref","id","isRtl","el","holder","Tabs","opts","root","doc","tabs","vertical","uid","panel","current","panelOf","select","target","fromUser","index","changed","i","on","View","onClick","ev","onKeydown","enabled","t","pos","rtl","next","prev","to","initial","TYPES","DURATION","ICON","container","ensureContainer","d","show","type","message","opts","text","hb","hbClient","doc","el","escapeHtml","timer","closed","duration","close","arm","Toast","confirm","opts","d","doc","titleId","uid","messageId","danger","backdrop","escapeHtml","dialog","previous","inerted","n","resolve","finish","result","onKey","ev","items","focusables","first","last","active","action","copyText","text","value","nav","root","legacyCopy","d","doc","area","ok","attrs","map","k","v","escapeHtml","CopyButton","opts","cls","copyFromButton","btn","targetSel","target","toElement","label","announce","toggleReveal","input","show","normaliseOptions","options","o","fieldParts","kind","id","uid","helpId","errorId","describedBy","help","error","field","type","check","p","common","invalid","control","selected","secret","reveal","copy","setPath","obj","path","keys","node","getPath","controls","form","el","values","out","els","counts","name","list","fill","data","isPlainObject","mergeConfig","base","patch","track","baseline","baselineValues","dirty","busy","bar","host","setDirty","next","reset","setBusy","b","defaultSave","vals","hb","hbClient","blocks","config","save","custom","result","saved","Toast","err","errorMessage","discard","onBarClick","ev","onSubmit","Form","ACTIVATABLE","onClick","ev","copy","copyFromButton","reveal","toggleReveal","onKeydown","installDelegates","d","doc","Skeleton","opts","lines","html","i","escapeHtml","STATUS","StatusBadge","defaultItem","item","index","interactive","name","status","defaultFilter","keys","query","k","v","DeviceList","el","toElement","label","searchOpts","searchId","uid","filter","items","loading","visible","list","input","announce","text","paint","n","EmptyState","nr","onInput","onClick","ev","row","control","next","q","textOf","ANSI","stripAnsi","text","NEAR_BOTTOM","LogViewer","el","opts","toElement","d","maxLines","body","jump","follow","lines","atBottom","scrollToBottom","onScroll","append","input","incoming","stick","frag","line","row","extra","excess","i","formatPin","code","digits","safeImageSrc","src","s","safeUrl","pinHtml","opts","formatted","escapeHtml","spoken","id","uid","label","CopyButton","Pairing","el","toElement","qr","slot","STATE_TEXT","Auth","titleId","url","card","statusEl","statusText","retry","state","timer","expiry","running","interval","setState","next","message","stop","controller","schedule","tick","res","err","start","Steps","steps","current","paint","i","st","go","index","initial","panel","focusElement","announce","version","MpKit","escapeHtml","announce","StatusBadge","EmptyState","Loading","View","Footer","Tabs","Theme","Toast","confirm","Form","CopyButton","copyText","DeviceList","Skeleton","LogViewer","stripAnsi","Pairing","Auth","Steps","ai","installDelegates","root","MpKit"],"sourceRoot":""}