@starlove/orbit 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -7
- package/SKILL-ORBIT.md +26 -1
- package/dist/full/index.html +2 -2
- package/dist/full/js/app.a4f045fc.js +676 -0
- package/dist/full/js/app.a4f045fc.js.map +7 -0
- package/dist/full/{styles.14e9dbbd.css → styles.836872e7.css} +836 -39
- package/dist/full/version.json +2 -2
- package/docs/AGENT_PROTOCOL.md +23 -5
- package/docs/MCP_SETUP.md +5 -3
- package/docs/ORBIT_DISPATCH.md +185 -0
- package/docs/setup/orbit-init-wizard.md +174 -0
- package/package.json +2 -2
- package/public/js/actor-labels.js +65 -0
- package/public/js/app.js +8 -1
- package/public/js/card-actions.js +526 -0
- package/public/js/config.js +2 -1
- package/public/js/format.js +204 -10
- package/public/js/kanban.js +15 -0
- package/public/js/local-backend.js +24 -8
- package/public/js/router.js +3 -2
- package/public/js/search.js +6 -3
- package/public/js/settings.js +96 -26
- package/public/js/state.js +50 -0
- package/public/js/ticket-detail.js +428 -125
- package/public/styles.css +836 -39
- package/src/cli/orbit.js +217 -32
- package/src/core/agent.js +1 -18
- package/src/core/agents-md.js +15 -10
- package/src/core/attachments.js +238 -0
- package/src/core/auth.js +36 -0
- package/src/core/backups.js +9 -3
- package/src/core/board.js +31 -0
- package/src/core/boards.js +1 -1
- package/src/core/db.js +42 -2
- package/src/core/delete-board.js +87 -21
- package/src/core/dispatch.js +532 -0
- package/src/core/http.js +31 -11
- package/src/core/migrate.js +198 -0
- package/src/core/paths.js +6 -0
- package/src/core/registry.js +12 -9
- package/src/core/router.js +61 -5
- package/src/core/search.js +3 -3
- package/src/core/snapshots.js +14 -2
- package/src/mcp/orbit-client.js +81 -38
- package/src/mcp-server.js +190 -6
- package/src/server.js +20 -0
- package/dist/full/js/app.f4fd5e94.js +0 -604
- package/dist/full/js/app.f4fd5e94.js.map +0 -7
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["public/js/dom.js", "public/js/motion-preference.js", "public/js/theme-preference.js", "public/js/settings-tabs.js", "public/js/state.js", "public/js/format.js", "public/js/toast.js", "public/js/transport.js", "public/js/api.js", "public/js/drawer.js", "public/js/unread.js", "public/js/kanban.js", "public/js/config.js", "public/js/settings.js", "public/js/ticket-detail.js", "public/js/sse.js", "public/js/app.js", "public/js/create-card.js", "public/js/board-menu.js", "public/js/url-routes.js", "public/js/router.js", "public/js/starscape.js", "public/js/main.js", "public/js/search.js", "public/js/modal.js"],
|
|
4
|
-
"sourcesContent": ["// Cached DOM references queried once at module-load time. Importing this\n// module assumes the body has been parsed (the script tag is at the bottom\n// of <body> and uses type=\"module\", so this holds).\n\nexport const $ = (selector) => document.querySelector(selector);\n\nexport const boardMenuBtn = $(\"#boardMenuBtn\");\nexport const boardFlyout = $(\"#boardFlyout\");\nexport const kanban = $(\"#kanban\");\nexport const drawer = $(\"#drawer\");\nexport const drawerInner = $(\"#drawerInner\");\nexport const drawerBackdrop = $(\"#drawerBackdrop\");\nexport const createFlyout = $(\"#createFlyout\");\nexport const createFlyoutInner = $(\"#createFlyoutInner\");\nexport const createFlyoutBackdrop = $(\"#createFlyoutBackdrop\");\nexport const searchInput = $(\"#searchInput\");\nexport const searchResults = $(\"#searchResults\");\nexport const themeToggle = $(\"#themeToggle\");\nexport const themeIcon = $(\"#themeIcon\");\n", "export const REDUCE_MOTION_STORAGE_KEY = \"mab_reduce_motion\";\n\nfunction safeStorage(storage) {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nfunction defaultMediaMatcher(query) {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(query)\n : { matches: false };\n}\n\nexport function storedReducedMotionPreference(storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = store?.getItem?.(REDUCE_MOTION_STORAGE_KEY);\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n return null;\n}\n\nexport function browserPrefersReducedMotion(mediaMatcher = defaultMediaMatcher) {\n try {\n return !!mediaMatcher(\"(prefers-reduced-motion: reduce)\")?.matches;\n } catch {\n return false;\n }\n}\n\nexport function effectiveReducedMotionPreference({ storage = safeStorage(), mediaMatcher = defaultMediaMatcher } = {}) {\n const stored = storedReducedMotionPreference(storage);\n return stored ?? browserPrefersReducedMotion(mediaMatcher);\n}\n\nexport function setReducedMotionPreference(reduce, storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = reduce ? \"true\" : \"false\";\n store?.setItem?.(REDUCE_MOTION_STORAGE_KEY, value);\n return reduce;\n}\n\nexport function applyReducedMotionPreference({\n doc = globalThis.document,\n storage = safeStorage(),\n mediaMatcher = defaultMediaMatcher\n} = {}) {\n const reduce = effectiveReducedMotionPreference({ storage, mediaMatcher });\n doc?.documentElement?.setAttribute(\"data-reduced-motion\", reduce ? \"reduce\" : \"allow\");\n return reduce;\n}\n", "export const THEME_STORAGE_KEY = \"mab_theme\";\nexport const THEME_CHANGE_EVENT = \"orbit:theme-change\";\n\nconst THEMES = new Set([\"light\", \"dark\"]);\n\nfunction safeStorage(storage) {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nfunction safeDocument(doc) {\n try {\n return doc ?? globalThis.document ?? null;\n } catch {\n return null;\n }\n}\n\nfunction safeEventTarget(eventTarget) {\n try {\n return eventTarget ?? globalThis.window ?? null;\n } catch {\n return null;\n }\n}\n\nexport function normalizeTheme(theme) {\n return THEMES.has(theme) ? theme : \"light\";\n}\n\nexport function storedThemePreference(storage = safeStorage()) {\n const store = safeStorage(storage);\n const value = store?.getItem?.(THEME_STORAGE_KEY);\n return THEMES.has(value) ? value : null;\n}\n\nexport function currentTheme({ doc = safeDocument(), storage = safeStorage() } = {}) {\n const rootTheme = safeDocument(doc)?.documentElement?.getAttribute?.(\"data-theme\");\n return THEMES.has(rootTheme) ? rootTheme : storedThemePreference(storage) ?? \"light\";\n}\n\nexport function applyStoredThemePreference({\n doc = safeDocument(),\n storage = safeStorage()\n} = {}) {\n const storedTheme = storedThemePreference(storage);\n if (storedTheme) {\n safeDocument(doc)?.documentElement?.setAttribute?.(\"data-theme\", storedTheme);\n }\n return currentTheme({ doc, storage });\n}\n\nexport function setThemePreference(theme, {\n doc = safeDocument(),\n storage = safeStorage(),\n eventTarget = safeEventTarget(),\n notify = true\n} = {}) {\n const next = normalizeTheme(theme);\n safeDocument(doc)?.documentElement?.setAttribute?.(\"data-theme\", next);\n safeStorage(storage)?.setItem?.(THEME_STORAGE_KEY, next);\n\n if (notify) {\n dispatchThemeChange(next, eventTarget);\n }\n\n return next;\n}\n\nexport function toggleThemePreference(options = {}) {\n const next = currentTheme(options) === \"dark\" ? \"light\" : \"dark\";\n return setThemePreference(next, options);\n}\n\nfunction dispatchThemeChange(theme, eventTarget = safeEventTarget()) {\n const target = safeEventTarget(eventTarget);\n if (typeof target?.dispatchEvent !== \"function\") return;\n\n if (typeof CustomEvent === \"function\") {\n target.dispatchEvent(new CustomEvent(THEME_CHANGE_EVENT, { detail: { theme } }));\n return;\n }\n\n target.dispatchEvent({ type: THEME_CHANGE_EVENT, detail: { theme } });\n}\n", "/** Settings drawer tab ids \u2014 must match URL segments `#/b/\u2026/settings/:tab` and `settings.js` tab config. */\nexport const SETTINGS_TAB_IDS = new Set([\"lanes\", \"appearance\", \"ai\", \"notes\", \"journal\", \"repository\", \"archive\"]);\n\nexport function normalizeSettingsTab(raw) {\n if (!raw || !SETTINGS_TAB_IDS.has(raw)) return \"lanes\";\n return raw;\n}\n", "import { normalizeSettingsTab } from \"./settings-tabs.js\";\n\n// Mutable application state plus board/ticket query helpers. The `state`\n// object is the single source of truth for \"what view is showing\" and\n// \"what data did the bootstrap give us\"; modules read it freely and mutate\n// it in-place. The query helpers wrap the most common slices.\n\nexport const state = {\n data: null,\n /** Currently selected board id. Single-board UI; this points at the active\n * board in `state.data.boards`. */\n boardId: \"\",\n /** URL-facing board identifier. Routes use slugs; API calls keep using ids. */\n boardSlug: \"\",\n selectedTicketId: \"\",\n expandedCardIds: new Set(),\n /** \"empty\" | \"ticket\" | \"settings\" \u2014 drives the main right overlay drawer (not the New flyout). */\n detailMode: \"empty\",\n /** \"lanes\" | \"ai\" | \"repository\" | \"notes\" | \"journal\" \u2014 which Settings tab is active. */\n settingsTab: normalizeSettingsTab(localStorage.getItem(\"mab_settings_tab\")),\n /** Whether to render the priority pill on kanban / related cards. The detail\n * drawer header always shows it. Default on; user can toggle it from the\n * Lanes settings tab. */\n showPriority: localStorage.getItem(\"mab_show_priority\") !== \"false\",\n eventSource: null\n};\n\nexport function getSettingsTab() {\n return normalizeSettingsTab(state.settingsTab || localStorage.getItem(\"mab_settings_tab\"));\n}\n\nexport function syncBoardSelection() {\n if (!state.data) return;\n const boards = state.data.boards || [];\n let board = state.boardId ? boards.find((b) => b.id === state.boardId) : null;\n if (!board && state.boardSlug) {\n board = boards.find((b) => b.slug === state.boardSlug) || boards.find((b) => b.id === state.boardSlug);\n }\n if (!board) {\n const activeBoardId = state.data.active_board_id;\n board = boards.find((b) => b.id === activeBoardId) || boards[0] || null;\n }\n state.boardId = board?.id || \"\";\n state.boardSlug = board?.slug || \"\";\n}\n\nexport function currentBoard() {\n return (state.data?.boards || []).find((b) => b.id === state.boardId);\n}\n\n/** Labels defined for the current board (from bootstrap), for autocomplete. */\nexport function boardLabelCatalog() {\n if (!state.boardId) return [];\n return (state.data?.labels || []).filter((label) => label.board_id === state.boardId);\n}\n\nexport function statesForProject() {\n return state.data.states.filter((item) => item.board_id === state.boardId);\n}\n\nexport function isAiReadyState(item) {\n return item?.role === \"ai_ready\" || item?.name === \"AI Ready\";\n}\n\nexport function visibleStatesForProject() {\n const states = statesForProject();\n if (currentBoard()?.ai_enabled !== 0) return states;\n return states.filter((item) => !isAiReadyState(item));\n}\n\nexport function selectableStatesForProject(currentStateId = \"\") {\n const states = statesForProject();\n if (currentBoard()?.ai_enabled !== 0) return states;\n return states.filter((item) => !isAiReadyState(item) || item.id === currentStateId);\n}\n\nexport function ticketsForProject() {\n return state.data.tickets.filter((item) => item.board_id === state.boardId);\n}\n", "// Pure string helpers: escape, dates, ticket/type/priority labels.\n// Zero side effects, no imports \u2014 safe to import from anywhere.\n\nexport function escapeHtml(value) {\n return String(value ?? \"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nconst SAFE_LINK_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\"]);\n\nfunction sanitizeMarkdownUrl(value) {\n const href = String(value || \"\").trim();\n if (!href) return \"\";\n\n // Collapse control characters/whitespace before checking the scheme so inputs\n // like `java\\nscript:` or `jav\\tascript:` cannot bypass the blocklist.\n const compact = href.replace(/[\\u0000-\\u001f\\u007f\\s]+/g, \"\").toLowerCase();\n if (/^(?:javascript|data|vbscript):/.test(compact)) return \"\";\n\n const scheme = compact.match(/^([a-z][a-z0-9+.-]*):/);\n if (scheme && !SAFE_LINK_PROTOCOLS.has(`${scheme[1]}:`)) return \"\";\n\n return href;\n}\n\nfunction renderEmphasis(text) {\n let html = escapeHtml(text);\n html = html.replace(/(\\*\\*|__)(?=\\S)([\\s\\S]*?\\S)\\1/g, \"<strong>$2</strong>\");\n html = html.replace(/(\\*|_)(?=\\S)([^*_]*?\\S)\\1/g, \"<em>$2</em>\");\n return html;\n}\n\nfunction renderLinksAndEmphasis(text) {\n const linkPattern = /\\[([^\\]\\n]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g;\n let html = \"\";\n let lastIndex = 0;\n let match;\n\n while ((match = linkPattern.exec(text))) {\n html += renderEmphasis(text.slice(lastIndex, match.index));\n\n const labelHtml = renderEmphasis(match[1]);\n const href = sanitizeMarkdownUrl(match[2]);\n html += href\n ? `<a href=\"${escapeHtml(href)}\" target=\"_blank\" rel=\"noopener noreferrer\">${labelHtml}</a>`\n : labelHtml;\n\n lastIndex = match.index + match[0].length;\n }\n\n html += renderEmphasis(text.slice(lastIndex));\n return html;\n}\n\nfunction renderInlineMarkdown(text) {\n const source = String(text ?? \"\");\n let html = \"\";\n let cursor = 0;\n\n while (cursor < source.length) {\n const codeStart = source.indexOf(\"`\", cursor);\n if (codeStart === -1) {\n html += renderLinksAndEmphasis(source.slice(cursor));\n break;\n }\n\n const codeEnd = source.indexOf(\"`\", codeStart + 1);\n if (codeEnd === -1) {\n html += renderLinksAndEmphasis(source.slice(cursor));\n break;\n }\n\n html += renderLinksAndEmphasis(source.slice(cursor, codeStart));\n html += `<code>${escapeHtml(source.slice(codeStart + 1, codeEnd))}</code>`;\n cursor = codeEnd + 1;\n }\n\n return html;\n}\n\nfunction renderParagraph(lines) {\n return `<p>${renderInlineMarkdown(lines.join(\"\\n\")).replaceAll(\"\\n\", \"<br>\")}</p>`;\n}\n\nexport function renderMarkdown(value) {\n const source = String(value ?? \"\").replace(/\\r\\n?/g, \"\\n\");\n if (!source.trim()) return \"\";\n\n const blocks = [];\n const lines = source.split(\"\\n\");\n let paragraph = [];\n let list = null;\n\n const flushParagraph = () => {\n if (!paragraph.length) return;\n blocks.push(renderParagraph(paragraph));\n paragraph = [];\n };\n\n const flushList = () => {\n if (!list) return;\n blocks.push(`<${list.type}>${list.items.map((item) => `<li>${item}</li>`).join(\"\")}</${list.type}>`);\n list = null;\n };\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i];\n\n if (/^\\s*```/.test(line)) {\n flushParagraph();\n flushList();\n const codeLines = [];\n i += 1;\n while (i < lines.length && !/^\\s*```\\s*$/.test(lines[i])) {\n codeLines.push(lines[i]);\n i += 1;\n }\n blocks.push(`<pre><code>${escapeHtml(codeLines.join(\"\\n\"))}</code></pre>`);\n continue;\n }\n\n if (!line.trim()) {\n flushParagraph();\n flushList();\n continue;\n }\n\n const ordered = line.match(/^\\s*\\d+[.)]\\s+(.+)$/);\n const unordered = line.match(/^\\s*[-*+]\\s+(.+)$/);\n if (ordered || unordered) {\n flushParagraph();\n const type = ordered ? \"ol\" : \"ul\";\n if (!list || list.type !== type) {\n flushList();\n list = { type, items: [] };\n }\n list.items.push(renderInlineMarkdown((ordered || unordered)[1].trim()).replaceAll(\"\\n\", \"<br>\"));\n continue;\n }\n\n flushList();\n paragraph.push(line.trim());\n }\n\n flushParagraph();\n flushList();\n\n return blocks.join(\"\");\n}\n\nexport function formatDate(value) {\n if (!value) return \"\";\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\"\n }).format(new Date(value));\n}\n\n/** Richer timestamp for the detail pane \u201CUpdated\u201D line (refreshes after every save). */\nexport function formatDateDetail(value) {\n if (!value) return \"\";\n return new Intl.DateTimeFormat(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n second: \"2-digit\"\n }).format(new Date(value));\n}\n\nexport function ticketLabel(ticket) {\n return `#${ticket.number}`;\n}\n\nexport function canonicalTicketType(type) {\n if (type === \"epic\" || type === \"feature\" || type === \"bug\" || type === \"task\") return type;\n return \"task\";\n}\n\n// Short label for dense surfaces (card pills, child-card pills).\nexport function typeLabel(type) {\n const labels = {\n epic: \"Epic\",\n feature: \"Feature\",\n task: \"Task\",\n bug: \"Bug\"\n };\n return labels[canonicalTicketType(type)] || \"Task\";\n}\n\n// Long, hierarchy-aware label for dropdowns where we have the room. Epic/Story\n// pairs older vocabulary so existing terminology still resonates.\nexport function typeLabelLong(type) {\n const labels = {\n epic: \"Epic / Story\",\n feature: \"Feature\",\n task: \"Task\",\n bug: \"Bug\"\n };\n return labels[canonicalTicketType(type)] || \"Task\";\n}\n\nexport function priorityLabel(priority) {\n const labels = {\n 0: \"MAYBE\",\n 1: \"LOW\",\n 2: \"MED\",\n 3: \"HIGH\",\n 4: \"URGENT\"\n };\n return labels[Number(priority)] || \"MED\";\n}\n\n/** Lowercase key used for CSS class targeting: `priority-maybe`, `priority-urgent`, etc. */\nexport function priorityKeyFor(priority) {\n const keys = [\"maybe\", \"low\", \"med\", \"high\", \"urgent\"];\n const n = Number(priority);\n return keys[Number.isFinite(n) ? Math.max(0, Math.min(4, n)) : 2];\n}\n\nexport function renderLabels(labels = []) {\n if (!labels.length) return \"\";\n return `\n <div class=\"labels\">\n ${labels\n .map(\n (label) =>\n `<span class=\"label\" style=\"--label-color: ${escapeHtml(label.color)}\">${escapeHtml(label.name)}</span>`\n )\n .join(\"\")}\n </div>\n `;\n}\n\nexport function repoLabelFromUrl(repoUrl) {\n const raw = String(repoUrl || \"\").trim();\n if (!raw) return \"Not set\";\n const githubHttps = raw.match(/github\\.com\\/([^/\\s]+)\\/([^/\\s]+?)(?:\\.git)?$/i);\n if (githubHttps) return `${githubHttps[1]}/${githubHttps[2]}`;\n const githubSsh = raw.match(/github\\.com[:/]([^/\\s]+)\\/([^/\\s]+?)(?:\\.git)?$/i);\n if (githubSsh) return `${githubSsh[1]}/${githubSsh[2]}`;\n return raw;\n}\n", "// Toast notifications + small UI utilities (downloadJson, debounce).\n\nimport { escapeHtml } from \"./format.js\";\n\nconst toastIcons = {\n info: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\" clip-rule=\"evenodd\"/></svg>`,\n success: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\" clip-rule=\"evenodd\"/></svg>`,\n warning: `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z\" clip-rule=\"evenodd\"/></svg>`,\n error: `<svg viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\"/></svg>`\n};\n\nlet toastContainer = null;\n\nfunction ensureToastContainer() {\n if (toastContainer && toastContainer.isConnected) return toastContainer;\n toastContainer = document.createElement(\"div\");\n toastContainer.className = \"toast-container\";\n document.body.append(toastContainer);\n return toastContainer;\n}\n\nexport function toast(message, type = \"info\", duration = 4000) {\n const container = ensureToastContainer();\n\n const node = document.createElement(\"div\");\n node.className = `toast toast-${type}`;\n node.setAttribute(\"role\", \"status\");\n\n const icon = toastIcons[type];\n node.innerHTML = `<span class=\"toast-icon\">${icon}</span><span class=\"toast-msg\">${escapeHtml(message)}</span><button class=\"toast-close\" aria-label=\"Dismiss\">×</button>`;\n\n node.querySelector(\".toast-close\").addEventListener(\"click\", () => dismissToast(node));\n\n container.prepend(node);\n requestAnimationFrame(() => requestAnimationFrame(() => node.classList.add(\"toast-enter\")));\n\n const timer = setTimeout(() => dismissToast(node), duration);\n node.addEventListener(\"mouseenter\", () => clearTimeout(timer));\n node.addEventListener(\"mouseleave\", () => {\n const t2 = setTimeout(() => dismissToast(node), 1500);\n node.addEventListener(\"mouseenter\", () => clearTimeout(t2), { once: true });\n });\n}\n\ntoast.info = (msg, dur) => toast(msg, \"info\", dur);\ntoast.success = (msg, dur) => toast(msg, \"success\", dur);\ntoast.warning = (msg, dur) => toast(msg, \"warning\", dur);\ntoast.error = (msg, dur) => toast(msg, \"error\", dur);\n\nfunction dismissToast(node) {\n if (node.classList.contains(\"toast-exit\")) return;\n node.classList.add(\"toast-exit\");\n node.addEventListener(\"animationend\", () => node.remove(), { once: true });\n}\n\nexport function downloadJson(filename, value) {\n const blob = new Blob([JSON.stringify(value, null, 2)], { type: \"application/json\" });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\nexport function debounce(fn, wait) {\n let timer = 0;\n return (...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => fn(...args), wait);\n };\n}\n", "// Request transport. The full edition talks to the Orbit HTTP server; a\n// preview build will replace this module (or branch on `edition`) to dispatch\n// the same path/body shapes to a local IndexedDB backend. Keep this file\n// I/O-only \u2014 UI concerns (toasts, redirects) belong in api.js callers.\n\nexport async function request({ method = \"GET\", path, body, headers }) {\n const finalHeaders = { \"Content-Type\": \"application/json\", ...(headers || {}) };\n const response = await fetch(path, {\n method,\n headers: finalHeaders,\n body: body !== undefined ? JSON.stringify(body) : undefined\n });\n const text = await response.text();\n const payload = text ? JSON.parse(text) : {};\n if (!response.ok) {\n const error = new Error(payload.error || response.statusText);\n error.payload = payload;\n error.status = response.status;\n throw error;\n }\n return payload;\n}\n", "// Network layer. `api()` is the single fetch wrapper used everywhere; it\n// delegates raw I/O to transport.js (swappable per edition) and surfaces\n// errors as toasts. Path helpers live here because they're shared by every\n// caller regardless of transport.\n\nimport { state } from \"./state.js\";\nimport { toast } from \"./toast.js\";\nimport { request } from \"./transport.js\";\n\n/** Bootstrap for the currently selected board (server opens the right DB). */\nexport function bootstrapPath() {\n const q = state.boardId\n ? `?board_id=${encodeURIComponent(state.boardId)}`\n : state.boardSlug\n ? `?board=${encodeURIComponent(state.boardSlug)}`\n : \"\";\n return `/api/bootstrap${q}`;\n}\n\n/** Append board_id for ticket/state/entry routes when the path has no board prefix. */\nexport function withBoardQuery(path) {\n if (!state.boardId || path.includes(\"board_id=\")) return path;\n const sep = path.includes(\"?\") ? \"&\" : \"?\";\n return `${path}${sep}board_id=${encodeURIComponent(state.boardId)}`;\n}\n\nexport async function api(path, options = {}) {\n try {\n return await request({\n method: options.method || \"GET\",\n path,\n body: options.body,\n headers: options.headers\n });\n } catch (err) {\n toast.error(err.payload?.error || err.message || \"Request failed\");\n throw err;\n }\n}\n", "// Right-side overlay drawer used for ticket detail and project settings.\n// Owns the open/close transition state and the shared header layout\n// (eyebrow, title, subtitle, tabs, archive/close buttons). Bodies are\n// rendered by the feature modules that call `renderDrawerShell`.\n\nimport { drawer, drawerInner, drawerBackdrop } from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { escapeHtml } from \"./format.js\";\n\n/** Bumps on each open/close so a stale `transitionend` from an old close cannot clear a newly opened drawer. */\nlet drawerToken = 0;\n\n/** Slide the right drawer in (ticket detail, project settings, or create form). */\nexport function openDrawer() {\n drawerToken += 1;\n drawer.hidden = false;\n drawerBackdrop.hidden = false;\n requestAnimationFrame(() => {\n drawer.classList.add(\"is-open\");\n drawerBackdrop.classList.add(\"is-visible\");\n });\n}\n\n/**\n * Close the drawer overlay. Uses transitionend with a timeout fallback for `hidden`.\n * `drawerToken` invalidates pending finish callbacks if the user opens the drawer again mid-animation.\n */\nexport function closeDrawer() {\n const finishToken = ++drawerToken;\n const wasOpen = drawer.classList.contains(\"is-open\");\n drawer.classList.remove(\"is-open\");\n drawerBackdrop.classList.remove(\"is-visible\");\n\n const finish = () => {\n if (drawerToken !== finishToken) return;\n drawer.hidden = true;\n drawerBackdrop.hidden = true;\n drawerInner.innerHTML = \"\";\n const eyebrowEl = document.getElementById(\"drawerEyebrow\");\n const titleEl = document.getElementById(\"drawerTitle\");\n const subtitleEl = document.getElementById(\"drawerSubtitle\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n if (eyebrowEl) { eyebrowEl.textContent = \"\"; eyebrowEl.hidden = true; }\n if (titleEl) {\n for (const attr of Array.from(titleEl.attributes)) {\n if (attr.name !== \"id\") titleEl.removeAttribute(attr.name);\n }\n titleEl.className = \"drawer-title-text\";\n titleEl.textContent = \"\";\n }\n if (subtitleEl) { subtitleEl.innerHTML = \"\"; subtitleEl.hidden = true; }\n if (tabsEl) { tabsEl.innerHTML = \"\"; tabsEl.hidden = true; }\n drawer.classList.remove(\"is-wide\");\n };\n\n if (!wasOpen) {\n finish();\n return;\n }\n\n let ended = false;\n const end = () => {\n if (ended) return;\n ended = true;\n finish();\n };\n\n drawer.addEventListener(\"transitionend\", end, { once: true });\n setTimeout(end, 360);\n}\n\n/**\n * Fill the drawer's header + body slots. All drawer modes (ticket, project,\n * create) should route through this so the header/title/close/tabs stay\n * structurally consistent. `body` is an HTML string assigned to drawerInner.\n */\nexport function renderDrawerShell({ eyebrow, title, titleAttrs, subtitleHtml, tabs, activeTab, onTabSelect, body, mode }) {\n drawer.classList.toggle(\"is-settings\", mode === \"settings\");\n drawer.classList.toggle(\"is-wide\", mode === \"ticket\" || mode === \"settings\");\n const eyebrowEl = document.getElementById(\"drawerEyebrow\");\n const titleEl = document.getElementById(\"drawerTitle\");\n const subtitleEl = document.getElementById(\"drawerSubtitle\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n\n if (eyebrow) {\n eyebrowEl.textContent = eyebrow;\n eyebrowEl.hidden = false;\n } else {\n eyebrowEl.textContent = \"\";\n eyebrowEl.hidden = true;\n }\n\n if (subtitleHtml) {\n subtitleEl.innerHTML = subtitleHtml;\n subtitleEl.hidden = false;\n } else {\n subtitleEl.innerHTML = \"\";\n subtitleEl.hidden = true;\n }\n\n // Reset prior edit-attrs / classes each render so different modes don't\n // carry state from one another.\n for (const attr of Array.from(titleEl.attributes)) {\n if (attr.name !== \"id\") titleEl.removeAttribute(attr.name);\n }\n titleEl.className = \"drawer-title-text\";\n if (titleAttrs) {\n for (const [key, value] of Object.entries(titleAttrs)) {\n if (key === \"class\") titleEl.className = `drawer-title-text ${value}`;\n else titleEl.setAttribute(key, value);\n }\n }\n titleEl.textContent = title ?? \"\";\n\n if (tabs && tabs.length) {\n tabsEl.hidden = false;\n tabsEl.innerHTML = tabs\n .map(\n (t) =>\n `<button type=\"button\" role=\"tab\" class=\"drawer-tab ${\n t.id === activeTab ? \"is-active\" : \"\"\n }\" data-drawer-tab=\"${escapeHtml(t.id)}\" aria-selected=\"${t.id === activeTab}\">${escapeHtml(t.label)}</button>`\n )\n .join(\"\");\n if (typeof onTabSelect === \"function\") {\n tabsEl.querySelectorAll(\".drawer-tab\").forEach((btn) => {\n btn.addEventListener(\"click\", () => onTabSelect(btn.dataset.drawerTab));\n });\n }\n } else {\n tabsEl.hidden = true;\n tabsEl.innerHTML = \"\";\n }\n\n const archiveBtn = document.getElementById(\"drawerArchiveBtn\");\n if (archiveBtn) archiveBtn.hidden = state.detailMode !== \"ticket\";\n\n drawerInner.innerHTML = body ?? \"\";\n}\n", "// Per-card \"unread updates\" tracker. Lives client-side in localStorage so\n// no backend changes are needed. Each entry tracks both:\n// readAt \u2014 ISO timestamp the human last acknowledged this card\n// count \u2014 number of foreign-actor events received since that ack\n// Render uses a dot for count===1 and a numeric pill for count>=2.\n//\n// Acknowledgement happens on three paths:\n// - opening the card (renderDetail in ticket-detail.js)\n// - own action via SSE self-event suppression (sse.js)\n// - the one-time per-board seed below, so the very first load doesn't\n// flash badges on every existing card\n\nimport { state } from \"./state.js\";\n\nconst READ_KEY = (boardId) => `mab_card_read:${boardId}`;\nconst SEEDED_KEY = (boardId) => `mab_card_read_seeded:${boardId}`;\n\nconst cache = new Map();\n\n// Normalize a stored value into { readAt, count }. Tolerates the old\n// string-only shape so existing localStorage entries upgrade in place.\nfunction normalize(raw) {\n if (!raw) return { readAt: null, count: 0 };\n if (typeof raw === \"string\") return { readAt: raw, count: 0 };\n return { readAt: raw.readAt || null, count: Number(raw.count) || 0 };\n}\n\nfunction getMap(boardId) {\n if (!boardId) return new Map();\n let m = cache.get(boardId);\n if (m) return m;\n m = new Map();\n try {\n const raw = localStorage.getItem(READ_KEY(boardId));\n if (raw) {\n const obj = JSON.parse(raw);\n for (const [k, v] of Object.entries(obj)) m.set(k, normalize(v));\n }\n } catch { /* ignore */ }\n cache.set(boardId, m);\n return m;\n}\n\nfunction persist(boardId) {\n const m = cache.get(boardId);\n if (!m) return;\n try {\n const obj = {};\n for (const [k, v] of m) obj[k] = v;\n localStorage.setItem(READ_KEY(boardId), JSON.stringify(obj));\n } catch { /* ignore */ }\n}\n\nfunction entryFor(m, ticketId) {\n let e = m.get(ticketId);\n if (!e) {\n e = { readAt: null, count: 0 };\n m.set(ticketId, e);\n }\n return e;\n}\n\nexport function unreadCount(ticket) {\n const boardId = ticket?.board_id || state.boardId;\n if (!boardId || !ticket?.id) return 0;\n const m = getMap(boardId);\n const e = m.get(ticket.id);\n if (!e) {\n // Absence: if seeded, the card appeared post-seed \u2192 flag with count 1.\n // If never seeded, treat as read so first-ever load is quiet.\n return localStorage.getItem(SEEDED_KEY(boardId)) === \"1\" ? 1 : 0;\n }\n return e.count;\n}\n\nexport function isUnread(ticket) {\n return unreadCount(ticket) > 0;\n}\n\nexport function markRead(ticketId, timestamp) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n const e = entryFor(m, ticketId);\n if (e.count === 0 && e.readAt && timestamp && e.readAt >= timestamp) return;\n e.count = 0;\n if (timestamp) e.readAt = timestamp;\n persist(boardId);\n}\n\nexport function bumpUnread(ticketId) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n const e = entryFor(m, ticketId);\n e.count = (e.count || 0) + 1;\n persist(boardId);\n}\n\nexport function clearUnread(ticketId) {\n const boardId = state.boardId;\n if (!boardId || !ticketId) return;\n const m = getMap(boardId);\n if (!m.has(ticketId)) return;\n m.delete(ticketId);\n persist(boardId);\n}\n\n// One-time per-board seed so existing cards start \"read\" the first time the\n// user runs this version. Runs again per-board the first time each board is\n// visited.\nexport function seedReadIfNeeded(boardId, tickets) {\n if (!boardId) return;\n if (localStorage.getItem(SEEDED_KEY(boardId)) === \"1\") return;\n const m = getMap(boardId);\n for (const t of tickets || []) {\n if (!m.has(t.id) && t.updated_at) m.set(t.id, { readAt: t.updated_at, count: 0 });\n }\n persist(boardId);\n try { localStorage.setItem(SEEDED_KEY(boardId), \"1\"); } catch { /* ignore */ }\n}\n", "// Kanban board rendering plus the drag-to-pan interaction. `renderBoard()`\n// rebuilds every column from current state and rewires drop zones, card\n// click/drag handlers, and the per-column \"+\" button. Card detail is\n// owned by ticket-detail.js.\n\nimport { kanban } from \"./dom.js\";\nimport { state, visibleStatesForProject, ticketsForProject } from \"./state.js\";\nimport {\n escapeHtml,\n ticketLabel,\n canonicalTicketType,\n typeLabel,\n priorityLabel,\n priorityKeyFor,\n renderLabels,\n renderMarkdown\n} from \"./format.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { navigate } from \"./router.js\";\nimport { closeCreateFlyout, openCreateFlyout } from \"./create-card.js\";\nimport { load } from \"./app.js\";\nimport { unreadCount } from \"./unread.js\";\n\nexport function renderBoard() {\n const states = visibleStatesForProject();\n const tickets = ticketsForProject();\n kanban.innerHTML = states.map((column) => renderColumn(column, tickets)).join(\"\");\n\n kanban.querySelectorAll(\".column\").forEach((column) => {\n column.addEventListener(\"dragover\", (event) => {\n event.preventDefault();\n column.classList.add(\"drag-over\");\n });\n column.addEventListener(\"dragleave\", () => column.classList.remove(\"drag-over\"));\n column.addEventListener(\"drop\", async (event) => {\n event.preventDefault();\n column.classList.remove(\"drag-over\");\n const ticketId = event.dataTransfer.getData(\"text/plain\");\n if (!ticketId) return;\n closeCreateFlyout();\n await api(withBoardQuery(`/api/tickets/${ticketId}`), {\n method: \"PATCH\",\n body: { state_id: column.dataset.stateId }\n });\n // Refresh board only; do not open the ticket drawer (DnD also fires a\n // synthetic click on the card \u2014 suppressed in the card listener).\n await load();\n });\n });\n\n kanban.querySelectorAll(\"[data-add-to-state]\").forEach((btn) => {\n btn.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n openCreateFlyout(btn.dataset.addToState || \"\");\n });\n });\n\n kanban.querySelectorAll(\".epic-mini-header[data-ticket-id]\").forEach((header) => {\n header.addEventListener(\"click\", () => {\n closeCreateFlyout();\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: header.dataset.ticketId\n });\n });\n });\n\n kanban.querySelectorAll(\".card\").forEach((card) => {\n // HTML5 DnD ends with a synthetic click on the source element; ignore that\n // follow-up click so dropping a card does not also open the detail drawer.\n let suppressClickAfterDrag = false;\n card.addEventListener(\"click\", async (event) => {\n const clickTarget = event.target instanceof Element ? event.target : event.target?.parentElement;\n if (clickTarget?.closest(\"a\")) {\n event.stopPropagation();\n return;\n }\n if (suppressClickAfterDrag) {\n suppressClickAfterDrag = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n closeCreateFlyout();\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: card.dataset.ticketId\n });\n });\n const toggleBtn = card.querySelector(\"button.card-expand-trigger\");\n if (toggleBtn) {\n toggleBtn.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n event.preventDefault();\n const id = card.dataset.ticketId;\n if (state.expandedCardIds.has(id)) state.expandedCardIds.delete(id);\n else state.expandedCardIds.add(id);\n const expanded = card.classList.toggle(\"is-expanded\");\n toggleBtn.setAttribute(\"aria-expanded\", expanded ? \"true\" : \"false\");\n });\n }\n card.addEventListener(\"dragstart\", (event) => {\n event.dataTransfer.setData(\"text/plain\", card.dataset.ticketId);\n event.dataTransfer.effectAllowed = \"move\";\n });\n card.addEventListener(\"dragend\", () => {\n suppressClickAfterDrag = true;\n // If no click follows (e.g. drag cancelled oddly), do not eat the next real click.\n setTimeout(() => {\n suppressClickAfterDrag = false;\n }, 0);\n });\n });\n}\n\nfunction renderEmptyState(columnName) {\n const name = columnName.toLowerCase();\n let flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\"><path d=\"M18 6L6 18M6 6l12 12\" opacity=\"0.5\" /></svg>`,\n title: \"Nothing here\",\n subtitle: \"Tasks will appear when ready\"\n };\n\n if (name === \"ai ready\") {\n flair = {\n icon: `<svg class=\"empty-state-icon ai-sparkle\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z\" fill=\"currentColor\" opacity=\"0.65\" />\n <circle cx=\"12\" cy=\"11.5\" r=\"1.8\" fill=\"#fff\" />\n </svg>`,\n title: \"Ready for agents\",\n subtitle: \"Drop unblocked cards here \u2014 the claim-next tool picks them up\"\n };\n } else if (name.includes(\"progress\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon orbit\" viewBox=\"0 0 100 100\">\n <circle cx=\"50\" cy=\"50\" r=\"10\" fill=\"currentColor\" opacity=\"0.9\" />\n <circle class=\"ring\" cx=\"50\" cy=\"50\" r=\"30\" stroke=\"currentColor\" stroke-dasharray=\"4 6\" />\n <circle class=\"satellite\" cx=\"80\" cy=\"50\" r=\"4\" fill=\"currentColor\" />\n </svg>`,\n title: \"Work in progress\",\n subtitle: \"Active work will appear here\"\n };\n } else if (name.includes(\"review\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon star\" viewBox=\"0 0 24 24\">\n <path d=\"M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z\" fill=\"currentColor\" />\n </svg>`,\n title: \"Under review\",\n subtitle: \"Quality gate before merge\"\n };\n } else if (name.includes(\"todo\") || name.includes(\"backlog\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon ai-sparkle\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z\" fill=\"currentColor\" opacity=\"0.5\" />\n <path d=\"M19 8L20 10L21 8L20 6L19 8ZM19 16L20 18L21 16L20 14L19 16ZM5 8L6 10L7 8L6 6L5 8Z\" fill=\"currentColor\" />\n </svg>`,\n title: \"Ready for launch\",\n subtitle: \"Create a card manually or task an AI to generate tasks\"\n };\n } else if (name.includes(\"done\") || name.includes(\"finished\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12L11 15L16 9\" />\n </svg>`,\n title: \"Done\",\n subtitle: \"Move completed tickets here\"\n };\n } else if (name.includes(\"cancel\")) {\n flair = {\n icon: `<svg class=\"empty-state-icon\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" opacity=\"0.2\" />\n <path d=\"M15 9L9 15M9 9l6 6\" />\n </svg>`,\n title: \"Not moving forward\",\n subtitle: \"Parked or replaced\"\n };\n }\n\n return `\n <div class=\"column-empty-state\">\n <div class=\"empty-state-visual\">\n <div class=\"empty-state-glow\"></div>\n ${flair.icon}\n </div>\n <div class=\"empty-state-title\">${escapeHtml(flair.title)}</div>\n <div class=\"empty-state-subtitle\">${escapeHtml(flair.subtitle)}</div>\n </div>\n `;\n}\n\nfunction renderColumn(column, tickets) {\n const columnTickets = tickets.filter((ticket) => ticket.state_id === column.id);\n const isEmpty = columnTickets.length === 0;\n // The \"AI Ready\" lane is a contract between humans and agents: cards here\n // are the queue the claim-next MCP tool pulls from. Mark it so humans can\n // instantly see where agent-facing staging lives.\n const isAiReady = column.name === \"AI Ready\";\n const columnClasses = [\"column\"];\n if (isAiReady) columnClasses.push(\"column--ai-ready\");\n\n return `\n <section class=\"${columnClasses.join(\" \")}\" data-state-id=\"${column.id}\" data-state-name=\"${escapeHtml(column.name)}\">\n <div class=\"column-head\">\n <h2${isAiReady ? ' title=\"Agent staging \u2014 cards here are picked up by the claim-next tool when unblocked\"' : \"\"}>\n ${isAiReady ? '<span class=\"agent-dot\" aria-hidden=\"true\"></span>' : \"\"}${escapeHtml(column.name)}\n </h2>\n <div class=\"column-head-actions\">\n <button type=\"button\" class=\"column-add-btn ghost\" data-add-to-state=\"${escapeHtml(column.id)}\" title=\"New card\">+</button>\n <span class=\"count\">${columnTickets.length}</span>\n </div>\n </div>\n ${isEmpty ? renderEmptyState(column.name) : renderColumnBody(columnTickets, tickets)}\n <button type=\"button\" class=\"add-card-phantom\" data-add-to-state=\"${escapeHtml(column.id)}\">+ Add a card</button>\n </section>\n `;\n}\n\n/**\n * Lay out the cards inside a column with epic-aware grouping. Children of an\n * epic that's also in this column slide under the epic; children whose epic\n * lives in a different column appear under a thin \"mini epic header\" so the\n * relationship is still visible. Children get pulled to their group even if\n * the user dropped them out of order \u2014 the grouping always wins for clarity.\n */\nfunction renderColumnBody(columnTickets, allTickets) {\n const epicById = new Map(\n allTickets\n .filter((t) => canonicalTicketType(t.type) === \"epic\")\n .map((t) => [t.id, t])\n );\n const epicIdsInColumn = new Set(\n columnTickets\n .filter((t) => canonicalTicketType(t.type) === \"epic\")\n .map((t) => t.id)\n );\n const childrenByEpicId = new Map();\n for (const t of columnTickets) {\n if (t.parent_ticket_id && epicById.has(t.parent_ticket_id)) {\n const list = childrenByEpicId.get(t.parent_ticket_id) || [];\n list.push(t);\n childrenByEpicId.set(t.parent_ticket_id, list);\n }\n }\n\n const rendered = new Set();\n const blocks = [];\n for (const t of columnTickets) {\n if (rendered.has(t.id)) continue;\n\n if (canonicalTicketType(t.type) === \"epic\") {\n const children = childrenByEpicId.get(t.id) || [];\n if (children.length) {\n const childrenHtml = children.map((c) => renderCard(c, { asEpicChild: true })).join(\"\");\n blocks.push(`${renderCard(t)}<div class=\"epic-children\">${childrenHtml}</div>`);\n children.forEach((c) => rendered.add(c.id));\n } else {\n blocks.push(renderCard(t));\n }\n rendered.add(t.id);\n continue;\n }\n\n // Defer children whose epic is in this column \u2014 they'll render under the\n // epic when the loop reaches it. Without this skip, a child iterated before\n // its epic would render standalone here, then again inside epic-children\n // (rendered.add happens at the epic, which may come later in updated_at order).\n if (t.parent_ticket_id && epicIdsInColumn.has(t.parent_ticket_id)) {\n continue;\n }\n\n if (t.parent_ticket_id && epicById.has(t.parent_ticket_id) && !epicIdsInColumn.has(t.parent_ticket_id)) {\n const epic = epicById.get(t.parent_ticket_id);\n const siblings = childrenByEpicId.get(t.parent_ticket_id) || [];\n const childrenHtml = siblings.map((c) => renderCard(c, { asEpicChild: true })).join(\"\");\n blocks.push(`${renderEpicMiniHeader(epic)}<div class=\"epic-children\">${childrenHtml}</div>`);\n siblings.forEach((c) => rendered.add(c.id));\n continue;\n }\n\n blocks.push(renderCard(t));\n rendered.add(t.id);\n }\n\n return blocks.join(\"\");\n}\n\nfunction renderEpicMiniHeader(epic) {\n return `\n <div class=\"epic-mini-header\" data-ticket-id=\"${escapeHtml(epic.id)}\" title=\"Open epic\">\n <div class=\"card-type-id type-pill-epic\">\n ${renderTypeIcon(\"epic\")}\n <span class=\"card-type-label\">EPIC</span>\n </div>\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(epic))}</span>\n <span class=\"epic-mini-title\">${escapeHtml(epic.title)}</span>\n </div>\n `;\n}\n\n/** Pill mirroring the structure/feel of the Type pill, colored per priority. */\nexport function renderPriorityPill(priority) {\n const key = priorityKeyFor(priority);\n const label = priorityLabel(priority);\n return `<div class=\"card-priority-id priority-pill priority-pill-${escapeHtml(key)}\"><span class=\"card-priority-label\">${escapeHtml(label)}</span></div>`;\n}\n\nexport function renderTypeIcon(type) {\n const canonical = canonicalTicketType(type);\n let icon = \"\";\n let color = \"currentColor\";\n\n switch (canonical) {\n case \"epic\":\n color = \"#c084fc\"; // Purple\n icon = `<path d=\"M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z\" fill=\"currentColor\" />`;\n break;\n case \"feature\":\n color = \"#4ade80\"; // Green\n icon = `<path d=\"M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2v16z\" fill=\"currentColor\" />`;\n break;\n case \"bug\":\n color = \"#f87171\"; // Red\n icon = `<circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 8v4M12 16h.01\" />`;\n break;\n default: // task\n color = \"#60a5fa\"; // Blue\n icon = `<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" /><path d=\"M9 12l2 2 4-4\" />`;\n }\n\n return `\n <svg class=\"card-type-icon\" viewBox=\"0 0 24 24\" style=\"color: ${color}\">\n ${icon}\n </svg>\n `;\n}\n\nfunction renderCard(ticket, { asEpicChild = false } = {}) {\n const canonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const typeText = typeLabel(ticket.type).toUpperCase();\n const isExpanded = state.expandedCardIds.has(ticket.id);\n const hasDescription = Boolean(String(ticket.description || \"\").trim());\n const hasExpandable = hasDescription || (ticket.labels && ticket.labels.length) || ticket.parent_ticket || ticket.child_count;\n\n const triggerInner = `\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"card-type-id type-pill-${escapeHtml(canonicalType)}\">\n ${renderTypeIcon(ticket.type)}\n <span class=\"card-type-label\">${escapeHtml(typeText)}</span>\n </div>\n ${state.showPriority ? renderPriorityPill(ticket.priority) : \"\"}\n ${hasExpandable ? `<svg class=\"card-expand-chevron\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\" /></svg>` : \"\"}\n `;\n\n const unreadN = unreadCount(ticket);\n const unreadDot = unreadN === 0\n ? \"\"\n : unreadN === 1\n ? `<span class=\"card-unread-dot\" role=\"status\" aria-label=\"1 unread update\"></span>`\n : `<span class=\"card-unread-dot has-count\" role=\"status\" aria-label=\"${unreadN} unread updates\">${unreadN > 99 ? \"99+\" : unreadN}</span>`;\n\n return `\n <article class=\"card type-${escapeHtml(canonicalType)} priority-${escapeHtml(priorityKey)}${isExpanded ? \" is-expanded\" : \"\"}${asEpicChild ? \" is-epic-child\" : \"\"} ${ticket.id === state.selectedTicketId ? \"selected\" : \"\"}\" draggable=\"true\" data-ticket-id=\"${ticket.id}\">\n ${unreadDot}\n <h3>${escapeHtml(ticket.title)}</h3>\n\n <div class=\"card-meta\">\n ${hasExpandable\n ? `<button type=\"button\" class=\"card-expand-trigger\" data-card-toggle aria-expanded=\"${isExpanded ? \"true\" : \"false\"}\">${triggerInner}</button>`\n : `<div class=\"card-expand-trigger card-expand-trigger--static\">${triggerInner}</div>`}\n </div>\n\n ${hasExpandable ? `\n <div class=\"card-expandable\">\n ${hasDescription ? `<div class=\"card-description markdown-body\">${renderMarkdown(ticket.description)}</div>` : \"\"}\n ${renderLabels(ticket.labels)}\n ${ticket.parent_ticket ? `<div class=\"parent-line\">-> ${escapeHtml(ticketLabel(ticket.parent_ticket))}</div>` : \"\"}\n ${ticket.child_count ? `<div class=\"child-count\">${ticket.child_count} feature${ticket.child_count === 1 ? \"\" : \"s\"} inside</div>` : \"\"}\n </div>\n ` : \"\"}\n </article>\n `;\n}\n\n/**\n * Click-and-drag horizontal panning on the kanban container.\n * Skipped when the pointer starts on a .card (cards own their own click + HTML5 DnD),\n * or on any interactive control inside a column head.\n */\nexport function enableKanbanDragScroll() {\n const DRAG_THRESHOLD = 4; // px before we consider it a real drag (avoids eating clicks)\n const LINE_SCROLL_PX = 16;\n const PAGE_SCROLL_PX = () => Math.max(kanban.clientWidth, 1);\n let active = false;\n let dragged = false;\n let startX = 0;\n let startScroll = 0;\n let pointerId = 0;\n\n const shouldIgnore = (target) => {\n if (!(target instanceof Element)) return false;\n // Let cards keep their click/drag behavior untouched.\n if (target.closest(\".card\")) return true;\n // Don't hijack interactive controls that might land in the board area later.\n if (target.closest(\"a, button, input, select, textarea, [draggable='true']\")) return true;\n return false;\n };\n\n const wheelPixels = (value, mode) => {\n if (mode === WheelEvent.DOM_DELTA_LINE) return value * LINE_SCROLL_PX;\n if (mode === WheelEvent.DOM_DELTA_PAGE) return value * PAGE_SCROLL_PX();\n return value;\n };\n\n kanban.addEventListener(\n \"wheel\",\n (event) => {\n if (event.defaultPrevented || event.ctrlKey) return;\n const horizontalDelta = event.deltaX || (event.shiftKey ? event.deltaY : 0);\n if (!horizontalDelta) return;\n const horizontal = Math.abs(horizontalDelta) >= Math.abs(event.deltaY) || event.shiftKey;\n if (!horizontal || kanban.scrollWidth <= kanban.clientWidth) return;\n\n event.preventDefault();\n kanban.scrollLeft += wheelPixels(horizontalDelta, event.deltaMode);\n },\n { passive: false }\n );\n\n kanban.addEventListener(\"pointerdown\", (event) => {\n if (event.button !== 0) return;\n if (shouldIgnore(event.target)) return;\n\n active = true;\n dragged = false;\n pointerId = event.pointerId;\n startX = event.clientX;\n startScroll = kanban.scrollLeft;\n kanban.classList.add(\"is-grabbing\");\n });\n\n kanban.addEventListener(\"pointermove\", (event) => {\n if (!active || event.pointerId !== pointerId) return;\n const delta = event.clientX - startX;\n if (!dragged && Math.abs(delta) > DRAG_THRESHOLD) {\n dragged = true;\n // Capture so movement outside the element still pans smoothly.\n try {\n kanban.setPointerCapture(pointerId);\n } catch {\n /* no-op: some browsers can't capture here */\n }\n }\n if (dragged) {\n event.preventDefault();\n kanban.scrollLeft = startScroll - delta;\n }\n });\n\n const endDrag = (event) => {\n if (!active || (event && event.pointerId !== pointerId)) return;\n active = false;\n kanban.classList.remove(\"is-grabbing\");\n try {\n kanban.releasePointerCapture(pointerId);\n } catch {\n /* no-op */\n }\n };\n\n kanban.addEventListener(\"pointerup\", endDrag);\n kanban.addEventListener(\"pointercancel\", endDrag);\n kanban.addEventListener(\"pointerleave\", endDrag);\n\n // Suppress the synthetic click at the end of a real drag so empty-area panning\n // doesn't accidentally trigger downstream click handlers.\n kanban.addEventListener(\n \"click\",\n (event) => {\n if (dragged) {\n event.stopPropagation();\n event.preventDefault();\n dragged = false;\n }\n },\n true\n );\n}\n", "// Edition + feature flags. The build script replaces `__ORBIT_EDITION__`\n// via esbuild --define when producing dist/preview; in dev (raw modules\n// served from public/) the identifier is undefined and we fall back to\n// \"full\". `typeof` is the safe probe \u2014 bare reads of an undefined global\n// would throw.\n\nlet resolvedEdition = \"full\";\nif (typeof __ORBIT_EDITION__ !== \"undefined\") {\n resolvedEdition = __ORBIT_EDITION__;\n}\n\nexport const edition = resolvedEdition; // \"full\" | \"preview\"\n\nexport const features = {\n sse: edition === \"full\",\n ai: edition === \"full\",\n multiBoard: edition === \"full\",\n tokenAuth: edition === \"full\"\n};\n", "// Project settings drawer (the cog/settings icon). Tabs: Lanes, Appearance,\n// Card Archive, Notes, Journal, AI, Repository. Owns lane CRUD/reorder, the\n// archive list, project context/notes form persistence, and per-tab handler wiring.\n\nimport { state, getSettingsTab, statesForProject, ticketsForProject, currentBoard } from \"./state.js\";\nimport { drawerInner, $ } from \"./dom.js\";\nimport { escapeHtml, formatDate, repoLabelFromUrl } from \"./format.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { toast, downloadJson } from \"./toast.js\";\nimport { renderDrawerShell } from \"./drawer.js\";\nimport { navigate } from \"./router.js\";\nimport { renderBoard } from \"./kanban.js\";\nimport { renderDetailCard } from \"./ticket-detail.js\";\nimport { load } from \"./app.js\";\nimport { features } from \"./config.js\";\nimport {\n applyReducedMotionPreference,\n browserPrefersReducedMotion,\n effectiveReducedMotionPreference,\n setReducedMotionPreference,\n storedReducedMotionPreference\n} from \"./motion-preference.js\";\nimport { currentTheme, setThemePreference } from \"./theme-preference.js\";\n\nconst repositoryDelete = {\n boardId: \"\",\n step: \"idle\",\n exported: false\n};\n\nexport async function renderProjectDetail() {\n const context = await api(`/api/boards/${state.boardId}/context?include_struck=true`);\n const project = context.board;\n const activeTab = getSettingsTab();\n\n const tabs = [\n { id: \"lanes\", label: \"Lanes\" },\n { id: \"appearance\", label: \"Appearance\" },\n { id: \"archive\", label: \"Card Archive\" },\n { id: \"notes\", label: \"Notes\" },\n { id: \"journal\", label: \"Journal\" },\n ...(features.ai ? [{ id: \"ai\", label: \"AI\" }] : []),\n { id: \"repository\", label: \"Repository\" }\n ];\n\n const resolvedTab = activeTab === \"ai\" && !features.ai ? \"lanes\" : activeTab;\n\n renderDrawerShell({\n eyebrow: \"SETTINGS\",\n mode: \"settings\",\n title: project.name,\n tabs,\n activeTab: resolvedTab,\n onTabSelect: async (id) => {\n navigate({\n boardId: state.boardId,\n view: \"settings\",\n tab: id\n });\n },\n body: renderProjectTabBody(context, resolvedTab)\n });\n\n bindProjectTabHandlers(context, resolvedTab);\n}\n\nfunction renderProjectTabBody(context, tab) {\n switch (tab) {\n case \"notes\":\n return renderNotesSettingsTab(context);\n case \"lanes\":\n return renderProjectLanesTab();\n case \"appearance\":\n return renderProjectAppearanceTab();\n case \"ai\":\n return features.ai ? renderProjectAiTab(context) : renderProjectLanesTab();\n case \"journal\":\n return renderProjectJournalTab(context);\n case \"archive\":\n return renderProjectArchiveTab();\n case \"repository\":\n default:\n return renderProjectRepositoryTab(context);\n }\n}\n\nconst MCP_OS_OPTIONS = {\n windows: {\n label: \"Windows\",\n shell: \"PowerShell\",\n serverPath: \"C:\\\\Path\\\\To\\\\StarscapeOrbit\\\\src\\\\mcp-server.js\"\n },\n macos: {\n label: \"macOS\",\n shell: \"Terminal\",\n serverPath: \"/Users/you/apps/starscape-orbit/src/mcp-server.js\"\n },\n linux: {\n label: \"Linux\",\n shell: \"Terminal\",\n serverPath: \"/home/you/apps/starscape-orbit/src/mcp-server.js\"\n }\n};\n\nconst MCP_CLIENTS = {\n \"claude-code\": {\n label: \"Claude Code\",\n format: \"CLI command\",\n helper: \"Run this command once. Claude Code records the local Orbit tool server for the project.\"\n },\n codex: {\n label: \"Codex\",\n format: \"config.toml\",\n helper: \"Paste this TOML into Codex config. Project-local config may require the project to be trusted.\"\n },\n cursor: {\n label: \"Cursor\",\n format: \"MCP JSON\",\n helper: \"Paste this JSON into Cursor MCP settings. Cursor starts Orbit when an agent needs the tools.\"\n },\n opencode: {\n label: \"OpenCode\",\n format: \"opencode.json\",\n helper: \"Paste this into OpenCode config under the local MCP server list.\"\n },\n openclaw: {\n label: \"OpenClaw\",\n format: \"MCP JSON\",\n helper: \"Paste this JSON into OpenClaw's MCP server list. OpenClaw will spawn Orbit on demand.\"\n },\n generic: {\n label: \"Other MCP app\",\n format: \"MCP JSON\",\n helper: \"Most MCP clients accept this JSON shape for local stdio servers.\"\n }\n};\n\nfunction renderProjectAiTab(context) {\n const project = context.board;\n const aiEnabled = project.ai_enabled !== 0;\n const aiDivider = aiEnabled ? `<div class=\"ai-section-divider\" aria-hidden=\"true\"></div>` : \"\";\n const agentContextSetup = aiEnabled ? renderAgentContextSection(project) : \"\";\n const mcpSetup = aiEnabled ? renderMcpSetupSection(context) : \"\";\n\n return `\n <div class=\"section\">\n <label class=\"orbit-check\" for=\"aiEnabledToggle\">\n <input\n type=\"checkbox\"\n id=\"aiEnabledToggle\"\n ${aiEnabled ? \"checked\" : \"\"}\n />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"orbit-check-label\">Enable AI</span>\n </label>\n <p class=\"description\">Provisions the <strong>AI Ready</strong>, <strong>In Progress</strong>, and <strong>Review</strong> lanes if missing, surfaces agent context fields, and exposes the MCP setup snippet. Disabling AI hides the AI Ready column but keeps its cards in place.</p>\n </div>\n ${aiDivider}\n ${agentContextSetup}\n ${aiDivider}\n ${mcpSetup}\n `;\n}\n\nfunction renderAgentContextSection(project) {\n const ph =\n \"This project is about\u2026\\n\\nHow any AI agent should use this board and work in this repo.\";\n return `\n <div class=\"section ai-subsection ai-context-setup\">\n <div class=\"ai-context-title-row\">\n <span class=\"ai-context-inline-mark\" aria-hidden=\"true\">Context</span>\n <h3>Agent Instructions</h3>\n </div>\n <p class=\"description\">This project-level context is provided to agents when they work on tickets.</p>\n <form id=\"agentInstructionsForm\" class=\"field-form\">\n <textarea name=\"agent_instructions\" placeholder=\"${escapeHtml(ph)}\">${escapeHtml(project.agent_instructions || \"\")}</textarea>\n <button type=\"submit\">Save</button>\n </form>\n </div>\n `;\n}\n\nfunction renderMcpSetupSection(context) {\n const osId = detectedMcpOs();\n const clientId = \"claude-code\";\n const paths = mcpDetectedPaths(context, osId);\n const configText = mcpConfigText(clientId, paths);\n const commandText = mcpRunCommand(osId, paths);\n const client = MCP_CLIENTS[clientId];\n return `\n <details class=\"section ai-subsection mcp-setup\" data-mcp-setup>\n <summary>\n <div class=\"mcp-title-row\">\n <span class=\"mcp-inline-mark\" aria-hidden=\"true\">MCP</span>\n <h3>Connect Your Agent to MCP</h3>\n </div>\n </summary>\n <div>\n <p class=\"description\">A tiny service running on your computer alongside your AI agent, providing it with tools and context to collaborate with you more effectively. Tell your AI to use the snippet below, it knows what MCP is.</p>\n <div class=\"mcp-flow\">\n <label>\n <span>Operating system</span>\n <select id=\"mcpOsSelect\" class=\"select-chevron-field\">\n ${Object.entries(MCP_OS_OPTIONS)\n .map(([id, option]) => `<option value=\"${id}\" ${id === osId ? \"selected\" : \"\"}>${escapeHtml(option.label)}</option>`)\n .join(\"\")}\n </select>\n </label>\n <label>\n <span>Agent app</span>\n <select id=\"mcpClientSelect\" class=\"select-chevron-field\">\n ${Object.entries(MCP_CLIENTS)\n .map(([id, option]) => `<option value=\"${id}\" ${id === clientId ? \"selected\" : \"\"}>${escapeHtml(option.label)}</option>`)\n .join(\"\")}\n </select>\n </label>\n </div>\n <div class=\"mcp-path-grid\">\n <label>\n <span>Orbit MCP server file</span>\n <input id=\"mcpServerPathInput\" value=\"${escapeHtml(paths.serverPath)}\" />\n </label>\n </div>\n </div>\n\n <div class=\"mcp-options-stack\">\n <div class=\"mcp-option-card\">\n <div class=\"mcp-option-card-head\">\n <div>\n <strong data-mcp-output-title>${escapeHtml(client.label)} setup</strong>\n <p class=\"description\" data-mcp-helper>${escapeHtml(client.helper)}</p>\n </div>\n <button type=\"button\" class=\"ghost\" data-copy-mcp=\"config\">Copy setup</button>\n </div>\n <div class=\"mcp-terminal\">\n <div class=\"mcp-terminal-chrome\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <pre class=\"mcp-snippet\"><code data-mcp-config>${escapeHtml(configText)}</code></pre>\n </div>\n </div>\n\n <div class=\"mcp-or-divider\" aria-hidden=\"true\"><span>OR</span></div>\n\n <div class=\"mcp-option-card\">\n <div class=\"mcp-option-card-head\">\n <div>\n <strong>Manual run command</strong>\n <p class=\"description\">Use this only when an app asks you to start the MCP server yourself.</p>\n </div>\n <button type=\"button\" class=\"ghost\" data-copy-mcp=\"command\">Copy command</button>\n </div>\n <div class=\"mcp-terminal\">\n <div class=\"mcp-terminal-chrome\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <pre class=\"mcp-snippet mcp-snippet--compact\"><code data-mcp-command>${escapeHtml(commandText)}</code></pre>\n </div>\n </div>\n </div>\n </details>\n `;\n}\n\nfunction detectedMcpOs() {\n const platform = String(navigator.userAgentData?.platform || navigator.platform || navigator.userAgent || \"\").toLowerCase();\n if (platform.includes(\"win\")) return \"windows\";\n if (platform.includes(\"mac\")) return \"macos\";\n return \"linux\";\n}\n\nfunction mcpDefaultPaths(osId) {\n const option = MCP_OS_OPTIONS[osId] || MCP_OS_OPTIONS.linux;\n return {\n serverPath: option.serverPath\n };\n}\n\nfunction mcpDetectedPaths(context, osId) {\n const template = mcpDefaultPaths(osId);\n const deployment = context.deployment || {};\n return {\n serverPath: deployment.mcp_server_path || template.serverPath\n };\n}\n\nfunction mcpPathsFromForm() {\n return {\n serverPath: $(\"#mcpServerPathInput\")?.value || \"\"\n };\n}\n\nfunction mcpConfigText(clientId, paths) {\n if (clientId === \"claude-code\") return claudeCodeMcpCommand(paths);\n if (clientId === \"codex\") return codexMcpToml(paths);\n if (clientId === \"opencode\") return opencodeMcpJson(paths);\n\n const config = {\n mcpServers: {\n \"starscape-orbit\": {\n command: \"node\",\n args: [paths.serverPath]\n }\n }\n };\n return JSON.stringify(config, null, 2);\n}\n\nfunction opencodeMcpJson(paths) {\n return JSON.stringify(\n {\n $schema: \"https://opencode.ai/config.json\",\n mcp: {\n \"starscape-orbit\": {\n type: \"local\",\n command: [\"node\", paths.serverPath],\n enabled: true\n }\n }\n },\n null,\n 2\n );\n}\n\nfunction codexMcpToml(paths) {\n return `[mcp_servers.starscape-orbit]\ncommand = \"node\"\nargs = [\"${escapeToml(paths.serverPath)}\"]\nenabled = true`;\n}\n\nfunction claudeCodeMcpCommand(paths) {\n return [\"claude mcp add starscape-orbit\", \"--\", \"node\", shellQuote(paths.serverPath)].join(\" \");\n}\n\nfunction mcpRunCommand(osId, paths) {\n return `node ${shellQuote(paths.serverPath)}`;\n}\n\nfunction shellQuote(value) {\n return `\"${String(value || \"\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction escapeToml(value) {\n return String(value || \"\").replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\nfunction renderProjectArchiveTab() {\n return `\n <p class=\"description\">Archived cards are hidden from the kanban, search, and agent claim-next. Restore to put a card back on the board, or delete to permanently remove it.</p>\n <div class=\"section\">\n <div id=\"archiveList\" class=\"archive-list\">Loading\u2026</div>\n </div>\n `;\n}\n\nfunction renderProjectRepositoryTab(context) {\n const project = context.board;\n if (repositoryDelete.boardId !== project.id) {\n repositoryDelete.boardId = project.id;\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n }\n const repoMeta = features.multiBoard\n ? `\n <div class=\"detail-head project-manual-head\">\n <div class=\"meta-grid\">\n <div class=\"meta meta--repo-path\">\n <span>Repo</span>\n <strong>${escapeHtml(repoLabelFromUrl(project.repo_url))}</strong>\n <span>Path</span>\n <strong>${escapeHtml(project.system_path || context.deployment?.system_path || \"Not available\")}</strong>\n </div>\n </div>\n </div>`\n : `\n <p class=\"description\">This board lives in your browser only. Export a snapshot if you want to move it to a real Orbit install, or import one to seed this preview.</p>`;\n return `\n ${repoMeta}\n\n <div class=\"section\">\n <h3>Board Snapshot</h3>\n <div class=\"deployment-actions\">\n <button type=\"button\" class=\"ghost\" id=\"exportProject\">Export</button>\n <label class=\"import-button\">\n <input type=\"file\" id=\"importSnapshotFile\" accept=\".orbit.json,.json,application/json\" />\n <span>Import</span>\n </label>\n </div>\n </div>\n\n ${features.multiBoard ? renderDeleteBoardSection(project) : \"\"}\n `;\n}\n\nfunction renderDeleteBoardSection(project) {\n const slug = escapeHtml(project.slug || \"\");\n if (repositoryDelete.step === \"choice\") {\n return `\n <div class=\"section repository-danger-zone\">\n <h3>Delete Board</h3>\n <p class=\"description\">Delete this board from Orbit and remove its repo-local Orbit files. Export a snapshot first if you may need this board again.</p>\n <div class=\"repository-delete-actions\">\n <button type=\"button\" class=\"ghost\" id=\"deleteBoardExportFirst\">Export first</button>\n <button type=\"button\" class=\"ghost danger-button\" id=\"deleteBoardSkipExport\">Delete without exporting</button>\n <button type=\"button\" class=\"ghost\" id=\"deleteBoardCancel\">Cancel</button>\n </div>\n </div>\n `;\n }\n\n if (repositoryDelete.step === \"confirm\") {\n const exportedCopy = repositoryDelete.exported\n ? \"Snapshot exported. Type the board slug to confirm permanent deletion.\"\n : \"Type the board slug to confirm permanent deletion.\";\n return `\n <div class=\"section repository-danger-zone is-confirming\">\n <h3>Delete Board</h3>\n <p class=\"description\">${escapeHtml(exportedCopy)}</p>\n <label class=\"repository-confirm-field\">\n <span>Board slug</span>\n <strong>${slug}</strong>\n <input id=\"deleteBoardConfirmInput\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"${slug}\" autofocus />\n </label>\n <div class=\"repository-delete-actions\">\n <button type=\"button\" class=\"danger-button\" id=\"deleteBoardConfirm\" disabled>Delete board permanently</button>\n <button type=\"button\" class=\"ghost\" id=\"deleteBoardCancel\">Cancel</button>\n </div>\n </div>\n `;\n }\n\n return `\n <div class=\"section repository-danger-zone\">\n <h3>Delete Board</h3>\n <p class=\"description\">Remove this board from Orbit and delete its repo-local Orbit files. This cannot be undone without an exported snapshot.</p>\n <button type=\"button\" class=\"ghost danger-button\" id=\"deleteBoardStart\">Delete Board</button>\n </div>\n `;\n}\n\nfunction renderNotesSettingsTab(context) {\n const project = context.board;\n const notesPlaceholder =\n \"Remember to mention SKILL-ORBIT.md to my AI agents if they get confused\";\n return `\n <div class=\"section ai-fields\">\n <form id=\"notesSettingsForm\" class=\"field-form settings-notes-form\">\n <label class=\"settings-notes-field-group\">\n <span>Notes For You</span>\n <textarea\n name=\"project_notes\"\n class=\"settings-notes-textarea\"\n placeholder=\"${escapeHtml(notesPlaceholder)}\"\n >${escapeHtml(project.project_notes || \"\")}</textarea>\n </label>\n <button type=\"submit\" class=\"settings-notes-save\">Save</button>\n </form>\n </div>\n `;\n}\n\nfunction renderProjectLanesTab() {\n const showPriority = state.showPriority;\n return `\n <div class=\"section\">\n <label class=\"orbit-check\" for=\"showPriorityToggle\">\n <input\n type=\"checkbox\"\n id=\"showPriorityToggle\"\n ${showPriority ? \"checked\" : \"\"}\n />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"orbit-check-label\">Show priority label on cards</span>\n </label>\n <p class=\"description lanes-description\">Rename, reorder, add, or remove lanes.</p>\n ${renderLaneManager()}\n <form id=\"laneCreateForm\" class=\"lane-create-form\">\n <input name=\"name\" placeholder=\"New lane name...\" required />\n <button type=\"submit\">Add Lane</button>\n </form>\n </div>\n `;\n}\n\nfunction renderProjectAppearanceTab() {\n const theme = currentTheme();\n const reduceMotion = effectiveReducedMotionPreference();\n const storedMotion = storedReducedMotionPreference();\n const browserDefault = browserPrefersReducedMotion();\n const sourceLabel = storedMotion === null\n ? `Using browser default (${browserDefault ? \"reduced motion\" : \"motion allowed\"}).`\n : \"Using your saved preference.\";\n\n return `\n <div class=\"section appearance-theme-section\">\n <fieldset class=\"appearance-theme-field\">\n <legend>Theme</legend>\n <div class=\"appearance-theme-options\">\n ${renderThemeOption(\"light\", \"Light\", theme)}\n ${renderThemeOption(\"dark\", \"Dark\", theme)}\n </div>\n <p class=\"description\">Applies the light/dark theme used by the top rail toggle.</p>\n </fieldset>\n </div>\n <div class=\"section\">\n <label class=\"orbit-check\" for=\"reduceMotionToggle\">\n <input\n type=\"checkbox\"\n id=\"reduceMotionToggle\"\n ${reduceMotion ? \"checked\" : \"\"}\n />\n <span class=\"orbit-check-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" class=\"orbit-check-tick\"><path d=\"M3.5 8.5l3 3 6-7\" /></svg>\n </span>\n <span class=\"orbit-check-label\">Reduce theme motion</span>\n </label>\n <p class=\"description\">Turns off the animated starfield, meteors, and theme animations. ${escapeHtml(sourceLabel)}</p>\n </div>\n `;\n}\n\nfunction renderThemeOption(value, label, selectedTheme) {\n const checked = selectedTheme === value ? \"checked\" : \"\";\n const icon = value === \"dark\"\n ? '<path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />'\n : '<circle cx=\"12\" cy=\"12\" r=\"5\" /><path d=\"M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4\" />';\n\n return `\n <label class=\"appearance-theme-option\">\n <input type=\"radio\" name=\"themePreference\" value=\"${value}\" ${checked} />\n <span class=\"appearance-theme-option-mark\" aria-hidden=\"true\">\n <svg\n class=\"appearance-theme-option-icon\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >${icon}</svg>\n </span>\n <span class=\"appearance-theme-option-label\">${label}</span>\n </label>\n `;\n}\n\nfunction renderProjectJournalTab(context) {\n const aiEnabled = context.board?.ai_enabled !== 0;\n return `\n ${aiEnabled ? `<p class=\"description\">Agent-facing project memory: decisions to follow and lessons to apply. Struck entries stay visible here but are excluded from agent context.</p>` : \"\"}\n <div class=\"section\">\n ${renderProjectEntries(context.entries)}\n <form id=\"projectEntryForm\" class=\"comment-form project-entry-form\">\n <select name=\"type\" class=\"select-chevron-field\" aria-label=\"Entry type\">\n <option value=\"decision\">Decision</option>\n <option value=\"lesson\">Lesson</option>\n </select>\n <input name=\"title\" placeholder=\"Entry title...\" required />\n <textarea name=\"body\" placeholder=\"Decision rationale or lesson: do X instead of Y when working with Z.\" required></textarea>\n <button type=\"submit\">Add Entry</button>\n </form>\n </div>\n `;\n}\n\nfunction bindProjectTabHandlers(context, tab) {\n const project = context.board;\n\n if (tab === \"repository\") {\n const exportSnapshot = async () => {\n const snapshot = await api(`/api/boards/${project.id}/export`);\n downloadJson(`${project.slug}.orbit.json`, snapshot);\n };\n\n $(\"#exportProject\")?.addEventListener(\"click\", async () => {\n await exportSnapshot();\n });\n\n $(\"#importSnapshotFile\")?.addEventListener(\"change\", async (event) => {\n const file = event.currentTarget.files?.[0];\n if (!file) return;\n const text = await file.text();\n const snapshot = JSON.parse(text);\n await api(\"/api/admin/import\", {\n method: \"POST\",\n body: { snapshot, replace_existing: true, board_id: project.id }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Board imported\");\n event.currentTarget.value = \"\";\n });\n\n $(\"#deleteBoardStart\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"choice\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardExportFirst\")?.addEventListener(\"click\", async () => {\n await exportSnapshot();\n repositoryDelete.step = \"confirm\";\n repositoryDelete.exported = true;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardSkipExport\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"confirm\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n $(\"#deleteBoardCancel\")?.addEventListener(\"click\", async () => {\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n await renderProjectDetail();\n });\n\n const confirmInput = $(\"#deleteBoardConfirmInput\");\n const confirmButton = $(\"#deleteBoardConfirm\");\n confirmInput?.addEventListener(\"input\", () => {\n if (confirmButton) confirmButton.disabled = confirmInput.value.trim() !== project.slug;\n });\n confirmButton?.addEventListener(\"click\", async () => {\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"DELETE\",\n body: { confirm_slug: project.slug, delete_files: true }\n });\n repositoryDelete.step = \"idle\";\n repositoryDelete.exported = false;\n await load();\n toast.success(`Deleted board: ${project.name}`);\n navigate({ boardId: state.boardId, view: \"board\" }, { replace: true });\n });\n }\n\n if (tab === \"notes\") {\n $(\"#notesSettingsForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { project_notes: String(form.get(\"project_notes\") ?? \"\") }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n });\n }\n\n if (tab === \"lanes\") {\n drawerInner.querySelectorAll(\"[data-lane-action]\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n await handleLaneAction(button);\n });\n });\n\n drawerInner.querySelectorAll(\".lane-row input, .lane-row select\").forEach((field) => {\n field.addEventListener(\"change\", async () => {\n await updateLane(field.closest(\".lane-row\"));\n });\n });\n\n $(\"#laneCreateForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}/states`, {\n method: \"POST\",\n body: Object.fromEntries(form.entries())\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lane added\");\n });\n\n $(\"#showPriorityToggle\")?.addEventListener(\"change\", (event) => {\n state.showPriority = !!event.currentTarget.checked;\n localStorage.setItem(\"mab_show_priority\", state.showPriority ? \"true\" : \"false\");\n renderBoard();\n });\n }\n\n if (tab === \"appearance\") {\n drawerInner.querySelectorAll(\"input[name='themePreference']\").forEach((input) => {\n input.addEventListener(\"change\", (event) => {\n if (!event.currentTarget.checked) return;\n const theme = setThemePreference(event.currentTarget.value);\n toast.success(theme === \"dark\" ? \"Dark theme enabled\" : \"Light theme enabled\");\n });\n });\n\n $(\"#reduceMotionToggle\")?.addEventListener(\"change\", (event) => {\n const reduce = !!event.currentTarget.checked;\n setReducedMotionPreference(reduce);\n applyReducedMotionPreference();\n window.dispatchEvent(new CustomEvent(\"orbit:motion-preference-change\", { detail: { reduce } }));\n toast.success(reduce ? \"Theme motion reduced\" : \"Theme motion enabled\");\n });\n }\n\n if (tab === \"ai\") {\n const updateMcpPreview = () => {\n const osId = $(\"#mcpOsSelect\")?.value || detectedMcpOs();\n const clientId = $(\"#mcpClientSelect\")?.value || \"claude-code\";\n const client = MCP_CLIENTS[clientId] || MCP_CLIENTS.generic;\n const paths = mcpPathsFromForm();\n const configText = mcpConfigText(clientId, paths);\n const commandText = mcpRunCommand(osId, paths);\n\n const osNote = drawerInner.querySelector(\"[data-mcp-os-note]\");\n if (osNote) osNote.textContent = `Detected: ${MCP_OS_OPTIONS[detectedMcpOs()]?.label || \"Linux\"}`;\n\n const format = drawerInner.querySelector(\"[data-mcp-client-format]\");\n if (format) format.textContent = client.format;\n\n const title = drawerInner.querySelector(\"[data-mcp-output-title]\");\n if (title) title.textContent = `${client.label} setup`;\n\n const helper = drawerInner.querySelector(\"[data-mcp-helper]\");\n if (helper) helper.textContent = client.helper;\n\n const configEl = drawerInner.querySelector(\"[data-mcp-config]\");\n if (configEl) configEl.textContent = configText;\n\n const commandEl = drawerInner.querySelector(\"[data-mcp-command]\");\n if (commandEl) commandEl.textContent = commandText;\n };\n\n $(\"#mcpOsSelect\")?.addEventListener(\"change\", () => updateMcpPreview());\n $(\"#mcpClientSelect\")?.addEventListener(\"change\", () => updateMcpPreview());\n [\"#mcpServerPathInput\"].forEach((selector) => {\n $(selector)?.addEventListener(\"input\", () => updateMcpPreview());\n });\n\n drawerInner.querySelectorAll(\"[data-copy-mcp]\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n const osId = $(\"#mcpOsSelect\")?.value || detectedMcpOs();\n const clientId = $(\"#mcpClientSelect\")?.value || \"claude-code\";\n const paths = mcpPathsFromForm();\n const value = button.dataset.copyMcp === \"command\" ? mcpRunCommand(osId, paths) : mcpConfigText(clientId, paths);\n await copyText(value);\n toast.success(button.dataset.copyMcp === \"command\" ? \"MCP command copied\" : \"MCP config copied\");\n });\n });\n\n $(\"#agentInstructionsForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: Object.fromEntries(form.entries())\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n });\n\n $(\"#aiEnabledToggle\")?.addEventListener(\"change\", async (event) => {\n const enabled = !!event.currentTarget.checked;\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { ai_enabled: enabled }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(enabled ? \"AI features enabled \u2014 agent lanes provisioned\" : \"AI features disabled \u2014 AI Ready hidden\");\n });\n\n }\n\n if (tab === \"archive\") {\n const listEl = $(\"#archiveList\");\n if (listEl) {\n const refresh = async () => {\n try {\n const result = await api(`/api/boards/${encodeURIComponent(project.id)}/archive`);\n const tickets = result.tickets || [];\n if (tickets.length === 0) {\n listEl.innerHTML = `<p class=\"description\">No archived cards yet. Click the trash icon in the card detail header to archive a card.</p>`;\n return;\n }\n listEl.innerHTML = `<div class=\"detail-card-grid\">${tickets\n .map((t) => renderDetailCard(t, { archive: { id: t.id }, disableOpen: true }))\n .join(\"\")}</div>`;\n } catch (err) {\n listEl.innerHTML = `<p class=\"description\">Could not load archive: ${escapeHtml(err?.message || \"unknown error\")}</p>`;\n }\n };\n\n refresh();\n\n listEl.addEventListener(\"click\", async (event) => {\n const restoreBtn = event.target.closest(\"[data-archive-restore]\");\n const deleteBtn = event.target.closest(\"[data-archive-delete]\");\n if (!restoreBtn && !deleteBtn) return;\n event.stopPropagation();\n const card = (restoreBtn || deleteBtn).closest(\"article\");\n const cardTitle = card?.querySelector(\"h3\")?.textContent || \"card\";\n if (restoreBtn) {\n const id = restoreBtn.dataset.archiveRestore;\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(id)}/restore`), { method: \"POST\" });\n toast.success(`Restored: ${cardTitle}`);\n await load();\n await refresh();\n return;\n }\n if (deleteBtn) {\n const id = deleteBtn.dataset.archiveDelete;\n if (!confirm(`Permanently delete \"${cardTitle}\"? This cannot be undone.`)) return;\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(id)}`), { method: \"DELETE\" });\n toast.success(`Deleted: ${cardTitle}`);\n await refresh();\n }\n });\n }\n }\n\n if (tab === \"journal\") {\n drawerInner.querySelectorAll(\"[data-entry-action='toggle-struck']\").forEach((button) => {\n button.addEventListener(\"click\", async () => {\n await api(withBoardQuery(`/api/board-entries/${button.dataset.entryId}`), {\n method: \"PATCH\",\n body: { struck: button.dataset.struck !== \"true\" }\n });\n await load();\n state.detailMode = \"settings\";\n toast.info(button.dataset.struck === \"true\" ? \"Project entry restored\" : \"Project entry struck\");\n });\n });\n\n $(\"#projectEntryForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(`/api/boards/${project.id}/entries`, {\n method: \"POST\",\n body: Object.fromEntries(form.entries())\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Project entry added\");\n });\n }\n}\n\nasync function copyText(value) {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(value);\n return;\n }\n\n const textArea = document.createElement(\"textarea\");\n textArea.value = value;\n textArea.setAttribute(\"readonly\", \"\");\n textArea.style.position = \"fixed\";\n textArea.style.left = \"-9999px\";\n document.body.append(textArea);\n textArea.select();\n document.execCommand(\"copy\");\n textArea.remove();\n}\n\nfunction renderProjectEntries(entries = []) {\n if (!entries.length) return `<p class=\"description\">No project entries yet.</p>`;\n return entries\n .map(\n (entry) => {\n const isStruck = Boolean(entry.struck_at);\n return `\n <div class=\"comment project-entry ${escapeHtml(entry.type)} ${isStruck ? \"is-struck\" : \"\"}\">\n <div class=\"comment-meta\">\n <div>\n <strong>${escapeHtml(entry.type.toUpperCase())}: ${escapeHtml(entry.title)}</strong>\n ${isStruck ? `<span class=\"project-entry-status\">Excluded from agent context</span>` : \"\"}\n </div>\n <div class=\"project-entry-actions\">\n <span>${escapeHtml(entry.created_by)} - ${formatDate(entry.created_at)}</span>\n <button\n type=\"button\"\n class=\"ghost project-entry-strike\"\n data-entry-action=\"toggle-struck\"\n data-entry-id=\"${escapeHtml(entry.id)}\"\n data-struck=\"${isStruck ? \"true\" : \"false\"}\"\n aria-pressed=\"${isStruck ? \"true\" : \"false\"}\"\n >${isStruck ? \"Restore\" : \"Strike\"}</button>\n </div>\n </div>\n <div class=\"comment-body\">${escapeHtml(entry.body)}</div>\n </div>\n `;\n }\n )\n .join(\"\");\n}\n\n// In Progress and Review are core kanban lanes \u2014 undeletable regardless of\n// AI. AI Ready is only locked while AI is enabled; disabling AI hides it from\n// the board without moving its cards.\nconst CORE_LANE_ROLES = new Set([\"in_progress\", \"review\"]);\n\n/** A lane can't be deleted if it has cards (orphan risk), if it's the default\n * \"new cards land here\" lane (every project must keep exactly one), if it's\n * a core kanban lane (in_progress / review), or if it's the AI Ready lane\n * while AI is enabled. */\nfunction deleteDisabled(lane, counts, aiEnabled) {\n if (counts.get(lane.id)) return true;\n if (lane.is_default) return true;\n if (CORE_LANE_ROLES.has(lane.role)) return true;\n if (aiEnabled && lane.role === \"ai_ready\") return true;\n return false;\n}\n\nfunction deleteTitle(lane, counts, aiEnabled) {\n const count = counts.get(lane.id) || 0;\n if (count > 0) {\n return `Cannot delete \u2014 ${count} card${count === 1 ? \"\" : \"s\"} in this lane`;\n }\n if (lane.is_default) {\n return \"Cannot delete \u2014 default lane for new cards (move it first)\";\n }\n if (CORE_LANE_ROLES.has(lane.role)) {\n return \"Cannot delete \u2014 core kanban lane\";\n }\n if (aiEnabled && lane.role === \"ai_ready\") {\n return \"Cannot delete \u2014 required by agent flow while AI is enabled\";\n }\n return \"Delete lane\";\n}\n\nfunction renderLaneManager() {\n const lanes = statesForProject();\n const aiEnabled = currentBoard()?.ai_enabled !== 0;\n const counts = new Map();\n for (const ticket of ticketsForProject()) {\n counts.set(ticket.state_id, (counts.get(ticket.state_id) || 0) + 1);\n }\n\n return `\n <div class=\"lane-list\">\n ${lanes\n .map((lane, index) => {\n const isAiReady = lane.role === \"ai_ready\";\n const nameTitle = isAiReady\n ? \"AI Ready lane name is locked \u2014 disable AI to hide this column\"\n : \"\";\n return `\n <div class=\"lane-row${isAiReady ? \" lane-row--locked\" : \"\"}\" data-lane-id=\"${lane.id}\">\n <button type=\"button\" class=\"lane-icon-btn\" data-lane-action=\"up\" ${index === 0 ? \"disabled\" : \"\"} title=\"Move lane left\" aria-label=\"Move lane left\">\u2191</button>\n <button type=\"button\" class=\"lane-icon-btn\" data-lane-action=\"down\" ${index === lanes.length - 1 ? \"disabled\" : \"\"} title=\"Move lane right\" aria-label=\"Move lane right\">\u2193</button>\n <input name=\"name\" value=\"${escapeHtml(lane.name)}\" aria-label=\"Lane name\" ${isAiReady ? `readonly title=\"${escapeHtml(nameTitle)}\"` : \"\"} />\n <button type=\"button\" class=\"lane-new-toggle ${lane.is_default ? \"is-on\" : \"\"}\" data-lane-action=\"toggle-default\" aria-pressed=\"${lane.is_default ? \"true\" : \"false\"}\" title=\"${lane.is_default ? \"Default lane for new cards \u2014 click another lane to move it\" : \"Make this the default lane for new cards\"}\" aria-label=\"Default lane for new cards\">\n <span class=\"lane-new-sun\" aria-hidden=\"true\"></span>\n <span class=\"lane-new-label\">New</span>\n </button>\n <button type=\"button\" class=\"lane-delete-btn\" data-lane-action=\"delete\" ${deleteDisabled(lane, counts, aiEnabled) ? \"disabled\" : \"\"} title=\"${deleteTitle(lane, counts, aiEnabled)}\" aria-label=\"Delete lane\">\u00D7</button>\n </div>\n `;\n })\n .join(\"\")}\n </div>\n `;\n}\n\nasync function handleLaneAction(button) {\n const row = button.closest(\".lane-row\");\n const laneId = row.dataset.laneId;\n const action = button.dataset.laneAction;\n if (action === \"delete\") {\n await api(withBoardQuery(`/api/states/${laneId}`), { method: \"DELETE\" });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lane deleted\");\n return;\n }\n\n if (action === \"toggle-default\") {\n // Radio-style: one lane is always the default. Clicking the current\n // default is a no-op \u2014 to move it you click a different lane. This\n // guarantees new-card creation always has somewhere to land.\n const wasOn = button.getAttribute(\"aria-pressed\") === \"true\";\n if (wasOn) return;\n drawerInner.querySelectorAll('[data-lane-action=\"toggle-default\"]').forEach((btn) => {\n btn.setAttribute(\"aria-pressed\", \"false\");\n btn.classList.remove(\"is-on\");\n });\n button.setAttribute(\"aria-pressed\", \"true\");\n button.classList.add(\"is-on\");\n await updateLane(row, { silent: true });\n toast.success(\"Default lane updated\");\n return;\n }\n\n const lanes = statesForProject().map((lane) => lane.id);\n const index = lanes.indexOf(laneId);\n const swapWith = action === \"up\" ? index - 1 : index + 1;\n if (swapWith < 0 || swapWith >= lanes.length) return;\n [lanes[index], lanes[swapWith]] = [lanes[swapWith], lanes[index]];\n await api(`/api/boards/${state.boardId}/states`, {\n method: \"PATCH\",\n body: { state_ids: lanes }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Lanes reordered\");\n}\n\nasync function updateLane(row, { silent = false } = {}) {\n const name = row.querySelector('input[name=\"name\"]').value;\n const toggle = row.querySelector('[data-lane-action=\"toggle-default\"]');\n const isDefault = toggle?.getAttribute(\"aria-pressed\") === \"true\";\n\n await api(withBoardQuery(`/api/states/${row.dataset.laneId}`), {\n method: \"PATCH\",\n body: {\n name,\n is_default: isDefault\n }\n });\n await load();\n state.detailMode = \"settings\";\n if (!silent) toast.success(\"Lane updated\");\n}\n", "// Ticket detail drawer: renders the full ticket pane (header meta, AI plan,\n// status history, comments) and wires every editable surface \u2014 inline title\n// and description editors, meta selects, label management, parent epic, and\n// related cards. Also owns the small render helpers (status history,\n// comments, detail-card) that are only used inside the drawer.\n\nimport { state, ticketsForProject, selectableStatesForProject, boardLabelCatalog, currentBoard } from \"./state.js\";\nimport { drawerInner, drawer, $ } from \"./dom.js\";\nimport {\n escapeHtml,\n formatDate,\n formatDateDetail,\n ticketLabel,\n canonicalTicketType,\n typeLabel,\n typeLabelLong,\n priorityLabel,\n priorityKeyFor,\n renderMarkdown\n} from \"./format.js\";\nimport { renderTypeIcon, renderPriorityPill } from \"./kanban.js\";\nimport { renderDrawerShell, openDrawer, closeDrawer } from \"./drawer.js\";\nimport { navigate } from \"./router.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { toast } from \"./toast.js\";\nimport { load } from \"./app.js\";\nimport { renderProjectDetail } from \"./settings.js\";\nimport { unreadCount, markRead } from \"./unread.js\";\n\n/**\n * PATCH a ticket then reload + re-render the drawer in ticket mode. Lives\n * here because every caller is a drawer interaction; api.js stays I/O-only.\n */\nasync function patchTicket(ticketId, body) {\n await api(withBoardQuery(`/api/tickets/${ticketId}`), { method: \"PATCH\", body });\n await load();\n state.selectedTicketId = ticketId;\n state.detailMode = \"ticket\";\n await renderDetail();\n}\n\n/**\n * Replace a static node with an inline editor; commit on Enter / blur, cancel on Esc.\n * For multi-line fields, Ctrl/Cmd+Enter commits and plain Enter inserts a newline.\n */\nfunction startInlineEdit(node, field, initialValue, ticketId) {\n if (!node || node.dataset.editing === \"true\") return;\n node.dataset.editing = \"true\";\n\n const isTextarea = field === \"description\";\n const editor = document.createElement(isTextarea ? \"textarea\" : \"input\");\n editor.className = isTextarea ? \"inline-desc-editor\" : \"inline-title-editor\";\n editor.value = initialValue;\n editor.setAttribute(\"data-editing-field\", field);\n if (!isTextarea) {\n editor.type = \"text\";\n editor.maxLength = 500;\n } else {\n editor.rows = Math.max(3, String(initialValue).split(\"\\n\").length + 1);\n }\n\n node.replaceWith(editor);\n editor.focus();\n if (!isTextarea) editor.select();\n else editor.setSelectionRange(editor.value.length, editor.value.length);\n\n let done = false;\n\n const commit = async () => {\n if (done) return;\n done = true;\n const next = editor.value;\n if (String(next) === String(initialValue)) {\n await renderDetail();\n return;\n }\n if (field === \"title\" && !next.trim()) {\n toast.warning(\"Title cannot be empty\");\n await renderDetail();\n return;\n }\n await patchTicket(ticketId, { [field]: next });\n };\n\n const cancel = async () => {\n if (done) return;\n done = true;\n await renderDetail();\n };\n\n editor.addEventListener(\"blur\", commit);\n editor.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n void cancel();\n return;\n }\n if (event.key === \"Enter\") {\n if (!isTextarea) {\n event.preventDefault();\n void commit();\n } else if (event.metaKey || event.ctrlKey) {\n event.preventDefault();\n void commit();\n }\n }\n });\n}\n\n/** Wire inline editors on the ticket detail header (meta fields, labels). */\nfunction wireTicketDetailEditors(ticket) {\n const ticketId = ticket.id;\n\n const titleEl = drawer.querySelector('[data-edit-field=\"title\"]');\n if (titleEl) {\n titleEl.addEventListener(\"click\", () => {\n startInlineEdit(titleEl, \"title\", ticket.title || \"\", ticketId);\n });\n titleEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n startInlineEdit(titleEl, \"title\", ticket.title || \"\", ticketId);\n }\n });\n }\n\n const descEl = drawerInner.querySelector('[data-edit-field=\"description\"]');\n if (descEl) {\n descEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n startInlineEdit(descEl, \"description\", ticket.description || \"\", ticketId);\n });\n descEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n startInlineEdit(descEl, \"description\", ticket.description || \"\", ticketId);\n }\n });\n }\n\n drawerInner.querySelectorAll(\".meta-select[data-meta-field]\").forEach((select) => {\n select.addEventListener(\"change\", async () => {\n const field = select.dataset.metaField;\n if (field === \"type\") {\n await patchTicket(ticketId, { type: select.value });\n return;\n }\n if (field === \"state_id\") {\n await patchTicket(ticketId, { state_id: select.value });\n return;\n }\n if (field === \"parent_ticket_id\") {\n await patchTicket(ticketId, { parent_ticket_id: select.value || null });\n return;\n }\n if (field === \"priority\") {\n await patchTicket(ticketId, { priority: Number(select.value) });\n }\n });\n });\n\n const applyLabelPatch = async (nextNames) => {\n await patchTicket(ticketId, { labels: nextNames });\n };\n\n drawerInner.querySelectorAll(\"[data-remove-label]\").forEach((btn) => {\n btn.addEventListener(\"click\", async () => {\n const removeName = btn.getAttribute(\"data-remove-label\");\n const names = (ticket.labels || []).map((l) => l.name).filter((n) => n !== removeName);\n await applyLabelPatch(names);\n });\n });\n\n const addLabel = async () => {\n const input = drawerInner.querySelector(\"[data-label-input]\");\n if (!input) return;\n const name = input.value.trim();\n if (!name) return;\n const names = (ticket.labels || []).map((l) => l.name);\n if (names.includes(name)) {\n input.value = \"\";\n return;\n }\n names.push(name);\n input.value = \"\";\n await applyLabelPatch(names);\n };\n\n drawerInner.querySelector(\"[data-label-add]\")?.addEventListener(\"click\", () => {\n void addLabel();\n });\n drawerInner.querySelector(\"[data-label-input]\")?.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n void addLabel();\n }\n });\n}\n\nexport async function renderDetail() {\n if (state.detailMode === \"settings\") {\n await renderProjectDetail();\n openDrawer();\n return;\n }\n\n if (!state.selectedTicketId) {\n closeDrawer();\n return;\n }\n\n const [context, statusHistory] = await Promise.all([\n api(withBoardQuery(`/api/tickets/${state.selectedTicketId}/context?depth=1`)),\n api(withBoardQuery(`/api/tickets/${state.selectedTicketId}/history`))\n ]);\n const ticket = context.ticket;\n // Acknowledge the read receipt: clear the unread dot on this card.\n // Also wipe the dot from the already-rendered card in the board so the\n // user doesn't see it lingering until the next full re-render.\n markRead(ticket.id, ticket.updated_at);\n document.querySelector(`.card[data-ticket-id=\"${CSS.escape(ticket.id)}\"] .card-unread-dot`)?.remove();\n const states = selectableStatesForProject(ticket.state_id);\n\n // Ordered by the canonical hierarchy so the dropdown visually reinforces scale:\n // Epic (biggest) \u2192 Feature \u2192 Task \u2192 Bug.\n const typeOptions = [\"epic\", \"feature\", \"task\", \"bug\"]\n .map(\n (value) =>\n `<option value=\"${escapeHtml(value)}\" ${canonicalTicketType(ticket.type) === value ? \"selected\" : \"\"}>${escapeHtml(typeLabelLong(value))}</option>`\n )\n .join(\"\");\n\n const stateOptions = states\n .map(\n (s) =>\n `<option value=\"${escapeHtml(s.id)}\" ${s.id === ticket.state_id ? \"selected\" : \"\"}>${escapeHtml(s.name)}</option>`\n )\n .join(\"\");\n\n const priorityOptions = [0, 1, 2, 3, 4]\n .map(\n (p) =>\n `<option value=\"${p}\" ${Number(ticket.priority) === p ? \"selected\" : \"\"}>${escapeHtml(priorityLabel(p))}</option>`\n )\n .join(\"\");\n\n const labelPills = (ticket.labels || [])\n .map(\n (label) => `\n <span class=\"label-pill-removable\" style=\"--label-color: ${escapeHtml(label.color)}\">\n ${escapeHtml(label.name)}\n <button type=\"button\" class=\"label-pill-remove\" data-remove-label=\"${escapeHtml(label.name)}\" title=\"Remove label\">\u00D7</button>\n </span>`\n )\n .join(\"\");\n\n const catalogNames = boardLabelCatalog()\n .map((l) => l.name)\n .filter((name) => !ticket.labels?.some((tl) => tl.name === name));\n\n const datalistOptions = catalogNames.map((name) => `<option value=\"${escapeHtml(name)}\"></option>`).join(\"\");\n\n const detailCanonicalType = canonicalTicketType(ticket.type);\n const detailTypeText = typeLabel(ticket.type).toUpperCase();\n const detailSubtitleHtml = `\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"card-type-id type-pill-${escapeHtml(detailCanonicalType)}\">\n ${renderTypeIcon(ticket.type)}\n <span class=\"card-type-label\">${escapeHtml(detailTypeText)}</span>\n </div>\n ${renderPriorityPill(ticket.priority)}\n `;\n\n renderDrawerShell({\n mode: \"ticket\",\n title: ticket.title,\n titleAttrs: {\n class: \"editable-field\",\n \"data-edit-field\": \"title\",\n tabindex: \"0\",\n title: \"Click to edit\"\n },\n subtitleHtml: detailSubtitleHtml,\n body: `\n <div class=\"detail-head\">\n <p class=\"detail-updated\" title=\"Last saved change\">Updated ${escapeHtml(formatDateDetail(ticket.updated_at))}</p>\n <div class=\"description markdown-body editable-field ${ticket.description ? \"\" : \"is-placeholder\"}\" data-edit-field=\"description\" tabindex=\"0\" title=\"Click to edit\">${ticket.description ? renderMarkdown(ticket.description) : escapeHtml(\"No description yet.\")}</div>\n <dl class=\"ticket-meta\" id=\"ticketMetaGrid\" data-ticket-id=\"${escapeHtml(ticket.id)}\">\n <div class=\"ticket-meta-row\">\n <dt>State</dt>\n <dd><select class=\"meta-select meta-inline\" data-meta-field=\"state_id\" aria-label=\"Lane / state\">${stateOptions}</select></dd>\n </div>\n <div class=\"ticket-meta-row\">\n <dt>Type</dt>\n <dd><select class=\"meta-select meta-inline\" data-meta-field=\"type\" aria-label=\"Ticket type\">${typeOptions}</select></dd>\n </div>\n <div class=\"ticket-meta-row\">\n <dt>Priority</dt>\n <dd><select class=\"meta-select meta-inline\" data-meta-field=\"priority\" aria-label=\"Priority\">${priorityOptions}</select></dd>\n </div>\n <div class=\"ticket-meta-row ticket-meta-row--stack\">\n <dt>Labels</dt>\n <dd>\n <div class=\"label-pills-row\" data-other-labels>${labelPills}</div>\n <div class=\"label-add-row\">\n <input type=\"text\" class=\"label-add-input meta-inline-input\" data-label-input list=\"board-label-suggestions\" placeholder=\"Add label\u2026\" aria-label=\"Add label\" />\n <datalist id=\"board-label-suggestions\">${datalistOptions}</datalist>\n <button type=\"button\" class=\"ghost meta-add-btn\" data-label-add>Add</button>\n </div>\n </dd>\n </div>\n </dl>\n </div>\n\n ${renderHierarchySection(ticket, context)}\n\n ${renderParentEpicSection(ticket, context)}\n\n <div class=\"section\">\n <h3>Related</h3>\n ${renderRelated(context.relations, ticket)}\n </div>\n\n ${currentBoard()?.ai_enabled !== 0 ? `\n <details class=\"section ai-fields\" data-ai-plan-toggle data-ticket-id=\"${escapeHtml(ticket.id)}\"${aiPlanOpen(ticket.id) ? \" open\" : \"\"}>\n <summary><h3>AI Plan / Implementation Record</h3></summary>\n <form id=\"aiFieldsForm\" class=\"field-form\">\n <label>\n <span>AI-Written Plan</span>\n <textarea name=\"ai_plan\" placeholder=\"Paste or let an AI write the plan...\">${escapeHtml(ticket.ai_plan || \"\")}</textarea>\n </label>\n <label>\n <span>Implementation Summary</span>\n <textarea name=\"implementation_summary\" placeholder=\"What changed, what shipped, what remains...\">${escapeHtml(ticket.implementation_summary || \"\")}</textarea>\n </label>\n <label>\n <span>Implementation Updates / Lessons</span>\n <textarea name=\"implementation_updates\" placeholder=\"Progress notes, mistakes to avoid, discoveries...\">${escapeHtml(ticket.implementation_updates || \"\")}</textarea>\n </label>\n <button type=\"submit\">Save Fields</button>\n </form>\n </details>` : \"\"}\n\n <div class=\"section\">\n <h3>Status History</h3>\n ${renderStatusHistory(statusHistory)}\n </div>\n\n <div class=\"section\">\n <h3>Comments</h3>\n ${context.comments.map(renderComment).join(\"\") || `<p class=\"description\">No comments yet.</p>`}\n <form class=\"comment-form\" id=\"detailCommentForm\">\n <textarea name=\"body\" placeholder=\"Add a comment, decision, or instruction...\" required></textarea>\n <button type=\"submit\">Comment</button>\n </form>\n </div>\n `\n });\n\n wireTicketDetailEditors(ticket);\n\n $(\"#aiFieldsForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n await api(withBoardQuery(`/api/tickets/${ticket.id}`), {\n method: \"PATCH\",\n body: {\n ai_plan: form.get(\"ai_plan\"),\n implementation_summary: form.get(\"implementation_summary\"),\n implementation_updates: form.get(\"implementation_updates\")\n }\n });\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n toast.success(\"AI fields saved\");\n });\n\n $(\"#detailCommentForm\").addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const body = new FormData(event.currentTarget).get(\"body\").trim();\n if (!body) return;\n await api(withBoardQuery(`/api/tickets/${ticket.id}/comments`), {\n method: \"POST\",\n body: { body }\n });\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n });\n\n drawerInner.querySelectorAll(\"[data-open-ticket]\").forEach((card) => {\n card.addEventListener(\"click\", async (event) => {\n if (event.target.closest(\"[data-detach-child],[data-detach-parent],[data-detach-relation]\")) return;\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: card.dataset.openTicket\n });\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-child]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const childId = btn.dataset.detachChild;\n try {\n await api(withBoardQuery(`/api/tickets/${childId}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: null }\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove child\");\n return;\n }\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n toast.success(\"Removed from epic\");\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-parent]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n try {\n await api(withBoardQuery(`/api/tickets/${ticket.id}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: null }\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove parent\");\n return;\n }\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n toast.success(\"Parent epic removed\");\n });\n });\n\n drawerInner.querySelectorAll(\"[data-detach-relation]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const relationId = btn.dataset.detachRelation;\n try {\n await api(withBoardQuery(`/api/relations/${relationId}`), { method: \"DELETE\" });\n } catch (err) {\n toast.error(err.message || \"Failed to remove relation\");\n return;\n }\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n toast.success(\"Relation removed\");\n });\n });\n\n const aiPlanEl = drawerInner.querySelector(\"[data-ai-plan-toggle]\");\n if (aiPlanEl) {\n aiPlanEl.addEventListener(\"toggle\", () => {\n const id = aiPlanEl.dataset.ticketId;\n if (aiPlanEl.open) localStorage.setItem(`mab_ai_plan_open:${id}`, \"1\");\n else localStorage.removeItem(`mab_ai_plan_open:${id}`);\n });\n }\n\n const parentEpicForm = drawerInner.querySelector(\"#parentEpicForm\");\n if (parentEpicForm) {\n const parentInput = parentEpicForm.querySelector(\"[name=target]\");\n const parentClear = parentEpicForm.querySelector(\"[data-parent-epic-clear]\");\n const syncParentClear = () => {\n parentEpicForm.classList.toggle(\"has-value\", parentInput.value.length > 0);\n };\n parentInput.addEventListener(\"input\", syncParentClear);\n syncParentClear();\n parentClear.addEventListener(\"click\", () => {\n parentInput.value = \"\";\n syncParentClear();\n parentInput.focus();\n });\n parentEpicForm.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const targetLabel = String(new FormData(event.currentTarget).get(\"target\") || \"\").trim();\n if (!targetLabel) return;\n const targetId = resolveTicketIdFromLabel(targetLabel, ticket.id);\n if (!targetId) {\n toast.warning(\"Pick an epic from the suggestions\");\n return;\n }\n const target = ticketsForProject().find((t) => t.id === targetId);\n if (!target || canonicalTicketType(target.type) !== \"epic\") {\n toast.warning(\"Parent must be an epic\");\n return;\n }\n try {\n await api(withBoardQuery(`/api/tickets/${ticket.id}`), {\n method: \"PATCH\",\n body: { parent_ticket_id: targetId }\n });\n } catch (err) {\n toast.error(err.message || \"Failed to set parent epic\");\n return;\n }\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n toast.success(\"Parent epic set\");\n });\n }\n\n const relatedAddForm = drawerInner.querySelector(\"#relatedAddForm\");\n if (relatedAddForm) {\n const relatedInput = relatedAddForm.querySelector(\"[name=target]\");\n const relatedClear = relatedAddForm.querySelector(\"[data-related-clear]\");\n const syncRelatedClear = () => {\n relatedAddForm.classList.toggle(\"has-value\", relatedInput.value.length > 0);\n };\n relatedInput.addEventListener(\"input\", syncRelatedClear);\n syncRelatedClear();\n relatedClear.addEventListener(\"click\", () => {\n relatedInput.value = \"\";\n syncRelatedClear();\n relatedInput.focus();\n });\n relatedAddForm.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n const targetLabel = String(form.get(\"target\") || \"\").trim();\n const relationType = String(form.get(\"type\") || \"relates_to\");\n if (!targetLabel) return;\n const targetId = resolveTicketIdFromLabel(targetLabel, ticket.id);\n if (!targetId) {\n toast.warning(\"Pick a ticket from the suggestions\");\n return;\n }\n try {\n await api(withBoardQuery(`/api/relations`), {\n method: \"POST\",\n body: { source_ticket_id: ticket.id, target_ticket_id: targetId, type: relationType }\n });\n } catch (err) {\n toast.error(err.message || \"Failed to add relation\");\n return;\n }\n await load();\n state.selectedTicketId = ticket.id;\n state.detailMode = \"ticket\";\n await renderDetail();\n });\n }\n\n openDrawer();\n}\n\nfunction aiPlanOpen(ticketId) {\n return localStorage.getItem(`mab_ai_plan_open:${ticketId}`) === \"1\";\n}\n\nfunction resolveTicketIdFromLabel(label, selfId) {\n const trimmed = label.trim();\n const match = trimmed.match(/^#?(\\d+)\\b/);\n const tickets = ticketsForProject().filter((t) => t.id !== selfId);\n if (match) {\n const n = Number(match[1]);\n const hit = tickets.find((t) => t.number === n);\n if (hit) return hit.id;\n }\n const exact = tickets.find((t) => `#${t.number} \u2014 ${t.title}` === trimmed);\n return exact ? exact.id : \"\";\n}\n\nfunction renderStatusHistory(history) {\n if (!history || history.length === 0) {\n return `<p class=\"description\">No status changes yet.</p>`;\n }\n return history\n .map((event) => {\n const body = event.body;\n const from = body.from ? escapeHtml(body.from) : \"?\";\n const to = escapeHtml(body.to || body.state || body.next_state || \"?\");\n const actorType = body.actor_type || \"human\";\n const actorName = escapeHtml(event.actor);\n const actorId = body.actor_id && body.actor_id !== event.actor ? escapeHtml(body.actor_id) : null;\n const byLine =\n actorType === \"agent\"\n ? `agent \u00B7 ${actorId ? `${actorName} (${actorId})` : actorName}`\n : `you`;\n return `<div class=\"comment status-change\">\n <div class=\"comment-meta\">\n <span class=\"status-route\">${from} \u2192 ${to}</span>\n <span>${byLine} \u00B7 ${formatDate(event.created_at)}</span>\n </div>\n </div>`;\n })\n .join(\"\");\n}\n\nfunction renderComment(comment) {\n return `\n <div class=\"comment ${comment.kind === \"checkpoint\" ? \"checkpoint\" : \"\"}\">\n <div class=\"comment-meta\">\n <strong>${escapeHtml(comment.author)}</strong>\n <span>${comment.kind === \"human_comment\" ? \"\" : `${escapeHtml(comment.kind)} - `}${formatDate(comment.created_at)}</span>\n </div>\n <div class=\"comment-body\">${escapeHtml(comment.body)}</div>\n </div>\n `;\n}\n\nfunction renderRelated(relations = [], ticket) {\n const relatedIds = new Set(relations.map((r) => r.other_ticket.id));\n const hierarchyIds = new Set();\n if (ticket?.parent_ticket_id) hierarchyIds.add(ticket.parent_ticket_id);\n if (ticket?.id) {\n for (const t of ticketsForProject()) {\n if (t.parent_ticket_id === ticket.id) hierarchyIds.add(t.id);\n }\n }\n const candidates = ticketsForProject().filter(\n (t) => t.id !== ticket?.id && !relatedIds.has(t.id) && !hierarchyIds.has(t.id)\n );\n const datalistOptions = candidates\n .map((t) => `<option value=\"#${t.number} \u2014 ${escapeHtml(t.title)}\"></option>`)\n .join(\"\");\n\n const list = relations.length\n ? `<div class=\"detail-card-grid\">${relations.map((r) => renderRelatedCard(r)).join(\"\")}</div>`\n : \"\";\n\n const form = `\n <form id=\"relatedAddForm\" class=\"related-add-row\">\n <div class=\"related-add-input-wrap\">\n <input type=\"text\" name=\"target\" class=\"related-add-input meta-inline-input\" list=\"related-ticket-suggestions\" placeholder=\"Add related ticket\u2026\" aria-label=\"Add related ticket\" autocomplete=\"off\" />\n <button type=\"button\" class=\"related-add-clear\" data-related-clear aria-label=\"Clear\" tabindex=\"-1\">\u00D7</button>\n <datalist id=\"related-ticket-suggestions\">${datalistOptions}</datalist>\n </div>\n <select name=\"type\" class=\"related-add-type meta-inline\" aria-label=\"Relation type\">\n <option value=\"relates_to\">relates to</option>\n <option value=\"blocks\">blocks</option>\n <option value=\"blocked_by\">blocked by</option>\n </select>\n <button type=\"submit\" class=\"ghost meta-add-btn\">Add</button>\n </form>\n `;\n\n return list + form;\n}\n\nfunction renderHierarchySection(ticket, context) {\n const isEpic = canonicalTicketType(ticket.type) === \"epic\";\n if (isEpic) {\n const cards = context.child_tickets || [];\n const body = cards.length\n ? `<div class=\"detail-card-grid\">${cards.map((c) => renderDetailCard(c, { detach: { mode: \"child\", id: c.id } })).join(\"\")}</div>`\n : `<p class=\"description\">No child features yet. Create a feature / task card and set this epic as its parent.</p>`;\n return `\n <div class=\"section\">\n <h3>Features inside this Epic</h3>\n ${body}\n </div>\n `;\n }\n return \"\";\n}\n\nfunction renderParentEpicSection(ticket, context) {\n if (canonicalTicketType(ticket.type) === \"epic\") return \"\";\n\n const epics = ticketsForProject().filter((t) => t.type === \"epic\" && t.id !== ticket.id);\n const datalistOptions = epics\n .map((t) => `<option value=\"#${t.number} \u2014 ${escapeHtml(t.title)}\"></option>`)\n .join(\"\");\n\n const body = context.parent_ticket\n ? `<div class=\"detail-card-grid detail-card-grid--single\">${renderDetailCard(context.parent_ticket, { detach: { mode: \"parent\" } })}</div>`\n : `\n <form id=\"parentEpicForm\" class=\"related-add-row\">\n <div class=\"related-add-input-wrap\">\n <input type=\"text\" name=\"target\" class=\"related-add-input meta-inline-input\" list=\"parent-epic-suggestions\" placeholder=\"Set parent epic\u2026\" aria-label=\"Set parent epic\" autocomplete=\"off\" />\n <button type=\"button\" class=\"related-add-clear\" data-parent-epic-clear aria-label=\"Clear\" tabindex=\"-1\">\u00D7</button>\n <datalist id=\"parent-epic-suggestions\">${datalistOptions}</datalist>\n </div>\n <button type=\"submit\" class=\"ghost meta-add-btn\">Set</button>\n </form>\n `;\n\n return `\n <div class=\"section\">\n <h3>Epic</h3>\n ${body}\n </div>\n `;\n}\n\nexport function renderDetailCard(ticket, options = {}) {\n const canonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const typeText = typeLabel(ticket.type).toUpperCase();\n const eyebrow = options.eyebrow\n ? `<span class=\"card-eyebrow\">${escapeHtml(options.eyebrow)}</span>`\n : \"\";\n let detachBtn = \"\";\n if (options.detach) {\n const { mode, id } = options.detach;\n let attr = \"\";\n let label = \"\";\n if (mode === \"child\") {\n attr = `data-detach-child=\"${escapeHtml(id)}\"`;\n label = \"Remove from epic\";\n } else if (mode === \"parent\") {\n attr = `data-detach-parent=\"1\"`;\n label = \"Remove parent epic\";\n } else if (mode === \"relation\") {\n attr = `data-detach-relation=\"${escapeHtml(id)}\"`;\n label = \"Remove relation\";\n }\n detachBtn = `<button type=\"button\" class=\"card-detach-btn\" ${attr} aria-label=\"${label}\" title=\"${label}\">\u00D7</button>`;\n } else if (options.archive) {\n const tid = escapeHtml(options.archive.id);\n const restoreSvg = `<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 12a9 9 0 1 0 3-6.7\"/><path d=\"M3 4v5h5\"/></svg>`;\n const trashSvg = `<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/></svg>`;\n detachBtn = `\n <div class=\"card-archive-actions\">\n <button type=\"button\" class=\"card-archive-btn card-archive-btn--restore\" data-archive-restore=\"${tid}\" aria-label=\"Restore to board\" title=\"Restore to board\">${restoreSvg}</button>\n <button type=\"button\" class=\"card-archive-btn card-archive-btn--delete\" data-archive-delete=\"${tid}\" aria-label=\"Delete permanently\" title=\"Delete permanently\">${trashSvg}</button>\n </div>\n `;\n }\n const unreadN = unreadCount(ticket);\n const unreadDot = unreadN === 0\n ? \"\"\n : unreadN === 1\n ? `<span class=\"card-unread-dot\" role=\"status\" aria-label=\"1 unread update\"></span>`\n : `<span class=\"card-unread-dot has-count\" role=\"status\" aria-label=\"${unreadN} unread updates\">${unreadN > 99 ? \"99+\" : unreadN}</span>`;\n return `\n <article class=\"card card--detail type-${escapeHtml(canonicalType)} priority-${escapeHtml(priorityKey)}\"${options.disableOpen ? \"\" : ` data-open-ticket=\"${escapeHtml(ticket.id)}\"`}>\n ${unreadDot}\n ${detachBtn}\n ${eyebrow}\n <h3>${escapeHtml(ticket.title)}</h3>\n <div class=\"card-meta\">\n <div class=\"card-expand-trigger card-expand-trigger--static\">\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"card-type-id type-pill-${escapeHtml(canonicalType)}\">\n ${renderTypeIcon(ticket.type)}\n <span class=\"card-type-label\">${escapeHtml(typeText)}</span>\n </div>\n ${state.showPriority ? renderPriorityPill(ticket.priority) : \"\"}\n </div>\n </div>\n </article>\n `;\n}\n\nfunction renderRelatedCard(relation) {\n const verb = String(relation.type || \"\").replace(/_/g, \" \");\n const direction = relation.direction === \"incoming\" ? \"from\" : \"to\";\n return renderDetailCard(relation.other_ticket, {\n eyebrow: `${verb} ${direction}`,\n detach: { mode: \"relation\", id: relation.id }\n });\n}\n", "// Server-sent events client. Subscribes to /api/events/stream and turns\n// server events into a debounced bootstrap reload + toast notifications.\n// Owns its own reconnect backoff for the rare case where the browser's\n// auto-reconnect gives up (e.g., HTTP error \u2192 CLOSED state).\n\nimport { state, syncBoardSelection } from \"./state.js\";\nimport { api, bootstrapPath } from \"./api.js\";\nimport { toast, debounce } from \"./toast.js\";\nimport { render } from \"./app.js\";\nimport { markRead, bumpUnread, clearUnread } from \"./unread.js\";\n\n// Event types that meaningfully change a card's state from the human's POV\n// \u2014 these are the ones that should bump the per-card unread count.\nconst CARD_TOUCHING_EVENTS = new Set([\n \"ticket_created\",\n \"state_changed\",\n \"ticket_updated\",\n \"comment_created\",\n \"agent_claimed\",\n \"checkpoint_requested\",\n \"agent_completed\"\n]);\n\n// Manual reconnect backoff for the rare case the browser's auto-reconnect\n// gives up (e.g., the server returned an HTTP error and EventSource entered\n// the CLOSED state). Reset on every successful open.\nlet sseReconnectDelayMs = 1000;\nlet sseReconnectTimer = null;\nlet sseDisconnectToastShown = false;\n\nexport function connectEventStream() {\n if (sseReconnectTimer) {\n clearTimeout(sseReconnectTimer);\n sseReconnectTimer = null;\n }\n if (state.eventSource) {\n state.eventSource.close();\n state.eventSource = null;\n }\n\n const params = new URLSearchParams();\n if (state.boardId) params.set(\"board_id\", state.boardId);\n const url = `/api/events/stream${params.toString() ? `?${params}` : \"\"}`;\n\n const es = new EventSource(url);\n state.eventSource = es;\n\n es.addEventListener(\"open\", () => {\n sseReconnectDelayMs = 1000;\n if (sseDisconnectToastShown) {\n toast.success(\"Live updates reconnected\");\n sseDisconnectToastShown = false;\n }\n });\n\n es.addEventListener(\"board\", async (msg) => {\n let event;\n try {\n event = JSON.parse(msg.data);\n } catch {\n return;\n }\n\n const eventType = event.type;\n const findTicket = () => state.data?.tickets?.find((t) => t.id === event.ticket_id);\n\n // Per-card unread counter:\n // - my own events \u2192 mark read (no badge for my own changes)\n // - foreign card-touching events \u2192 bump count by 1\n // - delete \u2192 clear the entry entirely\n const me = state.data?.actor?.name;\n const isMine = event.actor && me && event.actor === me;\n if (event.ticket_id) {\n if (isMine) {\n markRead(event.ticket_id, event.timestamp);\n } else if (eventType === \"ticket_deleted\") {\n clearUnread(event.ticket_id);\n } else if (CARD_TOUCHING_EVENTS.has(eventType)) {\n bumpUnread(event.ticket_id);\n }\n }\n\n if (eventType === \"ticket_created\") {\n toast.success(`Card created: ${event.data.title || \"New card\"}`);\n scheduleSSEReload();\n } else if (eventType === \"state_changed\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number} ${ticket.title}` : \"Card\";\n toast.info(`${label} \u2192 ${event.data.to}`);\n scheduleSSEReload();\n } else if (eventType === \"ticket_updated\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number}` : \"Card\";\n const fields = event.data.fields ? Object.keys(event.data.fields).join(\", \") : \"\";\n toast.info(`${label} updated${fields ? `: ${fields}` : \"\"}`);\n scheduleSSEReload();\n } else if (eventType === \"comment_created\") {\n const ticket = findTicket();\n const label = ticket ? `#${ticket.number}` : \"ticket\";\n toast.info(`New comment on ${label}`);\n scheduleSSEReload();\n } else if (eventType === \"agent_claimed\") {\n const ticket = findTicket();\n toast.info(`Agent claimed ${ticket ? `#${ticket.number} ${ticket.title}` : \"a ticket\"}`);\n scheduleSSEReload();\n } else if (eventType === \"checkpoint_requested\") {\n const ticket = findTicket();\n toast.warning(`Checkpoint on ${ticket ? `#${ticket.number}` : \"ticket\"} \u2014 needs human input`);\n scheduleSSEReload();\n } else if (eventType === \"agent_completed\") {\n const ticket = findTicket();\n toast.success(`Agent completed ${ticket ? `#${ticket.number} ${ticket.title}` : \"a ticket\"}`);\n scheduleSSEReload();\n } else if (\n eventType === \"ticket_deleted\" ||\n eventType === \"states_reordered\" ||\n eventType === \"state_created\" ||\n eventType === \"state_deleted\" ||\n eventType === \"board_updated\" ||\n eventType === \"board_imported\"\n ) {\n scheduleSSEReload();\n }\n });\n\n es.onerror = () => {\n // EventSource has three readyStates:\n // 0 (CONNECTING) \u2014 browser will auto-reconnect, no action needed.\n // 1 (OPEN) \u2014 transient blip, browser handles it.\n // 2 (CLOSED) \u2014 browser gave up (e.g., HTTP error). Surface and retry.\n if (es.readyState !== EventSource.CLOSED) return;\n\n if (!sseDisconnectToastShown) {\n toast.warning(\"Live updates disconnected \u2014 retrying\u2026\");\n sseDisconnectToastShown = true;\n }\n\n if (sseReconnectTimer) return;\n const delay = sseReconnectDelayMs;\n sseReconnectDelayMs = Math.min(sseReconnectDelayMs * 2, 30000);\n sseReconnectTimer = setTimeout(() => {\n sseReconnectTimer = null;\n connectEventStream();\n }, delay);\n };\n}\n\nexport const scheduleSSEReload = debounce(async () => {\n const selectedId = state.selectedTicketId;\n const mode = state.detailMode;\n state.data = await api(bootstrapPath());\n syncBoardSelection();\n state.selectedTicketId = selectedId;\n state.detailMode = mode;\n await render();\n}, 300);\n", "// Bootstrap reload + top-level render. Extracted from main.js so feature\n// modules can import `load` / `render` without pulling in the entry-point\n// init wiring (which would create import cycles).\n\nimport { state, syncBoardSelection } from \"./state.js\";\nimport { api, bootstrapPath } from \"./api.js\";\nimport { renderBoard } from \"./kanban.js\";\nimport { renderDetail } from \"./ticket-detail.js\";\nimport { closeMenuFlyouts, updateTopbarChips } from \"./board-menu.js\";\nimport { connectEventStream } from \"./sse.js\";\nimport { seedReadIfNeeded } from \"./unread.js\";\nimport { features } from \"./config.js\";\n\nlet sseBoardId = null;\n\nexport async function load() {\n closeMenuFlyouts();\n state.data = await api(bootstrapPath());\n syncBoardSelection();\n // First-time-per-board seed so existing cards don't all flash unread.\n // No-op once the seed flag is set for this board.\n seedReadIfNeeded(state.boardId, state.data?.tickets || []);\n await render();\n if (features.sse && state.boardId !== sseBoardId) {\n sseBoardId = state.boardId;\n connectEventStream();\n }\n}\n\nexport async function render() {\n syncBoardSelection();\n updateTopbarChips();\n renderBoard();\n await renderDetail();\n}\n", "// \"New card\" flyout (top-right panel, separate from the main ticket\n// drawer). Handles open/close transitions, form rendering, and submission.\n\nimport {\n $,\n createFlyout,\n createFlyoutInner,\n createFlyoutBackdrop\n} from \"./dom.js\";\nimport { state, visibleStatesForProject, ticketsForProject } from \"./state.js\";\nimport { escapeHtml, ticketLabel } from \"./format.js\";\nimport { api } from \"./api.js\";\nimport { syncUrlFromState } from \"./router.js\";\nimport { closeDrawer } from \"./drawer.js\";\nimport { closeMenuFlyouts } from \"./board-menu.js\";\nimport { load } from \"./app.js\";\n\n/** Clears any pending hide timeout when reopening the create flyout quickly. */\nlet createFlyoutHideTimer = 0;\n\nexport function isCreateFlyoutOpen() {\n return createFlyout?.classList.contains(\"is-open\");\n}\n\n/** Compact top-right panel for creating a card (separate from the main ticket drawer). */\nexport function openCreateFlyout(preselectedLaneId) {\n clearTimeout(createFlyoutHideTimer);\n closeMenuFlyouts();\n closeDrawer();\n createFlyoutInner.innerHTML = renderCreateForm(preselectedLaneId || \"\");\n wireCreateForm();\n $(\"#createFlyoutClose\")?.addEventListener(\"click\", () => closeCreateFlyout());\n createFlyout.hidden = false;\n createFlyoutBackdrop.hidden = false;\n requestAnimationFrame(() => {\n createFlyout.classList.add(\"is-open\");\n createFlyoutBackdrop.classList.add(\"is-visible\");\n });\n requestAnimationFrame(() => {\n $(\"#createTicketTitle\")?.focus();\n });\n}\n\nexport function closeCreateFlyout() {\n clearTimeout(createFlyoutHideTimer);\n createFlyout.classList.remove(\"is-open\");\n createFlyoutBackdrop.classList.remove(\"is-visible\");\n createFlyoutHideTimer = setTimeout(() => {\n createFlyout.hidden = true;\n createFlyoutBackdrop.hidden = true;\n createFlyoutInner.innerHTML = \"\";\n }, 220);\n}\n\n/** HTML for the \u201CNew\u201D flyout: lane + type + priority on one row, then parent and labels. */\nfunction renderCreateForm(preselectedLaneId) {\n const states = visibleStatesForProject();\n const defaultState = states.find((item) => item.is_default) || states[0];\n const effectiveStateId =\n preselectedLaneId && states.some((s) => s.id === preselectedLaneId)\n ? preselectedLaneId\n : defaultState?.id || \"\";\n const stateOptions = states\n .map(\n (item) =>\n `<option value=\"${escapeHtml(item.id)}\" ${item.id === effectiveStateId ? \"selected\" : \"\"}>${escapeHtml(item.name)}</option>`\n )\n .join(\"\");\n const parentOptions = ticketsForProject()\n .filter((ticket) => ticket.type === \"epic\")\n .map((ticket) => `<option value=\"${escapeHtml(ticket.id)}\">${escapeHtml(ticketLabel(ticket))}</option>`)\n .join(\"\");\n return `\n <div class=\"create-flyout-head\">\n <h2>New card</h2>\n <button type=\"button\" class=\"create-flyout-close ghost\" id=\"createFlyoutClose\" aria-label=\"Close\">\u00D7</button>\n </div>\n <form id=\"createTicketForm\" class=\"create-flyout-form\">\n <input id=\"createTicketTitle\" name=\"title\" type=\"text\" placeholder=\"Title \u2014 what is this card?\" autocomplete=\"off\" required />\n <textarea id=\"createTicketDescription\" name=\"description\" placeholder=\"Description (optional)\"></textarea>\n <div class=\"create-flyout-grid\">\n <label>\n Lane\n <select id=\"createTicketState\" name=\"state\" class=\"select-chevron-field\" aria-label=\"Lane\">${stateOptions}</select>\n </label>\n <label>\n Type\n <select id=\"createTicketType\" name=\"type\" class=\"select-chevron-field\" aria-label=\"Ticket type\">\n <option value=\"epic\">Epic / Story</option>\n <option value=\"feature\">Feature</option>\n <option value=\"task\" selected>Task</option>\n <option value=\"bug\">Bug</option>\n </select>\n </label>\n <label>\n Priority\n <select id=\"createTicketPriority\" name=\"priority\" class=\"select-chevron-field\" aria-label=\"Priority\">\n <option value=\"0\">MAYBE</option>\n <option value=\"1\">LOW</option>\n <option value=\"2\" selected>MED</option>\n <option value=\"3\">HIGH</option>\n <option value=\"4\">URGENT</option>\n </select>\n </label>\n </div>\n <label>\n Parent epic\n <select id=\"createTicketParent\" name=\"parent_ticket_id\" class=\"select-chevron-field\" aria-label=\"Parent epic\">\n <option value=\"\">None</option>\n ${parentOptions}\n </select>\n </label>\n <input id=\"createTicketLabels\" name=\"labels\" type=\"text\" placeholder=\"Labels (comma-separated)\" />\n <button type=\"submit\">Create card</button>\n </form>\n `;\n}\n\nfunction wireCreateForm() {\n const form = $(\"#createTicketForm\");\n if (!form) return;\n form.addEventListener(\"submit\", createTicketFromDrawer);\n}\n\nasync function createTicketFromDrawer(event) {\n event.preventDefault();\n const form = event.currentTarget;\n const data = new FormData(form);\n const labels = String(data.get(\"labels\") || \"\")\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n\n const created = await api(\"/api/tickets\", {\n method: \"POST\",\n body: {\n board_id: state.boardId,\n title: data.get(\"title\"),\n description: data.get(\"description\"),\n type: data.get(\"type\"),\n parent_ticket_id: data.get(\"parent_ticket_id\") || null,\n state_id: data.get(\"state\"),\n priority: Number(data.get(\"priority\")),\n labels\n }\n });\n\n closeCreateFlyout();\n state.selectedTicketId = created.id;\n state.detailMode = \"ticket\";\n await load();\n syncUrlFromState();\n}\n", "// Board picker flyout (the \"Board\" chip in the topbar). Lists every board\n// the actor can see, switches between them, and \u2014 for owners \u2014 exposes the\n// new-board form. Also owns the topbar chip label/title sync.\n\nimport { boardFlyout, boardMenuBtn } from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { escapeHtml } from \"./format.js\";\nimport { api } from \"./api.js\";\nimport { navigate, syncUrlFromState } from \"./router.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\nimport { toast } from \"./toast.js\";\nimport { load } from \"./app.js\";\nimport { features } from \"./config.js\";\n\nexport function closeBoardFlyout() {\n if (!boardFlyout) return;\n boardFlyout.hidden = true;\n boardFlyout.innerHTML = \"\";\n boardMenuBtn?.setAttribute(\"aria-expanded\", \"false\");\n}\n\nexport function closeMenuFlyouts() {\n closeBoardFlyout();\n}\n\nexport function updateTopbarChips() {\n if (!state.data) return;\n const board = (state.data.boards || []).find((b) => b.id === state.boardId);\n if (boardMenuBtn) {\n boardMenuBtn.textContent = board?.name || \"Board\";\n boardMenuBtn.title = board ? `${board.name} \u2014 slug: ${board.slug}` : \"Choose board\";\n }\n}\n\nfunction renderBoardFlyoutInner() {\n const boards = state.data.boards || [];\n const rows = boards\n .map(\n (b) => `\n <button type=\"button\" class=\"menu-flyout-item ${b.id === state.boardId ? \"is-current\" : \"\"}\" data-pick-board=\"${escapeHtml(b.id)}\" role=\"menuitem\">\n <span class=\"menu-flyout-item-title\">${escapeHtml(b.name)}</span>\n <span class=\"menu-flyout-item-meta\">${escapeHtml(b.slug)}</span>\n </button>`\n )\n .join(\"\");\n const listBody =\n rows ||\n `<p class=\"menu-flyout-hint menu-flyout-hint--empty\">No boards yet. Create one below if you can.</p>`;\n const createBlock = features.multiBoard\n ? `\n <div class=\"menu-flyout-section\">\n <h3 class=\"menu-flyout-heading\">New board</h3>\n <form id=\"createBoardForm\" class=\"menu-flyout-form\">\n <div class=\"folder-picker-field\">\n <input id=\"repoPathInput\" name=\"repo_path\" type=\"text\" required readonly placeholder=\"Choose a folder\" autocomplete=\"off\" />\n <button type=\"button\" id=\"pickRepoFolderBtn\">Browse</button>\n </div>\n <p class=\"menu-flyout-hint menu-flyout-hint--intro\">Board data is stored in <code>.orbit/</code> under this folder.</p>\n <input name=\"name\" type=\"text\" required placeholder=\"Board name\" autocomplete=\"off\" />\n <input name=\"slug\" type=\"text\" placeholder=\"Slug (optional)\" autocomplete=\"off\" />\n <input name=\"default_branch\" type=\"text\" placeholder=\"Default branch (optional)\" autocomplete=\"off\" />\n <input name=\"repo_url\" type=\"text\" placeholder=\"Repo URL (optional)\" autocomplete=\"off\" />\n <button type=\"submit\">Create board</button>\n </form>\n </div>`\n : \"\";\n return `\n <div class=\"menu-flyout-head\">Board</div>\n <div class=\"menu-flyout-list\">${listBody}</div>\n ${createBlock}\n `;\n}\n\nfunction wireBoardFlyout() {\n boardFlyout.querySelectorAll(\"[data-pick-board]\").forEach((btn) => {\n btn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n const id = btn.getAttribute(\"data-pick-board\");\n closeBoardFlyout();\n if (id === state.boardId) return;\n closeCreateFlyout();\n await navigate({\n boardId: id,\n view: \"board\"\n });\n });\n });\n const form = boardFlyout.querySelector(\"#createBoardForm\");\n if (form) {\n const pickRepoFolderBtn = form.querySelector(\"#pickRepoFolderBtn\");\n const repoPathInput = form.querySelector(\"#repoPathInput\");\n pickRepoFolderBtn?.addEventListener(\"click\", async (event) => {\n event.preventDefault();\n pickRepoFolderBtn.disabled = true;\n try {\n const result = await api(\"/api/system/pick-folder\", { method: \"POST\" });\n if (result.path) {\n repoPathInput.value = result.path;\n repoPathInput.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }\n } catch (error) {\n toast.error(error?.message || \"Folder picker unavailable\");\n } finally {\n pickRepoFolderBtn.disabled = false;\n }\n });\n form.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const fd = new FormData(form);\n const slug = String(fd.get(\"slug\") || \"\").trim();\n const branch = String(fd.get(\"default_branch\") || \"\").trim();\n const repo = String(fd.get(\"repo_url\") || \"\").trim();\n const repoPath = String(fd.get(\"repo_path\") || \"\").trim();\n if (!repoPath) {\n repoPathInput?.reportValidity();\n return;\n }\n const created = await api(\"/api/boards\", {\n method: \"POST\",\n body: {\n name: fd.get(\"name\"),\n repo_path: repoPath,\n ...(slug ? { slug } : {}),\n ...(branch ? { default_branch: branch } : {}),\n ...(repo ? { repo_url: repo } : {})\n }\n });\n closeBoardFlyout();\n state.boardId = created.id;\n state.selectedTicketId = \"\";\n state.detailMode = \"settings\";\n await load();\n syncUrlFromState();\n toast.success(\"Board created\");\n });\n }\n}\n\nexport function openBoardFlyout() {\n closeCreateFlyout();\n boardFlyout.innerHTML = renderBoardFlyoutInner();\n boardFlyout.hidden = false;\n boardMenuBtn?.setAttribute(\"aria-expanded\", \"true\");\n wireBoardFlyout();\n}\n", "import { SETTINGS_TAB_IDS } from \"./settings-tabs.js\";\n\nconst EMPTY_ROUTE = Object.freeze({ boardSlug: \"\", view: \"board\", ticketId: \"\", tab: \"\" });\n\nfunction emptyRoute() {\n return { ...EMPTY_ROUTE };\n}\n\nfunction normalizeLocation(input = globalThis.location) {\n if (typeof input === \"string\") {\n const url = new URL(input, \"http://orbit.local\");\n return { pathname: url.pathname || \"/\", search: url.search || \"\", hash: url.hash || \"\" };\n }\n return {\n pathname: input?.pathname || \"/\",\n search: input?.search || \"\",\n hash: input?.hash || \"\"\n };\n}\n\nfunction decodeSegment(value) {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction routeSegments(value) {\n return String(value || \"\")\n .replace(/^#/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\")\n .split(\"/\")\n .filter(Boolean);\n}\n\nfunction routeFromSegments(parts) {\n if (!parts.length) return null;\n\n const out = emptyRoute();\n let i = 0;\n\n if (parts[i] === \"b\") {\n if (!parts[i + 1]) return null;\n out.boardSlug = decodeSegment(parts[i + 1]);\n i += 2;\n } else if (parts[i] !== \"t\" && parts[i] !== \"settings\") {\n return null;\n }\n\n if (parts[i] === \"t\" && parts[i + 1]) {\n out.view = \"ticket\";\n out.ticketId = decodeSegment(parts[i + 1]);\n } else if (parts[i] === \"settings\") {\n out.view = \"settings\";\n const tab = parts[i + 1] ? decodeSegment(parts[i + 1]) : \"\";\n if (tab && SETTINGS_TAB_IDS.has(tab)) out.tab = tab;\n }\n\n return out;\n}\n\nexport function parseLegacyHashRoute(hash) {\n const raw = String(hash || \"\");\n if (!raw || raw === \"#\" || raw === \"#/\") return null;\n return routeFromSegments(routeSegments(raw));\n}\n\nexport function parseRoute(input = globalThis.location) {\n const loc = normalizeLocation(input);\n return parseLegacyHashRoute(loc.hash) || emptyRoute();\n}\n\nexport function hasRoute(input = globalThis.location) {\n const loc = normalizeLocation(input);\n return Boolean(parseLegacyHashRoute(loc.hash));\n}\n\nexport function buildRoute({ boardSlug = \"\", view = \"board\", ticketId = \"\", tab = \"\" } = {}) {\n const segs = [];\n if (boardSlug) segs.push(\"b\", encodeURIComponent(boardSlug));\n if (view === \"ticket\" && ticketId) segs.push(\"t\", encodeURIComponent(ticketId));\n else if (view === \"settings\") {\n segs.push(\"settings\");\n if (tab && SETTINGS_TAB_IDS.has(tab)) segs.push(tab);\n }\n return \"#/\" + segs.join(\"/\");\n}\n\nexport function isCanonicalRouteUrl(input = globalThis.location, routeObj = parseRoute(input)) {\n const loc = normalizeLocation(input);\n return loc.hash === buildRoute(routeObj);\n}\n", "// Hash router. Copy/share URLs use board slugs, such as\n// `#/b/<boardSlug>`, `#/b/<boardSlug>/t/<ticketId>`, and\n// `#/b/<boardSlug>/settings/<tab>`. Keeping routing in the hash lets the\n// preview app keep working when mounted under `/app/` or opened as static HTML.\n\nimport { currentBoard, state } from \"./state.js\";\nimport { normalizeSettingsTab } from \"./settings-tabs.js\";\nimport { closeMenuFlyouts } from \"./board-menu.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\nimport {\n buildRoute,\n hasRoute,\n isCanonicalRouteUrl,\n parseRoute\n} from \"./url-routes.js\";\n\nexport { buildRoute, hasRoute, parseRoute } from \"./url-routes.js\";\n\nfunction boardBySlugOrId(value) {\n if (!value) return null;\n const boards = state.data?.boards || [];\n return boards.find((b) => b.slug === value) || boards.find((b) => b.id === value) || null;\n}\n\nfunction routeBoardSlug(routeObj = {}) {\n if (routeObj.boardSlug) return routeObj.boardSlug;\n if (routeObj.boardId) return boardBySlugOrId(routeObj.boardId)?.slug || routeObj.boardId;\n return currentBoard()?.slug || state.boardSlug || \"\";\n}\n\nfunction normalizeRouteForUrl(routeObj = {}) {\n return {\n ...routeObj,\n boardSlug: routeBoardSlug(routeObj)\n };\n}\n\nfunction routeFromState() {\n let view = \"board\";\n if (state.detailMode === \"ticket\" && state.selectedTicketId) view = \"ticket\";\n else if (state.detailMode === \"settings\") view = \"settings\";\n return {\n boardSlug: currentBoard()?.slug || state.boardSlug,\n view,\n ticketId: state.selectedTicketId,\n tab: view === \"settings\" ? normalizeSettingsTab(state.settingsTab) : \"\"\n };\n}\n\nlet routerReady = false;\n\nexport function setRouterReady(value) {\n routerReady = value;\n}\n\nexport function currentRoute() {\n return parseRoute(location);\n}\n\nexport async function navigate(routeObj, { replace = false } = {}) {\n const route = normalizeRouteForUrl(routeObj);\n const url = buildRoute(route);\n if (isCanonicalRouteUrl(location, route)) {\n if (routerReady) await applyRoute();\n return;\n }\n if (replace) history.replaceState(null, \"\", url);\n else history.pushState(null, \"\", url);\n if (routerReady) await applyRoute();\n}\n\n// Push or replace the URL to match the current `state` without re-rendering.\n// Used after flows that already mutated state and called load()/render()\n// (e.g. ticket/board creation).\nexport function syncUrlFromState({ replace = false } = {}) {\n const route = routeFromState();\n const url = buildRoute(route);\n if (isCanonicalRouteUrl(location, route)) return;\n if (replace) history.replaceState(null, \"\", url);\n else history.pushState(null, \"\", url);\n}\n\nexport async function applyRoute() {\n const { load, render } = await import(\"./app.js\");\n const r = currentRoute();\n const urlHadRoute = hasRoute(location);\n const prevBoardId = state.boardId;\n const routeBoard = boardBySlugOrId(r.boardSlug);\n const fallbackBoard = routeBoard || (r.boardSlug ? currentBoard() : null);\n\n if (fallbackBoard) {\n state.boardId = fallbackBoard.id;\n state.boardSlug = fallbackBoard.slug;\n } else if (r.boardSlug) {\n state.boardSlug = r.boardSlug;\n }\n\n const canonicalRoute = fallbackBoard ? { ...r, boardSlug: fallbackBoard.slug } : r;\n if (urlHadRoute && !isCanonicalRouteUrl(location, canonicalRoute)) {\n history.replaceState(null, \"\", buildRoute(canonicalRoute));\n }\n\n if (r.view === \"ticket\") {\n state.selectedTicketId = r.ticketId || \"\";\n state.detailMode = r.ticketId ? \"ticket\" : \"empty\";\n } else if (r.view === \"settings\") {\n state.selectedTicketId = \"\";\n state.detailMode = \"settings\";\n if (r.tab) {\n state.settingsTab = r.tab;\n try {\n localStorage.setItem(\"mab_settings_tab\", r.tab);\n } catch {\n /* ignore */\n }\n }\n } else {\n state.selectedTicketId = \"\";\n state.detailMode = \"empty\";\n }\n\n closeMenuFlyouts();\n closeCreateFlyout();\n\n if (state.boardId && state.boardId !== prevBoardId) {\n await load();\n }\n await render();\n}\n\nwindow.addEventListener(\"popstate\", () => {\n if (routerReady) void applyRoute();\n});\n", "// Animated starfield background, signature stars, meteors, and the theme\n// toggle (which drives the starscape's dark/light state). Self-initializing:\n// importing this module starts the canvas, schedules the first meteor, and\n// wires the theme toggle button.\n//\n// Background stars are drawn on a 2D canvas so each star has its own twinkle\n// period, phase, and warmth \u2014 scintillation that reads as per-star rather\n// than whole-layer. Layers parallax to the cursor by depth. The Milky Way,\n// nebula ghosts, signature stars with spikes, and meteors stay in CSS.\n\nimport { themeToggle, themeIcon } from \"./dom.js\";\nimport { applyReducedMotionPreference, effectiveReducedMotionPreference } from \"./motion-preference.js\";\nimport {\n THEME_CHANGE_EVENT,\n applyStoredThemePreference,\n currentTheme,\n toggleThemePreference\n} from \"./theme-preference.js\";\n\n// Stored theme must be applied before startStarscape() so its first sync()\n// sees the real theme; otherwise the canvas stays stopped until next resize.\n{\n applyStoredThemePreference();\n applyReducedMotionPreference();\n}\n\nconst starscape = startStarscape();\nscheduleMeteor();\n\n// Sticky top bar gets a tinted glass panel once the page scrolls, so its\n// controls don't blend into whatever content is slipping behind them.\n{\n const updateScrolled = () => {\n document.body.classList.toggle(\"is-scrolled\", window.scrollY > 4);\n };\n window.addEventListener(\"scroll\", updateScrolled, { passive: true });\n updateScrolled();\n}\n\nsyncThemeIcon();\nthemeToggle?.addEventListener(\"click\", () => {\n toggleThemePreference();\n});\n\nwindow.addEventListener(THEME_CHANGE_EVENT, () => {\n syncThemeIcon();\n starscape.sync();\n});\n\nfunction syncThemeIcon() {\n if (!themeIcon) return;\n const dark = currentTheme() === \"dark\";\n themeIcon.innerHTML = dark\n ? '<path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />'\n : '<circle cx=\"12\" cy=\"12\" r=\"5\" /><path d=\"M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4\" />';\n}\n\nfunction startStarscape() {\n const grain = document.querySelector(\".grain\");\n if (!grain) return { sync: () => {} };\n\n buildSignatureStars(grain);\n\n const canvas = document.createElement(\"canvas\");\n canvas.className = \"starfield-canvas\";\n canvas.setAttribute(\"aria-hidden\", \"true\");\n const milkyWay = grain.querySelector(\".milky-way\");\n if (milkyWay && milkyWay.nextSibling) {\n grain.insertBefore(canvas, milkyWay.nextSibling);\n } else if (milkyWay) {\n grain.appendChild(canvas);\n } else {\n grain.insertBefore(canvas, grain.firstChild);\n }\n\n const ctx = canvas.getContext(\"2d\");\n const DPR = Math.min(window.devicePixelRatio || 1, 2);\n let width = 0;\n let height = 0;\n let stars = [];\n let rafId = 0;\n let running = false;\n\n // Eased mouse position, normalized to [-0.5, 0.5]. Lerp gives inertia.\n const mouse = { x: 0, y: 0, tx: 0, ty: 0 };\n\n function resize() {\n width = window.innerWidth;\n height = window.innerHeight;\n canvas.width = Math.round(width * DPR);\n canvas.height = Math.round(height * DPR);\n canvas.style.width = width + \"px\";\n canvas.style.height = height + \"px\";\n ctx.setTransform(DPR, 0, 0, DPR, 0, 0);\n buildStars();\n }\n\n function buildStars() {\n // Star count scales with viewport area so wide screens don't read empty.\n const density = (width * height) / (1440 * 900);\n const layers = [\n { count: Math.round(320 * density), depth: 0.12, sizes: [[1, 0.9], [1.4, 0.1]], glow: 0 },\n { count: Math.round(160 * density), depth: 0.30, sizes: [[1, 0.5], [1.6, 0.4], [2.4, 0.1]], glow: 1.8 },\n { count: Math.round(44 * density), depth: 0.58, sizes: [[1.8, 0.5], [2.6, 0.38], [3.6, 0.12]], glow: 2.4 }\n ];\n const rng = mulberry32(0xc0ffee);\n stars = [];\n for (const layer of layers) {\n for (let i = 0; i < layer.count; i++) {\n const size = pickWeighted(rng(), layer.sizes);\n stars.push({\n x: rng() * width,\n y: rng() * height,\n size,\n depth: layer.depth,\n glow: size >= 2 ? layer.glow : 0,\n rgb: pickStarColor(rng()),\n period: 2.2 + rng() * 5.4,\n phase: rng() * Math.PI * 2,\n amp: 0.25 + rng() * 0.5,\n baseAlpha: size < 1.5 ? 0.45 + rng() * 0.28 : 0.55 + rng() * 0.22\n });\n }\n }\n }\n\n function pickStarColor(r) {\n if (r < 0.80) return [255, 255, 255];\n if (r < 0.93) return [255, 222, 186];\n return [195, 218, 255];\n }\n\n function onPointerMove(e) {\n if (!width || !height) return;\n mouse.tx = e.clientX / width - 0.5;\n mouse.ty = e.clientY / height - 0.5;\n }\n\n function frame(t) {\n mouse.x += (mouse.tx - mouse.x) * 0.06;\n mouse.y += (mouse.ty - mouse.y) * 0.06;\n\n ctx.clearRect(0, 0, width, height);\n ctx.globalCompositeOperation = \"lighter\";\n\n const time = t / 1000;\n const parallaxPx = 70;\n\n for (let i = 0; i < stars.length; i++) {\n const s = stars[i];\n const pulse = 0.5 + 0.5 * Math.sin(time * ((2 * Math.PI) / s.period) + s.phase);\n const alpha = s.baseAlpha * (1 - s.amp + s.amp * pulse);\n const px = s.x - mouse.x * s.depth * parallaxPx;\n const py = s.y - mouse.y * s.depth * parallaxPx;\n const [r, g, b] = s.rgb;\n\n if (s.glow > 0) {\n // Glowed stars: soft halo + circular core (arc, not rect) so the\n // bright center doesn't read as a square at larger zoom levels.\n const radius = s.size * s.glow;\n const grad = ctx.createRadialGradient(px, py, 0, px, py, radius);\n grad.addColorStop(0, `rgba(${r},${g},${b},${alpha * 0.85})`);\n grad.addColorStop(0.35, `rgba(${r},${g},${b},${alpha * 0.3})`);\n grad.addColorStop(1, `rgba(${r},${g},${b},0)`);\n ctx.fillStyle = grad;\n ctx.beginPath();\n ctx.arc(px, py, radius, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;\n ctx.beginPath();\n ctx.arc(px, py, s.size / 2, 0, Math.PI * 2);\n ctx.fill();\n } else {\n // Sub-pixel dim stars: fillRect is fine \u2014 they're one device pixel.\n const half = s.size / 2;\n ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;\n ctx.fillRect(px - half, py - half, s.size, s.size);\n }\n }\n\n ctx.globalCompositeOperation = \"source-over\";\n if (running) rafId = requestAnimationFrame(frame);\n }\n\n function drawStaticFrame() {\n ctx.clearRect(0, 0, width, height);\n ctx.globalCompositeOperation = \"lighter\";\n for (const s of stars) {\n const [r, g, b] = s.rgb;\n ctx.fillStyle = `rgba(${r},${g},${b},${s.baseAlpha})`;\n if (s.glow > 0) {\n ctx.beginPath();\n ctx.arc(s.x, s.y, s.size / 2, 0, Math.PI * 2);\n ctx.fill();\n } else {\n const half = s.size / 2;\n ctx.fillRect(s.x - half, s.y - half, s.size, s.size);\n }\n }\n ctx.globalCompositeOperation = \"source-over\";\n }\n\n function start() {\n if (running) return;\n running = true;\n rafId = requestAnimationFrame(frame);\n }\n\n function stop() {\n running = false;\n cancelAnimationFrame(rafId);\n }\n\n function sync() {\n const isDark = currentTheme() === \"dark\";\n const reduced = effectiveReducedMotionPreference();\n if (!isDark) {\n stop();\n ctx.clearRect(0, 0, width, height);\n return;\n }\n if (!stars.length) resize();\n if (reduced || document.hidden) {\n stop();\n drawStaticFrame();\n } else {\n start();\n }\n }\n\n window.addEventListener(\"resize\", () => {\n resize();\n sync();\n }, { passive: true });\n window.addEventListener(\"pointermove\", onPointerMove, { passive: true });\n document.addEventListener(\"visibilitychange\", sync);\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").addEventListener(\"change\", () => {\n applyReducedMotionPreference();\n sync();\n });\n window.addEventListener(\"orbit:motion-preference-change\", sync);\n\n resize();\n sync();\n return { sync };\n}\n\nfunction buildSignatureStars(grain) {\n grain.querySelectorAll(\".signature-star\").forEach((el) => el.remove());\n const rng = mulberry32(0x5ca1e5);\n const SIG_COUNT = 7;\n for (let i = 0; i < SIG_COUNT; i++) {\n const star = document.createElement(\"div\");\n star.className = \"signature-star\";\n star.setAttribute(\"aria-hidden\", \"true\");\n star.style.left = (6 + rng() * 88).toFixed(2) + \"%\";\n star.style.top = (8 + rng() * 78).toFixed(2) + \"%\";\n star.style.animationDelay = (-rng() * 4.8).toFixed(2) + \"s\";\n grain.appendChild(star);\n }\n}\n\n/* Shooting stars \u2014 rare streaks that cross the sky. CSS handles the trail\n and fade; JS picks the trajectory and reschedules the next one. */\nfunction scheduleMeteor() {\n const delay = 14000 + Math.random() * 28000;\n setTimeout(spawnMeteor, delay);\n}\n\nfunction spawnMeteor() {\n const isDark = currentTheme() === \"dark\";\n const reduced = effectiveReducedMotionPreference();\n const grain = document.querySelector(\".grain\");\n if (!isDark || reduced || document.hidden || !grain) {\n scheduleMeteor();\n return;\n }\n\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const startX = Math.random() * vw * 0.6;\n const startY = Math.random() * vh * 0.55;\n const distance = 380 + Math.random() * 520;\n const angleDeg = 18 + Math.random() * 26;\n const rad = (angleDeg * Math.PI) / 180;\n const endX = startX + Math.cos(rad) * distance;\n const endY = startY + Math.sin(rad) * distance;\n\n const m = document.createElement(\"div\");\n m.className = \"meteor\";\n m.setAttribute(\"aria-hidden\", \"true\");\n m.style.setProperty(\"--from-x\", startX + \"px\");\n m.style.setProperty(\"--from-y\", startY + \"px\");\n m.style.setProperty(\"--to-x\", endX + \"px\");\n m.style.setProperty(\"--to-y\", endY + \"px\");\n m.style.setProperty(\"--angle\", angleDeg + \"deg\");\n grain.appendChild(m);\n m.addEventListener(\"animationend\", () => m.remove(), { once: true });\n\n scheduleMeteor();\n}\n\nfunction pickWeighted(r, table) {\n let acc = 0;\n for (const [value, weight] of table) {\n acc += weight;\n if (r < acc) return value;\n }\n return table[table.length - 1][0];\n}\n\nfunction mulberry32(seed) {\n let a = seed >>> 0;\n return function () {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n", "// Application entry point. Imports `starscape.js` for its side effects\n// (canvas + theme toggle init), wires the topbar buttons and global\n// keyboard/click listeners, and kicks off the bootstrap \u2192 router activation\n// sequence. The reusable `load` / `render` helpers live in app.js so feature\n// modules can import them without creating cycles back through this entry.\n\nimport \"./starscape.js\";\n\nimport {\n $,\n boardMenuBtn,\n boardFlyout,\n drawer,\n drawerBackdrop,\n createFlyoutBackdrop,\n searchInput\n} from \"./dom.js\";\nimport { state } from \"./state.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { toast, debounce } from \"./toast.js\";\nimport {\n navigate,\n applyRoute,\n currentRoute,\n hasRoute,\n syncUrlFromState,\n setRouterReady\n} from \"./router.js\";\nimport {\n openBoardFlyout,\n closeBoardFlyout,\n closeMenuFlyouts\n} from \"./board-menu.js\";\nimport {\n openCreateFlyout,\n closeCreateFlyout,\n isCreateFlyoutOpen\n} from \"./create-card.js\";\nimport { enableKanbanDragScroll } from \"./kanban.js\";\nimport { runSearch, hideSearch } from \"./search.js\";\nimport { load } from \"./app.js\";\nimport { edition } from \"./config.js\";\nimport { openModal, wireModal } from \"./modal.js\";\n\nasync function init() {\n const welcomeDialog = document.getElementById(\"welcomeDialog\");\n wireModal(welcomeDialog);\n if (edition === \"preview\") {\n openModal(welcomeDialog);\n }\n\n $(\"#settingsBtn\").addEventListener(\"click\", async () => {\n closeCreateFlyout();\n closeMenuFlyouts();\n navigate({\n boardId: state.boardId,\n view: \"settings\",\n tab: state.settingsTab || \"lanes\"\n });\n });\n\n boardMenuBtn?.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (!boardFlyout.hidden) {\n closeBoardFlyout();\n return;\n }\n openBoardFlyout();\n });\n\n $(\"#newTicketBtn\").addEventListener(\"click\", () => {\n if (isCreateFlyoutOpen()) {\n closeCreateFlyout();\n return;\n }\n openCreateFlyout(\"\");\n });\n\n createFlyoutBackdrop.addEventListener(\"click\", () => {\n closeCreateFlyout();\n });\n\n $(\"#drawerCloseBtn\").addEventListener(\"click\", () => {\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n $(\"#drawerArchiveBtn\").addEventListener(\"click\", async () => {\n const ticketId = state.selectedTicketId;\n if (!ticketId || state.detailMode !== \"ticket\") return;\n const ticket = state.data?.tickets?.find((t) => t.id === ticketId);\n const titleForToast = ticket?.title || \"card\";\n await api(withBoardQuery(`/api/tickets/${encodeURIComponent(ticketId)}/archive`), { method: \"POST\" });\n toast.error(`Archived: ${titleForToast}`);\n await load();\n navigate({ boardId: state.boardId, view: \"board\" });\n });\n\n drawerBackdrop.addEventListener(\"click\", () => {\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Escape\") return;\n if (!boardFlyout.hidden) {\n closeMenuFlyouts();\n return;\n }\n if (isCreateFlyoutOpen()) {\n closeCreateFlyout();\n return;\n }\n if (!drawer.classList.contains(\"is-open\")) return;\n const el = document.activeElement;\n if (el?.classList?.contains(\"inline-title-editor\") || el?.classList?.contains(\"inline-desc-editor\")) return;\n navigate({\n boardId: state.boardId,\n view: \"board\"\n });\n });\n\n searchInput.addEventListener(\"input\", debounce(runSearch, 220));\n document.addEventListener(\"click\", (event) => {\n if (!event.target.closest(\"#topbarSearch\")) hideSearch();\n if (!event.target.closest(\".topbar-menu\")) closeMenuFlyouts();\n });\n\n enableKanbanDragScroll();\n\n const initialRoute = currentRoute();\n if (initialRoute.boardSlug) state.boardSlug = initialRoute.boardSlug;\n await load();\n\n // Activate the router. If the page was loaded with a hash route, restore\n // that view; otherwise canonicalize the URL to reflect the current\n // state so the back button has a starting point.\n setRouterReady(true);\n if (hasRoute()) {\n await applyRoute();\n } else {\n syncUrlFromState({ replace: true });\n }\n}\n\ninit();\n", "// Topbar search. Debounced via the input handler in main.js; queries the\n// /api/search endpoint and renders a small results dropdown that navigates\n// to the chosen ticket on click.\n\nimport { searchInput, searchResults } from \"./dom.js\";\nimport { state, currentBoard } from \"./state.js\";\nimport { api } from \"./api.js\";\nimport { navigate } from \"./router.js\";\nimport { escapeHtml, ticketLabel } from \"./format.js\";\nimport { closeCreateFlyout } from \"./create-card.js\";\n\nexport async function runSearch() {\n const query = searchInput.value.trim();\n if (query.length < 2) {\n hideSearch();\n return;\n }\n const board = currentBoard();\n if (!board) return;\n const result = await api(`/api/search?q=${encodeURIComponent(query)}&board=${encodeURIComponent(board.slug)}`);\n if (result.results.length === 0) {\n searchResults.hidden = false;\n searchResults.innerHTML = `<div class=\"search-hit\">No results</div>`;\n return;\n }\n searchResults.hidden = false;\n searchResults.innerHTML = result.results\n .map(\n (ticket) => `\n <div class=\"search-hit\" data-ticket-id=\"${ticket.id}\">\n <strong>${escapeHtml(ticketLabel(ticket))}</strong>\n ${escapeHtml(ticket.title)}\n </div>\n `\n )\n .join(\"\");\n searchResults.querySelectorAll(\"[data-ticket-id]\").forEach((hit) => {\n hit.addEventListener(\"click\", async () => {\n closeCreateFlyout();\n hideSearch();\n navigate({\n boardId: state.boardId,\n view: \"ticket\",\n ticketId: hit.dataset.ticketId\n });\n });\n });\n}\n\nexport function hideSearch() {\n searchResults.hidden = true;\n searchResults.innerHTML = \"\";\n}\n", "// Generic <dialog> modal utility.\n//\n// Usage:\n// wireModal(el) \u2014 wire backdrop-click + [data-modal-close] buttons.\n// openModal(el) \u2014 show the dialog as a modal (focus-trapped overlay).\n// closeModal(el) \u2014 close it programmatically.\n//\n// Escape key is handled natively by the browser; no extra wiring needed.\n\nexport function openModal(dialogEl) {\n dialogEl?.showModal();\n}\n\nexport function closeModal(dialogEl) {\n if (dialogEl?.open) dialogEl.close();\n}\n\nexport function wireModal(dialogEl) {\n if (!dialogEl) return;\n\n // Close when the user clicks the backdrop (the dialog element itself,\n // outside its inner content box).\n dialogEl.addEventListener(\"click\", (event) => {\n if (event.target === dialogEl) closeModal(dialogEl);\n });\n\n // Close buttons: any element inside the dialog with [data-modal-close].\n dialogEl.querySelectorAll(\"[data-modal-close]\").forEach((btn) => {\n btn.addEventListener(\"click\", () => closeModal(dialogEl));\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["$", "boardMenuBtn", "boardFlyout", "kanban", "drawer", "drawerInner", "drawerBackdrop", "createFlyout", "createFlyoutInner", "createFlyoutBackdrop", "searchInput", "searchResults", "themeToggle", "themeIcon", "init_dom", "__esmMin", "selector", "safeStorage", "storage", "defaultMediaMatcher", "query", "storedReducedMotionPreference", "value", "REDUCE_MOTION_STORAGE_KEY", "browserPrefersReducedMotion", "mediaMatcher", "effectiveReducedMotionPreference", "setReducedMotionPreference", "reduce", "store", "applyReducedMotionPreference", "doc", "init_motion_preference", "__esmMin", "safeStorage", "storage", "safeDocument", "doc", "safeEventTarget", "eventTarget", "normalizeTheme", "theme", "THEMES", "storedThemePreference", "value", "THEME_STORAGE_KEY", "currentTheme", "rootTheme", "applyStoredThemePreference", "storedTheme", "setThemePreference", "notify", "next", "dispatchThemeChange", "toggleThemePreference", "options", "target", "THEME_CHANGE_EVENT", "init_theme_preference", "__esmMin", "normalizeSettingsTab", "raw", "SETTINGS_TAB_IDS", "init_settings_tabs", "__esmMin", "getSettingsTab", "normalizeSettingsTab", "state", "syncBoardSelection", "boards", "board", "b", "activeBoardId", "currentBoard", "boardLabelCatalog", "label", "statesForProject", "item", "isAiReadyState", "visibleStatesForProject", "states", "selectableStatesForProject", "currentStateId", "ticketsForProject", "init_state", "__esmMin", "init_settings_tabs", "escapeHtml", "value", "sanitizeMarkdownUrl", "href", "compact", "scheme", "SAFE_LINK_PROTOCOLS", "renderEmphasis", "text", "html", "renderLinksAndEmphasis", "linkPattern", "lastIndex", "match", "labelHtml", "renderInlineMarkdown", "source", "cursor", "codeStart", "codeEnd", "renderParagraph", "lines", "renderMarkdown", "blocks", "paragraph", "list", "flushParagraph", "flushList", "item", "i", "line", "codeLines", "ordered", "unordered", "type", "formatDate", "formatDateDetail", "ticketLabel", "ticket", "canonicalTicketType", "typeLabel", "typeLabelLong", "priorityLabel", "priority", "priorityKeyFor", "keys", "n", "renderLabels", "labels", "label", "repoLabelFromUrl", "repoUrl", "raw", "githubHttps", "githubSsh", "init_format", "__esmMin", "ensureToastContainer", "toastContainer", "toast", "message", "type", "duration", "container", "node", "icon", "toastIcons", "escapeHtml", "dismissToast", "timer", "t2", "downloadJson", "filename", "value", "blob", "url", "anchor", "debounce", "fn", "wait", "args", "init_toast", "__esmMin", "init_format", "msg", "dur", "request", "method", "path", "body", "headers", "finalHeaders", "response", "text", "payload", "error", "init_transport", "__esmMin", "bootstrapPath", "state", "withBoardQuery", "path", "sep", "api", "options", "request", "err", "toast", "init_api", "__esmMin", "init_state", "init_toast", "init_transport", "openDrawer", "drawerToken", "drawer", "drawerBackdrop", "closeDrawer", "finishToken", "wasOpen", "finish", "drawerInner", "eyebrowEl", "titleEl", "subtitleEl", "tabsEl", "attr", "ended", "end", "renderDrawerShell", "eyebrow", "title", "titleAttrs", "subtitleHtml", "tabs", "activeTab", "onTabSelect", "body", "mode", "key", "value", "t", "escapeHtml", "btn", "archiveBtn", "state", "init_drawer", "__esmMin", "init_dom", "init_state", "init_format", "normalize", "raw", "getMap", "boardId", "m", "cache", "READ_KEY", "obj", "k", "v", "persist", "entryFor", "ticketId", "e", "unreadCount", "ticket", "state", "SEEDED_KEY", "markRead", "timestamp", "bumpUnread", "clearUnread", "seedReadIfNeeded", "tickets", "t", "init_unread", "__esmMin", "init_state", "renderBoard", "states", "visibleStatesForProject", "tickets", "ticketsForProject", "kanban", "column", "renderColumn", "event", "ticketId", "closeCreateFlyout", "api", "withBoardQuery", "load", "btn", "openCreateFlyout", "header", "navigate", "state", "card", "suppressClickAfterDrag", "toggleBtn", "id", "expanded", "renderEmptyState", "columnName", "name", "flair", "escapeHtml", "columnTickets", "ticket", "isEmpty", "isAiReady", "columnClasses", "renderColumnBody", "allTickets", "epicById", "t", "canonicalTicketType", "epicIdsInColumn", "childrenByEpicId", "list", "rendered", "blocks", "children", "childrenHtml", "c", "renderCard", "epic", "siblings", "renderEpicMiniHeader", "renderTypeIcon", "ticketLabel", "renderPriorityPill", "priority", "key", "priorityKeyFor", "label", "priorityLabel", "type", "canonical", "icon", "color", "asEpicChild", "canonicalType", "priorityKey", "typeText", "typeLabel", "isExpanded", "hasDescription", "hasExpandable", "triggerInner", "unreadN", "unreadCount", "unreadDot", "renderMarkdown", "renderLabels", "enableKanbanDragScroll", "PAGE_SCROLL_PX", "active", "dragged", "startX", "startScroll", "pointerId", "shouldIgnore", "target", "wheelPixels", "value", "mode", "horizontalDelta", "delta", "endDrag", "init_kanban", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_create_card", "init_app", "init_unread", "resolvedEdition", "edition", "features", "init_config", "__esmMin", "renderProjectDetail", "context", "api", "state", "project", "activeTab", "getSettingsTab", "tabs", "features", "resolvedTab", "renderDrawerShell", "id", "navigate", "renderProjectTabBody", "bindProjectTabHandlers", "tab", "renderNotesSettingsTab", "renderProjectLanesTab", "renderProjectAppearanceTab", "renderProjectAiTab", "renderProjectJournalTab", "renderProjectArchiveTab", "renderProjectRepositoryTab", "aiEnabled", "aiDivider", "agentContextSetup", "renderAgentContextSection", "mcpSetup", "renderMcpSetupSection", "escapeHtml", "osId", "detectedMcpOs", "clientId", "paths", "mcpDetectedPaths", "configText", "mcpConfigText", "commandText", "mcpRunCommand", "client", "MCP_CLIENTS", "MCP_OS_OPTIONS", "option", "platform", "mcpDefaultPaths", "template", "mcpPathsFromForm", "$", "claudeCodeMcpCommand", "codexMcpToml", "opencodeMcpJson", "config", "escapeToml", "shellQuote", "value", "repositoryDelete", "repoLabelFromUrl", "renderDeleteBoardSection", "slug", "exportedCopy", "renderLaneManager", "theme", "currentTheme", "reduceMotion", "effectiveReducedMotionPreference", "storedMotion", "storedReducedMotionPreference", "browserDefault", "browserPrefersReducedMotion", "sourceLabel", "renderThemeOption", "label", "selectedTheme", "renderProjectEntries", "exportSnapshot", "snapshot", "downloadJson", "event", "file", "text", "load", "toast", "confirmInput", "confirmButton", "form", "drawerInner", "button", "handleLaneAction", "field", "updateLane", "renderBoard", "input", "setThemePreference", "reduce", "setReducedMotionPreference", "applyReducedMotionPreference", "updateMcpPreview", "osNote", "format", "title", "helper", "configEl", "commandEl", "selector", "copyText", "enabled", "listEl", "refresh", "tickets", "t", "renderDetailCard", "err", "restoreBtn", "deleteBtn", "cardTitle", "withBoardQuery", "textArea", "entries", "entry", "isStruck", "formatDate", "deleteDisabled", "lane", "counts", "CORE_LANE_ROLES", "deleteTitle", "count", "lanes", "statesForProject", "currentBoard", "ticket", "ticketsForProject", "index", "isAiReady", "nameTitle", "row", "laneId", "action", "btn", "swapWith", "silent", "name", "isDefault", "init_settings", "__esmMin", "init_state", "init_dom", "init_format", "init_api", "init_toast", "init_drawer", "init_router", "init_kanban", "init_ticket_detail", "init_app", "init_config", "init_motion_preference", "init_theme_preference", "patchTicket", "ticketId", "body", "api", "withBoardQuery", "load", "state", "renderDetail", "startInlineEdit", "node", "field", "initialValue", "isTextarea", "editor", "done", "commit", "next", "toast", "cancel", "event", "wireTicketDetailEditors", "ticket", "titleEl", "drawer", "descEl", "drawerInner", "select", "applyLabelPatch", "nextNames", "btn", "removeName", "names", "n", "addLabel", "input", "name", "renderProjectDetail", "openDrawer", "closeDrawer", "context", "statusHistory", "markRead", "states", "selectableStatesForProject", "typeOptions", "value", "escapeHtml", "canonicalTicketType", "typeLabelLong", "stateOptions", "s", "priorityOptions", "p", "priorityLabel", "labelPills", "label", "datalistOptions", "boardLabelCatalog", "l", "tl", "detailCanonicalType", "detailTypeText", "typeLabel", "detailSubtitleHtml", "ticketLabel", "renderTypeIcon", "renderPriorityPill", "renderDrawerShell", "formatDateDetail", "renderMarkdown", "renderHierarchySection", "renderParentEpicSection", "renderRelated", "currentBoard", "aiPlanOpen", "renderStatusHistory", "renderComment", "$", "form", "card", "navigate", "childId", "err", "relationId", "aiPlanEl", "id", "parentEpicForm", "parentInput", "parentClear", "syncParentClear", "targetLabel", "targetId", "resolveTicketIdFromLabel", "target", "ticketsForProject", "t", "relatedAddForm", "relatedInput", "relatedClear", "syncRelatedClear", "relationType", "selfId", "trimmed", "match", "tickets", "hit", "exact", "history", "from", "to", "actorType", "actorName", "actorId", "byLine", "formatDate", "comment", "relations", "relatedIds", "r", "hierarchyIds", "list", "renderRelatedCard", "cards", "c", "renderDetailCard", "options", "canonicalType", "priorityKey", "priorityKeyFor", "typeText", "eyebrow", "detachBtn", "mode", "attr", "tid", "unreadN", "unreadCount", "unreadDot", "relation", "verb", "direction", "init_ticket_detail", "__esmMin", "init_state", "init_dom", "init_format", "init_kanban", "init_drawer", "init_router", "init_api", "init_toast", "init_app", "init_settings", "init_unread", "connectEventStream", "sseReconnectTimer", "state", "params", "url", "es", "sseReconnectDelayMs", "sseDisconnectToastShown", "toast", "msg", "event", "eventType", "findTicket", "t", "me", "isMine", "markRead", "clearUnread", "CARD_TOUCHING_EVENTS", "bumpUnread", "scheduleSSEReload", "ticket", "label", "fields", "delay", "init_sse", "__esmMin", "init_state", "init_api", "init_toast", "init_app", "init_unread", "debounce", "selectedId", "mode", "api", "bootstrapPath", "syncBoardSelection", "render", "app_exports", "__export", "load", "render", "closeMenuFlyouts", "state", "api", "bootstrapPath", "syncBoardSelection", "seedReadIfNeeded", "features", "sseBoardId", "connectEventStream", "updateTopbarChips", "renderBoard", "renderDetail", "init_app", "__esmMin", "init_state", "init_api", "init_kanban", "init_ticket_detail", "init_board_menu", "init_sse", "init_unread", "init_config", "isCreateFlyoutOpen", "createFlyout", "openCreateFlyout", "preselectedLaneId", "createFlyoutHideTimer", "closeMenuFlyouts", "closeDrawer", "createFlyoutInner", "renderCreateForm", "wireCreateForm", "$", "closeCreateFlyout", "createFlyoutBackdrop", "states", "visibleStatesForProject", "defaultState", "item", "effectiveStateId", "s", "stateOptions", "escapeHtml", "parentOptions", "ticketsForProject", "ticket", "ticketLabel", "form", "createTicketFromDrawer", "event", "data", "labels", "created", "api", "state", "load", "syncUrlFromState", "init_create_card", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_drawer", "init_board_menu", "init_app", "closeBoardFlyout", "boardFlyout", "boardMenuBtn", "closeMenuFlyouts", "updateTopbarChips", "state", "board", "b", "renderBoardFlyoutInner", "listBody", "escapeHtml", "createBlock", "features", "wireBoardFlyout", "btn", "event", "id", "closeCreateFlyout", "navigate", "form", "pickRepoFolderBtn", "repoPathInput", "result", "api", "error", "toast", "fd", "slug", "branch", "repo", "repoPath", "created", "load", "syncUrlFromState", "openBoardFlyout", "init_board_menu", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_create_card", "init_toast", "init_app", "init_config", "emptyRoute", "EMPTY_ROUTE", "normalizeLocation", "input", "url", "decodeSegment", "value", "routeSegments", "routeFromSegments", "parts", "out", "i", "tab", "SETTINGS_TAB_IDS", "parseLegacyHashRoute", "hash", "raw", "parseRoute", "loc", "hasRoute", "buildRoute", "boardSlug", "view", "ticketId", "segs", "isCanonicalRouteUrl", "routeObj", "init_url_routes", "__esmMin", "init_settings_tabs", "boardBySlugOrId", "value", "boards", "state", "b", "routeBoardSlug", "routeObj", "currentBoard", "normalizeRouteForUrl", "routeFromState", "view", "normalizeSettingsTab", "setRouterReady", "routerReady", "currentRoute", "parseRoute", "navigate", "replace", "route", "url", "buildRoute", "isCanonicalRouteUrl", "applyRoute", "syncUrlFromState", "load", "render", "r", "urlHadRoute", "hasRoute", "prevBoardId", "fallbackBoard", "canonicalRoute", "closeMenuFlyouts", "closeCreateFlyout", "init_router", "__esmMin", "init_state", "init_settings_tabs", "init_board_menu", "init_create_card", "init_url_routes", "init_dom", "init_motion_preference", "init_theme_preference", "applyStoredThemePreference", "applyReducedMotionPreference", "starscape", "startStarscape", "scheduleMeteor", "updateScrolled", "syncThemeIcon", "themeToggle", "toggleThemePreference", "THEME_CHANGE_EVENT", "themeIcon", "dark", "currentTheme", "grain", "buildSignatureStars", "canvas", "milkyWay", "ctx", "DPR", "width", "height", "stars", "rafId", "running", "mouse", "resize", "buildStars", "density", "layers", "rng", "mulberry32", "layer", "i", "size", "pickWeighted", "pickStarColor", "r", "onPointerMove", "e", "frame", "t", "time", "parallaxPx", "s", "pulse", "alpha", "px", "py", "g", "b", "radius", "grad", "half", "drawStaticFrame", "start", "stop", "sync", "isDark", "reduced", "effectiveReducedMotionPreference", "el", "SIG_COUNT", "star", "delay", "spawnMeteor", "vw", "vh", "startX", "startY", "distance", "angleDeg", "rad", "endX", "endY", "m", "table", "acc", "value", "weight", "seed", "init_dom", "init_state", "init_api", "init_toast", "init_router", "init_board_menu", "init_create_card", "init_kanban", "init_dom", "init_state", "init_api", "init_router", "init_format", "init_create_card", "runSearch", "query", "searchInput", "hideSearch", "board", "currentBoard", "result", "api", "searchResults", "ticket", "escapeHtml", "ticketLabel", "hit", "closeCreateFlyout", "navigate", "state", "init_app", "init_config", "openModal", "dialogEl", "closeModal", "wireModal", "event", "btn", "init", "welcomeDialog", "wireModal", "edition", "openModal", "$", "closeCreateFlyout", "closeMenuFlyouts", "navigate", "state", "boardMenuBtn", "event", "boardFlyout", "closeBoardFlyout", "openBoardFlyout", "isCreateFlyoutOpen", "openCreateFlyout", "createFlyoutBackdrop", "ticketId", "titleForToast", "t", "api", "withBoardQuery", "toast", "load", "drawerBackdrop", "drawer", "el", "searchInput", "debounce", "runSearch", "hideSearch", "enableKanbanDragScroll", "initialRoute", "currentRoute", "setRouterReady", "hasRoute", "applyRoute", "syncUrlFromState"]
|
|
7
|
-
}
|