@starlove/orbit 1.3.5 → 1.4.1
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/Dockerfile +2 -1
- package/README.md +10 -9
- package/SKILL-ORBIT.md +41 -17
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/OFL.txt +93 -0
- package/dist/full/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/dist/full/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/dist/full/fonts/Inter/OFL.txt +93 -0
- package/dist/full/fonts/Inter/README.txt +118 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/JetBrains_Mono/OFL.txt +93 -0
- package/dist/full/fonts/JetBrains_Mono/README.txt +79 -0
- package/dist/full/fonts/OpenRing-Regular.ttf +0 -0
- package/dist/full/fonts/Open_Sans/OFL.txt +93 -0
- package/dist/full/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/dist/full/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/dist/full/fonts/Open_Sans/README.txt +100 -0
- package/dist/full/fonts/Orbitron/OFL.txt +93 -0
- package/dist/full/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/Orbitron/README.txt +68 -0
- package/dist/full/fonts/Rajdhani/OFL.txt +93 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/dist/full/fonts/runescape-uf.ttf +0 -0
- package/dist/full/index.html +135 -25
- package/dist/full/js/app.4e6fbe20.js +952 -0
- package/dist/full/js/app.4e6fbe20.js.map +7 -0
- package/dist/full/styles.4e60d824.css +1 -0
- package/dist/full/version.json +2 -2
- package/docs/AGENT_PROTOCOL.md +20 -13
- package/docs/ORBIT_DISPATCH.md +73 -38
- package/docs/UPDATING.md +114 -0
- package/package.json +5 -7
- package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/OFL.txt +93 -0
- package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/OFL.txt +93 -0
- package/public/fonts/Inter/README.txt +118 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/OFL.txt +93 -0
- package/public/fonts/JetBrains_Mono/README.txt +79 -0
- package/public/fonts/OpenRing-Regular.ttf +0 -0
- package/public/fonts/Open_Sans/OFL.txt +93 -0
- package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/README.txt +100 -0
- package/public/fonts/Orbitron/OFL.txt +93 -0
- package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/public/fonts/Orbitron/README.txt +68 -0
- package/public/fonts/Rajdhani/OFL.txt +93 -0
- package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/public/fonts/runescape-uf.ttf +0 -0
- package/public/index.html +133 -23
- package/public/js/artifact-drawer.js +79 -0
- package/public/js/board-export.js +161 -0
- package/public/js/board-menu.js +219 -17
- package/public/js/card-actions.js +1 -1
- package/public/js/create-card.js +60 -23
- package/public/js/drawer.js +164 -4
- package/public/js/font-preference.js +230 -0
- package/public/js/format.js +0 -10
- package/public/js/icons.js +16 -0
- package/public/js/local-backend.js +31 -4
- package/public/js/main.js +7 -1
- package/public/js/modal.js +3 -1
- package/public/js/panel.js +58 -0
- package/public/js/settings-tabs.js +1 -1
- package/public/js/settings.js +606 -275
- package/public/js/sse.js +3 -0
- package/public/js/state.js +1 -1
- package/public/js/text-editing.js +128 -0
- package/public/js/ticket-detail.js +377 -148
- package/public/js/ticket-typeahead.js +49 -0
- package/public/js/toast.js +19 -4
- package/public/js/topbar-notes.js +3 -3
- package/public/js/typeahead.js +206 -0
- package/public/js/update-check.js +58 -0
- package/public/styles.css +5447 -3572
- package/src/cli/orbit.js +9 -5
- package/src/core/agent.js +12 -4
- package/src/core/agents-md.js +3 -3
- package/src/core/artifacts.js +149 -0
- package/src/core/board.js +3 -2
- package/src/core/boards.js +0 -1
- package/src/core/css-bundle.js +1 -0
- package/src/core/db.js +6 -0
- package/src/core/dispatch.js +344 -34
- package/src/core/http.js +9 -2
- package/src/core/paths.js +26 -2
- package/src/core/router.js +33 -0
- package/src/core/search.js +3 -2
- package/src/core/snapshots.js +10 -5
- package/src/core/tickets.js +34 -3
- package/src/core/util.js +3 -2
- package/src/core/version-check.js +154 -0
- package/src/mcp/orbit-client.js +18 -2
- package/src/mcp-server.js +19 -14
- package/src/server.js +28 -3
- package/dist/full/js/app.4ae80764.js +0 -742
- package/dist/full/js/app.4ae80764.js.map +0 -7
- package/dist/full/styles.b9e0c130.css +0 -1
|
@@ -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/card-actions.js", "public/js/unread.js", "public/js/kanban.js", "public/js/config.js", "public/js/settings.js", "public/js/actor-labels.js", "public/js/ticket-detail.js", "public/js/sse.js", "public/js/topbar-notes.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", "public/js/help-menu.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 // Starscape v3 `data-motion` contract (three-state; shared with the\n // ui-system-v3 package and ss-nebula). Replaces the legacy two-state\n // `data-reduced-motion=\"reduce|allow\"`:\n // \u2022 stored reduce \u2192 data-motion=\"reduce\" (always reduce)\n // \u2022 stored allow \u2192 data-motion=\"full\" (ignore OS reduce)\n // \u2022 no stored pref \u2192 no attribute (follow OS prefers-reduced-motion)\n const root = doc?.documentElement;\n const stored = storedReducedMotionPreference(storage);\n if (root) {\n if (stored === true) root.setAttribute(\"data-motion\", \"reduce\");\n else if (stored === false) root.setAttribute(\"data-motion\", \"full\");\n else root.removeAttribute(\"data-motion\");\n }\n return effectiveReducedMotionPreference({ storage, mediaMatcher });\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\nfunction systemTheme() {\n try {\n return globalThis.matchMedia?.(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n } catch {\n return \"light\";\n }\n}\n\nexport function currentTheme({ doc = safeDocument(), storage = safeStorage() } = {}) {\n const rootTheme = safeDocument(doc)?.documentElement?.getAttribute?.(\"data-theme\");\n if (THEMES.has(rootTheme)) return rootTheme;\n return storedThemePreference(storage) ?? systemTheme();\n}\n\nexport function applyStoredThemePreference({\n doc = safeDocument(),\n storage = safeStorage()\n} = {}) {\n const theme = storedThemePreference(storage) ?? systemTheme();\n safeDocument(doc)?.documentElement?.setAttribute?.(\"data-theme\", theme);\n return theme;\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\nfunction compactTicketForBoard(ticket) {\n if (!ticket) return null;\n return {\n id: ticket.id,\n board_id: ticket.board_id,\n board_slug: ticket.board_slug,\n number: ticket.number,\n title: ticket.title,\n type: ticket.type,\n state_name: ticket.state_name,\n state_role: ticket.state_role,\n priority: ticket.priority\n };\n}\n\nfunction refreshBoardTicketDerivatives(boardId) {\n if (!state.data?.tickets) return;\n const boardTickets = state.data.tickets.filter((ticket) => ticket.board_id === boardId && !ticket.archived_at);\n const ticketById = new Map(boardTickets.map((ticket) => [ticket.id, ticket]));\n const childCountByParent = new Map();\n for (const ticket of boardTickets) {\n if (!ticket.parent_ticket_id) continue;\n childCountByParent.set(ticket.parent_ticket_id, (childCountByParent.get(ticket.parent_ticket_id) || 0) + 1);\n }\n for (const ticket of boardTickets) {\n ticket.parent_ticket = ticket.parent_ticket_id ? compactTicketForBoard(ticketById.get(ticket.parent_ticket_id)) : null;\n ticket.child_count = childCountByParent.get(ticket.id) || 0;\n }\n}\n\n/** Merge a ticket returned by a mutation/context endpoint into the bootstrap cache.\n * Keeps drawer edits responsive without paying for a full /api/bootstrap reload. */\nexport function upsertTicket(updatedTicket) {\n if (!state.data?.tickets || !updatedTicket?.id) return;\n const index = state.data.tickets.findIndex((ticket) => ticket.id === updatedTicket.id);\n const previous = index >= 0 ? state.data.tickets[index] : {};\n const merged = {\n ...previous,\n ...updatedTicket,\n labels: updatedTicket.labels || previous.labels || [],\n comment_count: updatedTicket.comment_count ?? previous.comment_count ?? 0,\n child_count: updatedTicket.child_count ?? previous.child_count ?? 0,\n parent_ticket: updatedTicket.parent_ticket || previous.parent_ticket || null\n };\n if (index >= 0) state.data.tickets.splice(index, 1, merged);\n else state.data.tickets.push(merged);\n state.data.tickets.sort((a, b) => String(b.updated_at || \"\").localeCompare(String(a.updated_at || \"\")) || String(a.id).localeCompare(String(b.id)));\n refreshBoardTicketDerivatives(merged.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\n// UTF-8 bytes mis-decoded as CP-437 (the typical Windows-tmux artifact).\n// Ported from a local fix-newlines utility \u2014 every entry is [mojibake sequence,\n// what it should have been]. Long sequences first so shorter prefixes do not\n// eat them.\nconst MOJIBAKE_REPLACEMENTS = [\n // General Punctuation (UTF-8 E2 80 XX \u2192 CP-437 \"\u0393\u00C7\" + glyph)\n [\"\u0393\u00C7\u00F4\", \"\u2013\"],\n [\"\u0393\u00C7\u00F6\", \"\u2014\"],\n [\"\u0393\u00C7\u00A3\", '\"'],\n [\"\u0393\u00C7\u00A5\", '\"'],\n [\"\u0393\u00C7\u00FF\", \"'\"],\n [\"\u0393\u00C7\u00D6\", \"'\"],\n [\"\u0393\u00C7\u00AA\", \"\u2026\"],\n [\"\u0393\u00C7\u00F3\", \"\u2022\"],\n [\"\u0393\u00C7\u2591\", \"\u2030\"],\n [\"\u0393\u00C7\u2563\", \"\u2039\"],\n [\"\u0393\u00C7\u2551\", \"\u203A\"],\n\n // Box drawing \u2014 light (UTF-8 E2 94 XX \u2192 CP-437 \"\u0393\u00F6\" + glyph)\n [\"\u0393\u00F6\u00C7\", \"\u2500\"],\n [\"\u0393\u00F6\u00E9\", \"\u2502\"],\n [\"\u0393\u00F6\u00EE\", \"\u250C\"],\n [\"\u0393\u00F6\u00C9\", \"\u2510\"],\n [\"\u0393\u00F6\u00F6\", \"\u2514\"],\n [\"\u0393\u00F6\u00FF\", \"\u2518\"],\n [\"\u0393\u00F6\u00A3\", \"\u251C\"],\n [\"\u0393\u00F6\u00F1\", \"\u2524\"],\n [\"\u0393\u00F6\u00BC\", \"\u252C\"],\n [\"\u0393\u00F6\u2524\", \"\u2534\"],\n [\"\u0393\u00F6\u255D\", \"\u253C\"],\n\n // Box drawing \u2014 heavy/double + rounded corners (UTF-8 E2 95 XX \u2192 \"\u0393\u00F2\" + glyph)\n [\"\u0393\u00F2\u00C9\", \"\u2550\"],\n [\"\u0393\u00F2\u00E6\", \"\u2551\"],\n [\"\u0393\u00F2\u00C6\", \"\u2552\"],\n [\"\u0393\u00F2\u00F6\", \"\u2554\"],\n [\"\u0393\u00F2\u00A1\", \"\u256D\"],\n [\"\u0393\u00F2\u00AB\", \"\u256E\"],\n [\"\u0393\u00F2\u00BB\", \"\u256F\"],\n [\"\u0393\u00F2\u2591\", \"\u2570\"],\n\n // Geometric shapes (UTF-8 E2 96 XX / E2 97 XX \u2192 \"\u0393\u00FB\" / \"\u0393\u00F9\" + glyph)\n [\"\u0393\u00FB\u00E6\", \"\u2591\"],\n [\"\u0393\u00FB\u00C6\", \"\u2592\"],\n [\"\u0393\u00FB\u00F4\", \"\u2593\"],\n [\"\u0393\u00FB\u00C9\", \"\u2590\"],\n [\"\u0393\u00FB\u00EE\", \"\u258C\"],\n [\"\u0393\u00FB\u00C4\", \">\"],\n [\"\u0393\u00FB\u00E1\", \"\u25A0\"],\n [\"\u0393\u00FB\u255D\", \"\u25BC\"],\n [\"\u0393\u00F9\u00C5\", \"\u25CF\"],\n [\"\u0393\u00F9\u00EF\", \"\u25CB\"],\n\n // Misc symbols (UTF-8 E2 9A XX \u2192 \"\u0393\u00DC\" + glyph)\n [\"\u0393\u00DC\u00F2\", \"\u2695\"],\n [\"\u0393\u00DC\u00E1\", \"\u26A0\"],\n [\"\u0393\u00DC\u00ED\", \"\u26A1\"],\n [\"\u0393\u00DC\u00F4\", \"\u2693\"],\n\n // Arrows (UTF-8 E2 86 XX \u2192 \"\u0393\u00E5\" + glyph)\n [\"\u0393\u00E5\u00C9\", \"\u2190\"],\n [\"\u0393\u00E5\u00E6\", \"\u2191\"],\n [\"\u0393\u00E5\u00C6\", \"\u2192\"],\n [\"\u0393\u00E5\u00F4\", \"\u2193\"],\n [\"\u0393\u00E5\u00F6\", \"\u2194\"],\n\n // Latin-1 Supplement (UTF-8 C2 XX \u2192 CP-437 \"\u252C\" + glyph)\n [\"\u252C\u00E1\", \" \"],\n [\"\u252C\u2310\", \"\u00A9\"],\n [\"\u252C\u00AB\", \"\u00AE\"],\n [\"\u252C\u2591\", \"\u00B0\"],\n [\"\u252C\u00BA\", \"\u00A7\"],\n [\"\u252C\u2556\", \"\u00B7\"],\n\n // Stray curly quotes that survived as proper Unicode; normalize to ASCII\n // straight quotes so pasted terminal/log text stays consistent.\n [\"\u201C\", '\"'],\n [\"\u201D\", '\"'],\n [\"\u2018\", \"'\"],\n [\"\u2019\", \"'\"],\n];\n\nfunction fixMojibake(text) {\n if (!text) return text;\n let out = text;\n for (const [from, to] of MOJIBAKE_REPLACEMENTS) {\n out = out.split(from).join(to);\n }\n return out;\n}\n\n/**\n * Repair common mojibake and normalize line endings without disturbing the\n * author's indentation or soft line breaks. Use this on inbound text before\n * saving (so the DB stays clean going forward) and again before rendering (so\n * existing dirty rows display fixed without a migration).\n */\nexport function cleanText(value) {\n if (!value) return \"\";\n return fixMojibake(String(value)).replace(/\\r\\n?/g, \"\\n\");\n}\n\nexport function renderPreservedText(value) {\n return escapeHtml(cleanText(value));\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\nfunction renderTaskItem(rawContent) {\n // GFM-style `- [ ] text` or `- [x] text`. We render as a disabled checkbox\n // followed by the inline-rendered remainder. The list itself gets a\n // `task-list` class so CSS can drop the default bullet.\n const match = rawContent.match(/^\\[( |x|X)\\]\\s+(.*)$/);\n if (!match) return null;\n const checked = match[1].toLowerCase() === \"x\";\n const body = renderInlineMarkdown(match[2].trim()).replaceAll(\"\\n\", \"<br>\");\n return {\n checked,\n html: `<input type=\"checkbox\" disabled${checked ? \" checked\" : \"\"}> ${body}`,\n };\n}\n\nexport function renderMarkdown(value) {\n // Mojibake repair runs at render time too so existing dirty rows display\n // cleanly without a backfill. cleanText also normalizes line endings.\n const source = cleanText(value);\n if (!source.trim()) return \"\";\n\n const blocks = [];\n const lines = source.split(\"\\n\");\n let paragraph = [];\n let list = null;\n let blockquote = 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 const classAttr = list.taskList ? ' class=\"task-list\"' : \"\";\n blocks.push(\n `<${list.type}${classAttr}>${list.items\n .map((item) => `<li${item.taskClass ? ` class=\"${item.taskClass}\"` : \"\"}>${item.html}</li>`)\n .join(\"\")}</${list.type}>`\n );\n list = null;\n };\n\n const flushBlockquote = () => {\n if (!blockquote) return;\n blocks.push(`<blockquote>${renderMarkdown(blockquote.join(\"\\n\"))}</blockquote>`);\n blockquote = null;\n };\n\n const flushAll = () => {\n flushParagraph();\n flushList();\n flushBlockquote();\n };\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i];\n\n if (/^\\s*```/.test(line)) {\n flushAll();\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 // Horizontal rule: a line of three+ dashes / asterisks / underscores.\n if (/^\\s*(?:-\\s*){3,}\\s*$/.test(line) || /^\\s*(?:\\*\\s*){3,}\\s*$/.test(line) || /^\\s*(?:_\\s*){3,}\\s*$/.test(line)) {\n flushAll();\n blocks.push(\"<hr>\");\n continue;\n }\n\n // ATX header: 1-6 # followed by a space and content.\n const header = line.match(/^\\s{0,3}(#{1,6})\\s+(.+?)\\s*#*\\s*$/);\n if (header) {\n flushAll();\n const level = header[1].length;\n blocks.push(`<h${level}>${renderInlineMarkdown(header[2])}</h${level}>`);\n continue;\n }\n\n // Blockquote: `> ...`. We collect consecutive `>` lines, strip the leading\n // marker, and recurse so quoted content can itself contain lists/headers.\n const quoteMatch = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quoteMatch) {\n flushParagraph();\n flushList();\n if (!blockquote) blockquote = [];\n blockquote.push(quoteMatch[1]);\n continue;\n }\n if (blockquote && !line.trim()) {\n flushBlockquote();\n continue;\n }\n flushBlockquote();\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 const content = (ordered || unordered)[1].trim();\n\n let task = null;\n if (unordered) task = renderTaskItem(content);\n\n if (!list || list.type !== type || Boolean(list.taskList) !== Boolean(task)) {\n flushList();\n list = { type, items: [], taskList: Boolean(task) };\n }\n\n if (task) {\n list.items.push({\n html: task.html,\n taskClass: task.checked ? \"task-item task-item-done\" : \"task-item\",\n });\n } else {\n list.items.push({\n html: renderInlineMarkdown(content).replaceAll(\"\\n\", \"<br>\"),\n });\n }\n continue;\n }\n\n flushList();\n paragraph.push(line);\n }\n\n flushAll();\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 stateClassFor(ticketOrState) {\n const source =\n ticketOrState?.state_role || ticketOrState?.role || ticketOrState?.state_name || ticketOrState?.name || \"state\";\n return String(source)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\") || \"state\";\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.\nexport function typeLabelLong(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\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 titleBlockEl = document.getElementById(\"drawerTitleBlock\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n if (titleBlockEl) titleBlockEl.innerHTML = \"\";\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 titleBlockEl = document.getElementById(\"drawerTitleBlock\");\n const tabsEl = document.getElementById(\"drawerTabs\");\n\n // Rebuild the eyebrow / title / subtitle wholesale each render. Like\n // drawerInner.innerHTML below, this means any listeners the caller attached\n // last render (e.g. the inline title editor's click handler) die with the\n // old nodes, instead of stacking on persistent shell elements.\n const extraTitleClass = titleAttrs?.class ? ` ${titleAttrs.class}` : \"\";\n let titleAttrHtml = ` class=\"drawer-title drawer-title-text${extraTitleClass}\"`;\n for (const [key, value] of Object.entries(titleAttrs || {})) {\n if (key === \"class\") continue;\n titleAttrHtml += ` ${key}=\"${escapeHtml(String(value))}\"`;\n }\n const segments = [];\n if (eyebrow) segments.push(`<span class=\"drawer-eyebrow\">${escapeHtml(eyebrow)}</span>`);\n segments.push(`<h2${titleAttrHtml}>${escapeHtml(title ?? \"\")}</h2>`);\n if (subtitleHtml) segments.push(`<div class=\"drawer-subtitle\">${subtitleHtml}</div>`);\n titleBlockEl.innerHTML = segments.join(\"\");\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", "// Shared card action menu data, mutations, and desktop context-menu presentation.\n// Mobile can reuse buildCardActionMenu() + createCardActionHandlers() and render\n// the same model as a bottom sheet without duplicating mutation logic.\n//\n// Submenus are reparented to document.body on open so they escape the menu's\n// backdrop-filter containing block (otherwise position: fixed coords would be\n// interpreted relative to the menu instead of the viewport).\n\nimport { api, withBoardQuery } from \"./api.js\";\nimport { state, visibleStatesForProject } from \"./state.js\";\nimport { canonicalTicketType, escapeHtml, priorityLabel, typeLabel } from \"./format.js\";\nimport { toast } from \"./toast.js\";\n\nconst CARD_TYPES = [\"epic\", \"feature\", \"task\", \"bug\"];\nconst PRIORITIES = [0, 1, 2, 3, 4];\nconst MENU_MARGIN = 8;\nconst SUBMENU_GAP = 6;\nconst HOVER_CLOSE_DELAY = 180;\n\nlet openMenu = null;\nlet dragInFlight = false;\nlet dismissController = null;\nlet lastFocusedElement = null;\nconst submenuByItem = new WeakMap();\nconst itemBySubmenu = new WeakMap();\nconst openSubmenus = new Set();\nlet pendingCloseTimer = null;\n\nexport function buildCardActionMenu(ticket, lanes = visibleStatesForProject()) {\n if (!ticket) return [];\n return [\n {\n id: \"move\",\n label: \"Move to\",\n children: lanes.map((lane) => ({\n id: `move:${lane.id}`,\n label: lane.name,\n action: \"move\",\n value: lane.id,\n checked: lane.id === ticket.state_id,\n disabled: lane.id === ticket.state_id\n }))\n },\n {\n id: \"priority\",\n label: \"Priority\",\n children: PRIORITIES.map((priority) => ({\n id: `priority:${priority}`,\n label: priorityLabel(priority),\n action: \"priority\",\n value: priority,\n checked: Number(ticket.priority) === priority,\n disabled: Number(ticket.priority) === priority\n }))\n },\n {\n id: \"type\",\n label: \"Type\",\n children: CARD_TYPES.map((type) => ({\n id: `type:${type}`,\n label: typeLabel(type),\n action: \"type\",\n value: type,\n checked: canonicalTicketType(ticket.type) === type,\n disabled: canonicalTicketType(ticket.type) === type\n }))\n },\n { id: \"open\", label: \"Open\", action: \"open\" },\n { id: \"archive\", label: \"Archive\", action: \"archive\", danger: true }\n ];\n}\n\nexport function calculateMenuPosition({ x, y, menuWidth, menuHeight, viewportWidth, viewportHeight, margin = MENU_MARGIN }) {\n const maxLeft = Math.max(margin, viewportWidth - menuWidth - margin);\n const maxTop = Math.max(margin, viewportHeight - menuHeight - margin);\n const preferredLeft = x + menuWidth + margin > viewportWidth ? x - menuWidth : x;\n const preferredTop = y + menuHeight + margin > viewportHeight ? y - menuHeight : y;\n return {\n left: Math.min(Math.max(margin, preferredLeft), maxLeft),\n top: Math.min(Math.max(margin, preferredTop), maxTop)\n };\n}\n\nexport function calculateSubmenuPosition({\n triggerRect,\n submenuWidth,\n submenuHeight,\n viewportWidth,\n viewportHeight,\n margin = MENU_MARGIN,\n gap = SUBMENU_GAP\n}) {\n const maxLeft = Math.max(margin, viewportWidth - submenuWidth - margin);\n const rightLeft = triggerRect.right + gap;\n const leftLeft = triggerRect.left - submenuWidth - gap;\n const fitsRight = rightLeft + submenuWidth + margin <= viewportWidth;\n const fitsLeft = leftLeft >= margin;\n const preferredLeft = fitsRight || !fitsLeft ? rightLeft : leftLeft;\n const maxHeight = Math.max(0, viewportHeight - margin * 2);\n const boundedHeight = Math.min(submenuHeight, maxHeight);\n const maxTop = Math.max(margin, viewportHeight - boundedHeight - margin);\n const preferredTop = triggerRect.top - gap;\n\n return {\n left: Math.min(Math.max(margin, preferredLeft), maxLeft),\n top: Math.min(Math.max(margin, preferredTop), maxTop),\n maxHeight\n };\n}\n\nexport function createCardActionHandlers({ apiClient = api, navigator = null, confirmer = globalThis.confirm } = {}) {\n async function patchTicket(ticket, body) {\n await apiClient(withBoardQuery(`/api/tickets/${encodeURIComponent(ticket.id)}`), {\n method: \"PATCH\",\n body\n });\n }\n\n return {\n async open(ticket) {\n if (navigator) return navigator({ boardId: state.boardId, view: \"ticket\", ticketId: ticket.id });\n return null;\n },\n async move(ticket, stateId) {\n await patchTicket(ticket, { state_id: stateId });\n },\n async priority(ticket, priority) {\n await patchTicket(ticket, { priority });\n },\n async type(ticket, type) {\n await patchTicket(ticket, { type });\n },\n async archive(ticket) {\n if (typeof confirmer === \"function\" && !confirmer(`Archive \"${ticket.title || \"card\"}\"? You can restore it from Settings \u2192 Card Archive.`)) return false;\n await apiClient(withBoardQuery(`/api/tickets/${encodeURIComponent(ticket.id)}/archive`), { method: \"POST\" });\n toast.error(`Archived: ${ticket.title || \"card\"}`);\n return true;\n }\n };\n}\n\nexport function setCardActionDragInFlight(value) {\n dragInFlight = Boolean(value);\n}\n\nexport function closeCardActionMenu({ restoreFocus = false } = {}) {\n cancelPendingClose();\n if (dismissController) {\n dismissController.abort();\n dismissController = null;\n }\n for (const submenu of openSubmenus) {\n if (submenu.isConnected) submenu.remove();\n }\n openSubmenus.clear();\n if (openMenu) {\n openMenu.querySelectorAll(\".card-action-menu-item.has-submenu\").forEach((item) => {\n const submenu = submenuByItem.get(item);\n if (submenu?.isConnected) submenu.remove();\n submenuByItem.delete(item);\n });\n openMenu.remove();\n openMenu = null;\n }\n if (restoreFocus && lastFocusedElement?.isConnected) {\n lastFocusedElement.focus({ preventScroll: true });\n }\n lastFocusedElement = null;\n}\n\nexport function openCardActionMenu({ ticket, anchor, x, y, handlers = createCardActionHandlers(), onBeforeOpen = null }) {\n closeCardActionMenu();\n if (!ticket || dragInFlight) return null;\n\n if (typeof onBeforeOpen === \"function\") onBeforeOpen();\n lastFocusedElement = anchor || document.activeElement;\n\n const menu = document.createElement(\"div\");\n menu.className = \"card-action-menu\";\n menu.setAttribute(\"role\", \"menu\");\n menu.setAttribute(\"aria-label\", `Actions for #${ticket.number || \"\"} ${ticket.title || \"card\"}`.trim());\n menu.dataset.ticketId = ticket.id;\n menu.innerHTML = renderMenuItems(buildCardActionMenu(ticket));\n document.body.append(menu);\n openMenu = menu;\n\n // Detach each submenu from its <li> and reparent to document.body. The menu's\n // backdrop-filter creates a containing block, so a nested position:fixed\n // submenu would be positioned relative to the menu, not the viewport.\n menu.querySelectorAll(\".card-action-menu-item.has-submenu\").forEach((item) => {\n const submenu = item.querySelector(\":scope > .card-action-submenu\");\n if (!submenu) return;\n submenu.remove();\n document.body.append(submenu);\n submenuByItem.set(item, submenu);\n itemBySubmenu.set(submenu, item);\n wireSubmenu(submenu, ticket, handlers);\n });\n\n const rect = menu.getBoundingClientRect();\n const position = calculateMenuPosition({\n x,\n y,\n menuWidth: rect.width,\n menuHeight: rect.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight\n });\n menu.style.left = `${position.left}px`;\n menu.style.top = `${position.top}px`;\n\n wireMenu(menu, ticket, handlers);\n const first = firstEnabledItem(menu);\n first?.focus({ preventScroll: true });\n\n dismissController = new AbortController();\n const signal = dismissController.signal;\n requestAnimationFrame(() => {\n document.addEventListener(\"pointerdown\", dismissOnOutsidePointer, { signal, capture: true });\n });\n document.addEventListener(\"keydown\", dismissOnEscape, { signal, capture: true });\n document.addEventListener(\"scroll\", dismissOnScroll, { signal, capture: true, passive: true });\n window.addEventListener(\"resize\", () => closeCardActionMenu(), { signal, passive: true });\n window.addEventListener(\"blur\", () => closeCardActionMenu(), { signal });\n\n return menu;\n}\n\nexport function bindCardContextMenu(card, ticket, { handlers = createCardActionHandlers(), onBeforeOpen = null } = {}) {\n card.addEventListener(\"contextmenu\", (event) => {\n event.preventDefault();\n event.stopPropagation();\n if (dragInFlight) {\n closeCardActionMenu();\n return;\n }\n openCardActionMenu({\n ticket,\n anchor: card,\n x: event.clientX,\n y: event.clientY,\n handlers,\n onBeforeOpen\n });\n });\n}\n\n// Delegated variant: a single listener on the board container resolves the card\n// and its ticket per event. Lets renderBoard() swap innerHTML freely without\n// re-binding a contextmenu listener onto every card on every render.\nexport function bindCardContextMenuDelegated(container, resolveTicket, { handlers = createCardActionHandlers(), onBeforeOpen = null } = {}) {\n container.addEventListener(\"contextmenu\", (event) => {\n const card = event.target instanceof Element ? event.target.closest(\".card\") : null;\n if (!card) return;\n const ticket = resolveTicket(card.dataset.ticketId);\n if (!ticket) return;\n event.preventDefault();\n event.stopPropagation();\n if (dragInFlight) {\n closeCardActionMenu();\n return;\n }\n openCardActionMenu({ ticket, anchor: card, x: event.clientX, y: event.clientY, handlers, onBeforeOpen });\n });\n}\n\nfunction renderMenuItems(items) {\n return `<ul class=\"card-action-menu-list\" role=\"none\">${items.map(renderMenuItem).join(\"\")}</ul>`;\n}\n\nfunction renderMenuItem(item) {\n const hasChildren = Boolean(item.children?.length);\n const classes = [\"card-action-menu-item\"];\n if (hasChildren) classes.push(\"has-submenu\");\n if (item.danger) classes.push(\"is-danger\");\n const check = item.checked ? `<span class=\"card-action-check\" aria-hidden=\"true\">\u2713</span>` : `<span class=\"card-action-check\" aria-hidden=\"true\"></span>`;\n const suffix = hasChildren ? `<span class=\"card-action-arrow\" aria-hidden=\"true\">\u203A</span>` : \"\";\n return `\n <li class=\"${classes.join(\" \")}\" role=\"none\">\n <button type=\"button\"\n class=\"card-action-button\"\n role=\"menuitem${item.checked ? \"checkbox\" : \"\"}\"\n data-action=\"${escapeHtml(item.action || \"\")}\" data-value=\"${escapeHtml(item.value ?? \"\")}\" data-menu-id=\"${escapeHtml(item.id)}\"\n ${item.disabled ? \"disabled\" : \"\"}\n ${item.checked ? 'aria-checked=\"true\"' : \"\"}\n ${hasChildren ? 'aria-haspopup=\"menu\" aria-expanded=\"false\"' : \"\"}>\n ${hasChildren ? \"\" : check}\n <span class=\"card-action-label\">${escapeHtml(item.label)}</span>\n ${suffix}\n </button>\n ${hasChildren ? `<div class=\"card-action-submenu\" role=\"menu\">${renderMenuItems(item.children)}</div>` : \"\"}\n </li>\n `;\n}\n\nfunction wireMenu(menu, ticket, handlers) {\n menu.addEventListener(\"pointerover\", (event) => {\n const item = event.target instanceof Element ? event.target.closest(\".card-action-menu-item\") : null;\n if (!item || !menu.contains(item)) return;\n if (item.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(item);\n } else {\n scheduleCloseOtherSubmenus(menu);\n }\n }, true);\n\n menu.addEventListener(\"focusin\", (event) => {\n const item = event.target instanceof Element ? event.target.closest(\".card-action-menu-item\") : null;\n if (!item || !menu.contains(item)) return;\n if (item.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(item);\n } else {\n cancelPendingClose();\n closeOpenSubmenus(menu);\n }\n });\n\n menu.addEventListener(\"click\", (event) => handleItemClick(event, menu, ticket, handlers));\n menu.addEventListener(\"keydown\", (event) => handleMenuKeydown(event, menu));\n}\n\nfunction wireSubmenu(submenu, ticket, handlers) {\n // Keep the submenu open while the pointer is inside it.\n submenu.addEventListener(\"pointerenter\", cancelPendingClose);\n submenu.addEventListener(\"pointerover\", (event) => {\n if (event.target instanceof Element && submenu.contains(event.target)) {\n cancelPendingClose();\n }\n }, true);\n\n submenu.addEventListener(\"click\", (event) => {\n if (!openMenu) return;\n handleItemClick(event, openMenu, ticket, handlers, submenu);\n });\n submenu.addEventListener(\"keydown\", (event) => {\n if (!openMenu) return;\n handleMenuKeydown(event, openMenu);\n });\n}\n\nfunction handleItemClick(event, rootMenu, ticket, handlers, container = rootMenu) {\n const button = event.target instanceof Element ? event.target.closest(\"button.card-action-button\") : null;\n if (!button || !container.contains(button) || button.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n\n const parent = button.closest(\".card-action-menu-item\");\n if (parent?.classList.contains(\"has-submenu\")) {\n cancelPendingClose();\n openSubmenu(parent);\n firstEnabledItem(submenuByItem.get(parent))?.focus({ preventScroll: true });\n return;\n }\n\n const action = button.dataset.action;\n const value = button.dataset.value;\n closeCardActionMenu();\n if (action === \"open\") return handlers.open(ticket);\n if (action === \"move\") return handlers.move(ticket, value);\n if (action === \"priority\") return handlers.priority(ticket, Number(value));\n if (action === \"type\") return handlers.type(ticket, value);\n if (action === \"archive\") return handlers.archive(ticket);\n}\n\nfunction handleMenuKeydown(event, rootMenu) {\n const button = event.target instanceof Element ? event.target.closest(\"button.card-action-button\") : null;\n if (!button) return;\n const submenu = button.closest(\".card-action-submenu\");\n const inRoot = rootMenu.contains(button);\n if (!inRoot && !submenu) return;\n\n const currentMenu = button.closest(\".card-action-menu-list\");\n const item = button.closest(\".card-action-menu-item\");\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n if (submenu) {\n const parentItem = itemBySubmenu.get(submenu);\n const parentButton = parentItem?.querySelector(\":scope > .card-action-button\");\n closeSubmenu(parentItem);\n parentButton?.focus({ preventScroll: true });\n } else {\n closeCardActionMenu({ restoreFocus: true });\n }\n return;\n }\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n moveFocus(currentMenu, button, event.key === \"ArrowDown\" ? 1 : -1);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const enabled = enabledItems(currentMenu);\n enabled[event.key === \"Home\" ? 0 : enabled.length - 1]?.focus({ preventScroll: true });\n return;\n }\n\n if (event.key === \"ArrowRight\" && item?.classList.contains(\"has-submenu\")) {\n event.preventDefault();\n cancelPendingClose();\n openSubmenu(item);\n firstEnabledItem(submenuByItem.get(item))?.focus({ preventScroll: true });\n return;\n }\n\n if (event.key === \"ArrowLeft\" && submenu) {\n const parentItem = itemBySubmenu.get(submenu);\n const parentButton = parentItem?.querySelector(\":scope > .card-action-button\");\n if (parentButton) {\n event.preventDefault();\n closeSubmenu(parentItem);\n parentButton.focus({ preventScroll: true });\n }\n }\n}\n\nfunction dismissOnOutsidePointer(event) {\n if (!openMenu) return;\n if (isEventInsideAnyMenu(event)) return;\n closeCardActionMenu();\n}\n\nfunction dismissOnEscape(event) {\n if (event.key === \"Escape\" && openMenu) {\n event.preventDefault();\n closeCardActionMenu({ restoreFocus: true });\n }\n}\n\nfunction dismissOnScroll(event) {\n if (!openMenu) return;\n if (isEventInsideAnyMenu(event)) return;\n closeCardActionMenu();\n}\n\nfunction isEventInsideAnyMenu(event) {\n const target = event.target;\n if (!(target instanceof Node)) return false;\n if (openMenu?.contains(target)) return true;\n for (const submenu of openSubmenus) {\n if (submenu.contains(target)) return true;\n }\n return false;\n}\n\nfunction openSubmenu(item) {\n const siblings = item.parentElement?.children || [];\n for (const sibling of siblings) {\n if (sibling !== item && sibling.classList?.contains(\"has-submenu\") && sibling.classList.contains(\"is-open\")) {\n closeSubmenu(sibling);\n }\n }\n const submenu = submenuByItem.get(item);\n if (!submenu) return;\n if (item.classList.contains(\"is-open\")) {\n positionSubmenu(item, submenu);\n return;\n }\n item.classList.add(\"is-open\");\n item.querySelector(\":scope > .card-action-button\")?.setAttribute(\"aria-expanded\", \"true\");\n submenu.classList.add(\"is-open\");\n openSubmenus.add(submenu);\n positionSubmenu(item, submenu);\n}\n\nfunction closeSubmenu(item) {\n if (!item) return;\n item.classList.remove(\"is-open\");\n item.querySelector(\":scope > .card-action-button\")?.setAttribute(\"aria-expanded\", \"false\");\n const submenu = submenuByItem.get(item);\n if (!submenu) return;\n submenu.classList.remove(\"is-open\");\n submenu.style.removeProperty(\"left\");\n submenu.style.removeProperty(\"top\");\n submenu.style.removeProperty(\"max-height\");\n openSubmenus.delete(submenu);\n}\n\nfunction closeOpenSubmenus(scope) {\n scope.querySelectorAll(\".card-action-menu-item.has-submenu.is-open\").forEach(closeSubmenu);\n}\n\nfunction scheduleCloseOtherSubmenus(rootMenu) {\n cancelPendingClose();\n pendingCloseTimer = setTimeout(() => {\n pendingCloseTimer = null;\n if (openMenu === rootMenu) closeOpenSubmenus(rootMenu);\n }, HOVER_CLOSE_DELAY);\n}\n\nfunction cancelPendingClose() {\n if (pendingCloseTimer != null) {\n clearTimeout(pendingCloseTimer);\n pendingCloseTimer = null;\n }\n}\n\nfunction positionSubmenu(item, submenu) {\n const trigger = item.querySelector(\":scope > .card-action-button\");\n if (!submenu || !trigger) return;\n\n const availableHeight = Math.max(0, window.innerHeight - MENU_MARGIN * 2);\n submenu.style.maxHeight = `${availableHeight}px`;\n submenu.style.left = \"0px\";\n submenu.style.top = \"0px\";\n\n const submenuRect = submenu.getBoundingClientRect();\n const position = calculateSubmenuPosition({\n triggerRect: trigger.getBoundingClientRect(),\n submenuWidth: submenuRect.width,\n submenuHeight: submenuRect.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight\n });\n\n submenu.style.left = `${position.left}px`;\n submenu.style.top = `${position.top}px`;\n submenu.style.maxHeight = `${position.maxHeight}px`;\n}\n\nfunction enabledItems(scope) {\n if (!scope) return [];\n const list = scope.classList?.contains(\"card-action-menu-list\")\n ? scope\n : scope.querySelector(\":scope > .card-action-menu-list\");\n if (!list) return [];\n return [...list.querySelectorAll(\":scope > .card-action-menu-item > .card-action-button\")].filter((button) => !button.disabled);\n}\n\nfunction firstEnabledItem(scope) {\n return enabledItems(scope)[0] || null;\n}\n\nfunction moveFocus(scope, current, step) {\n const items = enabledItems(scope);\n if (!items.length) return;\n const index = items.indexOf(current);\n const nextIndex = index === -1 ? 0 : (index + step + items.length) % items.length;\n items[nextIndex].focus({ preventScroll: true });\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 { bindCardContextMenuDelegated, closeCardActionMenu, createCardActionHandlers, setCardActionDragInFlight } from \"./card-actions.js\";\nimport { unreadCount } from \"./unread.js\";\n\n// Lookup for the current board's tickets, keyed by id. Refreshed on every\n// renderBoard() so the single, persistent set of delegated listeners can\n// resolve a card's ticket in O(1) without re-binding anything per render.\nlet boardTicketsById = new Map();\n// Created once (lazily) and reused \u2014 handlers are stateless w.r.t. a given card.\nlet cardActionHandlers = null;\n// HTML5 DnD ends with a synthetic click on the drag source; this flag lets the\n// delegated click handler swallow that one click so a drop doesn't also open\n// the ticket drawer. Module-scoped because there's now one shared listener.\nlet suppressClickAfterDrag = false;\n\n// renderBoard() is hot: it runs on every drag-drop, every SSE board event, and\n// every settings toggle. Keep it to a single innerHTML write plus a Map refresh.\n// All interaction wiring lives in enableKanbanInteractions(), attached ONCE to\n// the persistent `kanban` element (see below), so re-rendering never re-binds\n// per-card/column/button listeners or rescans the ticket list.\nexport function renderBoard() {\n const states = visibleStatesForProject();\n const tickets = ticketsForProject();\n boardTicketsById = new Map(tickets.map((ticket) => [ticket.id, ticket]));\n kanban.innerHTML = states.map((column) => renderColumn(column, tickets)).join(\"\");\n}\n\nfunction toggleCardExpansion(card) {\n if (!card) return;\n const id = card.dataset.ticketId;\n const willExpand = !state.expandedCardIds.has(id);\n if (willExpand) {\n state.expandedCardIds.add(id);\n // Build the expandable body (markdown parse + labels + relations) the first\n // time a card opens. Collapsed cards \u2014 the overwhelming majority on render \u2014\n // never pay this cost. Once built it stays cached in the DOM for re-toggles.\n if (!card.querySelector(\".card-expandable\")) {\n const ticket = boardTicketsById.get(id);\n const meta = card.querySelector(\".card-meta\");\n if (ticket && meta) meta.insertAdjacentHTML(\"afterend\", renderCardExpandable(ticket));\n }\n } else {\n state.expandedCardIds.delete(id);\n }\n card.classList.toggle(\"is-expanded\", willExpand);\n const toggleBtn = card.querySelector(\"button.card-expand-trigger\");\n if (toggleBtn) toggleBtn.setAttribute(\"aria-expanded\", willExpand ? \"true\" : \"false\");\n}\n\n// One-time setup: attach delegated listeners to the persistent board container.\n// Because events bubble to `kanban`, these survive every innerHTML swap, so\n// renderBoard() does zero listener work regardless of card count.\nexport function enableKanbanInteractions() {\n cardActionHandlers = cardActionHandlers || createCardActionHandlers({ navigator: navigate });\n\n // --- Drag & drop (HTML5 DnD events bubble, so one set covers all cards) ---\n let dragOverColumn = null;\n const setDragOverColumn = (column) => {\n if (dragOverColumn === column) return;\n if (dragOverColumn) dragOverColumn.classList.remove(\"drag-over\");\n dragOverColumn = column;\n if (dragOverColumn) dragOverColumn.classList.add(\"drag-over\");\n };\n\n kanban.addEventListener(\"dragstart\", (event) => {\n const card = event.target instanceof Element ? event.target.closest(\".card\") : null;\n if (!card) return;\n closeCardActionMenu();\n setCardActionDragInFlight(true);\n event.dataTransfer.setData(\"text/plain\", card.dataset.ticketId);\n event.dataTransfer.effectAllowed = \"move\";\n });\n\n kanban.addEventListener(\"dragover\", (event) => {\n const column = event.target instanceof Element ? event.target.closest(\".column\") : null;\n if (!column) return;\n event.preventDefault();\n setDragOverColumn(column);\n });\n\n kanban.addEventListener(\"dragend\", () => {\n setCardActionDragInFlight(false);\n setDragOverColumn(null);\n suppressClickAfterDrag = true;\n // If no synthetic click follows (e.g. drag cancelled oddly), don't eat the\n // next real click.\n setTimeout(() => {\n suppressClickAfterDrag = false;\n }, 0);\n });\n\n kanban.addEventListener(\"drop\", async (event) => {\n const column = event.target instanceof Element ? event.target.closest(\".column\") : null;\n if (!column) return;\n event.preventDefault();\n setDragOverColumn(null);\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 by suppressClickAfterDrag).\n await load();\n });\n\n // --- Clicks (precedence: add-button > expand toggle > link > epic header > card) ---\n kanban.addEventListener(\"click\", (event) => {\n const target = event.target instanceof Element ? event.target : event.target?.parentElement;\n if (!target) return;\n\n const addBtn = target.closest(\"[data-add-to-state]\");\n if (addBtn) {\n event.stopPropagation();\n openCreateFlyout(addBtn.dataset.addToState || \"\");\n return;\n }\n\n const toggle = target.closest(\"button.card-expand-trigger\");\n if (toggle) {\n event.stopPropagation();\n event.preventDefault();\n toggleCardExpansion(toggle.closest(\".card\"));\n return;\n }\n\n // Anchors inside a card keep their native behavior.\n if (target.closest(\"a\")) {\n event.stopPropagation();\n return;\n }\n\n const epicHeader = target.closest(\".epic-mini-header[data-ticket-id]\");\n if (epicHeader) {\n closeCreateFlyout();\n navigate({ boardId: state.boardId, view: \"ticket\", ticketId: epicHeader.dataset.ticketId });\n return;\n }\n\n const card = target.closest(\".card\");\n if (!card) return;\n if (suppressClickAfterDrag) {\n suppressClickAfterDrag = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n closeCreateFlyout();\n navigate({ boardId: state.boardId, view: \"ticket\", ticketId: card.dataset.ticketId });\n });\n\n // --- Context menu ---\n bindCardContextMenuDelegated(kanban, (id) => boardTicketsById.get(id), {\n handlers: cardActionHandlers,\n onBeforeOpen: closeCreateFlyout\n });\n}\n\nexport function renderBoardSelection() {\n kanban.querySelectorAll(\".card.selected\").forEach((card) => card.classList.remove(\"selected\"));\n if (!state.selectedTicketId) return;\n kanban\n .querySelectorAll(`.card[data-ticket-id=\"${CSS.escape(state.selectedTicketId)}\"]`)\n .forEach((card) => card.classList.add(\"selected\"));\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\", \"lane\"];\n if (isAiReady) columnClasses.push(\"column--ai-ready\");\n const accentAttr = isAiReady ? ' data-accent=\"ai-ready\"' : \"\";\n\n return `\n <section class=\"${columnClasses.join(\" \")}\" data-flat${accentAttr} data-state-id=\"${column.id}\" data-state-name=\"${escapeHtml(column.name)}\">\n <div class=\"column-head lane-head\">\n <h2 class=\"lane-title\"${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 lane-actions\">\n <button type=\"button\" class=\"column-add-btn\" data-variant=\"plus\" 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\" data-variant=\"${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\" : \"\"}\" data-variant=\"${escapeHtml(canonicalType)}\" 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-variant=\"card-accordion\" 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 && isExpanded ? renderCardExpandable(ticket) : \"\"}\n </article>\n `;\n}\n\n// The expandable body holds the only genuinely expensive per-card work: a full\n// markdown parse of the description. It's rendered eagerly only for cards that\n// are already expanded; collapsed cards get it injected on first open (see\n// toggleCardExpansion). Kept as its own function so both paths share one source.\nfunction renderCardExpandable(ticket) {\n const hasDescription = Boolean(String(ticket.description || \"\").trim());\n return `\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}\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 // Clear stale drag-click suppression on any fresh primary press \u2014 even over\n // a card \u2014 so a both-button / two-finger pan that emitted no trailing click\n // can't swallow the next genuine click.\n dragged = false;\n if (shouldIgnore(event.target)) return;\n\n active = true;\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 // --- Both-button mouse drag + two-finger touch drag -----------------------\n // A second panning affordance that works ANYWHERE on the board, including\n // directly over cards. A plain left-click / single-finger tap is left to the\n // cards (so they still open + drag); holding *both* mouse buttons, or dragging\n // with *two fingers*, pans the board horizontally without engaging a card.\n let bothBtnPanning = false;\n let bothBtnLastX = 0;\n let suppressContextMenu = false;\n\n // Pressing the second mouse button (buttons bitmask 1|2 === 3) arms the pan\n // and cancels any single-button drag already in flight (see `active` above).\n kanban.addEventListener(\"pointerdown\", (event) => {\n if (event.pointerType !== \"mouse\" || (event.buttons & 3) !== 3) return;\n bothBtnPanning = true;\n bothBtnLastX = event.clientX;\n suppressContextMenu = true;\n active = false; // hand control off from the left-button drag\n kanban.classList.add(\"is-grabbing\");\n });\n\n kanban.addEventListener(\"pointermove\", (event) => {\n if (event.pointerType !== \"mouse\") return;\n const bothDown = (event.buttons & 3) === 3;\n if (bothDown) {\n event.preventDefault();\n if (!bothBtnPanning) {\n bothBtnPanning = true;\n bothBtnLastX = event.clientX;\n suppressContextMenu = true;\n active = false;\n kanban.classList.add(\"is-grabbing\");\n return;\n }\n const delta = event.clientX - bothBtnLastX;\n if (delta) {\n kanban.scrollLeft -= delta;\n bothBtnLastX = event.clientX;\n dragged = true; // eat the trailing synthetic click\n }\n } else if (bothBtnPanning) {\n bothBtnPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n });\n\n kanban.addEventListener(\"pointerup\", (event) => {\n if (event.pointerType === \"mouse\" && bothBtnPanning && (event.buttons & 3) !== 3) {\n bothBtnPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n });\n\n // Right-click handling on the board:\n // - after a both-button pan, swallow the trailing context menu;\n // - otherwise suppress the native browser menu everywhere EXCEPT over a card,\n // which owns its own context menu (see bindCardContextMenuDelegated).\n kanban.addEventListener(\"contextmenu\", (event) => {\n if (suppressContextMenu) {\n event.preventDefault();\n event.stopPropagation();\n suppressContextMenu = false;\n return;\n }\n const onCard = event.target instanceof Element && event.target.closest(\".card\");\n if (!onCard) {\n event.preventDefault();\n event.stopPropagation();\n }\n });\n\n // Two-finger touch pan. Touch events (not pointer events) are used here so we\n // can reliably preventDefault the browser's native two-finger scroll/zoom.\n let touchPanning = false;\n let touchPanLastX = 0;\n const twoFingerCentroidX = (touches) => (touches[0].clientX + touches[1].clientX) / 2;\n\n kanban.addEventListener(\n \"touchstart\",\n (event) => {\n // Fresh gesture \u2014 clear any leftover drag-click suppression so a real tap\n // is never swallowed when the prior two-finger pan emitted no click.\n dragged = false;\n if (event.touches.length === 2) {\n touchPanning = true;\n touchPanLastX = twoFingerCentroidX(event.touches);\n active = false; // cancel any single-finger drag that started\n kanban.classList.add(\"is-grabbing\");\n } else {\n touchPanning = false;\n }\n },\n { passive: true }\n );\n\n kanban.addEventListener(\n \"touchmove\",\n (event) => {\n if (!touchPanning || event.touches.length !== 2) return;\n const x = twoFingerCentroidX(event.touches);\n const delta = x - touchPanLastX;\n if (delta) {\n event.preventDefault();\n kanban.scrollLeft -= delta;\n touchPanLastX = x;\n dragged = true; // eat the trailing tap so a card doesn't open\n }\n },\n { passive: false }\n );\n\n const endTouchPan = (event) => {\n if (event.touches.length < 2 && touchPanning) {\n touchPanning = false;\n kanban.classList.remove(\"is-grabbing\");\n }\n };\n kanban.addEventListener(\"touchend\", endTouchPan, { passive: true });\n kanban.addEventListener(\"touchcancel\", endTouchPan, { passive: true });\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 attachments: 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, renderPreservedText, cleanText } 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, startInlineEdit } 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 vscode: {\n label: \"VS Code\",\n format: \"mcp.json\",\n helper: \"Paste this JSON into VS Code's user or workspace MCP configuration.\"\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=\"separator\" aria-hidden=\"true\"></div>` : \"\";\n const agentContextSetup = aiEnabled ? renderAgentContextSection(project) : \"\";\n const helperFilesSetup = aiEnabled && features.multiBoard ? renderHelperFilesSection(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 ${helperFilesSetup ? `${aiDivider}${helperFilesSetup}` : \"\"}\n ${aiDivider}\n ${mcpSetup}\n `;\n}\n\nfunction renderAgentContextSection(project) {\n const instructionsPlaceholder =\n \"This project is about\u2026\\n\\nHow any AI agent should use this board and work in this repo.\";\n const instructions = project.agent_instructions || \"\";\n const hasInstructions = Boolean(instructions.trim());\n const placeholderClass = hasInstructions ? \"\" : \"is-placeholder\";\n const inner = hasInstructions ? renderPreservedText(instructions) : escapeHtml(instructionsPlaceholder);\n return `\n <div class=\"section ai-subsection ai-context-setup\">\n <div class=\"ai-context-title-row\">\n <span class=\"section-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 <div class=\"inline-md-field\">\n <div\n class=\"inline-md-field-body preserved-text-body editable-field settings-agent-instructions-body ${placeholderClass}\"\n data-edit-field=\"agent_instructions\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit Agent Instructions\"\n >${inner}</div>\n </div>\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=\"section-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\" data-variant=\"secondary\" 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\" data-variant=\"secondary\" 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 if (clientId === \"vscode\") return vscodeMcpJson(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 vscodeMcpJson(paths) {\n return JSON.stringify(\n {\n servers: {\n starscapeOrbit: {\n type: \"stdio\",\n command: \"node\",\n args: [paths.serverPath]\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 ${features.multiBoard ? renderBoardRenameSection(project) : \"\"}\n\n <div class=\"section\">\n <h3>Board Snapshot</h3>\n <p class=\"description\">Import accepts Orbit snapshots or Trello board JSON exports. The default import creates a separate board and leaves this board untouched.</p>\n ${features.attachments ? `\n <label class=\"orbit-check\">\n <input type=\"checkbox\" id=\"exportProjectImages\" />\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>Include attached images</span>\n </label>\n <p class=\"description\">Image exports are embedded in the .orbit.json snapshot and may be much larger.</p>\n ` : \"\"}\n <div class=\"deployment-actions\">\n <button type=\"button\" data-variant=\"secondary\" id=\"exportProject\">Export</button>\n <input type=\"file\" id=\"importSnapshotAsNewFile\" class=\"import-file-input\" accept=\".orbit.json,.json,application/json\" />\n <button type=\"button\" data-variant=\"secondary\" id=\"importSnapshotAsNewButton\">Import as New Board</button>\n </div>\n </div>\n\n <div class=\"section repository-danger-zone\">\n <h3>Replace Current Board</h3>\n <p class=\"description\">Advanced: replace this board from an Orbit snapshot or Trello export after making the normal pre-import backup. Type <strong>${escapeHtml(project.slug || \"\")}</strong> to enable replacement.</p>\n <label class=\"repository-confirm-field\">\n <span>Board slug</span>\n <input id=\"replaceImportConfirmInput\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"${escapeHtml(project.slug || \"\")}\" />\n </label>\n <div class=\"deployment-actions\">\n <input type=\"file\" id=\"replaceCurrentBoardImportFile\" class=\"import-file-input\" accept=\".orbit.json,.json,application/json\" disabled />\n <button type=\"button\" data-variant=\"secondary\" id=\"replaceCurrentBoardImportButton\" disabled>Replace Current Board</button>\n </div>\n </div>\n\n ${features.multiBoard ? renderDeleteBoardSection(project) : \"\"}\n `;\n}\n\nfunction renderHelperFilesSection(project) {\n const hasFolder = Boolean(project.system_path);\n const managed = Boolean(project.manage_helper_files);\n return `\n <div class=\"section ai-subsection helper-files-section\">\n <div class=\"ai-context-title-row\">\n <span class=\"section-mark\" aria-hidden=\"true\">Files</span>\n <h3>AI Helper Files</h3>\n </div>\n <p class=\"description\">Orbit can keep <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> in this board's coding project folder so your AI agent knows how to use Orbit.${hasFolder ? \"\" : \" Link a folder to enable this.\"}</p>\n <div class=\"folder-picker-field helper-files-folder\">\n <input id=\"helperFolderInput\" type=\"text\" readonly placeholder=\"No folder linked\" value=\"${escapeHtml(project.system_path || \"\")}\" />\n <button type=\"button\" id=\"helperPickFolderBtn\">${hasFolder ? \"Change\" : \"Browse\"}</button>\n </div>\n <label class=\"orbit-check\">\n <input type=\"checkbox\" id=\"manageHelperFilesToggle\" ${managed ? \"checked\" : \"\"} ${hasFolder ? \"\" : \"disabled\"} />\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>Generate & maintain helper files in this folder</span>\n </label>\n </div>\n `;\n}\n\nfunction renderBoardRenameSection(project) {\n return `\n <div class=\"section board-rename-section\">\n <h3>Board Name</h3>\n <p class=\"description\">Rename the board display name only. The canonical URL slug stays <strong>${escapeHtml(project.slug || \"\")}</strong>, so existing board links keep working.</p>\n <form id=\"boardRenameForm\" class=\"field-form\">\n <label>\n <span>Display name</span>\n <input name=\"name\" value=\"${escapeHtml(project.name || \"\")}\" maxlength=\"120\" required />\n </label>\n <button type=\"submit\" data-variant=\"secondary\">Rename Board</button>\n </form>\n </div>\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\" data-variant=\"secondary\" id=\"deleteBoardExportFirst\">Export first</button>\n <button type=\"button\" data-variant=\"ghost\" class=\"danger-button\" id=\"deleteBoardSkipExport\">Delete without exporting</button>\n <button type=\"button\" data-variant=\"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\" data-variant=\"primary\" class=\"danger-button\" id=\"deleteBoardConfirm\" disabled>Delete board permanently</button>\n <button type=\"button\" data-variant=\"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\" data-variant=\"ghost\" class=\"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 const notes = project.project_notes || \"\";\n const hasNotes = Boolean(notes.trim());\n const placeholderClass = hasNotes ? \"\" : \"is-placeholder\";\n const inner = hasNotes ? renderPreservedText(notes) : escapeHtml(notesPlaceholder);\n return `\n <div class=\"section ai-fields\">\n <div class=\"inline-md-field\">\n <span class=\"inline-md-field-label\">Notes For You</span>\n <div\n class=\"inline-md-field-body preserved-text-body editable-field settings-notes-body ${placeholderClass}\"\n data-edit-field=\"project_notes\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit Notes For You\"\n >${inner}</div>\n </div>\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\" data-variant=\"primary\">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\" data-variant=\"primary\">Add Entry</button>\n </form>\n </div>\n `;\n}\n\nfunction parseImportSnapshotText(text) {\n const trimmed = String(text || \"\").trimStart();\n if (trimmed.startsWith(\"<\")) {\n throw new Error(\"That file looks like an HTML page instead of JSON. In Trello, use Export JSON/download the board JSON, not Save Page As.\");\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(error?.message || \"invalid JSON\");\n }\n}\n\nfunction bindProjectTabHandlers(context, tab) {\n const project = context.board;\n\n if (tab === \"repository\") {\n const exportSnapshot = async (includeAttachments = Boolean($(\"#exportProjectImages\")?.checked)) => {\n const suffix = includeAttachments ? \"?include_attachments=true\" : \"\";\n const snapshot = await api(`/api/boards/${encodeURIComponent(project.id)}/export${suffix}`);\n const filename = includeAttachments ? `${project.slug}.with-images.orbit.json` : `${project.slug}.orbit.json`;\n downloadJson(filename, snapshot);\n };\n\n $(\"#exportProject\")?.addEventListener(\"click\", async () => {\n await exportSnapshot();\n });\n\n $(\"#boardRenameForm\")?.addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n const nextName = String(form.get(\"name\") || \"\").trim();\n if (!nextName || nextName === project.name) return;\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { name: nextName }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(`Renamed board to ${nextName}. Canonical slug unchanged: ${project.slug}`);\n });\n\n const importSnapshotFile = async (file, bodyForSnapshot) => {\n const text = await file.text();\n const snapshot = parseImportSnapshotText(text);\n return api(\"/api/admin/import\", {\n method: \"POST\",\n body: bodyForSnapshot(snapshot)\n });\n };\n\n const importSnapshotAsNewFile = $(\"#importSnapshotAsNewFile\");\n $(\"#importSnapshotAsNewButton\")?.addEventListener(\"click\", () => {\n importSnapshotAsNewFile?.click();\n });\n\n importSnapshotAsNewFile?.addEventListener(\"change\", async (event) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n if (!file) return;\n try {\n const result = await importSnapshotFile(file, (snapshot) => ({ snapshot, create_new: true, board_id: project.id }));\n state.boardId = result.imported_board_id;\n state.boardSlug = result.imported_board_slug;\n state.detailMode = \"empty\";\n await load();\n await navigate({ boardId: result.imported_board_id, view: \"board\" });\n const counts = result.imported_counts || {};\n const cardCount = Number.isFinite(Number(counts.tickets)) ? ` (${counts.tickets} cards)` : \"\";\n toast.success(result.source_format === \"trello-board-export\" ? `Trello board imported as new board${cardCount}` : \"Board imported as new board\");\n } catch (err) {\n toast.error(`Import failed: ${err?.message || \"invalid JSON\"}`);\n } finally {\n input.value = \"\";\n }\n });\n\n const replaceImportConfirmInput = $(\"#replaceImportConfirmInput\");\n const replaceCurrentBoardImportFile = $(\"#replaceCurrentBoardImportFile\");\n const replaceCurrentBoardImportButton = $(\"#replaceCurrentBoardImportButton\");\n replaceImportConfirmInput?.addEventListener(\"input\", () => {\n const disabled = replaceImportConfirmInput.value.trim() !== project.slug;\n if (replaceCurrentBoardImportFile) replaceCurrentBoardImportFile.disabled = disabled;\n if (replaceCurrentBoardImportButton) replaceCurrentBoardImportButton.disabled = disabled;\n });\n\n replaceCurrentBoardImportButton?.addEventListener(\"click\", () => {\n if (replaceCurrentBoardImportButton.disabled || replaceCurrentBoardImportFile?.disabled) return;\n replaceCurrentBoardImportFile?.click();\n });\n\n replaceCurrentBoardImportFile?.addEventListener(\"change\", async (event) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n if (!file) return;\n if (replaceImportConfirmInput.value.trim() !== project.slug) {\n toast.error(\"Type the board slug before replacing this board.\");\n input.value = \"\";\n return;\n }\n try {\n const result = await importSnapshotFile(file, (snapshot) => ({ snapshot, replace_existing: true, board_id: project.id }));\n await load();\n state.detailMode = \"settings\";\n const counts = result.imported_counts || {};\n const cardCount = Number.isFinite(Number(counts.tickets)) ? ` (${counts.tickets} cards)` : \"\";\n toast.success(result.source_format === \"trello-board-export\" ? `Trello board replaced from Trello import${cardCount}` : \"Board replaced from snapshot\");\n } catch (err) {\n toast.error(`Import failed: ${err?.message || \"invalid JSON\"}`);\n } finally {\n input.value = \"\";\n }\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 const notesEl = drawerInner.querySelector('[data-edit-field=\"project_notes\"]');\n if (notesEl) {\n const edit = () =>\n startInlineEdit(notesEl, {\n fieldName: \"project_notes\",\n multiline: true,\n initialValue: project.project_notes || \"\",\n ariaLabel: \"Edit Notes For You\",\n rerender: async () => {\n state.detailMode = \"settings\";\n await renderProjectDetail();\n },\n commit: async (next) => {\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { project_notes: cleanText(next) }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n }\n });\n notesEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit();\n });\n notesEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\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 const instructionsEl = drawerInner.querySelector('[data-edit-field=\"agent_instructions\"]');\n if (instructionsEl) {\n const edit = () =>\n startInlineEdit(instructionsEl, {\n fieldName: \"agent_instructions\",\n multiline: true,\n initialValue: project.agent_instructions || \"\",\n ariaLabel: \"Edit Agent Instructions\",\n rerender: async () => {\n state.detailMode = \"settings\";\n await renderProjectDetail();\n },\n commit: async (next) => {\n await api(`/api/boards/${project.id}`, {\n method: \"PATCH\",\n body: { agent_instructions: cleanText(next) }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Saved\");\n }\n });\n instructionsEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit();\n });\n instructionsEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\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 const helperPickFolderBtn = $(\"#helperPickFolderBtn\");\n helperPickFolderBtn?.addEventListener(\"click\", async () => {\n helperPickFolderBtn.disabled = true;\n try {\n const result = await api(\"/api/system/pick-folder\", { method: \"POST\" });\n if (!result.path) return;\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { system_path: result.path }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\"Linked coding project folder updated\");\n } catch (error) {\n toast.error(error?.message || \"Folder picker unavailable\");\n } finally {\n helperPickFolderBtn.disabled = false;\n }\n });\n\n const manageHelperFilesToggle = $(\"#manageHelperFilesToggle\");\n manageHelperFilesToggle?.addEventListener(\"change\", async () => {\n const enabled = manageHelperFilesToggle.checked;\n manageHelperFilesToggle.disabled = true;\n try {\n await api(`/api/boards/${encodeURIComponent(project.id)}`, {\n method: \"PATCH\",\n body: { manage_helper_files: enabled }\n });\n await load();\n state.detailMode = \"settings\";\n toast.success(\n enabled\n ? \"Generated SKILL-ORBIT.md and AGENTS.md \u2014 Orbit will keep them in sync\"\n : \"Stopped maintaining helper files (existing files left in place)\"\n );\n } catch (error) {\n manageHelperFilesToggle.checked = !enabled;\n manageHelperFilesToggle.disabled = false;\n toast.error(error?.message || \"Could not update helper files setting\");\n }\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 data-variant=\"ghost\"\n class=\"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\" data-variant=\"ghost\" class=\"settings-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\" data-variant=\"ghost\" class=\"settings-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\" data-variant=\"${lane.is_default ? \"secondary\" : \"ghost\"}\" class=\"settings-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\" data-variant=\"ghost\" class=\"settings-lane-delete-btn danger-button\" 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.setAttribute(\"data-variant\", \"ghost\");\n btn.classList.remove(\"is-on\");\n });\n button.setAttribute(\"aria-pressed\", \"true\");\n button.setAttribute(\"data-variant\", \"secondary\");\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", "// Human-facing actor labels for ticket activity. The storage layer keeps\n// compact/internal identifiers such as \"local\" and \"local-agent\"; the drawer\n// should translate those into labels that explain who acted without exposing\n// implementation details or blaming agent actions on the current user.\n\nconst INTERNAL_LOCAL_NAMES = new Set([\"local\", \"local-owner\", \"owner\"]);\nconst GENERIC_AGENT_NAMES = new Set([\"agent\", \"local-agent\", \"orbit-agent\"]);\nconst AGENT_COMMENT_KINDS = new Set([\"agent_note\", \"checkpoint\", \"completion\"]);\n\nfunction clean(value) {\n return String(value || \"\").trim();\n}\n\nfunction humanizeIdentifier(value) {\n const raw = clean(value);\n if (!raw) return \"\";\n return raw\n .replace(/^@+/, \"\")\n .replace(/[-_]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\nfunction agentNameFrom({ actor, actorId } = {}) {\n const name = clean(actor);\n const id = clean(actorId);\n const lowerName = name.toLowerCase();\n const lowerId = id.toLowerCase();\n\n if (name && !INTERNAL_LOCAL_NAMES.has(lowerName) && !GENERIC_AGENT_NAMES.has(lowerName)) {\n return humanizeIdentifier(name);\n }\n if (id && !INTERNAL_LOCAL_NAMES.has(lowerId) && !GENERIC_AGENT_NAMES.has(lowerId)) {\n return humanizeIdentifier(id);\n }\n return \"\";\n}\n\nexport function formatActorLabel({ actor, actorType, actorId } = {}) {\n const type = clean(actorType).toLowerCase();\n const name = clean(actor);\n const lowerName = name.toLowerCase();\n\n if (type === \"agent\") {\n const agentName = agentNameFrom({ actor: name, actorId });\n return agentName ? `Agent \u00B7 ${agentName}` : \"Agent\";\n }\n\n if (!name || INTERNAL_LOCAL_NAMES.has(lowerName)) return \"You\";\n return humanizeIdentifier(name);\n}\n\nexport function formatCommentAuthor(comment = {}) {\n const kind = clean(comment.kind).toLowerCase();\n const author = clean(comment.author);\n const isAgentKind = AGENT_COMMENT_KINDS.has(kind) || (kind && kind !== \"human_comment\");\n\n if (isAgentKind) {\n const agentName = agentNameFrom({ actor: author });\n return agentName ? `Agent \u00B7 ${agentName}` : \"Agent\";\n }\n\n return formatActorLabel({ actor: author, actorType: \"human\" });\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 {\n state,\n ticketsForProject,\n selectableStatesForProject,\n boardLabelCatalog,\n currentBoard,\n upsertTicket,\n} 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 renderPreservedText,\n stateClassFor,\n cleanText,\n} from \"./format.js\";\nimport { renderTypeIcon, renderPriorityPill, renderBoard } from \"./kanban.js\";\nimport { renderDrawerShell, openDrawer, closeDrawer } from \"./drawer.js\";\nimport { navigate } from \"./router.js\";\nimport { api, withBoardQuery } from \"./api.js\";\nimport { features } from \"./config.js\";\nimport { toast } from \"./toast.js\";\n// `load()` is intentionally not used for drawer-local mutations. Reloading\n// /api/bootstrap rebuilds the whole app; these helpers patch the local ticket\n// cache and refresh only the surfaces that actually changed.\nimport { renderProjectDetail } from \"./settings.js\";\nimport { unreadCount, markRead } from \"./unread.js\";\nimport { formatActorLabel, formatCommentAuthor } from \"./actor-labels.js\";\n\n/**\n * Refresh the open drawer from the focused ticket context endpoint. When the\n * board card itself changed, also rebuild the board from the patched local\n * cache; otherwise leave the board DOM alone.\n */\nasync function refreshTicketDetail(\n ticketId,\n { renderBoardAfter = false } = {},\n) {\n const [context, statusHistory, commentsResult] = await Promise.all([\n api(withBoardQuery(`/api/tickets/${ticketId}/context?depth=1`)),\n api(withBoardQuery(`/api/tickets/${ticketId}/history`)),\n api(withBoardQuery(`/api/tickets/${ticketId}/comments`)),\n ]);\n if (context.ticket?.id !== ticketId) return;\n upsertTicket(context.ticket);\n if (renderBoardAfter) renderBoard();\n if (state.detailMode !== \"ticket\" || state.selectedTicketId !== ticketId)\n return;\n await renderDetail({\n context,\n statusHistory,\n comments: commentsResult.comments || [],\n });\n}\n\n/**\n * PATCH a ticket then refresh only the board/detail surfaces that depend on\n * the changed ticket. This avoids the previous full /api/bootstrap reload for\n * every drawer edit.\n */\nasync function patchTicket(ticketId, body) {\n await api(withBoardQuery(`/api/tickets/${ticketId}`), {\n method: \"PATCH\",\n body,\n });\n await refreshTicketDetail(ticketId, { renderBoardAfter: true });\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 *\n * Options:\n * - fieldName: short identifier used for aria-label / data attribute (e.g. \"title\").\n * - multiline: true for <textarea> + Ctrl+Enter commit; false for <input> + Enter commit.\n * - initialValue: text shown in the editor on open.\n * - ariaLabel: full label for screen readers.\n * - emptyMessage: if set, an empty trimmed value triggers a warning toast and cancels.\n * - sourceEvent: optional pointer/click event used to seed the textarea caret near the clicked text.\n * - rerender: async fn called on cancel / no-change to put the static node back.\n * - commit: async fn called with the new value when the user accepts a real change.\n * Receives the *raw* editor value; the caller is responsible for any\n * trimming, cleanText, or PATCH wiring.\n */\nfunction inlineTextOffsetFromPoint(node, sourceEvent, maxLength) {\n if (\n !node ||\n !sourceEvent ||\n typeof sourceEvent.clientX !== \"number\" ||\n typeof sourceEvent.clientY !== \"number\"\n )\n return null;\n\n let range = null;\n if (document.caretPositionFromPoint) {\n const position = document.caretPositionFromPoint(\n sourceEvent.clientX,\n sourceEvent.clientY,\n );\n if (\n position?.offsetNode &&\n (position.offsetNode === node || node.contains(position.offsetNode))\n ) {\n range = document.createRange();\n range.setStart(node, 0);\n range.setEnd(position.offsetNode, position.offset);\n }\n } else if (document.caretRangeFromPoint) {\n const caretRange = document.caretRangeFromPoint(\n sourceEvent.clientX,\n sourceEvent.clientY,\n );\n if (\n caretRange?.startContainer &&\n (caretRange.startContainer === node ||\n node.contains(caretRange.startContainer))\n ) {\n range = document.createRange();\n range.setStart(node, 0);\n range.setEnd(caretRange.startContainer, caretRange.startOffset);\n }\n }\n\n if (!range) return null;\n return Math.max(0, Math.min(maxLength, range.toString().length));\n}\n\nfunction captureInlineEditScrollState(node) {\n const scrollContainer = node?.closest?.(\".drawer-inner\");\n if (!scrollContainer) return null;\n return {\n scrollContainer,\n nodeRect: node.getBoundingClientRect(),\n scrollTop: scrollContainer.scrollTop,\n };\n}\n\nfunction restoreInlineEditScroll(scrollState, editor) {\n if (!scrollState?.scrollContainer || !editor?.isConnected) return;\n const editorRect = editor.getBoundingClientRect();\n const nextScrollTop = Math.max(\n 0,\n scrollState.scrollContainer.scrollTop +\n (editorRect.top - scrollState.nodeRect.top),\n );\n if (Number.isFinite(nextScrollTop))\n scrollState.scrollContainer.scrollTop = nextScrollTop;\n else scrollState.scrollContainer.scrollTop = scrollState.scrollTop;\n}\n\nfunction focusWithoutScrolling(editor) {\n try {\n editor.focus({ preventScroll: true });\n } catch {\n editor.focus();\n }\n}\n\nexport function startInlineEdit(node, opts) {\n if (!node || node.dataset.editing === \"true\") return;\n const {\n fieldName,\n multiline = true,\n initialValue = \"\",\n ariaLabel,\n emptyMessage,\n sourceEvent,\n rerender,\n commit: commitHandler,\n } = opts;\n\n const scrollState = multiline ? captureInlineEditScrollState(node) : null;\n const initialString = String(initialValue);\n const clickedCaretOffset = multiline\n ? inlineTextOffsetFromPoint(node, sourceEvent, initialString.length)\n : null;\n\n node.dataset.editing = \"true\";\n\n const editor = document.createElement(multiline ? \"textarea\" : \"input\");\n editor.className = multiline ? \"inline-desc-editor\" : \"inline-title-editor\";\n editor.value = initialString;\n if (fieldName) editor.setAttribute(\"data-editing-field\", fieldName);\n if (ariaLabel) editor.setAttribute(\"aria-label\", ariaLabel);\n if (!multiline) {\n editor.type = \"text\";\n editor.maxLength = 500;\n editor.autocomplete = \"off\";\n editor.spellcheck = true;\n } else {\n editor.rows = Math.max(3, initialString.split(\"\\n\").length + 1);\n const sourceHeight = node.getBoundingClientRect().height;\n if (Number.isFinite(sourceHeight) && sourceHeight > 0) {\n editor.style.minHeight = `${Math.ceil(sourceHeight)}px`;\n }\n }\n\n node.replaceWith(editor);\n focusWithoutScrolling(editor);\n if (!multiline) {\n editor.select();\n } else {\n const selectionStart = clickedCaretOffset ?? 0;\n editor.setSelectionRange(selectionStart, selectionStart);\n restoreInlineEditScroll(scrollState, editor);\n }\n\n let done = false;\n\n const stopWatchingOutsideClicks = () => {\n document.removeEventListener(\"pointerdown\", handleOutsidePointerDown, true);\n };\n\n // If a downstream render rebuilds the title block while the editor is open,\n // the editor is dropped along with everything else; only restore the saved\n // node when our editor is still connected to the DOM.\n const restoreNode = () => {\n if (editor.isConnected) editor.replaceWith(node);\n delete node.dataset.editing;\n };\n\n const finish = () => {\n done = true;\n stopWatchingOutsideClicks();\n restoreNode();\n };\n\n function handleOutsidePointerDown(event) {\n if (done || event.target === editor || editor.contains(event.target))\n return;\n // Some drawer/header surfaces are not focusable, so clicking them does not\n // reliably blur the input in every browser. Force the blur path used on\n // commit so the edit styling cannot get stuck.\n editor.blur();\n }\n\n document.addEventListener(\"pointerdown\", handleOutsidePointerDown, true);\n\n const commit = async () => {\n if (done) return;\n const next = multiline ? editor.value : editor.value.trim();\n finish();\n if (String(next) === String(initialValue)) {\n if (rerender) await rerender();\n return;\n }\n if (emptyMessage && !next.trim()) {\n toast.warning(emptyMessage);\n if (rerender) await rerender();\n return;\n }\n if (commitHandler) await commitHandler(next);\n };\n\n const cancel = async () => {\n if (done) return;\n finish();\n if (rerender) await rerender();\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 (!multiline) {\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 editTitle = () =>\n startInlineEdit(titleEl, {\n fieldName: \"title\",\n multiline: false,\n initialValue: ticket.title || \"\",\n ariaLabel: \"Edit ticket title\",\n emptyMessage: \"Title cannot be empty\",\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { title: next }),\n });\n\n const titleEl = drawer.querySelector('[data-edit-field=\"title\"]');\n if (titleEl) {\n titleEl.addEventListener(\"click\", editTitle);\n titleEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n editTitle();\n }\n });\n }\n\n const descEl = drawerInner.querySelector('[data-edit-field=\"description\"]');\n const editDescription = (sourceEvent) =>\n startInlineEdit(descEl, {\n fieldName: \"description\",\n multiline: true,\n initialValue: ticket.description || \"\",\n ariaLabel: \"Edit ticket description\",\n sourceEvent,\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { description: cleanText(next) }),\n });\n\n if (descEl) {\n descEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n editDescription(event);\n });\n descEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n editDescription();\n }\n });\n }\n\n // AI Plan / Implementation fields: each becomes its own click-to-edit\n // surface so they save independently on blur / Ctrl+Enter, matching the\n // description field. The \"ai_plan\" / \"implementation_summary\" /\n // \"implementation_updates\" data-edit-field selectors are emitted by the\n // detail body template below.\n const AI_FIELDS = [\n { key: \"ai_plan\", label: \"AI plan\" },\n { key: \"implementation_summary\", label: \"Implementation summary\" },\n {\n key: \"implementation_updates\",\n label: \"Implementation updates / lessons\",\n },\n ];\n for (const { key, label } of AI_FIELDS) {\n const fieldEl = drawerInner.querySelector(`[data-edit-field=\"${key}\"]`);\n if (!fieldEl) continue;\n const edit = (sourceEvent) =>\n startInlineEdit(fieldEl, {\n fieldName: key,\n multiline: true,\n initialValue: ticket[key] || \"\",\n ariaLabel: `Edit ${label}`,\n sourceEvent,\n rerender: () => renderDetail(),\n commit: (next) => patchTicket(ticketId, { [key]: cleanText(next) }),\n });\n fieldEl.addEventListener(\"click\", (event) => {\n event.preventDefault();\n edit(event);\n });\n fieldEl.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n edit();\n }\n });\n }\n\n drawer.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 || [])\n .map((l) => l.name)\n .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\n .querySelector(\"[data-label-add]\")\n ?.addEventListener(\"click\", () => {\n void addLabel();\n });\n drawerInner\n .querySelector(\"[data-label-input]\")\n ?.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n void addLabel();\n }\n });\n}\n\nexport async function renderDetail(options = {}) {\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 requestedTicketId = state.selectedTicketId;\n const hasOption = (key) => Object.prototype.hasOwnProperty.call(options, key);\n const [context, statusHistory, comments, attachmentList] = await Promise.all([\n hasOption(\"context\")\n ? Promise.resolve(options.context)\n : api(\n withBoardQuery(`/api/tickets/${requestedTicketId}/context?depth=1`),\n ),\n hasOption(\"statusHistory\")\n ? Promise.resolve(options.statusHistory)\n : api(withBoardQuery(`/api/tickets/${requestedTicketId}/history`)),\n hasOption(\"comments\")\n ? Promise.resolve(options.comments)\n : api(withBoardQuery(`/api/tickets/${requestedTicketId}/comments`)).then(\n (result) => result.comments || [],\n ),\n hasOption(\"attachmentList\")\n ? Promise.resolve(options.attachmentList)\n : features.attachments\n ? api(\n withBoardQuery(`/api/tickets/${requestedTicketId}/attachments`),\n ).catch(() => ({ attachments: [] }))\n : Promise.resolve({ attachments: [] }),\n ]);\n if (\n state.detailMode !== \"ticket\" ||\n state.selectedTicketId !== requestedTicketId\n )\n return;\n if (context.ticket?.id !== requestedTicketId) return;\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\n .querySelector(\n `.card[data-ticket-id=\"${CSS.escape(ticket.id)}\"] .card-unread-dot`,\n )\n ?.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\n .map((name) => `<option value=\"${escapeHtml(name)}\"></option>`)\n .join(\"\");\n\n const detailCanonicalType = canonicalTicketType(ticket.type);\n const priorityKey = priorityKeyFor(ticket.priority);\n const currentState = states.find((s) => s.id === ticket.state_id);\n const stateClass = stateClassFor(currentState);\n const descriptionHtml = ticket.description\n ? renderPreservedText(ticket.description)\n : escapeHtml(\"No description yet.\");\n const descriptionClass = ticket.description\n ? \"description preserved-text-body editable-field\"\n : \"description editable-field is-placeholder\";\n const detailSubtitleHtml = `\n <span class=\"ticket-number\">${escapeHtml(ticketLabel(ticket))}</span>\n <div class=\"detail-meta-badge-row\" aria-label=\"Ticket metadata controls\">\n <select class=\"detail-meta-badge detail-state-badge meta-select\" data-variant=\"${escapeHtml(stateClass)}\" data-meta-field=\"state_id\" aria-label=\"Ticket state\">${stateOptions}</select>\n <select class=\"detail-meta-badge detail-type-badge type-pill-${escapeHtml(detailCanonicalType)} meta-select\" data-meta-field=\"type\" aria-label=\"Ticket type\">${typeOptions}</select>\n <select class=\"detail-meta-badge detail-priority-badge priority-pill meta-select\" data-variant=\"${escapeHtml(priorityKey)}\" data-meta-field=\"priority\" aria-label=\"Ticket priority\">${priorityOptions}</select>\n </div>\n `;\n\n renderDrawerShell({\n mode: \"ticket\",\n title: ticket.title,\n titleAttrs: {\n class: \"editable-field\",\n \"data-edit-field\": \"title\",\n role: \"button\",\n tabindex: \"0\",\n title: \"Click or press Enter to edit ticket title\",\n \"aria-label\": \"Edit ticket title\",\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=\"${descriptionClass}\" data-edit-field=\"description\" tabindex=\"0\" title=\"Click to edit\">${descriptionHtml}</div>\n <dl class=\"ticket-meta\" id=\"ticketMetaGrid\" data-ticket-id=\"${escapeHtml(ticket.id)}\">\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 ${features.attachments ? renderAttachmentSection(ticket, attachmentList.attachments || []) : \"\"}\n\n ${renderParentEpicSection(ticket, context)}\n\n <div class=\"section\">\n <h3>Related</h3>\n ${renderRelated(context.relations, ticket)}\n </div>\n\n ${\n currentBoard()?.ai_enabled !== 0\n ? `\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 <div class=\"ai-fields-grid\">\n ${renderInlinePreservedTextField({\n fieldName: \"ai_plan\",\n label: \"AI-Written Plan\",\n value: ticket.ai_plan,\n placeholder: \"Paste or let an AI write the plan...\",\n })}\n ${renderInlinePreservedTextField({\n fieldName: \"implementation_summary\",\n label: \"Implementation Summary\",\n value: ticket.implementation_summary,\n placeholder: \"What changed, what shipped, what remains...\",\n })}\n ${renderInlinePreservedTextField({\n fieldName: \"implementation_updates\",\n label: \"Implementation Updates / Lessons\",\n value: ticket.implementation_updates,\n placeholder: \"Progress notes, mistakes to avoid, discoveries...\",\n })}\n </div>\n </details>`\n : \"\"\n }\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 ${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 if (features.attachments) wireAttachmentControls(ticket);\n\n $(\"#detailCommentForm\").addEventListener(\"submit\", async (event) => {\n event.preventDefault();\n const body = cleanText(\n new FormData(event.currentTarget).get(\"body\"),\n ).trim();\n if (!body) return;\n await api(withBoardQuery(`/api/tickets/${ticket.id}/comments`), {\n method: \"POST\",\n body: { body },\n });\n await refreshTicketDetail(ticket.id);\n });\n\n drawerInner.querySelectorAll(\"[data-open-ticket]\").forEach((card) => {\n card.addEventListener(\"click\", async (event) => {\n if (\n event.target.closest(\n \"[data-detach-child],[data-detach-parent],[data-detach-relation]\",\n )\n )\n 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 refreshTicketDetail(ticket.id, { renderBoardAfter: true });\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 refreshTicketDetail(ticket.id, { renderBoardAfter: true });\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}`), {\n method: \"DELETE\",\n });\n } catch (err) {\n toast.error(err.message || \"Failed to remove relation\");\n return;\n }\n await refreshTicketDetail(ticket.id);\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(\n \"[data-parent-epic-clear]\",\n );\n const syncParentClear = () => {\n parentEpicForm.classList.toggle(\n \"has-value\",\n parentInput.value.length > 0,\n );\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(\n new FormData(event.currentTarget).get(\"target\") || \"\",\n ).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 refreshTicketDetail(ticket.id, { renderBoardAfter: true });\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(\n \"has-value\",\n relatedInput.value.length > 0,\n );\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: {\n source_ticket_id: ticket.id,\n target_ticket_id: targetId,\n type: relationType,\n },\n });\n } catch (err) {\n toast.error(err.message || \"Failed to add relation\");\n return;\n }\n await refreshTicketDetail(ticket.id);\n });\n }\n\n openDrawer();\n}\n\nfunction aiPlanOpen(ticketId) {\n return localStorage.getItem(`mab_ai_plan_open:${ticketId}`) === \"1\";\n}\n\nfunction renderAttachmentSection(ticket, attachments = []) {\n const cards = attachments.length\n ? `<div class=\"attachment-grid\">${attachments.map((attachment) => renderAttachmentCard(ticket, attachment)).join(\"\")}</div>`\n : `<p class=\"description\">No images attached yet.</p>`;\n return `\n <div class=\"section attachments-section\" data-attachment-section data-ticket-id=\"${escapeHtml(ticket.id)}\">\n <div class=\"attachment-heading-row\">\n <h3>Images</h3>\n <label class=\"ghost attachment-upload-button\">\n Upload\n <input type=\"file\" accept=\"image/*\" multiple data-attachment-input />\n </label>\n </div>\n <div class=\"attachment-dropzone\" data-attachment-dropzone tabindex=\"0\">\n <strong>Paste, drag, or upload images</strong>\n <span>PNG, JPG, GIF, WebP, SVG, BMP, or AVIF up to 10 MB each.</span>\n </div>\n ${cards}\n </div>\n `;\n}\n\nfunction renderAttachmentCard(ticket, attachment) {\n const name = escapeHtml(attachment.original_name || \"image\");\n const meta = `${formatBytes(attachment.size_bytes)} \u00B7 ${escapeHtml(attachment.mime_type || \"image\")}`;\n if (attachment.missing) {\n return `\n <article class=\"attachment-card is-missing\">\n <div class=\"attachment-missing-thumb\">Missing</div>\n <div class=\"attachment-card-meta\"><strong>${name}</strong><span>${meta}</span></div>\n <button type=\"button\" class=\"attachment-delete\" data-delete-attachment=\"${escapeHtml(attachment.id)}\" aria-label=\"Remove missing image\">\u00D7</button>\n </article>\n `;\n }\n const src = withBoardQuery(\n attachment.content_url ||\n `/api/tickets/${ticket.id}/attachments/${attachment.id}/content`,\n );\n return `\n <article class=\"attachment-card\">\n <button type=\"button\" class=\"attachment-thumb-button\" data-open-lightbox=\"${escapeHtml(src)}\" data-lightbox-title=\"${name}\">\n <img src=\"${escapeHtml(src)}\" alt=\"${name}\" loading=\"lazy\" />\n </button>\n <div class=\"attachment-card-meta\"><strong>${name}</strong><span>${meta}</span></div>\n <button type=\"button\" class=\"attachment-delete\" data-delete-attachment=\"${escapeHtml(attachment.id)}\" aria-label=\"Remove image\">\u00D7</button>\n </article>\n `;\n}\n\nfunction formatBytes(value) {\n const bytes = Number(value || 0);\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction imageFilesFromList(files) {\n return [...(files || [])].filter(\n (file) => file && String(file.type || \"\").startsWith(\"image/\"),\n );\n}\n\nasync function uploadAttachmentFiles(ticket, files) {\n const imageFiles = imageFilesFromList(files);\n if (!imageFiles.length) {\n toast.warning(\"No image files found\");\n return;\n }\n for (const file of imageFiles) {\n const response = await fetch(\n withBoardQuery(\n `/api/tickets/${ticket.id}/attachments?filename=${encodeURIComponent(file.name || \"image\")}`,\n ),\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": file.type || \"application/octet-stream\",\n \"X-File-Name\": file.name || \"image\",\n },\n body: file,\n },\n );\n if (!response.ok) {\n let payload = {};\n try {\n payload = await response.json();\n } catch {}\n throw new Error(payload.error || `Upload failed (${response.status})`);\n }\n }\n await refreshTicketDetail(ticket.id);\n toast.success(\n imageFiles.length === 1\n ? \"Image attached\"\n : `${imageFiles.length} images attached`,\n );\n}\n\nfunction wireAttachmentControls(ticket) {\n const section = drawerInner.querySelector(\"[data-attachment-section]\");\n if (!section) return;\n const input = section.querySelector(\"[data-attachment-input]\");\n input?.addEventListener(\"change\", async () => {\n try {\n await uploadAttachmentFiles(ticket, input.files);\n input.value = \"\";\n } catch (err) {\n toast.error(err.message || \"Upload failed\");\n }\n });\n\n const dropzone = section.querySelector(\"[data-attachment-dropzone]\");\n dropzone?.addEventListener(\"dragover\", (event) => {\n event.preventDefault();\n dropzone.classList.add(\"is-dragover\");\n });\n dropzone?.addEventListener(\"dragleave\", () =>\n dropzone.classList.remove(\"is-dragover\"),\n );\n dropzone?.addEventListener(\"drop\", async (event) => {\n event.preventDefault();\n dropzone.classList.remove(\"is-dragover\");\n try {\n await uploadAttachmentFiles(ticket, event.dataTransfer?.files || []);\n } catch (err) {\n toast.error(err.message || \"Upload failed\");\n }\n });\n\n drawerInner.onpaste = async (event) => {\n if (event.target.closest(\"input, textarea, [contenteditable='true']\"))\n return;\n const files = imageFilesFromList(event.clipboardData?.files || []);\n if (!files.length) return;\n event.preventDefault();\n try {\n await uploadAttachmentFiles(ticket, files);\n } catch (err) {\n toast.error(err.message || \"Paste upload failed\");\n }\n };\n\n section.querySelectorAll(\"[data-delete-attachment]\").forEach((btn) => {\n btn.addEventListener(\"click\", async () => {\n try {\n await api(\n withBoardQuery(\n `/api/tickets/${ticket.id}/attachments/${btn.dataset.deleteAttachment}`,\n ),\n { method: \"DELETE\" },\n );\n await refreshTicketDetail(ticket.id);\n toast.success(\"Image removed\");\n } catch (err) {\n toast.error(err.message || \"Delete failed\");\n }\n });\n });\n\n section.querySelectorAll(\"[data-open-lightbox]\").forEach((btn) => {\n btn.addEventListener(\"click\", () =>\n openAttachmentLightbox(\n btn.dataset.openLightbox,\n btn.dataset.lightboxTitle || \"Image\",\n ),\n );\n });\n}\n\nfunction openAttachmentLightbox(src, title) {\n const existing = document.querySelector(\".attachment-lightbox\");\n existing?.remove();\n const overlay = document.createElement(\"div\");\n overlay.className = \"attachment-lightbox\";\n overlay.innerHTML = `\n <div class=\"attachment-lightbox-panel\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${escapeHtml(title)}\">\n <button type=\"button\" class=\"attachment-lightbox-close\" aria-label=\"Close image\">\u00D7</button>\n <img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(title)}\" />\n <p>${escapeHtml(title)}</p>\n </div>\n `;\n const close = () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n overlay.remove();\n };\n function onKeyDown(event) {\n if (event.key === \"Escape\") close();\n }\n overlay.addEventListener(\"click\", (event) => {\n if (\n event.target === overlay ||\n event.target.closest(\".attachment-lightbox-close\")\n )\n close();\n });\n document.addEventListener(\"keydown\", onKeyDown);\n document.body.append(overlay);\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 byLine = escapeHtml(\n formatActorLabel({\n actor: event.actor,\n actorType: body.actor_type || \"human\",\n actorId: body.actor_id,\n }),\n );\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(formatCommentAuthor(comment))}</strong>\n <span>${comment.kind === \"human_comment\" ? \"\" : `${escapeHtml(comment.kind)} - `}${formatDate(comment.created_at)}</span>\n </div>\n <div class=\"comment-body preserved-text-body\">${renderPreservedText(comment.body)}</div>\n </div>\n `;\n}\n\n/**\n * Click-to-edit row for AI Plan / Implementation fields and any other\n * long-form ticket field that should render literal read-only text and become\n * a textarea on click. The wiring (event handlers + commit) lives in\n * wireTicketDetailEditors so this helper stays a pure template.\n */\nexport function renderInlinePreservedTextField({\n fieldName,\n label,\n value,\n placeholder,\n}) {\n const text = value || \"\";\n const hasValue = Boolean(text.trim());\n const inner = hasValue\n ? renderPreservedText(text)\n : escapeHtml(placeholder || \"\");\n const placeholderClass = hasValue ? \"\" : \"is-placeholder\";\n return `\n <div class=\"inline-md-field\">\n <span class=\"inline-md-field-label\">${escapeHtml(label)}</span>\n <div\n class=\"inline-md-field-body preserved-text-body editable-field ${placeholderClass}\"\n data-edit-field=\"${escapeHtml(fieldName)}\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit ${escapeHtml(label)}\"\n >${inner}</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) =>\n t.id !== ticket?.id && !relatedIds.has(t.id) && !hierarchyIds.has(t.id),\n );\n const datalistOptions = candidates\n .map(\n (t) => `<option value=\"#${t.number} \u2014 ${escapeHtml(t.title)}\"></option>`,\n )\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(\n (t) => t.type === \"epic\" && t.id !== ticket.id,\n );\n const datalistOptions = epics\n .map(\n (t) => `<option value=\"#${t.number} \u2014 ${escapeHtml(t.title)}\"></option>`,\n )\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 stateClass = stateClassFor(ticket);\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 =\n 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)}\" data-variant=\"${escapeHtml(canonicalType)}\"${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 <span class=\"detail-card-state\" data-variant=\"${escapeHtml(stateClass)}\">${escapeHtml(ticket.state_name || \"State\")}</span>\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", "import { cleanText, escapeHtml, renderPreservedText } from \"./format.js\";\n\nconst NOTE_FALLBACK = \"No board notes yet\";\nconst NOTES_PLACEHOLDER = \"Add board notes for yourself and your agents\u2026\";\n\nfunction compactText(value) {\n return cleanText(value || \"\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nexport function boardNotesSummary(board = {}) {\n return compactText(board.project_notes) || NOTE_FALLBACK;\n}\n\nfunction updateCachedBoard(board, appState) {\n if (!board?.id || !appState?.data?.boards) return;\n const index = appState.data.boards.findIndex((item) => item.id === board.id);\n if (index >= 0) appState.data.boards.splice(index, 1, { ...appState.data.boards[index], ...board });\n}\n\nlet lastRenderedBoard = {};\n\nfunction renderNotesBody(board) {\n const notes = board?.project_notes || \"\";\n const hasNotes = Boolean(notes.trim());\n const placeholderClass = hasNotes ? \"\" : \" is-placeholder\";\n const inner = hasNotes ? renderPreservedText(notes) : escapeHtml(NOTES_PLACEHOLDER);\n return `\n <div\n class=\"inline-md-field-body preserved-text-body editable-field brand-focus-notes-edit${placeholderClass}\"\n data-edit-field=\"project_notes\"\n tabindex=\"0\"\n title=\"Click to edit\"\n role=\"button\"\n aria-label=\"Edit board notes\"\n >${inner}</div>\n `;\n}\n\nexport function renderTopbarFocus(board = lastRenderedBoard) {\n lastRenderedBoard = board || {};\n const summary = boardNotesSummary(lastRenderedBoard);\n const notesButton = document.getElementById(\"brandNotesBtn\");\n const notesText = document.getElementById(\"brandNotesText\");\n const notesBody = document.getElementById(\"brandFocusNotes\");\n\n if (notesButton) {\n notesButton.hidden = false;\n notesButton.dataset.empty = summary === NOTE_FALLBACK ? \"true\" : \"false\";\n notesButton.setAttribute(\"aria-label\", `Show board notes: ${summary}`);\n }\n if (notesText) notesText.textContent = summary === NOTE_FALLBACK ? \"\" : summary;\n if (notesBody) notesBody.innerHTML = renderNotesBody(lastRenderedBoard);\n}\n\nfunction setPopoverOpen(open) {\n const buttons = [\n document.getElementById(\"brandFocusBtn\"),\n document.getElementById(\"brandNotesBtn\")\n ].filter(Boolean);\n const popover = document.getElementById(\"brandFocusPopover\");\n if (!popover) return;\n for (const button of buttons) {\n button.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n button.dataset.state = open ? \"open\" : \"closed\";\n }\n popover.hidden = !open;\n}\n\nfunction togglePopover() {\n const popover = document.getElementById(\"brandFocusPopover\");\n renderTopbarFocus();\n setPopoverOpen(Boolean(popover?.hidden));\n}\n\nasync function startBoardNotesEdit(sourceEvent) {\n const notesEl = document.querySelector('#brandFocusPopover [data-edit-field=\"project_notes\"]');\n if (!notesEl || !lastRenderedBoard?.id) return;\n const { startInlineEdit } = await import(\"./ticket-detail.js\");\n startInlineEdit(notesEl, {\n fieldName: \"project_notes\",\n multiline: true,\n initialValue: lastRenderedBoard.project_notes || \"\",\n ariaLabel: \"Edit board notes\",\n sourceEvent,\n rerender: async () => {\n renderTopbarFocus(lastRenderedBoard);\n setPopoverOpen(true);\n },\n commit: async (next) => {\n const [{ api }, { state }] = await Promise.all([\n import(\"./api.js\"),\n import(\"./state.js\")\n ]);\n const updatedBoard = await api(`/api/boards/${encodeURIComponent(lastRenderedBoard.id || state.boardId)}`, {\n method: \"PATCH\",\n body: { project_notes: cleanText(next) }\n });\n lastRenderedBoard = { ...lastRenderedBoard, ...updatedBoard };\n updateCachedBoard(lastRenderedBoard, state);\n renderTopbarFocus(lastRenderedBoard);\n setPopoverOpen(true);\n }\n });\n}\n\nexport function wireTopbarFocus() {\n const logoButton = document.getElementById(\"brandFocusBtn\");\n const notesButton = document.getElementById(\"brandNotesBtn\");\n const popover = document.getElementById(\"brandFocusPopover\");\n if (!logoButton || !notesButton || !popover) return;\n\n logoButton.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n togglePopover();\n });\n\n notesButton.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n togglePopover();\n });\n\n popover.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (event.target.closest('[data-edit-field=\"project_notes\"]')) {\n void startBoardNotesEdit(event);\n }\n });\n\n popover.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n if (!event.target.closest('[data-edit-field=\"project_notes\"]')) return;\n event.preventDefault();\n void startBoardNotesEdit(event);\n });\n\n document.addEventListener(\"click\", (event) => {\n if (\n event.target.closest(\"#brandFocusBtn\") ||\n event.target.closest(\"#brandNotesBtn\") ||\n event.target.closest(\"#brandFocusPopover\")\n ) return;\n setPopoverOpen(false);\n });\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key !== \"Escape\") return;\n setPopoverOpen(false);\n });\n}\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, currentBoard } from \"./state.js\";\nimport { api, bootstrapPath } from \"./api.js\";\nimport { renderBoard, renderBoardSelection } 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\";\nimport { renderTopbarFocus } from \"./topbar-notes.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 renderTopbarFocus(currentBoard());\n renderBoard();\n await renderDetail();\n}\n\nexport async function renderDetailOnly() {\n syncBoardSelection();\n updateTopbarChips();\n renderTopbarFocus(currentBoard());\n renderBoardSelection();\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</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\nconst boardChipIcon = `\n <svg\n class=\"topbar-icon\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect x=\"4\" y=\"4\" width=\"6\" height=\"16\" rx=\"0.75\" stroke=\"currentColor\" stroke-width=\"2\" />\n <rect x=\"14\" y=\"4\" width=\"6\" height=\"16\" rx=\"0.75\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>`;\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 const label = board?.name || \"Board\";\n boardMenuBtn.innerHTML = `${boardChipIcon}<span class=\"topbar-chip-label\">${escapeHtml(label)}</span>`;\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-variant=\"menu-item\" 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 <input name=\"name\" type=\"text\" required placeholder=\"Board name\" autocomplete=\"off\" />\n <div class=\"folder-picker-field\">\n <input id=\"repoPathInput\" name=\"repo_path\" type=\"text\" readonly placeholder=\"Coding project folder (optional)\" autocomplete=\"off\" />\n <button type=\"button\" id=\"pickRepoFolderBtn\">Browse</button>\n </div>\n <div id=\"helperFilesReveal\" hidden>\n <p class=\"menu-flyout-hint menu-flyout-hint--intro\">Orbit writes <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> into this folder for your AI coding agent.</p>\n <label class=\"menu-flyout-check\">\n <input id=\"helperFilesCheckbox\" name=\"manage_helper_files\" type=\"checkbox\" checked />\n <span>Generate AI helper files (<code>SKILL-ORBIT.md</code>, <code>AGENTS.md</code>)</span>\n </label>\n </div>\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 const helperFilesReveal = form.querySelector(\"#helperFilesReveal\");\n // The folder explanation and \"Generate AI helper files\" option only make\n // sense once a folder is chosen \u2014 there's nowhere to write them otherwise.\n // Reveal both with the folder value rather than disabling.\n const syncHelperFilesVisibility = () => {\n if (helperFilesReveal) helperFilesReveal.hidden = !repoPathInput.value.trim();\n };\n syncHelperFilesVisibility();\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 syncHelperFilesVisibility();\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 // Folder is optional. Only forward the helper-files choice when a folder\n // is set; the server ignores it otherwise.\n const created = await api(\"/api/boards\", {\n method: \"POST\",\n body: {\n name: fd.get(\"name\"),\n ...(repoPath ? { repo_path: repoPath, manage_helper_files: fd.get(\"manage_helper_files\") === \"on\" } : {}),\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, renderDetailOnly } = 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 return;\n }\n await renderDetailOnly();\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 storedThemePreference,\n setThemePreference,\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\n// When there's no explicit user preference stored, track OS changes live so\n// data-theme stays in sync and CSS selectors ([data-theme=\"dark\"]) keep working.\nwindow.matchMedia(\"(prefers-color-scheme: dark)\").addEventListener(\"change\", (e) => {\n if (!storedThemePreference()) {\n setThemePreference(e.matches ? \"dark\" : \"light\", { notify: true });\n }\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, enableKanbanInteractions } 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\";\nimport { wireTopbarFocus } from \"./topbar-notes.js\";\nimport { wireHelpMenu } from \"./help-menu.js\";\n\nasync function init() {\n const welcomeDialog = document.getElementById(\"welcomeDialog\");\n wireModal(welcomeDialog);\n wireTopbarFocus();\n wireHelpMenu();\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 enableKanbanInteractions();\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, stateClassFor, 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 <span class=\"search-hit-main\">\n <strong>${escapeHtml(ticketLabel(ticket))}</strong>\n <span class=\"search-hit-title\">${escapeHtml(ticket.title)}</span>\n </span>\n <span class=\"search-hit-state\" data-variant=\"${escapeHtml(stateClassFor(ticket))}\">${escapeHtml(ticket.state_name || \"State\")}</span>\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", "// Help & About dialog. The topbar \"Help\" button opens a centered\n// .orbit-dialog (same shell as the welcome dialog) describing what Orbit is,\n// how to get started, and where the docs live. modal.js owns the\n// Escape/backdrop/close-button behavior; this module only wires the open\n// trigger and best-effort fills the version pill from the build's version.json.\n\nimport { openModal, wireModal } from \"./modal.js\";\n\nasync function fillVersion(pill) {\n if (!pill) return;\n try {\n const res = await fetch(\"./version.json\", { cache: \"no-store\" });\n if (!res.ok) return;\n const info = await res.json();\n if (info?.version) pill.textContent = `v${info.version}`;\n } catch {\n // Dev edition serves raw modules without version.json \u2014 leave the\n // static \"Orbit\" label in place.\n }\n}\n\nexport function wireHelpMenu() {\n const dialog = document.getElementById(\"helpDialog\");\n const helpBtn = document.getElementById(\"helpBtn\");\n if (!dialog || !helpBtn) return;\n\n wireModal(dialog);\n fillVersion(document.getElementById(\"helpDialogVersion\"));\n\n helpBtn.addEventListener(\"click\", () => openModal(dialog));\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", "root", "stored", "init_motion_preference", "__esmMin", "safeStorage", "storage", "safeDocument", "doc", "safeEventTarget", "eventTarget", "normalizeTheme", "theme", "THEMES", "storedThemePreference", "value", "THEME_STORAGE_KEY", "systemTheme", "currentTheme", "rootTheme", "applyStoredThemePreference", "setThemePreference", "notify", "next", "dispatchThemeChange", "toggleThemePreference", "options", "target", "THEME_CHANGE_EVENT", "init_theme_preference", "__esmMin", "normalizeSettingsTab", "raw", "SETTINGS_TAB_IDS", "init_settings_tabs", "__esmMin", "state_exports", "__export", "boardLabelCatalog", "currentBoard", "getSettingsTab", "isAiReadyState", "selectableStatesForProject", "state", "statesForProject", "syncBoardSelection", "ticketsForProject", "upsertTicket", "visibleStatesForProject", "normalizeSettingsTab", "boards", "board", "b", "activeBoardId", "label", "item", "states", "currentStateId", "compactTicketForBoard", "ticket", "refreshBoardTicketDerivatives", "boardId", "boardTickets", "ticketById", "childCountByParent", "updatedTicket", "index", "previous", "merged", "a", "init_state", "__esmMin", "init_settings_tabs", "escapeHtml", "value", "fixMojibake", "text", "out", "from", "to", "MOJIBAKE_REPLACEMENTS", "cleanText", "renderPreservedText", "sanitizeMarkdownUrl", "href", "compact", "scheme", "SAFE_LINK_PROTOCOLS", "renderEmphasis", "html", "renderLinksAndEmphasis", "linkPattern", "lastIndex", "match", "labelHtml", "renderInlineMarkdown", "source", "cursor", "codeStart", "codeEnd", "renderParagraph", "lines", "renderTaskItem", "rawContent", "checked", "body", "renderMarkdown", "blocks", "paragraph", "list", "blockquote", "flushParagraph", "flushList", "classAttr", "item", "flushBlockquote", "flushAll", "i", "line", "codeLines", "header", "level", "quoteMatch", "ordered", "unordered", "type", "content", "task", "formatDate", "formatDateDetail", "ticketLabel", "ticket", "stateClassFor", "ticketOrState", "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", "api_exports", "__export", "api", "bootstrapPath", "withBoardQuery", "state", "path", "sep", "options", "request", "err", "toast", "init_api", "__esmMin", "init_state", "init_toast", "init_transport", "openDrawer", "drawerToken", "drawer", "drawerBackdrop", "closeDrawer", "finishToken", "wasOpen", "finish", "drawerInner", "titleBlockEl", "tabsEl", "ended", "end", "renderDrawerShell", "eyebrow", "title", "titleAttrs", "subtitleHtml", "tabs", "activeTab", "onTabSelect", "body", "mode", "titleAttrHtml", "key", "value", "escapeHtml", "segments", "t", "btn", "archiveBtn", "state", "init_drawer", "__esmMin", "init_dom", "init_state", "init_format", "buildCardActionMenu", "ticket", "lanes", "visibleStatesForProject", "lane", "PRIORITIES", "priority", "priorityLabel", "CARD_TYPES", "type", "typeLabel", "canonicalTicketType", "calculateMenuPosition", "x", "y", "menuWidth", "menuHeight", "viewportWidth", "viewportHeight", "margin", "MENU_MARGIN", "maxLeft", "maxTop", "preferredLeft", "preferredTop", "calculateSubmenuPosition", "triggerRect", "submenuWidth", "submenuHeight", "gap", "SUBMENU_GAP", "rightLeft", "leftLeft", "fitsRight", "fitsLeft", "maxHeight", "boundedHeight", "createCardActionHandlers", "apiClient", "api", "navigator", "confirmer", "patchTicket", "body", "withBoardQuery", "state", "stateId", "toast", "setCardActionDragInFlight", "value", "dragInFlight", "closeCardActionMenu", "restoreFocus", "cancelPendingClose", "dismissController", "submenu", "openSubmenus", "openMenu", "item", "submenuByItem", "lastFocusedElement", "openCardActionMenu", "anchor", "handlers", "onBeforeOpen", "menu", "renderMenuItems", "itemBySubmenu", "wireSubmenu", "rect", "position", "wireMenu", "firstEnabledItem", "signal", "dismissOnOutsidePointer", "dismissOnEscape", "dismissOnScroll", "bindCardContextMenuDelegated", "container", "resolveTicket", "event", "card", "items", "renderMenuItem", "hasChildren", "classes", "check", "suffix", "escapeHtml", "openSubmenu", "scheduleCloseOtherSubmenus", "closeOpenSubmenus", "handleItemClick", "handleMenuKeydown", "rootMenu", "button", "parent", "action", "currentMenu", "parentItem", "parentButton", "closeSubmenu", "moveFocus", "enabled", "enabledItems", "isEventInsideAnyMenu", "target", "siblings", "sibling", "positionSubmenu", "scope", "pendingCloseTimer", "HOVER_CLOSE_DELAY", "trigger", "availableHeight", "submenuRect", "list", "current", "step", "index", "nextIndex", "init_card_actions", "__esmMin", "init_api", "init_state", "init_format", "init_toast", "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", "boardTicketsById", "ticket", "kanban", "column", "renderColumn", "toggleCardExpansion", "card", "id", "willExpand", "state", "meta", "renderCardExpandable", "toggleBtn", "enableKanbanInteractions", "cardActionHandlers", "createCardActionHandlers", "navigate", "dragOverColumn", "setDragOverColumn", "event", "closeCardActionMenu", "setCardActionDragInFlight", "suppressClickAfterDrag", "ticketId", "closeCreateFlyout", "api", "withBoardQuery", "load", "target", "addBtn", "openCreateFlyout", "toggle", "epicHeader", "bindCardContextMenuDelegated", "renderBoardSelection", "renderEmptyState", "columnName", "name", "flair", "escapeHtml", "columnTickets", "isEmpty", "isAiReady", "columnClasses", "accentAttr", "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", "hasExpandable", "triggerInner", "unreadN", "unreadCount", "unreadDot", "renderMarkdown", "renderLabels", "enableKanbanDragScroll", "PAGE_SCROLL_PX", "active", "dragged", "startX", "startScroll", "pointerId", "shouldIgnore", "wheelPixels", "value", "mode", "horizontalDelta", "delta", "endDrag", "bothBtnPanning", "bothBtnLastX", "suppressContextMenu", "touchPanning", "touchPanLastX", "twoFingerCentroidX", "touches", "x", "endTouchPan", "init_kanban", "__esmMin", "init_dom", "init_state", "init_format", "init_api", "init_router", "init_create_card", "init_app", "init_card_actions", "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", "helperFilesSetup", "renderHelperFilesSection", "mcpSetup", "renderMcpSetupSection", "instructionsPlaceholder", "instructions", "hasInstructions", "placeholderClass", "inner", "renderPreservedText", "escapeHtml", "osId", "detectedMcpOs", "clientId", "paths", "mcpDetectedPaths", "configText", "mcpConfigText", "commandText", "mcpRunCommand", "client", "MCP_CLIENTS", "MCP_OS_OPTIONS", "option", "platform", "mcpDefaultPaths", "template", "mcpPathsFromForm", "$", "claudeCodeMcpCommand", "codexMcpToml", "opencodeMcpJson", "vscodeMcpJson", "config", "escapeToml", "shellQuote", "value", "repositoryDelete", "repoLabelFromUrl", "renderBoardRenameSection", "renderDeleteBoardSection", "hasFolder", "managed", "slug", "exportedCopy", "notesPlaceholder", "notes", "hasNotes", "renderLaneManager", "theme", "currentTheme", "reduceMotion", "effectiveReducedMotionPreference", "storedMotion", "storedReducedMotionPreference", "browserDefault", "browserPrefersReducedMotion", "sourceLabel", "renderThemeOption", "label", "selectedTheme", "renderProjectEntries", "parseImportSnapshotText", "text", "error", "exportSnapshot", "includeAttachments", "suffix", "snapshot", "filename", "downloadJson", "event", "form", "nextName", "load", "toast", "importSnapshotFile", "file", "bodyForSnapshot", "importSnapshotAsNewFile", "input", "result", "counts", "cardCount", "err", "replaceImportConfirmInput", "replaceCurrentBoardImportFile", "replaceCurrentBoardImportButton", "disabled", "confirmInput", "confirmButton", "notesEl", "drawerInner", "edit", "startInlineEdit", "next", "cleanText", "button", "handleLaneAction", "field", "updateLane", "renderBoard", "setThemePreference", "reduce", "setReducedMotionPreference", "applyReducedMotionPreference", "updateMcpPreview", "osNote", "format", "title", "helper", "configEl", "commandEl", "selector", "copyText", "instructionsEl", "enabled", "helperPickFolderBtn", "manageHelperFilesToggle", "listEl", "refresh", "tickets", "t", "renderDetailCard", "restoreBtn", "deleteBtn", "cardTitle", "withBoardQuery", "textArea", "entries", "entry", "isStruck", "formatDate", "deleteDisabled", "lane", "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", "clean", "value", "humanizeIdentifier", "raw", "char", "agentNameFrom", "actor", "actorId", "name", "id", "lowerName", "lowerId", "INTERNAL_LOCAL_NAMES", "GENERIC_AGENT_NAMES", "formatActorLabel", "actorType", "type", "agentName", "formatCommentAuthor", "comment", "kind", "author", "AGENT_COMMENT_KINDS", "init_actor_labels", "__esmMin", "ticket_detail_exports", "__export", "renderDetail", "renderDetailCard", "renderInlinePreservedTextField", "startInlineEdit", "refreshTicketDetail", "ticketId", "renderBoardAfter", "context", "statusHistory", "commentsResult", "api", "withBoardQuery", "upsertTicket", "renderBoard", "state", "patchTicket", "body", "inlineTextOffsetFromPoint", "node", "sourceEvent", "maxLength", "range", "position", "caretRange", "captureInlineEditScrollState", "scrollContainer", "restoreInlineEditScroll", "scrollState", "editor", "editorRect", "nextScrollTop", "focusWithoutScrolling", "opts", "fieldName", "multiline", "initialValue", "ariaLabel", "emptyMessage", "rerender", "commitHandler", "initialString", "clickedCaretOffset", "sourceHeight", "selectionStart", "done", "stopWatchingOutsideClicks", "handleOutsidePointerDown", "restoreNode", "finish", "event", "commit", "next", "toast", "cancel", "wireTicketDetailEditors", "ticket", "editTitle", "titleEl", "drawer", "descEl", "drawerInner", "editDescription", "cleanText", "AI_FIELDS", "key", "label", "fieldEl", "edit", "select", "field", "applyLabelPatch", "nextNames", "btn", "removeName", "names", "l", "n", "addLabel", "input", "name", "options", "renderProjectDetail", "openDrawer", "closeDrawer", "requestedTicketId", "hasOption", "comments", "attachmentList", "result", "features", "markRead", "states", "selectableStatesForProject", "typeOptions", "value", "escapeHtml", "canonicalTicketType", "typeLabelLong", "stateOptions", "s", "priorityOptions", "p", "priorityLabel", "labelPills", "datalistOptions", "boardLabelCatalog", "tl", "detailCanonicalType", "priorityKey", "priorityKeyFor", "currentState", "stateClass", "stateClassFor", "descriptionHtml", "renderPreservedText", "descriptionClass", "detailSubtitleHtml", "ticketLabel", "renderDrawerShell", "formatDateDetail", "renderHierarchySection", "renderAttachmentSection", "renderParentEpicSection", "renderRelated", "currentBoard", "aiPlanOpen", "renderStatusHistory", "renderComment", "wireAttachmentControls", "$", "card", "navigate", "childId", "err", "relationId", "aiPlanEl", "id", "parentEpicForm", "parentInput", "parentClear", "syncParentClear", "targetLabel", "targetId", "resolveTicketIdFromLabel", "target", "ticketsForProject", "t", "relatedAddForm", "relatedInput", "relatedClear", "syncRelatedClear", "form", "relationType", "attachments", "cards", "attachment", "renderAttachmentCard", "meta", "formatBytes", "src", "bytes", "imageFilesFromList", "files", "file", "uploadAttachmentFiles", "imageFiles", "response", "payload", "section", "dropzone", "openAttachmentLightbox", "title", "overlay", "close", "onKeyDown", "selfId", "trimmed", "match", "tickets", "hit", "exact", "history", "from", "to", "byLine", "formatActorLabel", "formatDate", "comment", "formatCommentAuthor", "placeholder", "text", "hasValue", "inner", "placeholderClass", "relations", "relatedIds", "r", "hierarchyIds", "list", "renderRelatedCard", "c", "canonicalType", "typeText", "typeLabel", "eyebrow", "detachBtn", "mode", "attr", "tid", "unreadN", "unreadCount", "unreadDot", "renderTypeIcon", "renderPriorityPill", "relation", "verb", "direction", "init_ticket_detail", "__esmMin", "init_state", "init_dom", "init_format", "init_kanban", "init_drawer", "init_router", "init_api", "init_config", "init_toast", "init_settings", "init_unread", "init_actor_labels", "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", "compactText", "value", "cleanText", "line", "boardNotesSummary", "board", "NOTE_FALLBACK", "updateCachedBoard", "appState", "index", "item", "renderNotesBody", "notes", "hasNotes", "placeholderClass", "inner", "renderPreservedText", "escapeHtml", "NOTES_PLACEHOLDER", "renderTopbarFocus", "lastRenderedBoard", "summary", "notesButton", "notesText", "notesBody", "setPopoverOpen", "open", "buttons", "popover", "button", "togglePopover", "startBoardNotesEdit", "sourceEvent", "notesEl", "startInlineEdit", "next", "api", "state", "updatedBoard", "wireTopbarFocus", "logoButton", "event", "init_topbar_notes", "__esmMin", "init_format", "app_exports", "__export", "load", "render", "renderDetailOnly", "closeMenuFlyouts", "state", "api", "bootstrapPath", "syncBoardSelection", "seedReadIfNeeded", "features", "sseBoardId", "connectEventStream", "updateTopbarChips", "renderTopbarFocus", "currentBoard", "renderBoard", "renderDetail", "renderBoardSelection", "init_app", "__esmMin", "init_state", "init_api", "init_kanban", "init_ticket_detail", "init_board_menu", "init_sse", "init_unread", "init_config", "init_topbar_notes", "isCreateFlyoutOpen", "createFlyout", "openCreateFlyout", "preselectedLaneId", "createFlyoutHideTimer", "closeMenuFlyouts", "closeDrawer", "createFlyoutInner", "renderCreateForm", "wireCreateForm", "$", "closeCreateFlyout", "createFlyoutBackdrop", "states", "visibleStatesForProject", "defaultState", "item", "effectiveStateId", "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", "label", "boardChipIcon", "escapeHtml", "renderBoardFlyoutInner", "listBody", "createBlock", "features", "wireBoardFlyout", "btn", "event", "id", "closeCreateFlyout", "navigate", "form", "pickRepoFolderBtn", "repoPathInput", "helperFilesReveal", "syncHelperFilesVisibility", "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", "renderDetailOnly", "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", "storedThemePreference", "setThemePreference", "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", "a", "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", "stateClassFor", "hit", "closeCreateFlyout", "navigate", "state", "init_app", "init_config", "openModal", "dialogEl", "closeModal", "wireModal", "event", "btn", "init_topbar_notes", "fillVersion", "pill", "res", "info", "wireHelpMenu", "dialog", "helpBtn", "wireModal", "openModal", "init", "welcomeDialog", "wireModal", "wireTopbarFocus", "wireHelpMenu", "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", "enableKanbanInteractions", "initialRoute", "currentRoute", "setRouterReady", "hasRoute", "applyRoute", "syncUrlFromState"]
|
|
7
|
-
}
|