@starlove/orbit 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,604 @@
1
+ var za=Object.defineProperty;var E=(e,a)=>()=>(e&&(a=e(e=0)),a);var Ga=(e,a)=>{for(var t in a)za(e,t,{get:a[t],enumerable:!0})};var b,Q,z,S,j,k,re,se,kt,ne,Je,V,Yt,$t,J=E(()=>{b=e=>document.querySelector(e),Q=b("#boardMenuBtn"),z=b("#boardFlyout"),S=b("#kanban"),j=b("#drawer"),k=b("#drawerInner"),re=b("#drawerBackdrop"),se=b("#createFlyout"),kt=b("#createFlyoutInner"),ne=b("#createFlyoutBackdrop"),Je=b("#searchInput"),V=b("#searchResults"),Yt=b("#themeToggle"),$t=b("#themeIcon")});function ce(e){try{return e??globalThis.localStorage??null}catch{return null}}function xt(e){return typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(e):{matches:!1}}function St(e=ce()){let t=ce(e)?.getItem?.(Xt);return t==="true"?!0:t==="false"?!1:null}function Lt(e=xt){try{return!!e("(prefers-reduced-motion: reduce)")?.matches}catch{return!1}}function de({storage:e=ce(),mediaMatcher:a=xt}={}){return St(e)??Lt(a)}function Zt(e,a=ce()){let t=ce(a),r=e?"true":"false";return t?.setItem?.(Xt,r),e}function Ee({doc:e=globalThis.document,storage:a=ce(),mediaMatcher:t=xt}={}){let r=de({storage:a,mediaMatcher:t});return e?.documentElement?.setAttribute("data-reduced-motion",r?"reduce":"allow"),r}var Xt,Et=E(()=>{Xt="mab_reduce_motion"});function le(e){try{return e??globalThis.localStorage??null}catch{return null}}function pe(e){try{return e??globalThis.document??null}catch{return null}}function Tt(e){try{return e??globalThis.window??null}catch{return null}}function Ja(e){return It.has(e)?e:"light"}function Vt(e=le()){let t=le(e)?.getItem?.(Qt);return It.has(t)?t:null}function ee({doc:e=pe(),storage:a=le()}={}){let t=pe(e)?.documentElement?.getAttribute?.("data-theme");return It.has(t)?t:Vt(a)??"light"}function ea({doc:e=pe(),storage:a=le()}={}){let t=Vt(a);return t&&pe(e)?.documentElement?.setAttribute?.("data-theme",t),ee({doc:e,storage:a})}function _t(e,{doc:a=pe(),storage:t=le(),eventTarget:r=Tt(),notify:n=!0}={}){let o=Ja(e);return pe(a)?.documentElement?.setAttribute?.("data-theme",o),le(t)?.setItem?.(Qt,o),n&&Ka(o,r),o}function ta(e={}){let a=ee(e)==="dark"?"light":"dark";return _t(a,e)}function Ka(e,a=Tt()){let t=Tt(a);if(typeof t?.dispatchEvent=="function"){if(typeof CustomEvent=="function"){t.dispatchEvent(new CustomEvent(Ke,{detail:{theme:e}}));return}t.dispatchEvent({type:Ke,detail:{theme:e}})}}var Qt,Ke,It,Ct=E(()=>{Qt="mab_theme",Ke="orbit:theme-change",It=new Set(["light","dark"])});function Te(e){return!e||!We.has(e)?"lanes":e}var We,Ye=E(()=>{We=new Set(["lanes","appearance","ai","notes","journal","repository","archive"])});function na(){return Te(s.settingsTab||localStorage.getItem("mab_settings_tab"))}function Ie(){if(!s.data)return;let e=s.data.boards||[],a=s.boardId?e.find(t=>t.id===s.boardId):null;if(!a&&s.boardSlug&&(a=e.find(t=>t.slug===s.boardSlug)||e.find(t=>t.id===s.boardSlug)),!a){let t=s.data.active_board_id;a=e.find(r=>r.id===t)||e[0]||null}s.boardId=a?.id||"",s.boardSlug=a?.slug||""}function q(){return(s.data?.boards||[]).find(e=>e.id===s.boardId)}function oa(){return s.boardId?(s.data?.labels||[]).filter(e=>e.board_id===s.boardId):[]}function _e(){return s.data.states.filter(e=>e.board_id===s.boardId)}function ia(e){return e?.role==="ai_ready"||e?.name==="AI Ready"}function Xe(){let e=_e();return q()?.ai_enabled!==0?e:e.filter(a=>!ia(a))}function sa(e=""){let a=_e();return q()?.ai_enabled!==0?a:a.filter(t=>!ia(t)||t.id===e)}function U(){return s.data.tickets.filter(e=>e.board_id===s.boardId)}var s,O=E(()=>{Ye();s={data:null,boardId:"",boardSlug:"",selectedTicketId:"",expandedCardIds:new Set,detailMode:"empty",settingsTab:Te(localStorage.getItem("mab_settings_tab")),showPriority:localStorage.getItem("mab_show_priority")!=="false",eventSource:null}});function d(e){return String(e??"").replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#039;")}function er(e){let a=String(e||"").trim();if(!a)return"";let t=a.replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();if(/^(?:javascript|data|vbscript):/.test(t))return"";let r=t.match(/^([a-z][a-z0-9+.-]*):/);return r&&!Va.has(`${r[1]}:`)?"":a}function Pt(e){let a=d(e);return a=a.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),a=a.replace(/(\*|_)(?=\S)([^*_]*?\S)\1/g,"<em>$2</em>"),a}function At(e){let a=/\[([^\]\n]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g,t="",r=0,n;for(;n=a.exec(e);){t+=Pt(e.slice(r,n.index));let o=Pt(n[1]),i=er(n[2]);t+=i?`<a href="${d(i)}" target="_blank" rel="noopener noreferrer">${o}</a>`:o,r=n.index+n[0].length}return t+=Pt(e.slice(r)),t}function ca(e){let a=String(e??""),t="",r=0;for(;r<a.length;){let n=a.indexOf("`",r);if(n===-1){t+=At(a.slice(r));break}let o=a.indexOf("`",n+1);if(o===-1){t+=At(a.slice(r));break}t+=At(a.slice(r,n)),t+=`<code>${d(a.slice(n+1,o))}</code>`,r=o+1}return t}function tr(e){return`<p>${ca(e.join(`
2
+ `)).replaceAll(`
3
+ `,"<br>")}</p>`}function Ze(e){let a=String(e??"").replace(/\r\n?/g,`
4
+ `);if(!a.trim())return"";let t=[],r=a.split(`
5
+ `),n=[],o=null,i=()=>{n.length&&(t.push(tr(n)),n=[])},c=()=>{o&&(t.push(`<${o.type}>${o.items.map(p=>`<li>${p}</li>`).join("")}</${o.type}>`),o=null)};for(let p=0;p<r.length;p+=1){let l=r[p];if(/^\s*```/.test(l)){i(),c();let g=[];for(p+=1;p<r.length&&!/^\s*```\s*$/.test(r[p]);)g.push(r[p]),p+=1;t.push(`<pre><code>${d(g.join(`
6
+ `))}</code></pre>`);continue}if(!l.trim()){i(),c();continue}let f=l.match(/^\s*\d+[.)]\s+(.+)$/),u=l.match(/^\s*[-*+]\s+(.+)$/);if(f||u){i();let g=f?"ol":"ul";(!o||o.type!==g)&&(c(),o={type:g,items:[]}),o.items.push(ca((f||u)[1].trim()).replaceAll(`
7
+ `,"<br>"));continue}c(),n.push(l.trim())}return i(),c(),t.join("")}function Ce(e){return e?new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}).format(new Date(e)):""}function da(e){return e?new Intl.DateTimeFormat(void 0,{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"}).format(new Date(e)):""}function G(e){return`#${e.number}`}function D(e){return e==="epic"||e==="feature"||e==="bug"||e==="task"?e:"task"}function Me(e){return{epic:"Epic",feature:"Feature",task:"Task",bug:"Bug"}[D(e)]||"Task"}function la(e){return{epic:"Epic / Story",feature:"Feature",task:"Task",bug:"Bug"}[D(e)]||"Task"}function Qe(e){return{0:"MAYBE",1:"LOW",2:"MED",3:"HIGH",4:"URGENT"}[Number(e)]||"MED"}function Pe(e){let a=["maybe","low","med","high","urgent"],t=Number(e);return a[Number.isFinite(t)?Math.max(0,Math.min(4,t)):2]}function pa(e=[]){return e.length?`
8
+ <div class="labels">
9
+ ${e.map(a=>`<span class="label" style="--label-color: ${d(a.color)}">${d(a.name)}</span>`).join("")}
10
+ </div>
11
+ `:""}function ua(e){let a=String(e||"").trim();if(!a)return"Not set";let t=a.match(/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);if(t)return`${t[1]}/${t[2]}`;let r=a.match(/github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);return r?`${r[1]}/${r[2]}`:a}var Va,X=E(()=>{Va=new Set(["http:","https:","mailto:","tel:"])});function rr(){return oe&&oe.isConnected||(oe=document.createElement("div"),oe.className="toast-container",document.body.append(oe)),oe}function m(e,a="info",t=4e3){let r=rr(),n=document.createElement("div");n.className=`toast toast-${a}`,n.setAttribute("role","status");let o=ar[a];n.innerHTML=`<span class="toast-icon">${o}</span><span class="toast-msg">${d(e)}</span><button class="toast-close" aria-label="Dismiss">&times;</button>`,n.querySelector(".toast-close").addEventListener("click",()=>Rt(n)),r.prepend(n),requestAnimationFrame(()=>requestAnimationFrame(()=>n.classList.add("toast-enter")));let i=setTimeout(()=>Rt(n),t);n.addEventListener("mouseenter",()=>clearTimeout(i)),n.addEventListener("mouseleave",()=>{let c=setTimeout(()=>Rt(n),1500);n.addEventListener("mouseenter",()=>clearTimeout(c),{once:!0})})}function Rt(e){e.classList.contains("toast-exit")||(e.classList.add("toast-exit"),e.addEventListener("animationend",()=>e.remove(),{once:!0}))}function ma(e,a){let t=new Blob([JSON.stringify(a,null,2)],{type:"application/json"}),r=URL.createObjectURL(t),n=document.createElement("a");n.href=r,n.download=e,document.body.append(n),n.click(),n.remove(),URL.revokeObjectURL(r)}function Ve(e,a){let t=0;return(...r)=>{clearTimeout(t),t=setTimeout(()=>e(...r),a)}}var ar,oe,ie=E(()=>{X();ar={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>',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>',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>',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>'},oe=null;m.info=(e,a)=>m(e,"info",a);m.success=(e,a)=>m(e,"success",a);m.warning=(e,a)=>m(e,"warning",a);m.error=(e,a)=>m(e,"error",a)});async function fa({method:e="GET",path:a,body:t,headers:r}){let n={"Content-Type":"application/json",...r||{}},o=await fetch(a,{method:e,headers:n,body:t!==void 0?JSON.stringify(t):void 0}),i=await o.text(),c=i?JSON.parse(i):{};if(!o.ok){let p=new Error(c.error||o.statusText);throw p.payload=c,p.status=o.status,p}return c}var ha=E(()=>{});function et(){return`/api/bootstrap${s.boardId?`?board_id=${encodeURIComponent(s.boardId)}`:s.boardSlug?`?board=${encodeURIComponent(s.boardSlug)}`:""}`}function T(e){if(!s.boardId||e.includes("board_id="))return e;let a=e.includes("?")?"&":"?";return`${e}${a}board_id=${encodeURIComponent(s.boardId)}`}async function y(e,a={}){try{return await fa({method:a.method||"GET",path:e,body:a.body,headers:a.headers})}catch(t){throw m.error(t.payload?.error||t.message||"Request failed"),t}}var K=E(()=>{O();ie();ha()});function Bt(){Dt+=1,j.hidden=!1,re.hidden=!1,requestAnimationFrame(()=>{j.classList.add("is-open"),re.classList.add("is-visible")})}function tt(){let e=++Dt,a=j.classList.contains("is-open");j.classList.remove("is-open"),re.classList.remove("is-visible");let t=()=>{if(Dt!==e)return;j.hidden=!0,re.hidden=!0,k.innerHTML="";let o=document.getElementById("drawerEyebrow"),i=document.getElementById("drawerTitle"),c=document.getElementById("drawerSubtitle"),p=document.getElementById("drawerTabs");if(o&&(o.textContent="",o.hidden=!0),i){for(let l of Array.from(i.attributes))l.name!=="id"&&i.removeAttribute(l.name);i.className="drawer-title-text",i.textContent=""}c&&(c.innerHTML="",c.hidden=!0),p&&(p.innerHTML="",p.hidden=!0),j.classList.remove("is-wide")};if(!a){t();return}let r=!1,n=()=>{r||(r=!0,t())};j.addEventListener("transitionend",n,{once:!0}),setTimeout(n,360)}function at({eyebrow:e,title:a,titleAttrs:t,subtitleHtml:r,tabs:n,activeTab:o,onTabSelect:i,body:c,mode:p}){j.classList.toggle("is-settings",p==="settings"),j.classList.toggle("is-wide",p==="ticket"||p==="settings");let l=document.getElementById("drawerEyebrow"),f=document.getElementById("drawerTitle"),u=document.getElementById("drawerSubtitle"),g=document.getElementById("drawerTabs");e?(l.textContent=e,l.hidden=!1):(l.textContent="",l.hidden=!0),r?(u.innerHTML=r,u.hidden=!1):(u.innerHTML="",u.hidden=!0);for(let x of Array.from(f.attributes))x.name!=="id"&&f.removeAttribute(x.name);if(f.className="drawer-title-text",t)for(let[x,B]of Object.entries(t))x==="class"?f.className=`drawer-title-text ${B}`:f.setAttribute(x,B);f.textContent=a??"",n&&n.length?(g.hidden=!1,g.innerHTML=n.map(x=>`<button type="button" role="tab" class="drawer-tab ${x.id===o?"is-active":""}" data-drawer-tab="${d(x.id)}" aria-selected="${x.id===o}">${d(x.label)}</button>`).join(""),typeof i=="function"&&g.querySelectorAll(".drawer-tab").forEach(x=>{x.addEventListener("click",()=>i(x.dataset.drawerTab))})):(g.hidden=!0,g.innerHTML="");let N=document.getElementById("drawerArchiveBtn");N&&(N.hidden=s.detailMode!=="ticket"),k.innerHTML=c??""}var Dt,rt=E(()=>{J();O();X();Dt=0});function nr(e){return e?typeof e=="string"?{readAt:e,count:0}:{readAt:e.readAt||null,count:Number(e.count)||0}:{readAt:null,count:0}}function Ae(e){if(!e)return new Map;let a=jt.get(e);if(a)return a;a=new Map;try{let t=localStorage.getItem(ba(e));if(t){let r=JSON.parse(t);for(let[n,o]of Object.entries(r))a.set(n,nr(o))}}catch{}return jt.set(e,a),a}function nt(e){let a=jt.get(e);if(a)try{let t={};for(let[r,n]of a)t[r]=n;localStorage.setItem(ba(e),JSON.stringify(t))}catch{}}function ga(e,a){let t=e.get(a);return t||(t={readAt:null,count:0},e.set(a,t)),t}function ot(e){let a=e?.board_id||s.boardId;if(!a||!e?.id)return 0;let r=Ae(a).get(e.id);return r?r.count:localStorage.getItem(Ft(a))==="1"?1:0}function it(e,a){let t=s.boardId;if(!t||!e)return;let r=Ae(t),n=ga(r,e);n.count===0&&n.readAt&&a&&n.readAt>=a||(n.count=0,a&&(n.readAt=a),nt(t))}function ya(e){let a=s.boardId;if(!a||!e)return;let t=Ae(a),r=ga(t,e);r.count=(r.count||0)+1,nt(a)}function va(e){let a=s.boardId;if(!a||!e)return;let t=Ae(a);t.has(e)&&(t.delete(e),nt(a))}function wa(e,a){if(!e||localStorage.getItem(Ft(e))==="1")return;let t=Ae(e);for(let r of a||[])!t.has(r.id)&&r.updated_at&&t.set(r.id,{readAt:r.updated_at,count:0});nt(e);try{localStorage.setItem(Ft(e),"1")}catch{}}var ba,Ft,jt,Re=E(()=>{O();ba=e=>`mab_card_read:${e}`,Ft=e=>`mab_card_read_seeded:${e}`,jt=new Map});function st(){let e=Xe(),a=U();S.innerHTML=e.map(t=>ir(t,a)).join(""),S.querySelectorAll(".column").forEach(t=>{t.addEventListener("dragover",r=>{r.preventDefault(),t.classList.add("drag-over")}),t.addEventListener("dragleave",()=>t.classList.remove("drag-over")),t.addEventListener("drop",async r=>{r.preventDefault(),t.classList.remove("drag-over");let n=r.dataTransfer.getData("text/plain");n&&(_(),await y(T(`/api/tickets/${n}`),{method:"PATCH",body:{state_id:t.dataset.stateId}}),await v())})}),S.querySelectorAll("[data-add-to-state]").forEach(t=>{t.addEventListener("click",r=>{r.stopPropagation(),dt(t.dataset.addToState||"")})}),S.querySelectorAll(".epic-mini-header[data-ticket-id]").forEach(t=>{t.addEventListener("click",()=>{_(),C({boardId:s.boardId,view:"ticket",ticketId:t.dataset.ticketId})})}),S.querySelectorAll(".card").forEach(t=>{let r=!1;t.addEventListener("click",async o=>{if((o.target instanceof Element?o.target:o.target?.parentElement)?.closest("a")){o.stopPropagation();return}if(r){r=!1,o.preventDefault(),o.stopPropagation();return}_(),C({boardId:s.boardId,view:"ticket",ticketId:t.dataset.ticketId})});let n=t.querySelector("button.card-expand-trigger");n&&n.addEventListener("click",o=>{o.stopPropagation(),o.preventDefault();let i=t.dataset.ticketId;s.expandedCardIds.has(i)?s.expandedCardIds.delete(i):s.expandedCardIds.add(i);let c=t.classList.toggle("is-expanded");n.setAttribute("aria-expanded",c?"true":"false")}),t.addEventListener("dragstart",o=>{o.dataTransfer.setData("text/plain",t.dataset.ticketId),o.dataTransfer.effectAllowed="move"}),t.addEventListener("dragend",()=>{r=!0,setTimeout(()=>{r=!1},0)})})}function or(e){let a=e.toLowerCase(),t={icon:'<svg class="empty-state-icon" viewBox="0 0 24 24"><path d="M18 6L6 18M6 6l12 12" opacity="0.5" /></svg>',title:"Nothing here",subtitle:"Tasks will appear when ready"};return a==="ai ready"?t={icon:`<svg class="empty-state-icon ai-sparkle" viewBox="0 0 24 24">
12
+ <path d="M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z" fill="currentColor" opacity="0.65" />
13
+ <circle cx="12" cy="11.5" r="1.8" fill="#fff" />
14
+ </svg>`,title:"Ready for agents",subtitle:"Drop unblocked cards here \u2014 the claim-next tool picks them up"}:a.includes("progress")?t={icon:`<svg class="empty-state-icon orbit" viewBox="0 0 100 100">
15
+ <circle cx="50" cy="50" r="10" fill="currentColor" opacity="0.9" />
16
+ <circle class="ring" cx="50" cy="50" r="30" stroke="currentColor" stroke-dasharray="4 6" />
17
+ <circle class="satellite" cx="80" cy="50" r="4" fill="currentColor" />
18
+ </svg>`,title:"Work in progress",subtitle:"Active work will appear here"}:a.includes("review")?t={icon:`<svg class="empty-state-icon star" viewBox="0 0 24 24">
19
+ <path d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z" fill="currentColor" />
20
+ </svg>`,title:"Under review",subtitle:"Quality gate before merge"}:a.includes("todo")||a.includes("backlog")?t={icon:`<svg class="empty-state-icon ai-sparkle" viewBox="0 0 24 24">
21
+ <path d="M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z" fill="currentColor" opacity="0.5" />
22
+ <path d="M19 8L20 10L21 8L20 6L19 8ZM19 16L20 18L21 16L20 14L19 16ZM5 8L6 10L7 8L6 6L5 8Z" fill="currentColor" />
23
+ </svg>`,title:"Ready for launch",subtitle:"Create a card manually or task an AI to generate tasks"}:a.includes("done")||a.includes("finished")?t={icon:`<svg class="empty-state-icon" viewBox="0 0 24 24">
24
+ <circle cx="12" cy="12" r="10" />
25
+ <path d="M8 12L11 15L16 9" />
26
+ </svg>`,title:"Done",subtitle:"Move completed tickets here"}:a.includes("cancel")&&(t={icon:`<svg class="empty-state-icon" viewBox="0 0 24 24">
27
+ <circle cx="12" cy="12" r="10" opacity="0.2" />
28
+ <path d="M15 9L9 15M9 9l6 6" />
29
+ </svg>`,title:"Not moving forward",subtitle:"Parked or replaced"}),`
30
+ <div class="column-empty-state">
31
+ <div class="empty-state-visual">
32
+ <div class="empty-state-glow"></div>
33
+ ${t.icon}
34
+ </div>
35
+ <div class="empty-state-title">${d(t.title)}</div>
36
+ <div class="empty-state-subtitle">${d(t.subtitle)}</div>
37
+ </div>
38
+ `}function ir(e,a){let t=a.filter(i=>i.state_id===e.id),r=t.length===0,n=e.name==="AI Ready",o=["column"];return n&&o.push("column--ai-ready"),`
39
+ <section class="${o.join(" ")}" data-state-id="${e.id}" data-state-name="${d(e.name)}">
40
+ <div class="column-head">
41
+ <h2${n?' title="Agent staging \u2014 cards here are picked up by the claim-next tool when unblocked"':""}>
42
+ ${n?'<span class="agent-dot" aria-hidden="true"></span>':""}${d(e.name)}
43
+ </h2>
44
+ <div class="column-head-actions">
45
+ <button type="button" class="column-add-btn ghost" data-add-to-state="${d(e.id)}" title="New card">+</button>
46
+ <span class="count">${t.length}</span>
47
+ </div>
48
+ </div>
49
+ ${r?or(e.name):sr(t,a)}
50
+ <button type="button" class="add-card-phantom" data-add-to-state="${d(e.id)}">+ Add a card</button>
51
+ </section>
52
+ `}function sr(e,a){let t=new Map(a.filter(c=>D(c.type)==="epic").map(c=>[c.id,c])),r=new Set(e.filter(c=>D(c.type)==="epic").map(c=>c.id)),n=new Map;for(let c of e)if(c.parent_ticket_id&&t.has(c.parent_ticket_id)){let p=n.get(c.parent_ticket_id)||[];p.push(c),n.set(c.parent_ticket_id,p)}let o=new Set,i=[];for(let c of e)if(!o.has(c.id)){if(D(c.type)==="epic"){let p=n.get(c.id)||[];if(p.length){let l=p.map(f=>De(f,{asEpicChild:!0})).join("");i.push(`${De(c)}<div class="epic-children">${l}</div>`),p.forEach(f=>o.add(f.id))}else i.push(De(c));o.add(c.id);continue}if(!(c.parent_ticket_id&&r.has(c.parent_ticket_id))){if(c.parent_ticket_id&&t.has(c.parent_ticket_id)&&!r.has(c.parent_ticket_id)){let p=t.get(c.parent_ticket_id),l=n.get(c.parent_ticket_id)||[],f=l.map(u=>De(u,{asEpicChild:!0})).join("");i.push(`${cr(p)}<div class="epic-children">${f}</div>`),l.forEach(u=>o.add(u.id));continue}i.push(De(c)),o.add(c.id)}}return i.join("")}function cr(e){return`
53
+ <div class="epic-mini-header" data-ticket-id="${d(e.id)}" title="Open epic">
54
+ <div class="card-type-id type-pill-epic">
55
+ ${Be("epic")}
56
+ <span class="card-type-label">EPIC</span>
57
+ </div>
58
+ <span class="ticket-number">${d(G(e))}</span>
59
+ <span class="epic-mini-title">${d(e.title)}</span>
60
+ </div>
61
+ `}function ct(e){let a=Pe(e),t=Qe(e);return`<div class="card-priority-id priority-pill priority-pill-${d(a)}"><span class="card-priority-label">${d(t)}</span></div>`}function Be(e){let a=D(e),t="",r="currentColor";switch(a){case"epic":r="#c084fc",t='<path d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z" fill="currentColor" />';break;case"feature":r="#4ade80",t='<path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2v16z" fill="currentColor" />';break;case"bug":r="#f87171",t='<circle cx="12" cy="12" r="10" /><path d="M12 8v4M12 16h.01" />';break;default:r="#60a5fa",t='<rect x="3" y="3" width="18" height="18" rx="2" /><path d="M9 12l2 2 4-4" />'}return`
62
+ <svg class="card-type-icon" viewBox="0 0 24 24" style="color: ${r}">
63
+ ${t}
64
+ </svg>
65
+ `}function De(e,{asEpicChild:a=!1}={}){let t=D(e.type),r=Pe(e.priority),n=Me(e.type).toUpperCase(),o=s.expandedCardIds.has(e.id),i=!!String(e.description||"").trim(),c=i||e.labels&&e.labels.length||e.parent_ticket||e.child_count,p=`
66
+ <span class="ticket-number">${d(G(e))}</span>
67
+ <div class="card-type-id type-pill-${d(t)}">
68
+ ${Be(e.type)}
69
+ <span class="card-type-label">${d(n)}</span>
70
+ </div>
71
+ ${s.showPriority?ct(e.priority):""}
72
+ ${c?'<svg class="card-expand-chevron" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6" /></svg>':""}
73
+ `,l=ot(e),f=l===0?"":l===1?'<span class="card-unread-dot" role="status" aria-label="1 unread update"></span>':`<span class="card-unread-dot has-count" role="status" aria-label="${l} unread updates">${l>99?"99+":l}</span>`;return`
74
+ <article class="card type-${d(t)} priority-${d(r)}${o?" is-expanded":""}${a?" is-epic-child":""} ${e.id===s.selectedTicketId?"selected":""}" draggable="true" data-ticket-id="${e.id}">
75
+ ${f}
76
+ <h3>${d(e.title)}</h3>
77
+
78
+ <div class="card-meta">
79
+ ${c?`<button type="button" class="card-expand-trigger" data-card-toggle aria-expanded="${o?"true":"false"}">${p}</button>`:`<div class="card-expand-trigger card-expand-trigger--static">${p}</div>`}
80
+ </div>
81
+
82
+ ${c?`
83
+ <div class="card-expandable">
84
+ ${i?`<div class="card-description markdown-body">${Ze(e.description)}</div>`:""}
85
+ ${pa(e.labels)}
86
+ ${e.parent_ticket?`<div class="parent-line">-> ${d(G(e.parent_ticket))}</div>`:""}
87
+ ${e.child_count?`<div class="child-count">${e.child_count} feature${e.child_count===1?"":"s"} inside</div>`:""}
88
+ </div>
89
+ `:""}
90
+ </article>
91
+ `}function ka(){let t=()=>Math.max(S.clientWidth,1),r=!1,n=!1,o=0,i=0,c=0,p=u=>u instanceof Element?!!(u.closest(".card")||u.closest("a, button, input, select, textarea, [draggable='true']")):!1,l=(u,g)=>g===WheelEvent.DOM_DELTA_LINE?u*16:g===WheelEvent.DOM_DELTA_PAGE?u*t():u;S.addEventListener("wheel",u=>{if(u.defaultPrevented||u.ctrlKey)return;let g=u.deltaX||(u.shiftKey?u.deltaY:0);!g||!(Math.abs(g)>=Math.abs(u.deltaY)||u.shiftKey)||S.scrollWidth<=S.clientWidth||(u.preventDefault(),S.scrollLeft+=l(g,u.deltaMode))},{passive:!1}),S.addEventListener("pointerdown",u=>{u.button===0&&(p(u.target)||(r=!0,n=!1,c=u.pointerId,o=u.clientX,i=S.scrollLeft,S.classList.add("is-grabbing")))}),S.addEventListener("pointermove",u=>{if(!r||u.pointerId!==c)return;let g=u.clientX-o;if(!n&&Math.abs(g)>4){n=!0;try{S.setPointerCapture(c)}catch{}}n&&(u.preventDefault(),S.scrollLeft=i-g)});let f=u=>{if(!(!r||u&&u.pointerId!==c)){r=!1,S.classList.remove("is-grabbing");try{S.releasePointerCapture(c)}catch{}}};S.addEventListener("pointerup",f),S.addEventListener("pointercancel",f),S.addEventListener("pointerleave",f),S.addEventListener("click",u=>{n&&(u.stopPropagation(),u.preventDefault(),n=!1)},!0)}var Fe=E(()=>{J();O();X();K();te();ue();Z();Re()});var $a,me,W,je=E(()=>{$a="full";$a="full";me=$a,W={sse:me==="full",ai:me==="full",multiBoard:me==="full",tokenAuth:me==="full"}});async function fe(){let e=await y(`/api/boards/${s.boardId}/context?include_struck=true`),a=e.board,t=na(),r=[{id:"lanes",label:"Lanes"},{id:"appearance",label:"Appearance"},{id:"archive",label:"Card Archive"},{id:"notes",label:"Notes"},{id:"journal",label:"Journal"},...W.ai?[{id:"ai",label:"AI"}]:[],{id:"repository",label:"Repository"}],n=t==="ai"&&!W.ai?"lanes":t;at({eyebrow:"SETTINGS",mode:"settings",title:a.name,tabs:r,activeTab:n,onTabSelect:async o=>{C({boardId:s.boardId,view:"settings",tab:o})},body:dr(e,n)}),Lr(e,n)}function dr(e,a){switch(a){case"notes":return $r(e);case"lanes":return Sa();case"appearance":return xr();case"ai":return W.ai?lr(e):Sa();case"journal":return Sr(e);case"archive":return vr();case"repository":default:return wr(e)}}function lr(e){let a=e.board,t=a.ai_enabled!==0,r=t?'<div class="ai-section-divider" aria-hidden="true"></div>':"",n=t?pr(a):"",o=t?ur(e):"";return`
92
+ <div class="section">
93
+ <label class="orbit-check" for="aiEnabledToggle">
94
+ <input
95
+ type="checkbox"
96
+ id="aiEnabledToggle"
97
+ ${t?"checked":""}
98
+ />
99
+ <span class="orbit-check-box" aria-hidden="true">
100
+ <svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
101
+ </span>
102
+ <span class="orbit-check-label">Enable AI</span>
103
+ </label>
104
+ <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>
105
+ </div>
106
+ ${r}
107
+ ${n}
108
+ ${r}
109
+ ${o}
110
+ `}function pr(e){return`
111
+ <div class="section ai-subsection ai-context-setup">
112
+ <div class="ai-context-title-row">
113
+ <span class="ai-context-inline-mark" aria-hidden="true">Context</span>
114
+ <h3>Agent Instructions</h3>
115
+ </div>
116
+ <p class="description">This project-level context is provided to agents when they work on tickets.</p>
117
+ <form id="agentInstructionsForm" class="field-form">
118
+ <textarea name="agent_instructions" placeholder="${d(`This project is about\u2026
119
+
120
+ How any AI agent should use this board and work in this repo.`)}">${d(e.agent_instructions||"")}</textarea>
121
+ <button type="submit">Save</button>
122
+ </form>
123
+ </div>
124
+ `}function ur(e){let a=lt(),t="claude-code",r=fr(e,a),n=Ot(t,r),o=Nt(a,r),i=ut[t];return`
125
+ <details class="section ai-subsection mcp-setup" data-mcp-setup>
126
+ <summary>
127
+ <div class="mcp-title-row">
128
+ <span class="mcp-inline-mark" aria-hidden="true">MCP</span>
129
+ <h3>Connect Your Agent to MCP</h3>
130
+ </div>
131
+ </summary>
132
+ <div>
133
+ <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>
134
+ <div class="mcp-flow">
135
+ <label>
136
+ <span>Operating system</span>
137
+ <select id="mcpOsSelect" class="select-chevron-field">
138
+ ${Object.entries(pt).map(([c,p])=>`<option value="${c}" ${c===a?"selected":""}>${d(p.label)}</option>`).join("")}
139
+ </select>
140
+ </label>
141
+ <label>
142
+ <span>Agent app</span>
143
+ <select id="mcpClientSelect" class="select-chevron-field">
144
+ ${Object.entries(ut).map(([c,p])=>`<option value="${c}" ${c===t?"selected":""}>${d(p.label)}</option>`).join("")}
145
+ </select>
146
+ </label>
147
+ </div>
148
+ <div class="mcp-path-grid">
149
+ <label>
150
+ <span>Orbit MCP server file</span>
151
+ <input id="mcpServerPathInput" value="${d(r.serverPath)}" />
152
+ </label>
153
+ </div>
154
+ </div>
155
+
156
+ <div class="mcp-options-stack">
157
+ <div class="mcp-option-card">
158
+ <div class="mcp-option-card-head">
159
+ <div>
160
+ <strong data-mcp-output-title>${d(i.label)} setup</strong>
161
+ <p class="description" data-mcp-helper>${d(i.helper)}</p>
162
+ </div>
163
+ <button type="button" class="ghost" data-copy-mcp="config">Copy setup</button>
164
+ </div>
165
+ <div class="mcp-terminal">
166
+ <div class="mcp-terminal-chrome" aria-hidden="true"><span></span><span></span><span></span></div>
167
+ <pre class="mcp-snippet"><code data-mcp-config>${d(n)}</code></pre>
168
+ </div>
169
+ </div>
170
+
171
+ <div class="mcp-or-divider" aria-hidden="true"><span>OR</span></div>
172
+
173
+ <div class="mcp-option-card">
174
+ <div class="mcp-option-card-head">
175
+ <div>
176
+ <strong>Manual run command</strong>
177
+ <p class="description">Use this only when an app asks you to start the MCP server yourself.</p>
178
+ </div>
179
+ <button type="button" class="ghost" data-copy-mcp="command">Copy command</button>
180
+ </div>
181
+ <div class="mcp-terminal">
182
+ <div class="mcp-terminal-chrome" aria-hidden="true"><span></span><span></span><span></span></div>
183
+ <pre class="mcp-snippet mcp-snippet--compact"><code data-mcp-command>${d(o)}</code></pre>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </details>
188
+ `}function lt(){let e=String(navigator.userAgentData?.platform||navigator.platform||navigator.userAgent||"").toLowerCase();return e.includes("win")?"windows":e.includes("mac")?"macos":"linux"}function mr(e){return{serverPath:(pt[e]||pt.linux).serverPath}}function fr(e,a){let t=mr(a);return{serverPath:(e.deployment||{}).mcp_server_path||t.serverPath}}function xa(){return{serverPath:b("#mcpServerPathInput")?.value||""}}function Ot(e,a){if(e==="claude-code")return gr(a);if(e==="codex")return br(a);if(e==="opencode")return hr(a);let t={mcpServers:{"starscape-orbit":{command:"node",args:[a.serverPath]}}};return JSON.stringify(t,null,2)}function hr(e){return JSON.stringify({$schema:"https://opencode.ai/config.json",mcp:{"starscape-orbit":{type:"local",command:["node",e.serverPath],enabled:!0}}},null,2)}function br(e){return`[mcp_servers.starscape-orbit]
189
+ command = "node"
190
+ args = ["${yr(e.serverPath)}"]
191
+ enabled = true`}function gr(e){return["claude mcp add starscape-orbit","--","node",Ea(e.serverPath)].join(" ")}function Nt(e,a){return`node ${Ea(a.serverPath)}`}function Ea(e){return`"${String(e||"").replace(/"/g,'\\"')}"`}function yr(e){return String(e||"").replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function vr(){return`
192
+ <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>
193
+ <div class="section">
194
+ <div id="archiveList" class="archive-list">Loading\u2026</div>
195
+ </div>
196
+ `}function wr(e){let a=e.board;return P.boardId!==a.id&&(P.boardId=a.id,P.step="idle",P.exported=!1),`
197
+ ${W.multiBoard?`
198
+ <div class="detail-head project-manual-head">
199
+ <div class="meta-grid">
200
+ <div class="meta meta--repo-path">
201
+ <span>Repo</span>
202
+ <strong>${d(ua(a.repo_url))}</strong>
203
+ <span>Path</span>
204
+ <strong>${d(a.system_path||e.deployment?.system_path||"Not available")}</strong>
205
+ </div>
206
+ </div>
207
+ </div>`:`
208
+ <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>`}
209
+
210
+ <div class="section">
211
+ <h3>Board Snapshot</h3>
212
+ <div class="deployment-actions">
213
+ <button type="button" class="ghost" id="exportProject">Export</button>
214
+ <label class="import-button">
215
+ <input type="file" id="importSnapshotFile" accept=".orbit.json,.json,application/json" />
216
+ <span>Import</span>
217
+ </label>
218
+ </div>
219
+ </div>
220
+
221
+ ${W.multiBoard?kr(a):""}
222
+ `}function kr(e){let a=d(e.slug||"");if(P.step==="choice")return`
223
+ <div class="section repository-danger-zone">
224
+ <h3>Delete Board</h3>
225
+ <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>
226
+ <div class="repository-delete-actions">
227
+ <button type="button" class="ghost" id="deleteBoardExportFirst">Export first</button>
228
+ <button type="button" class="ghost danger-button" id="deleteBoardSkipExport">Delete without exporting</button>
229
+ <button type="button" class="ghost" id="deleteBoardCancel">Cancel</button>
230
+ </div>
231
+ </div>
232
+ `;if(P.step==="confirm"){let t=P.exported?"Snapshot exported. Type the board slug to confirm permanent deletion.":"Type the board slug to confirm permanent deletion.";return`
233
+ <div class="section repository-danger-zone is-confirming">
234
+ <h3>Delete Board</h3>
235
+ <p class="description">${d(t)}</p>
236
+ <label class="repository-confirm-field">
237
+ <span>Board slug</span>
238
+ <strong>${a}</strong>
239
+ <input id="deleteBoardConfirmInput" autocomplete="off" spellcheck="false" placeholder="${a}" autofocus />
240
+ </label>
241
+ <div class="repository-delete-actions">
242
+ <button type="button" class="danger-button" id="deleteBoardConfirm" disabled>Delete board permanently</button>
243
+ <button type="button" class="ghost" id="deleteBoardCancel">Cancel</button>
244
+ </div>
245
+ </div>
246
+ `}return`
247
+ <div class="section repository-danger-zone">
248
+ <h3>Delete Board</h3>
249
+ <p class="description">Remove this board from Orbit and delete its repo-local Orbit files. This cannot be undone without an exported snapshot.</p>
250
+ <button type="button" class="ghost danger-button" id="deleteBoardStart">Delete Board</button>
251
+ </div>
252
+ `}function $r(e){let a=e.board;return`
253
+ <div class="section ai-fields">
254
+ <form id="notesSettingsForm" class="field-form settings-notes-form">
255
+ <label class="settings-notes-field-group">
256
+ <span>Notes For You</span>
257
+ <textarea
258
+ name="project_notes"
259
+ class="settings-notes-textarea"
260
+ placeholder="${d("Remember to mention SKILL-ORBIT.md to my AI agents if they get confused")}"
261
+ >${d(a.project_notes||"")}</textarea>
262
+ </label>
263
+ <button type="submit" class="settings-notes-save">Save</button>
264
+ </form>
265
+ </div>
266
+ `}function Sa(){return`
267
+ <div class="section">
268
+ <label class="orbit-check" for="showPriorityToggle">
269
+ <input
270
+ type="checkbox"
271
+ id="showPriorityToggle"
272
+ ${s.showPriority?"checked":""}
273
+ />
274
+ <span class="orbit-check-box" aria-hidden="true">
275
+ <svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
276
+ </span>
277
+ <span class="orbit-check-label">Show priority label on cards</span>
278
+ </label>
279
+ <p class="description lanes-description">Rename, reorder, add, or remove lanes.</p>
280
+ ${Cr()}
281
+ <form id="laneCreateForm" class="lane-create-form">
282
+ <input name="name" placeholder="New lane name..." required />
283
+ <button type="submit">Add Lane</button>
284
+ </form>
285
+ </div>
286
+ `}function xr(){let e=ee(),a=de(),t=St(),r=Lt(),n=t===null?`Using browser default (${r?"reduced motion":"motion allowed"}).`:"Using your saved preference.";return`
287
+ <div class="section appearance-theme-section">
288
+ <fieldset class="appearance-theme-field">
289
+ <legend>Theme</legend>
290
+ <div class="appearance-theme-options">
291
+ ${La("light","Light",e)}
292
+ ${La("dark","Dark",e)}
293
+ </div>
294
+ <p class="description">Applies the light/dark theme used by the top rail toggle.</p>
295
+ </fieldset>
296
+ </div>
297
+ <div class="section">
298
+ <label class="orbit-check" for="reduceMotionToggle">
299
+ <input
300
+ type="checkbox"
301
+ id="reduceMotionToggle"
302
+ ${a?"checked":""}
303
+ />
304
+ <span class="orbit-check-box" aria-hidden="true">
305
+ <svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
306
+ </span>
307
+ <span class="orbit-check-label">Reduce theme motion</span>
308
+ </label>
309
+ <p class="description">Turns off the animated starfield, meteors, and theme animations. ${d(n)}</p>
310
+ </div>
311
+ `}function La(e,a,t){return`
312
+ <label class="appearance-theme-option">
313
+ <input type="radio" name="themePreference" value="${e}" ${t===e?"checked":""} />
314
+ <span class="appearance-theme-option-mark" aria-hidden="true">
315
+ <svg
316
+ class="appearance-theme-option-icon"
317
+ width="16"
318
+ height="16"
319
+ viewBox="0 0 24 24"
320
+ fill="none"
321
+ stroke="currentColor"
322
+ stroke-width="2"
323
+ stroke-linecap="round"
324
+ stroke-linejoin="round"
325
+ >${e==="dark"?'<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />':'<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" />'}</svg>
326
+ </span>
327
+ <span class="appearance-theme-option-label">${a}</span>
328
+ </label>
329
+ `}function Sr(e){return`
330
+ ${e.board?.ai_enabled!==0?'<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>':""}
331
+ <div class="section">
332
+ ${Tr(e.entries)}
333
+ <form id="projectEntryForm" class="comment-form project-entry-form">
334
+ <select name="type" class="select-chevron-field" aria-label="Entry type">
335
+ <option value="decision">Decision</option>
336
+ <option value="lesson">Lesson</option>
337
+ </select>
338
+ <input name="title" placeholder="Entry title..." required />
339
+ <textarea name="body" placeholder="Decision rationale or lesson: do X instead of Y when working with Z." required></textarea>
340
+ <button type="submit">Add Entry</button>
341
+ </form>
342
+ </div>
343
+ `}function Lr(e,a){let t=e.board;if(a==="repository"){let r=async()=>{let i=await y(`/api/boards/${t.id}/export`);ma(`${t.slug}.orbit.json`,i)};b("#exportProject")?.addEventListener("click",async()=>{await r()}),b("#importSnapshotFile")?.addEventListener("change",async i=>{let c=i.currentTarget.files?.[0];if(!c)return;let p=await c.text(),l=JSON.parse(p);await y("/api/admin/import",{method:"POST",body:{snapshot:l,replace_existing:!0,board_id:t.id}}),await v(),s.detailMode="settings",m.success("Board imported"),i.currentTarget.value=""}),b("#deleteBoardStart")?.addEventListener("click",async()=>{P.step="choice",P.exported=!1,await fe()}),b("#deleteBoardExportFirst")?.addEventListener("click",async()=>{await r(),P.step="confirm",P.exported=!0,await fe()}),b("#deleteBoardSkipExport")?.addEventListener("click",async()=>{P.step="confirm",P.exported=!1,await fe()}),b("#deleteBoardCancel")?.addEventListener("click",async()=>{P.step="idle",P.exported=!1,await fe()});let n=b("#deleteBoardConfirmInput"),o=b("#deleteBoardConfirm");n?.addEventListener("input",()=>{o&&(o.disabled=n.value.trim()!==t.slug)}),o?.addEventListener("click",async()=>{await y(`/api/boards/${encodeURIComponent(t.id)}`,{method:"DELETE",body:{confirm_slug:t.slug,delete_files:!0}}),P.step="idle",P.exported=!1,await v(),m.success(`Deleted board: ${t.name}`),C({boardId:s.boardId,view:"board"},{replace:!0})})}if(a==="notes"&&b("#notesSettingsForm")?.addEventListener("submit",async r=>{r.preventDefault();let n=new FormData(r.currentTarget);await y(`/api/boards/${t.id}`,{method:"PATCH",body:{project_notes:String(n.get("project_notes")??"")}}),await v(),s.detailMode="settings",m.success("Saved")}),a==="lanes"&&(k.querySelectorAll("[data-lane-action]").forEach(r=>{r.addEventListener("click",async()=>{await Mr(r)})}),k.querySelectorAll(".lane-row input, .lane-row select").forEach(r=>{r.addEventListener("change",async()=>{await Ia(r.closest(".lane-row"))})}),b("#laneCreateForm")?.addEventListener("submit",async r=>{r.preventDefault();let n=new FormData(r.currentTarget);await y(`/api/boards/${t.id}/states`,{method:"POST",body:Object.fromEntries(n.entries())}),await v(),s.detailMode="settings",m.success("Lane added")}),b("#showPriorityToggle")?.addEventListener("change",r=>{s.showPriority=!!r.currentTarget.checked,localStorage.setItem("mab_show_priority",s.showPriority?"true":"false"),st()})),a==="appearance"&&(k.querySelectorAll("input[name='themePreference']").forEach(r=>{r.addEventListener("change",n=>{if(!n.currentTarget.checked)return;let o=_t(n.currentTarget.value);m.success(o==="dark"?"Dark theme enabled":"Light theme enabled")})}),b("#reduceMotionToggle")?.addEventListener("change",r=>{let n=!!r.currentTarget.checked;Zt(n),Ee(),window.dispatchEvent(new CustomEvent("orbit:motion-preference-change",{detail:{reduce:n}})),m.success(n?"Theme motion reduced":"Theme motion enabled")})),a==="ai"){let r=()=>{let n=b("#mcpOsSelect")?.value||lt(),o=b("#mcpClientSelect")?.value||"claude-code",i=ut[o]||ut.generic,c=xa(),p=Ot(o,c),l=Nt(n,c),f=k.querySelector("[data-mcp-os-note]");f&&(f.textContent=`Detected: ${pt[lt()]?.label||"Linux"}`);let u=k.querySelector("[data-mcp-client-format]");u&&(u.textContent=i.format);let g=k.querySelector("[data-mcp-output-title]");g&&(g.textContent=`${i.label} setup`);let N=k.querySelector("[data-mcp-helper]");N&&(N.textContent=i.helper);let x=k.querySelector("[data-mcp-config]");x&&(x.textContent=p);let B=k.querySelector("[data-mcp-command]");B&&(B.textContent=l)};b("#mcpOsSelect")?.addEventListener("change",()=>r()),b("#mcpClientSelect")?.addEventListener("change",()=>r()),["#mcpServerPathInput"].forEach(n=>{b(n)?.addEventListener("input",()=>r())}),k.querySelectorAll("[data-copy-mcp]").forEach(n=>{n.addEventListener("click",async()=>{let o=b("#mcpOsSelect")?.value||lt(),i=b("#mcpClientSelect")?.value||"claude-code",c=xa(),p=n.dataset.copyMcp==="command"?Nt(o,c):Ot(i,c);await Er(p),m.success(n.dataset.copyMcp==="command"?"MCP command copied":"MCP config copied")})}),b("#agentInstructionsForm")?.addEventListener("submit",async n=>{n.preventDefault();let o=new FormData(n.currentTarget);await y(`/api/boards/${t.id}`,{method:"PATCH",body:Object.fromEntries(o.entries())}),await v(),s.detailMode="settings",m.success("Saved")}),b("#aiEnabledToggle")?.addEventListener("change",async n=>{let o=!!n.currentTarget.checked;await y(`/api/boards/${t.id}`,{method:"PATCH",body:{ai_enabled:o}}),await v(),s.detailMode="settings",m.success(o?"AI features enabled \u2014 agent lanes provisioned":"AI features disabled \u2014 AI Ready hidden")})}if(a==="archive"){let r=b("#archiveList");if(r){let n=async()=>{try{let i=(await y(`/api/boards/${encodeURIComponent(t.id)}/archive`)).tickets||[];if(i.length===0){r.innerHTML='<p class="description">No archived cards yet. Click the trash icon in the card detail header to archive a card.</p>';return}r.innerHTML=`<div class="detail-card-grid">${i.map(c=>Oe(c,{archive:{id:c.id},disableOpen:!0})).join("")}</div>`}catch(o){r.innerHTML=`<p class="description">Could not load archive: ${d(o?.message||"unknown error")}</p>`}};n(),r.addEventListener("click",async o=>{let i=o.target.closest("[data-archive-restore]"),c=o.target.closest("[data-archive-delete]");if(!i&&!c)return;o.stopPropagation();let l=(i||c).closest("article")?.querySelector("h3")?.textContent||"card";if(i){let f=i.dataset.archiveRestore;await y(T(`/api/tickets/${encodeURIComponent(f)}/restore`),{method:"POST"}),m.success(`Restored: ${l}`),await v(),await n();return}if(c){let f=c.dataset.archiveDelete;if(!confirm(`Permanently delete "${l}"? This cannot be undone.`))return;await y(T(`/api/tickets/${encodeURIComponent(f)}`),{method:"DELETE"}),m.success(`Deleted: ${l}`),await n()}})}}a==="journal"&&(k.querySelectorAll("[data-entry-action='toggle-struck']").forEach(r=>{r.addEventListener("click",async()=>{await y(T(`/api/board-entries/${r.dataset.entryId}`),{method:"PATCH",body:{struck:r.dataset.struck!=="true"}}),await v(),s.detailMode="settings",m.info(r.dataset.struck==="true"?"Project entry restored":"Project entry struck")})}),b("#projectEntryForm")?.addEventListener("submit",async r=>{r.preventDefault();let n=new FormData(r.currentTarget);await y(`/api/boards/${t.id}/entries`,{method:"POST",body:Object.fromEntries(n.entries())}),await v(),s.detailMode="settings",m.success("Project entry added")}))}async function Er(e){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(e);return}let a=document.createElement("textarea");a.value=e,a.setAttribute("readonly",""),a.style.position="fixed",a.style.left="-9999px",document.body.append(a),a.select(),document.execCommand("copy"),a.remove()}function Tr(e=[]){return e.length?e.map(a=>{let t=!!a.struck_at;return`
344
+ <div class="comment project-entry ${d(a.type)} ${t?"is-struck":""}">
345
+ <div class="comment-meta">
346
+ <div>
347
+ <strong>${d(a.type.toUpperCase())}: ${d(a.title)}</strong>
348
+ ${t?'<span class="project-entry-status">Excluded from agent context</span>':""}
349
+ </div>
350
+ <div class="project-entry-actions">
351
+ <span>${d(a.created_by)} - ${Ce(a.created_at)}</span>
352
+ <button
353
+ type="button"
354
+ class="ghost project-entry-strike"
355
+ data-entry-action="toggle-struck"
356
+ data-entry-id="${d(a.id)}"
357
+ data-struck="${t?"true":"false"}"
358
+ aria-pressed="${t?"true":"false"}"
359
+ >${t?"Restore":"Strike"}</button>
360
+ </div>
361
+ </div>
362
+ <div class="comment-body">${d(a.body)}</div>
363
+ </div>
364
+ `}).join(""):'<p class="description">No project entries yet.</p>'}function Ir(e,a,t){return!!(a.get(e.id)||e.is_default||Ta.has(e.role)||t&&e.role==="ai_ready")}function _r(e,a,t){let r=a.get(e.id)||0;return r>0?`Cannot delete \u2014 ${r} card${r===1?"":"s"} in this lane`:e.is_default?"Cannot delete \u2014 default lane for new cards (move it first)":Ta.has(e.role)?"Cannot delete \u2014 core kanban lane":t&&e.role==="ai_ready"?"Cannot delete \u2014 required by agent flow while AI is enabled":"Delete lane"}function Cr(){let e=_e(),a=q()?.ai_enabled!==0,t=new Map;for(let r of U())t.set(r.state_id,(t.get(r.state_id)||0)+1);return`
365
+ <div class="lane-list">
366
+ ${e.map((r,n)=>{let o=r.role==="ai_ready",i=o?"AI Ready lane name is locked \u2014 disable AI to hide this column":"";return`
367
+ <div class="lane-row${o?" lane-row--locked":""}" data-lane-id="${r.id}">
368
+ <button type="button" class="lane-icon-btn" data-lane-action="up" ${n===0?"disabled":""} title="Move lane left" aria-label="Move lane left">\u2191</button>
369
+ <button type="button" class="lane-icon-btn" data-lane-action="down" ${n===e.length-1?"disabled":""} title="Move lane right" aria-label="Move lane right">\u2193</button>
370
+ <input name="name" value="${d(r.name)}" aria-label="Lane name" ${o?`readonly title="${d(i)}"`:""} />
371
+ <button type="button" class="lane-new-toggle ${r.is_default?"is-on":""}" data-lane-action="toggle-default" aria-pressed="${r.is_default?"true":"false"}" title="${r.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">
372
+ <span class="lane-new-sun" aria-hidden="true"></span>
373
+ <span class="lane-new-label">New</span>
374
+ </button>
375
+ <button type="button" class="lane-delete-btn" data-lane-action="delete" ${Ir(r,t,a)?"disabled":""} title="${_r(r,t,a)}" aria-label="Delete lane">\xD7</button>
376
+ </div>
377
+ `}).join("")}
378
+ </div>
379
+ `}async function Mr(e){let a=e.closest(".lane-row"),t=a.dataset.laneId,r=e.dataset.laneAction;if(r==="delete"){await y(T(`/api/states/${t}`),{method:"DELETE"}),await v(),s.detailMode="settings",m.success("Lane deleted");return}if(r==="toggle-default"){if(e.getAttribute("aria-pressed")==="true")return;k.querySelectorAll('[data-lane-action="toggle-default"]').forEach(p=>{p.setAttribute("aria-pressed","false"),p.classList.remove("is-on")}),e.setAttribute("aria-pressed","true"),e.classList.add("is-on"),await Ia(a,{silent:!0}),m.success("Default lane updated");return}let n=_e().map(c=>c.id),o=n.indexOf(t),i=r==="up"?o-1:o+1;i<0||i>=n.length||([n[o],n[i]]=[n[i],n[o]],await y(`/api/boards/${s.boardId}/states`,{method:"PATCH",body:{state_ids:n}}),await v(),s.detailMode="settings",m.success("Lanes reordered"))}async function Ia(e,{silent:a=!1}={}){let t=e.querySelector('input[name="name"]').value,n=e.querySelector('[data-lane-action="toggle-default"]')?.getAttribute("aria-pressed")==="true";await y(T(`/api/states/${e.dataset.laneId}`),{method:"PATCH",body:{name:t,is_default:n}}),await v(),s.detailMode="settings",a||m.success("Lane updated")}var P,pt,ut,Ta,_a=E(()=>{O();J();X();K();ie();rt();te();Fe();Ht();Z();je();Et();Ct();P={boardId:"",step:"idle",exported:!1};pt={windows:{label:"Windows",shell:"PowerShell",serverPath:"C:\\Path\\To\\StarscapeOrbit\\src\\mcp-server.js"},macos:{label:"macOS",shell:"Terminal",serverPath:"/Users/you/apps/starscape-orbit/src/mcp-server.js"},linux:{label:"Linux",shell:"Terminal",serverPath:"/home/you/apps/starscape-orbit/src/mcp-server.js"}},ut={"claude-code":{label:"Claude Code",format:"CLI command",helper:"Run this command once. Claude Code records the local Orbit tool server for the project."},codex:{label:"Codex",format:"config.toml",helper:"Paste this TOML into Codex config. Project-local config may require the project to be trusted."},cursor:{label:"Cursor",format:"MCP JSON",helper:"Paste this JSON into Cursor MCP settings. Cursor starts Orbit when an agent needs the tools."},opencode:{label:"OpenCode",format:"opencode.json",helper:"Paste this into OpenCode config under the local MCP server list."},openclaw:{label:"OpenClaw",format:"MCP JSON",helper:"Paste this JSON into OpenClaw's MCP server list. OpenClaw will spawn Orbit on demand."},generic:{label:"Other MCP app",format:"MCP JSON",helper:"Most MCP clients accept this JSON shape for local stdio servers."}};Ta=new Set(["in_progress","review"])});async function he(e,a){await y(T(`/api/tickets/${e}`),{method:"PATCH",body:a}),await v(),s.selectedTicketId=e,s.detailMode="ticket",await H()}function mt(e,a,t,r){if(!e||e.dataset.editing==="true")return;e.dataset.editing="true";let n=a==="description",o=document.createElement(n?"textarea":"input");o.className=n?"inline-desc-editor":"inline-title-editor",o.value=t,o.setAttribute("data-editing-field",a),n?o.rows=Math.max(3,String(t).split(`
380
+ `).length+1):(o.type="text",o.maxLength=500),e.replaceWith(o),o.focus(),n?o.setSelectionRange(o.value.length,o.value.length):o.select();let i=!1,c=async()=>{if(i)return;i=!0;let l=o.value;if(String(l)===String(t)){await H();return}if(a==="title"&&!l.trim()){m.warning("Title cannot be empty"),await H();return}await he(r,{[a]:l})},p=async()=>{i||(i=!0,await H())};o.addEventListener("blur",c),o.addEventListener("keydown",l=>{if(l.key==="Escape"){l.preventDefault(),p();return}l.key==="Enter"&&(n?(l.metaKey||l.ctrlKey)&&(l.preventDefault(),c()):(l.preventDefault(),c()))})}function Pr(e){let a=e.id,t=j.querySelector('[data-edit-field="title"]');t&&(t.addEventListener("click",()=>{mt(t,"title",e.title||"",a)}),t.addEventListener("keydown",i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),mt(t,"title",e.title||"",a))}));let r=k.querySelector('[data-edit-field="description"]');r&&(r.addEventListener("click",i=>{i.preventDefault(),mt(r,"description",e.description||"",a)}),r.addEventListener("keydown",i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),mt(r,"description",e.description||"",a))})),k.querySelectorAll(".meta-select[data-meta-field]").forEach(i=>{i.addEventListener("change",async()=>{let c=i.dataset.metaField;if(c==="type"){await he(a,{type:i.value});return}if(c==="state_id"){await he(a,{state_id:i.value});return}if(c==="parent_ticket_id"){await he(a,{parent_ticket_id:i.value||null});return}c==="priority"&&await he(a,{priority:Number(i.value)})})});let n=async i=>{await he(a,{labels:i})};k.querySelectorAll("[data-remove-label]").forEach(i=>{i.addEventListener("click",async()=>{let c=i.getAttribute("data-remove-label"),p=(e.labels||[]).map(l=>l.name).filter(l=>l!==c);await n(p)})});let o=async()=>{let i=k.querySelector("[data-label-input]");if(!i)return;let c=i.value.trim();if(!c)return;let p=(e.labels||[]).map(l=>l.name);if(p.includes(c)){i.value="";return}p.push(c),i.value="",await n(p)};k.querySelector("[data-label-add]")?.addEventListener("click",()=>{o()}),k.querySelector("[data-label-input]")?.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),o())})}async function H(){if(s.detailMode==="settings"){await fe(),Bt();return}if(!s.selectedTicketId){tt();return}let[e,a]=await Promise.all([y(T(`/api/tickets/${s.selectedTicketId}/context?depth=1`)),y(T(`/api/tickets/${s.selectedTicketId}/history`))]),t=e.ticket;it(t.id,t.updated_at),document.querySelector(`.card[data-ticket-id="${CSS.escape(t.id)}"] .card-unread-dot`)?.remove();let r=sa(t.state_id),n=["epic","feature","task","bug"].map(h=>`<option value="${d(h)}" ${D(t.type)===h?"selected":""}>${d(la(h))}</option>`).join(""),o=r.map(h=>`<option value="${d(h.id)}" ${h.id===t.state_id?"selected":""}>${d(h.name)}</option>`).join(""),i=[0,1,2,3,4].map(h=>`<option value="${h}" ${Number(t.priority)===h?"selected":""}>${d(Qe(h))}</option>`).join(""),c=(t.labels||[]).map(h=>`
381
+ <span class="label-pill-removable" style="--label-color: ${d(h.color)}">
382
+ ${d(h.name)}
383
+ <button type="button" class="label-pill-remove" data-remove-label="${d(h.name)}" title="Remove label">\xD7</button>
384
+ </span>`).join(""),l=oa().map(h=>h.name).filter(h=>!t.labels?.some(L=>L.name===h)).map(h=>`<option value="${d(h)}"></option>`).join(""),f=D(t.type),u=Me(t.type).toUpperCase(),g=`
385
+ <span class="ticket-number">${d(G(t))}</span>
386
+ <div class="card-type-id type-pill-${d(f)}">
387
+ ${Be(t.type)}
388
+ <span class="card-type-label">${d(u)}</span>
389
+ </div>
390
+ ${ct(t.priority)}
391
+ `;at({mode:"ticket",title:t.title,titleAttrs:{class:"editable-field","data-edit-field":"title",tabindex:"0",title:"Click to edit"},subtitleHtml:g,body:`
392
+ <div class="detail-head">
393
+ <p class="detail-updated" title="Last saved change">Updated ${d(da(t.updated_at))}</p>
394
+ <div class="description markdown-body editable-field ${t.description?"":"is-placeholder"}" data-edit-field="description" tabindex="0" title="Click to edit">${t.description?Ze(t.description):d("No description yet.")}</div>
395
+ <dl class="ticket-meta" id="ticketMetaGrid" data-ticket-id="${d(t.id)}">
396
+ <div class="ticket-meta-row">
397
+ <dt>State</dt>
398
+ <dd><select class="meta-select meta-inline" data-meta-field="state_id" aria-label="Lane / state">${o}</select></dd>
399
+ </div>
400
+ <div class="ticket-meta-row">
401
+ <dt>Type</dt>
402
+ <dd><select class="meta-select meta-inline" data-meta-field="type" aria-label="Ticket type">${n}</select></dd>
403
+ </div>
404
+ <div class="ticket-meta-row">
405
+ <dt>Priority</dt>
406
+ <dd><select class="meta-select meta-inline" data-meta-field="priority" aria-label="Priority">${i}</select></dd>
407
+ </div>
408
+ <div class="ticket-meta-row ticket-meta-row--stack">
409
+ <dt>Labels</dt>
410
+ <dd>
411
+ <div class="label-pills-row" data-other-labels>${c}</div>
412
+ <div class="label-add-row">
413
+ <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" />
414
+ <datalist id="board-label-suggestions">${l}</datalist>
415
+ <button type="button" class="ghost meta-add-btn" data-label-add>Add</button>
416
+ </div>
417
+ </dd>
418
+ </div>
419
+ </dl>
420
+ </div>
421
+
422
+ ${Fr(t,e)}
423
+
424
+ ${jr(t,e)}
425
+
426
+ <div class="section">
427
+ <h3>Related</h3>
428
+ ${Br(e.relations,t)}
429
+ </div>
430
+
431
+ ${q()?.ai_enabled!==0?`
432
+ <details class="section ai-fields" data-ai-plan-toggle data-ticket-id="${d(t.id)}"${Ar(t.id)?" open":""}>
433
+ <summary><h3>AI Plan / Implementation Record</h3></summary>
434
+ <form id="aiFieldsForm" class="field-form">
435
+ <label>
436
+ <span>AI-Written Plan</span>
437
+ <textarea name="ai_plan" placeholder="Paste or let an AI write the plan...">${d(t.ai_plan||"")}</textarea>
438
+ </label>
439
+ <label>
440
+ <span>Implementation Summary</span>
441
+ <textarea name="implementation_summary" placeholder="What changed, what shipped, what remains...">${d(t.implementation_summary||"")}</textarea>
442
+ </label>
443
+ <label>
444
+ <span>Implementation Updates / Lessons</span>
445
+ <textarea name="implementation_updates" placeholder="Progress notes, mistakes to avoid, discoveries...">${d(t.implementation_updates||"")}</textarea>
446
+ </label>
447
+ <button type="submit">Save Fields</button>
448
+ </form>
449
+ </details>`:""}
450
+
451
+ <div class="section">
452
+ <h3>Status History</h3>
453
+ ${Rr(a)}
454
+ </div>
455
+
456
+ <div class="section">
457
+ <h3>Comments</h3>
458
+ ${e.comments.map(Dr).join("")||'<p class="description">No comments yet.</p>'}
459
+ <form class="comment-form" id="detailCommentForm">
460
+ <textarea name="body" placeholder="Add a comment, decision, or instruction..." required></textarea>
461
+ <button type="submit">Comment</button>
462
+ </form>
463
+ </div>
464
+ `}),Pr(t),b("#aiFieldsForm")?.addEventListener("submit",async h=>{h.preventDefault();let L=new FormData(h.currentTarget);await y(T(`/api/tickets/${t.id}`),{method:"PATCH",body:{ai_plan:L.get("ai_plan"),implementation_summary:L.get("implementation_summary"),implementation_updates:L.get("implementation_updates")}}),await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H(),m.success("AI fields saved")}),b("#detailCommentForm").addEventListener("submit",async h=>{h.preventDefault();let L=new FormData(h.currentTarget).get("body").trim();L&&(await y(T(`/api/tickets/${t.id}/comments`),{method:"POST",body:{body:L}}),await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H())}),k.querySelectorAll("[data-open-ticket]").forEach(h=>{h.addEventListener("click",async L=>{L.target.closest("[data-detach-child],[data-detach-parent],[data-detach-relation]")||C({boardId:s.boardId,view:"ticket",ticketId:h.dataset.openTicket})})}),k.querySelectorAll("[data-detach-child]").forEach(h=>{h.addEventListener("click",async L=>{L.stopPropagation();let A=h.dataset.detachChild;try{await y(T(`/api/tickets/${A}`),{method:"PATCH",body:{parent_ticket_id:null}})}catch(R){m.error(R.message||"Failed to remove child");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H(),m.success("Removed from epic")})}),k.querySelectorAll("[data-detach-parent]").forEach(h=>{h.addEventListener("click",async L=>{L.stopPropagation();try{await y(T(`/api/tickets/${t.id}`),{method:"PATCH",body:{parent_ticket_id:null}})}catch(A){m.error(A.message||"Failed to remove parent");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H(),m.success("Parent epic removed")})}),k.querySelectorAll("[data-detach-relation]").forEach(h=>{h.addEventListener("click",async L=>{L.stopPropagation();let A=h.dataset.detachRelation;try{await y(T(`/api/relations/${A}`),{method:"DELETE"})}catch(R){m.error(R.message||"Failed to remove relation");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H(),m.success("Relation removed")})});let N=k.querySelector("[data-ai-plan-toggle]");N&&N.addEventListener("toggle",()=>{let h=N.dataset.ticketId;N.open?localStorage.setItem(`mab_ai_plan_open:${h}`,"1"):localStorage.removeItem(`mab_ai_plan_open:${h}`)});let x=k.querySelector("#parentEpicForm");if(x){let h=x.querySelector("[name=target]"),L=x.querySelector("[data-parent-epic-clear]"),A=()=>{x.classList.toggle("has-value",h.value.length>0)};h.addEventListener("input",A),A(),L.addEventListener("click",()=>{h.value="",A(),h.focus()}),x.addEventListener("submit",async R=>{R.preventDefault();let w=String(new FormData(R.currentTarget).get("target")||"").trim();if(!w)return;let F=Ca(w,t.id);if(!F){m.warning("Pick an epic from the suggestions");return}let I=U().find(M=>M.id===F);if(!I||D(I.type)!=="epic"){m.warning("Parent must be an epic");return}try{await y(T(`/api/tickets/${t.id}`),{method:"PATCH",body:{parent_ticket_id:F}})}catch(M){m.error(M.message||"Failed to set parent epic");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H(),m.success("Parent epic set")})}let B=k.querySelector("#relatedAddForm");if(B){let h=B.querySelector("[name=target]"),L=B.querySelector("[data-related-clear]"),A=()=>{B.classList.toggle("has-value",h.value.length>0)};h.addEventListener("input",A),A(),L.addEventListener("click",()=>{h.value="",A(),h.focus()}),B.addEventListener("submit",async R=>{R.preventDefault();let w=new FormData(R.currentTarget),F=String(w.get("target")||"").trim(),I=String(w.get("type")||"relates_to");if(!F)return;let M=Ca(F,t.id);if(!M){m.warning("Pick a ticket from the suggestions");return}try{await y(T("/api/relations"),{method:"POST",body:{source_ticket_id:t.id,target_ticket_id:M,type:I}})}catch($){m.error($.message||"Failed to add relation");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await H()})}Bt()}function Ar(e){return localStorage.getItem(`mab_ai_plan_open:${e}`)==="1"}function Ca(e,a){let t=e.trim(),r=t.match(/^#?(\d+)\b/),n=U().filter(i=>i.id!==a);if(r){let i=Number(r[1]),c=n.find(p=>p.number===i);if(c)return c.id}let o=n.find(i=>`#${i.number} \u2014 ${i.title}`===t);return o?o.id:""}function Rr(e){return!e||e.length===0?'<p class="description">No status changes yet.</p>':e.map(a=>{let t=a.body,r=t.from?d(t.from):"?",n=d(t.to||t.state||t.next_state||"?"),o=t.actor_type||"human",i=d(a.actor),c=t.actor_id&&t.actor_id!==a.actor?d(t.actor_id):null,p=o==="agent"?`agent \xB7 ${c?`${i} (${c})`:i}`:"you";return`<div class="comment status-change">
465
+ <div class="comment-meta">
466
+ <span class="status-route">${r} \u2192 ${n}</span>
467
+ <span>${p} \xB7 ${Ce(a.created_at)}</span>
468
+ </div>
469
+ </div>`}).join("")}function Dr(e){return`
470
+ <div class="comment ${e.kind==="checkpoint"?"checkpoint":""}">
471
+ <div class="comment-meta">
472
+ <strong>${d(e.author)}</strong>
473
+ <span>${e.kind==="human_comment"?"":`${d(e.kind)} - `}${Ce(e.created_at)}</span>
474
+ </div>
475
+ <div class="comment-body">${d(e.body)}</div>
476
+ </div>
477
+ `}function Br(e=[],a){let t=new Set(e.map(p=>p.other_ticket.id)),r=new Set;if(a?.parent_ticket_id&&r.add(a.parent_ticket_id),a?.id)for(let p of U())p.parent_ticket_id===a.id&&r.add(p.id);let o=U().filter(p=>p.id!==a?.id&&!t.has(p.id)&&!r.has(p.id)).map(p=>`<option value="#${p.number} \u2014 ${d(p.title)}"></option>`).join(""),i=e.length?`<div class="detail-card-grid">${e.map(p=>Or(p)).join("")}</div>`:"",c=`
478
+ <form id="relatedAddForm" class="related-add-row">
479
+ <div class="related-add-input-wrap">
480
+ <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" />
481
+ <button type="button" class="related-add-clear" data-related-clear aria-label="Clear" tabindex="-1">\xD7</button>
482
+ <datalist id="related-ticket-suggestions">${o}</datalist>
483
+ </div>
484
+ <select name="type" class="related-add-type meta-inline" aria-label="Relation type">
485
+ <option value="relates_to">relates to</option>
486
+ <option value="blocks">blocks</option>
487
+ <option value="blocked_by">blocked by</option>
488
+ </select>
489
+ <button type="submit" class="ghost meta-add-btn">Add</button>
490
+ </form>
491
+ `;return i+c}function Fr(e,a){if(D(e.type)==="epic"){let r=a.child_tickets||[];return`
492
+ <div class="section">
493
+ <h3>Features inside this Epic</h3>
494
+ ${r.length?`<div class="detail-card-grid">${r.map(o=>Oe(o,{detach:{mode:"child",id:o.id}})).join("")}</div>`:'<p class="description">No child features yet. Create a feature / task card and set this epic as its parent.</p>'}
495
+ </div>
496
+ `}return""}function jr(e,a){if(D(e.type)==="epic")return"";let r=U().filter(o=>o.type==="epic"&&o.id!==e.id).map(o=>`<option value="#${o.number} \u2014 ${d(o.title)}"></option>`).join("");return`
497
+ <div class="section">
498
+ <h3>Epic</h3>
499
+ ${a.parent_ticket?`<div class="detail-card-grid detail-card-grid--single">${Oe(a.parent_ticket,{detach:{mode:"parent"}})}</div>`:`
500
+ <form id="parentEpicForm" class="related-add-row">
501
+ <div class="related-add-input-wrap">
502
+ <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" />
503
+ <button type="button" class="related-add-clear" data-parent-epic-clear aria-label="Clear" tabindex="-1">\xD7</button>
504
+ <datalist id="parent-epic-suggestions">${r}</datalist>
505
+ </div>
506
+ <button type="submit" class="ghost meta-add-btn">Set</button>
507
+ </form>
508
+ `}
509
+ </div>
510
+ `}function Oe(e,a={}){let t=D(e.type),r=Pe(e.priority),n=Me(e.type).toUpperCase(),o=a.eyebrow?`<span class="card-eyebrow">${d(a.eyebrow)}</span>`:"",i="";if(a.detach){let{mode:l,id:f}=a.detach,u="",g="";l==="child"?(u=`data-detach-child="${d(f)}"`,g="Remove from epic"):l==="parent"?(u='data-detach-parent="1"',g="Remove parent epic"):l==="relation"&&(u=`data-detach-relation="${d(f)}"`,g="Remove relation"),i=`<button type="button" class="card-detach-btn" ${u} aria-label="${g}" title="${g}">\xD7</button>`}else if(a.archive){let l=d(a.archive.id);i=`
511
+ <div class="card-archive-actions">
512
+ <button type="button" class="card-archive-btn card-archive-btn--restore" data-archive-restore="${l}" aria-label="Restore to board" title="Restore to board"><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></button>
513
+ <button type="button" class="card-archive-btn card-archive-btn--delete" data-archive-delete="${l}" aria-label="Delete permanently" title="Delete permanently"><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></button>
514
+ </div>
515
+ `}let c=ot(e),p=c===0?"":c===1?'<span class="card-unread-dot" role="status" aria-label="1 unread update"></span>':`<span class="card-unread-dot has-count" role="status" aria-label="${c} unread updates">${c>99?"99+":c}</span>`;return`
516
+ <article class="card card--detail type-${d(t)} priority-${d(r)}"${a.disableOpen?"":` data-open-ticket="${d(e.id)}"`}>
517
+ ${p}
518
+ ${i}
519
+ ${o}
520
+ <h3>${d(e.title)}</h3>
521
+ <div class="card-meta">
522
+ <div class="card-expand-trigger card-expand-trigger--static">
523
+ <span class="ticket-number">${d(G(e))}</span>
524
+ <div class="card-type-id type-pill-${d(t)}">
525
+ ${Be(e.type)}
526
+ <span class="card-type-label">${d(n)}</span>
527
+ </div>
528
+ ${s.showPriority?ct(e.priority):""}
529
+ </div>
530
+ </div>
531
+ </article>
532
+ `}function Or(e){let a=String(e.type||"").replace(/_/g," "),t=e.direction==="incoming"?"from":"to";return Oe(e.other_ticket,{eyebrow:`${a} ${t}`,detach:{mode:"relation",id:e.id}})}var Ht=E(()=>{O();J();X();Fe();rt();te();K();ie();Z();_a();Re()});function qt(){be&&(clearTimeout(be),be=null),s.eventSource&&(s.eventSource.close(),s.eventSource=null);let e=new URLSearchParams;s.boardId&&e.set("board_id",s.boardId);let a=`/api/events/stream${e.toString()?`?${e}`:""}`,t=new EventSource(a);s.eventSource=t,t.addEventListener("open",()=>{ft=1e3,ht&&(m.success("Live updates reconnected"),ht=!1)}),t.addEventListener("board",async r=>{let n;try{n=JSON.parse(r.data)}catch{return}let o=n.type,i=()=>s.data?.tickets?.find(l=>l.id===n.ticket_id),c=s.data?.actor?.name,p=n.actor&&c&&n.actor===c;if(n.ticket_id&&(p?it(n.ticket_id,n.timestamp):o==="ticket_deleted"?va(n.ticket_id):Nr.has(o)&&ya(n.ticket_id)),o==="ticket_created")m.success(`Card created: ${n.data.title||"New card"}`),ae();else if(o==="state_changed"){let l=i(),f=l?`#${l.number} ${l.title}`:"Card";m.info(`${f} \u2192 ${n.data.to}`),ae()}else if(o==="ticket_updated"){let l=i(),f=l?`#${l.number}`:"Card",u=n.data.fields?Object.keys(n.data.fields).join(", "):"";m.info(`${f} updated${u?`: ${u}`:""}`),ae()}else if(o==="comment_created"){let l=i(),f=l?`#${l.number}`:"ticket";m.info(`New comment on ${f}`),ae()}else if(o==="agent_claimed"){let l=i();m.info(`Agent claimed ${l?`#${l.number} ${l.title}`:"a ticket"}`),ae()}else if(o==="checkpoint_requested"){let l=i();m.warning(`Checkpoint on ${l?`#${l.number}`:"ticket"} \u2014 needs human input`),ae()}else if(o==="agent_completed"){let l=i();m.success(`Agent completed ${l?`#${l.number} ${l.title}`:"a ticket"}`),ae()}else(o==="ticket_deleted"||o==="states_reordered"||o==="state_created"||o==="state_deleted"||o==="board_updated"||o==="board_imported")&&ae()}),t.onerror=()=>{if(t.readyState!==EventSource.CLOSED||(ht||(m.warning("Live updates disconnected \u2014 retrying\u2026"),ht=!0),be))return;let r=ft;ft=Math.min(ft*2,3e4),be=setTimeout(()=>{be=null,qt()},r)}}var Nr,ft,be,ht,ae,Ma=E(()=>{O();K();ie();Z();Re();Nr=new Set(["ticket_created","state_changed","ticket_updated","comment_created","agent_claimed","checkpoint_requested","agent_completed"]),ft=1e3,be=null,ht=!1;ae=Ve(async()=>{let e=s.selectedTicketId,a=s.detailMode;s.data=await y(et()),Ie(),s.selectedTicketId=e,s.detailMode=a,await bt()},300)});var Aa={};Ga(Aa,{load:()=>v,render:()=>bt});async function v(){Y(),s.data=await y(et()),Ie(),wa(s.boardId,s.data?.tickets||[]),await bt(),W.sse&&s.boardId!==Pa&&(Pa=s.boardId,qt())}async function bt(){Ie(),Ra(),st(),await H()}var Pa,Z=E(()=>{O();K();Fe();Ht();Ne();Ma();Re();je();Pa=null});function zt(){return se?.classList.contains("is-open")}function dt(e){clearTimeout(Ut),Y(),tt(),kt.innerHTML=Hr(e||""),qr(),b("#createFlyoutClose")?.addEventListener("click",()=>_()),se.hidden=!1,ne.hidden=!1,requestAnimationFrame(()=>{se.classList.add("is-open"),ne.classList.add("is-visible")}),requestAnimationFrame(()=>{b("#createTicketTitle")?.focus()})}function _(){clearTimeout(Ut),se.classList.remove("is-open"),ne.classList.remove("is-visible"),Ut=setTimeout(()=>{se.hidden=!0,ne.hidden=!0,kt.innerHTML=""},220)}function Hr(e){let a=Xe(),t=a.find(i=>i.is_default)||a[0],r=e&&a.some(i=>i.id===e)?e:t?.id||"",n=a.map(i=>`<option value="${d(i.id)}" ${i.id===r?"selected":""}>${d(i.name)}</option>`).join(""),o=U().filter(i=>i.type==="epic").map(i=>`<option value="${d(i.id)}">${d(G(i))}</option>`).join("");return`
533
+ <div class="create-flyout-head">
534
+ <h2>New card</h2>
535
+ <button type="button" class="create-flyout-close ghost" id="createFlyoutClose" aria-label="Close">\xD7</button>
536
+ </div>
537
+ <form id="createTicketForm" class="create-flyout-form">
538
+ <input id="createTicketTitle" name="title" type="text" placeholder="Title \u2014 what is this card?" autocomplete="off" required />
539
+ <textarea id="createTicketDescription" name="description" placeholder="Description (optional)"></textarea>
540
+ <div class="create-flyout-grid">
541
+ <label>
542
+ Lane
543
+ <select id="createTicketState" name="state" class="select-chevron-field" aria-label="Lane">${n}</select>
544
+ </label>
545
+ <label>
546
+ Type
547
+ <select id="createTicketType" name="type" class="select-chevron-field" aria-label="Ticket type">
548
+ <option value="epic">Epic / Story</option>
549
+ <option value="feature">Feature</option>
550
+ <option value="task" selected>Task</option>
551
+ <option value="bug">Bug</option>
552
+ </select>
553
+ </label>
554
+ <label>
555
+ Priority
556
+ <select id="createTicketPriority" name="priority" class="select-chevron-field" aria-label="Priority">
557
+ <option value="0">MAYBE</option>
558
+ <option value="1">LOW</option>
559
+ <option value="2" selected>MED</option>
560
+ <option value="3">HIGH</option>
561
+ <option value="4">URGENT</option>
562
+ </select>
563
+ </label>
564
+ </div>
565
+ <label>
566
+ Parent epic
567
+ <select id="createTicketParent" name="parent_ticket_id" class="select-chevron-field" aria-label="Parent epic">
568
+ <option value="">None</option>
569
+ ${o}
570
+ </select>
571
+ </label>
572
+ <input id="createTicketLabels" name="labels" type="text" placeholder="Labels (comma-separated)" />
573
+ <button type="submit">Create card</button>
574
+ </form>
575
+ `}function qr(){let e=b("#createTicketForm");e&&e.addEventListener("submit",Ur)}async function Ur(e){e.preventDefault();let a=e.currentTarget,t=new FormData(a),r=String(t.get("labels")||"").split(",").map(o=>o.trim()).filter(Boolean),n=await y("/api/tickets",{method:"POST",body:{board_id:s.boardId,title:t.get("title"),description:t.get("description"),type:t.get("type"),parent_ticket_id:t.get("parent_ticket_id")||null,state_id:t.get("state"),priority:Number(t.get("priority")),labels:r}});_(),s.selectedTicketId=n.id,s.detailMode="ticket",await v(),ge()}var Ut,ue=E(()=>{J();O();X();K();te();rt();Ne();Z();Ut=0});function He(){z&&(z.hidden=!0,z.innerHTML="",Q?.setAttribute("aria-expanded","false"))}function Y(){He()}function Ra(){if(!s.data)return;let e=(s.data.boards||[]).find(a=>a.id===s.boardId);Q&&(Q.textContent=e?.name||"Board",Q.title=e?`${e.name} \u2014 slug: ${e.slug}`:"Choose board")}function zr(){let t=(s.data.boards||[]).map(n=>`
576
+ <button type="button" class="menu-flyout-item ${n.id===s.boardId?"is-current":""}" data-pick-board="${d(n.id)}" role="menuitem">
577
+ <span class="menu-flyout-item-title">${d(n.name)}</span>
578
+ <span class="menu-flyout-item-meta">${d(n.slug)}</span>
579
+ </button>`).join("")||'<p class="menu-flyout-hint menu-flyout-hint--empty">No boards yet. Create one below if you can.</p>',r=W.multiBoard?`
580
+ <div class="menu-flyout-section">
581
+ <h3 class="menu-flyout-heading">New board</h3>
582
+ <form id="createBoardForm" class="menu-flyout-form">
583
+ <div class="folder-picker-field">
584
+ <input id="repoPathInput" name="repo_path" type="text" required readonly placeholder="Choose a folder" autocomplete="off" />
585
+ <button type="button" id="pickRepoFolderBtn">Browse</button>
586
+ </div>
587
+ <p class="menu-flyout-hint menu-flyout-hint--intro">Board data is stored in <code>.orbit/</code> under this folder.</p>
588
+ <input name="name" type="text" required placeholder="Board name" autocomplete="off" />
589
+ <input name="slug" type="text" placeholder="Slug (optional)" autocomplete="off" />
590
+ <input name="default_branch" type="text" placeholder="Default branch (optional)" autocomplete="off" />
591
+ <input name="repo_url" type="text" placeholder="Repo URL (optional)" autocomplete="off" />
592
+ <button type="submit">Create board</button>
593
+ </form>
594
+ </div>`:"";return`
595
+ <div class="menu-flyout-head">Board</div>
596
+ <div class="menu-flyout-list">${t}</div>
597
+ ${r}
598
+ `}function Gr(){z.querySelectorAll("[data-pick-board]").forEach(a=>{a.addEventListener("click",async t=>{t.stopPropagation();let r=a.getAttribute("data-pick-board");He(),r!==s.boardId&&(_(),await C({boardId:r,view:"board"}))})});let e=z.querySelector("#createBoardForm");if(e){let a=e.querySelector("#pickRepoFolderBtn"),t=e.querySelector("#repoPathInput");a?.addEventListener("click",async r=>{r.preventDefault(),a.disabled=!0;try{let n=await y("/api/system/pick-folder",{method:"POST"});n.path&&(t.value=n.path,t.dispatchEvent(new Event("input",{bubbles:!0})))}catch(n){m.error(n?.message||"Folder picker unavailable")}finally{a.disabled=!1}}),e.addEventListener("submit",async r=>{r.preventDefault();let n=new FormData(e),o=String(n.get("slug")||"").trim(),i=String(n.get("default_branch")||"").trim(),c=String(n.get("repo_url")||"").trim(),p=String(n.get("repo_path")||"").trim();if(!p){t?.reportValidity();return}let l=await y("/api/boards",{method:"POST",body:{name:n.get("name"),repo_path:p,...o?{slug:o}:{},...i?{default_branch:i}:{},...c?{repo_url:c}:{}}});He(),s.boardId=l.id,s.selectedTicketId="",s.detailMode="settings",await v(),ge(),m.success("Board created")})}}function Da(){_(),z.innerHTML=zr(),z.hidden=!1,Q?.setAttribute("aria-expanded","true"),Gr()}var Ne=E(()=>{J();O();X();K();te();ue();ie();Z();je()});function Ba(){return{...Jr}}function Jt(e=globalThis.location){if(typeof e=="string"){let a=new URL(e,"http://orbit.local");return{pathname:a.pathname||"/",search:a.search||"",hash:a.hash||""}}return{pathname:e?.pathname||"/",search:e?.search||"",hash:e?.hash||""}}function Gt(e){try{return decodeURIComponent(e)}catch{return e}}function Kr(e){return String(e||"").replace(/^#/,"").replace(/^\/+/,"").replace(/\/+$/,"").split("/").filter(Boolean)}function Wr(e){if(!e.length)return null;let a=Ba(),t=0;if(e[t]==="b"){if(!e[t+1])return null;a.boardSlug=Gt(e[t+1]),t+=2}else if(e[t]!=="t"&&e[t]!=="settings")return null;if(e[t]==="t"&&e[t+1])a.view="ticket",a.ticketId=Gt(e[t+1]);else if(e[t]==="settings"){a.view="settings";let r=e[t+1]?Gt(e[t+1]):"";r&&We.has(r)&&(a.tab=r)}return a}function Fa(e){let a=String(e||"");return!a||a==="#"||a==="#/"?null:Wr(Kr(a))}function gt(e=globalThis.location){let a=Jt(e);return Fa(a.hash)||Ba()}function qe(e=globalThis.location){let a=Jt(e);return!!Fa(a.hash)}function ye({boardSlug:e="",view:a="board",ticketId:t="",tab:r=""}={}){let n=[];return e&&n.push("b",encodeURIComponent(e)),a==="ticket"&&t?n.push("t",encodeURIComponent(t)):a==="settings"&&(n.push("settings"),r&&We.has(r)&&n.push(r)),"#/"+n.join("/")}function yt(e=globalThis.location,a=gt(e)){return Jt(e).hash===ye(a)}var Jr,Kt=E(()=>{Ye();Jr=Object.freeze({boardSlug:"",view:"board",ticketId:"",tab:""})});function ja(e){if(!e)return null;let a=s.data?.boards||[];return a.find(t=>t.slug===e)||a.find(t=>t.id===e)||null}function Yr(e={}){return e.boardSlug?e.boardSlug:e.boardId?ja(e.boardId)?.slug||e.boardId:q()?.slug||s.boardSlug||""}function Xr(e={}){return{...e,boardSlug:Yr(e)}}function Zr(){let e="board";return s.detailMode==="ticket"&&s.selectedTicketId?e="ticket":s.detailMode==="settings"&&(e="settings"),{boardSlug:q()?.slug||s.boardSlug,view:e,ticketId:s.selectedTicketId,tab:e==="settings"?Te(s.settingsTab):""}}function Oa(e){vt=e}function Wt(){return gt(location)}async function C(e,{replace:a=!1}={}){let t=Xr(e),r=ye(t);if(yt(location,t)){vt&&await Ue();return}a?history.replaceState(null,"",r):history.pushState(null,"",r),vt&&await Ue()}function ge({replace:e=!1}={}){let a=Zr(),t=ye(a);yt(location,a)||(e?history.replaceState(null,"",t):history.pushState(null,"",t))}async function Ue(){let{load:e,render:a}=await Promise.resolve().then(()=>(Z(),Aa)),t=Wt(),r=qe(location),n=s.boardId,i=ja(t.boardSlug)||(t.boardSlug?q():null);i?(s.boardId=i.id,s.boardSlug=i.slug):t.boardSlug&&(s.boardSlug=t.boardSlug);let c=i?{...t,boardSlug:i.slug}:t;if(r&&!yt(location,c)&&history.replaceState(null,"",ye(c)),t.view==="ticket")s.selectedTicketId=t.ticketId||"",s.detailMode=t.ticketId?"ticket":"empty";else if(t.view==="settings"){if(s.selectedTicketId="",s.detailMode="settings",t.tab){s.settingsTab=t.tab;try{localStorage.setItem("mab_settings_tab",t.tab)}catch{}}}else s.selectedTicketId="",s.detailMode="empty";Y(),_(),s.boardId&&s.boardId!==n&&await e(),await a()}var vt,te=E(()=>{O();Ye();Ne();ue();Kt();Kt();vt=!1;window.addEventListener("popstate",()=>{vt&&Ue()})});J();Et();Ct();ea(),Ee();var Wa=Ya();Mt();{let e=()=>{document.body.classList.toggle("is-scrolled",window.scrollY>4)};window.addEventListener("scroll",e,{passive:!0}),e()}aa();Yt?.addEventListener("click",()=>{ta()});window.addEventListener(Ke,()=>{aa(),Wa.sync()});function aa(){if(!$t)return;let e=ee()==="dark";$t.innerHTML=e?'<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />':'<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" />'}function Ya(){let e=document.querySelector(".grain");if(!e)return{sync:()=>{}};Xa(e);let a=document.createElement("canvas");a.className="starfield-canvas",a.setAttribute("aria-hidden","true");let t=e.querySelector(".milky-way");t&&t.nextSibling?e.insertBefore(a,t.nextSibling):t?e.appendChild(a):e.insertBefore(a,e.firstChild);let r=a.getContext("2d"),n=Math.min(window.devicePixelRatio||1,2),o=0,i=0,c=[],p=0,l=!1,f={x:0,y:0,tx:0,ty:0};function u(){o=window.innerWidth,i=window.innerHeight,a.width=Math.round(o*n),a.height=Math.round(i*n),a.style.width=o+"px",a.style.height=i+"px",r.setTransform(n,0,0,n,0,0),g()}function g(){let w=o*i/1296e3,F=[{count:Math.round(320*w),depth:.12,sizes:[[1,.9],[1.4,.1]],glow:0},{count:Math.round(160*w),depth:.3,sizes:[[1,.5],[1.6,.4],[2.4,.1]],glow:1.8},{count:Math.round(44*w),depth:.58,sizes:[[1.8,.5],[2.6,.38],[3.6,.12]],glow:2.4}],I=ra(12648430);c=[];for(let M of F)for(let $=0;$<M.count;$++){let ve=Qa(I(),M.sizes);c.push({x:I()*o,y:I()*i,size:ve,depth:M.depth,glow:ve>=2?M.glow:0,rgb:N(I()),period:2.2+I()*5.4,phase:I()*Math.PI*2,amp:.25+I()*.5,baseAlpha:ve<1.5?.45+I()*.28:.55+I()*.22})}}function N(w){return w<.8?[255,255,255]:w<.93?[255,222,186]:[195,218,255]}function x(w){!o||!i||(f.tx=w.clientX/o-.5,f.ty=w.clientY/i-.5)}function B(w){f.x+=(f.tx-f.x)*.06,f.y+=(f.ty-f.y)*.06,r.clearRect(0,0,o,i),r.globalCompositeOperation="lighter";let F=w/1e3,I=70;for(let M=0;M<c.length;M++){let $=c[M],ve=.5+.5*Math.sin(F*(2*Math.PI/$.period)+$.phase),ze=$.baseAlpha*(1-$.amp+$.amp*ve),we=$.x-f.x*$.depth*I,ke=$.y-f.y*$.depth*I,[$e,xe,Se]=$.rgb;if($.glow>0){let Le=$.size*$.glow,Ge=r.createRadialGradient(we,ke,0,we,ke,Le);Ge.addColorStop(0,`rgba(${$e},${xe},${Se},${ze*.85})`),Ge.addColorStop(.35,`rgba(${$e},${xe},${Se},${ze*.3})`),Ge.addColorStop(1,`rgba(${$e},${xe},${Se},0)`),r.fillStyle=Ge,r.beginPath(),r.arc(we,ke,Le,0,Math.PI*2),r.fill(),r.fillStyle=`rgba(${$e},${xe},${Se},${ze})`,r.beginPath(),r.arc(we,ke,$.size/2,0,Math.PI*2),r.fill()}else{let Le=$.size/2;r.fillStyle=`rgba(${$e},${xe},${Se},${ze})`,r.fillRect(we-Le,ke-Le,$.size,$.size)}}r.globalCompositeOperation="source-over",l&&(p=requestAnimationFrame(B))}function h(){r.clearRect(0,0,o,i),r.globalCompositeOperation="lighter";for(let w of c){let[F,I,M]=w.rgb;if(r.fillStyle=`rgba(${F},${I},${M},${w.baseAlpha})`,w.glow>0)r.beginPath(),r.arc(w.x,w.y,w.size/2,0,Math.PI*2),r.fill();else{let $=w.size/2;r.fillRect(w.x-$,w.y-$,w.size,w.size)}}r.globalCompositeOperation="source-over"}function L(){l||(l=!0,p=requestAnimationFrame(B))}function A(){l=!1,cancelAnimationFrame(p)}function R(){let w=ee()==="dark",F=de();if(!w){A(),r.clearRect(0,0,o,i);return}c.length||u(),F||document.hidden?(A(),h()):L()}return window.addEventListener("resize",()=>{u(),R()},{passive:!0}),window.addEventListener("pointermove",x,{passive:!0}),document.addEventListener("visibilitychange",R),window.matchMedia("(prefers-reduced-motion: reduce)").addEventListener("change",()=>{Ee(),R()}),window.addEventListener("orbit:motion-preference-change",R),u(),R(),{sync:R}}function Xa(e){e.querySelectorAll(".signature-star").forEach(r=>r.remove());let a=ra(6070757),t=7;for(let r=0;r<t;r++){let n=document.createElement("div");n.className="signature-star",n.setAttribute("aria-hidden","true"),n.style.left=(6+a()*88).toFixed(2)+"%",n.style.top=(8+a()*78).toFixed(2)+"%",n.style.animationDelay=(-a()*4.8).toFixed(2)+"s",e.appendChild(n)}}function Mt(){let e=14e3+Math.random()*28e3;setTimeout(Za,e)}function Za(){let e=ee()==="dark",a=de(),t=document.querySelector(".grain");if(!e||a||document.hidden||!t){Mt();return}let r=window.innerWidth,n=window.innerHeight,o=Math.random()*r*.6,i=Math.random()*n*.55,c=380+Math.random()*520,p=18+Math.random()*26,l=p*Math.PI/180,f=o+Math.cos(l)*c,u=i+Math.sin(l)*c,g=document.createElement("div");g.className="meteor",g.setAttribute("aria-hidden","true"),g.style.setProperty("--from-x",o+"px"),g.style.setProperty("--from-y",i+"px"),g.style.setProperty("--to-x",f+"px"),g.style.setProperty("--to-y",u+"px"),g.style.setProperty("--angle",p+"deg"),t.appendChild(g),g.addEventListener("animationend",()=>g.remove(),{once:!0}),Mt()}function Qa(e,a){let t=0;for(let[r,n]of a)if(t+=n,e<t)return r;return a[a.length-1][0]}function ra(e){let a=e>>>0;return function(){a=a+1831565813>>>0;let t=a;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296}}J();O();K();ie();te();Ne();ue();Fe();J();O();K();te();X();ue();async function Na(){let e=Je.value.trim();if(e.length<2){wt();return}let a=q();if(!a)return;let t=await y(`/api/search?q=${encodeURIComponent(e)}&board=${encodeURIComponent(a.slug)}`);if(t.results.length===0){V.hidden=!1,V.innerHTML='<div class="search-hit">No results</div>';return}V.hidden=!1,V.innerHTML=t.results.map(r=>`
599
+ <div class="search-hit" data-ticket-id="${r.id}">
600
+ <strong>${d(G(r))}</strong>
601
+ ${d(r.title)}
602
+ </div>
603
+ `).join(""),V.querySelectorAll("[data-ticket-id]").forEach(r=>{r.addEventListener("click",async()=>{_(),wt(),C({boardId:s.boardId,view:"ticket",ticketId:r.dataset.ticketId})})})}function wt(){V.hidden=!0,V.innerHTML=""}Z();je();function qa(e){e?.showModal()}function Ha(e){e?.open&&e.close()}function Ua(e){e&&(e.addEventListener("click",a=>{a.target===e&&Ha(e)}),e.querySelectorAll("[data-modal-close]").forEach(a=>{a.addEventListener("click",()=>Ha(e))}))}async function Qr(){let e=document.getElementById("welcomeDialog");Ua(e),me==="preview"&&qa(e),b("#settingsBtn").addEventListener("click",async()=>{_(),Y(),C({boardId:s.boardId,view:"settings",tab:s.settingsTab||"lanes"})}),Q?.addEventListener("click",t=>{if(t.stopPropagation(),!z.hidden){He();return}Da()}),b("#newTicketBtn").addEventListener("click",()=>{if(zt()){_();return}dt("")}),ne.addEventListener("click",()=>{_()}),b("#drawerCloseBtn").addEventListener("click",()=>{C({boardId:s.boardId,view:"board"})}),b("#drawerArchiveBtn").addEventListener("click",async()=>{let t=s.selectedTicketId;if(!t||s.detailMode!=="ticket")return;let n=s.data?.tickets?.find(o=>o.id===t)?.title||"card";await y(T(`/api/tickets/${encodeURIComponent(t)}/archive`),{method:"POST"}),m.error(`Archived: ${n}`),await v(),C({boardId:s.boardId,view:"board"})}),re.addEventListener("click",()=>{C({boardId:s.boardId,view:"board"})}),document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;if(!z.hidden){Y();return}if(zt()){_();return}if(!j.classList.contains("is-open"))return;let r=document.activeElement;r?.classList?.contains("inline-title-editor")||r?.classList?.contains("inline-desc-editor")||C({boardId:s.boardId,view:"board"})}),Je.addEventListener("input",Ve(Na,220)),document.addEventListener("click",t=>{t.target.closest("#topbarSearch")||wt(),t.target.closest(".topbar-menu")||Y()}),ka();let a=Wt();a.boardSlug&&(s.boardSlug=a.boardSlug),await v(),Oa(!0),qe()?await Ue():ge({replace:!0})}Qr();
604
+ //# sourceMappingURL=app.js.map