@starlove/orbit 1.0.3 → 1.0.4
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/dist/full/index.html +1 -1
- package/dist/full/js/{app.70be7d06.js → app.7e25f59b.js} +57 -57
- package/dist/full/js/app.7e25f59b.js.map +7 -0
- package/dist/full/version.json +2 -2
- package/package.json +1 -1
- package/public/js/create-card.js +2 -2
- package/public/js/kanban.js +2 -2
- package/public/js/settings.js +8 -7
- package/public/js/state.js +16 -0
- package/public/js/ticket-detail.js +2 -2
- package/src/cli/orbit.js +15 -52
- package/src/core/agents-md.js +88 -0
- package/src/core/boards.js +12 -0
- package/src/core/delete-board.js +49 -5
- package/src/core/seed.js +2 -3
- package/dist/full/js/app.70be7d06.js.map +0 -7
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
1
|
+
var da=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ca=(e,a)=>{for(var t in a)da(e,t,{get:a[t],enumerable:!0})};var h,Z,U,L,q,k,ae,ie,ct,re,Re,Q,xt,Lt,J=T(()=>{h=e=>document.querySelector(e),Z=h("#boardMenuBtn"),U=h("#boardFlyout"),L=h("#kanban"),q=h("#drawer"),k=h("#drawerInner"),ae=h("#drawerBackdrop"),ie=h("#createFlyout"),ct=h("#createFlyoutInner"),re=h("#createFlyoutBackdrop"),Re=h("#searchInput"),Q=h("#searchResults"),xt=h("#themeToggle"),Lt=h("#themeIcon")});function we(e){return!e||!Oe.has(e)?"lanes":e}var Oe,pt=T(()=>{Oe=new Set(["lanes","ai","notes","journal","repository","archive"])});function It(){return we(s.settingsTab||localStorage.getItem("mab_settings_tab"))}function ke(){if(!s.data)return;let e=s.data.boards||[];(!s.boardId||!e.some(a=>a.id===s.boardId))&&(s.boardId=e[0]?.id||"")}function V(){return(s.data?.boards||[]).find(e=>e.id===s.boardId)}function Tt(){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 _t(e){return e?.role==="ai_ready"||e?.name==="AI Ready"}function Ne(){let e=$e();return V()?.ai_enabled!==0?e:e.filter(a=>!_t(a))}function Ct(e=""){let a=$e();return V()?.ai_enabled!==0?a:a.filter(t=>!_t(t)||t.id===e)}function H(){return s.data.tickets.filter(e=>e.board_id===s.boardId)}var s,R=T(()=>{pt();s={data:null,boardId:"",selectedTicketId:"",expandedCardIds:new Set,detailMode:"empty",settingsTab:we(localStorage.getItem("mab_settings_tab")),showPriority:localStorage.getItem("mab_show_priority")!=="false",eventSource:null}});function c(e){return String(e??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function xe(e){return e?new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}).format(new Date(e)):""}function Mt(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 z(e){return`#${e.number}`}function F(e){return e==="epic"||e==="feature"||e==="bug"||e==="task"?e:"task"}function Le(e){return{epic:"Epic",feature:"Feature",task:"Task",bug:"Bug"}[F(e)]||"Task"}function Pt(e){return{epic:"Epic / Story",feature:"Feature",task:"Task",bug:"Bug"}[F(e)]||"Task"}function qe(e){return{0:"MAYBE",1:"LOW",2:"MED",3:"HIGH",4:"URGENT"}[Number(e)]||"MED"}function Se(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 At(e=[]){return e.length?`
|
|
2
2
|
<div class="labels">
|
|
3
3
|
${e.map(a=>`<span class="label" style="--label-color: ${c(a.color)}">${c(a.name)}</span>`).join("")}
|
|
4
4
|
</div>
|
|
5
|
-
`:""}function
|
|
5
|
+
`:""}function Dt(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 Y=T(()=>{});function ba(){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=ba(),o=document.createElement("div");o.className=`toast toast-${a}`,o.setAttribute("role","status");let n=ha[a];o.innerHTML=`<span class="toast-icon">${n}</span><span class="toast-msg">${c(e)}</span><button class="toast-close" aria-label="Dismiss">×</button>`,o.querySelector(".toast-close").addEventListener("click",()=>ut(o)),r.prepend(o),requestAnimationFrame(()=>requestAnimationFrame(()=>o.classList.add("toast-enter")));let i=setTimeout(()=>ut(o),t);o.addEventListener("mouseenter",()=>clearTimeout(i)),o.addEventListener("mouseleave",()=>{let d=setTimeout(()=>ut(o),1500);o.addEventListener("mouseenter",()=>clearTimeout(d),{once:!0})})}function ut(e){e.classList.contains("toast-exit")||(e.classList.add("toast-exit"),e.addEventListener("animationend",()=>e.remove(),{once:!0}))}function Ft(e,a){let t=new Blob([JSON.stringify(a,null,2)],{type:"application/json"}),r=URL.createObjectURL(t),o=document.createElement("a");o.href=r,o.download=e,document.body.append(o),o.click(),o.remove(),URL.revokeObjectURL(r)}function He(e,a){let t=0;return(...r)=>{clearTimeout(t),t=setTimeout(()=>e(...r),a)}}var ha,oe,ne=T(()=>{Y();ha={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 Bt({method:e="GET",path:a,body:t,headers:r}){let o={"Content-Type":"application/json",...r||{}},n=await fetch(a,{method:e,headers:o,body:t!==void 0?JSON.stringify(t):void 0}),i=await n.text(),d=i?JSON.parse(i):{};if(!n.ok){let p=new Error(d.error||n.statusText);throw p.payload=d,p.status=n.status,p}return d}var jt=T(()=>{});function Ue(){return`/api/bootstrap${s.boardId?`?board_id=${encodeURIComponent(s.boardId)}`:""}`}function E(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 Bt({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 G=T(()=>{R();ne();jt()});function ft(){mt+=1,q.hidden=!1,ae.hidden=!1,requestAnimationFrame(()=>{q.classList.add("is-open"),ae.classList.add("is-visible")})}function ze(){let e=++mt,a=q.classList.contains("is-open");q.classList.remove("is-open"),ae.classList.remove("is-visible");let t=()=>{if(mt!==e)return;q.hidden=!0,ae.hidden=!0,k.innerHTML="";let n=document.getElementById("drawerEyebrow"),i=document.getElementById("drawerTitle"),d=document.getElementById("drawerSubtitle"),p=document.getElementById("drawerTabs");if(n&&(n.textContent="",n.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=""}d&&(d.innerHTML="",d.hidden=!0),p&&(p.innerHTML="",p.hidden=!0)};if(!a){t();return}let r=!1,o=()=>{r||(r=!0,t())};q.addEventListener("transitionend",o,{once:!0}),setTimeout(o,360)}function Je({eyebrow:e,title:a,titleAttrs:t,subtitleHtml:r,tabs:o,activeTab:n,onTabSelect:i,body:d,mode:p}){q.classList.toggle("is-settings",p==="settings");let l=document.getElementById("drawerEyebrow"),b=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(b.attributes))x.name!=="id"&&b.removeAttribute(x.name);if(b.className="drawer-title-text",t)for(let[x,B]of Object.entries(t))x==="class"?b.className=`drawer-title-text ${B}`:b.setAttribute(x,B);b.textContent=a??"",o&&o.length?(g.hidden=!1,g.innerHTML=o.map(x=>`<button type="button" role="tab" class="drawer-tab ${x.id===n?"is-active":""}" data-drawer-tab="${c(x.id)}" aria-selected="${x.id===n}">${c(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 O=document.getElementById("drawerArchiveBtn");O&&(O.hidden=s.detailMode!=="ticket"),k.innerHTML=d??""}var mt,Ge=T(()=>{J();R();Y();mt=0});function ya(e){return e?typeof e=="string"?{readAt:e,count:0}:{readAt:e.readAt||null,count:Number(e.count)||0}:{readAt:null,count:0}}function Ee(e){if(!e)return new Map;let a=bt.get(e);if(a)return a;a=new Map;try{let t=localStorage.getItem(Rt(e));if(t){let r=JSON.parse(t);for(let[o,n]of Object.entries(r))a.set(o,ya(n))}}catch{}return bt.set(e,a),a}function We(e){let a=bt.get(e);if(a)try{let t={};for(let[r,o]of a)t[r]=o;localStorage.setItem(Rt(e),JSON.stringify(t))}catch{}}function Ot(e,a){let t=e.get(a);return t||(t={readAt:null,count:0},e.set(a,t)),t}function Ke(e){let a=e?.board_id||s.boardId;if(!a||!e?.id)return 0;let r=Ee(a).get(e.id);return r?r.count:localStorage.getItem(ht(a))==="1"?1:0}function Ye(e,a){let t=s.boardId;if(!t||!e)return;let r=Ee(t),o=Ot(r,e);o.count===0&&o.readAt&&a&&o.readAt>=a||(o.count=0,a&&(o.readAt=a),We(t))}function Nt(e){let a=s.boardId;if(!a||!e)return;let t=Ee(a),r=Ot(t,e);r.count=(r.count||0)+1,We(a)}function qt(e){let a=s.boardId;if(!a||!e)return;let t=Ee(a);t.has(e)&&(t.delete(e),We(a))}function Ht(e,a){if(!e||localStorage.getItem(ht(e))==="1")return;let t=Ee(e);for(let r of a||[])!t.has(r.id)&&r.updated_at&&t.set(r.id,{readAt:r.updated_at,count:0});We(e);try{localStorage.setItem(ht(e),"1")}catch{}}var Rt,ht,bt,Ie=T(()=>{R();Rt=e=>`mab_card_read:${e}`,ht=e=>`mab_card_read_seeded:${e}`,bt=new Map});function Xe(){let e=Ne(),a=H();L.innerHTML=e.map(t=>va(t,a)).join(""),L.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 o=r.dataTransfer.getData("text/plain");o&&(_(),await y(E(`/api/tickets/${o}`),{method:"PATCH",body:{state_id:t.dataset.stateId}}),await v())})}),L.querySelectorAll("[data-add-to-state]").forEach(t=>{t.addEventListener("click",r=>{r.stopPropagation(),Qe(t.dataset.addToState||"")})}),L.querySelectorAll(".epic-mini-header[data-ticket-id]").forEach(t=>{t.addEventListener("click",()=>{_(),C({boardId:s.boardId,view:"ticket",ticketId:t.dataset.ticketId})})}),L.querySelectorAll(".card").forEach(t=>{let r=!1;t.addEventListener("click",async n=>{if(r){r=!1,n.preventDefault(),n.stopPropagation();return}_(),C({boardId:s.boardId,view:"ticket",ticketId:t.dataset.ticketId})});let o=t.querySelector("button.card-expand-trigger");o&&o.addEventListener("click",n=>{n.stopPropagation(),n.preventDefault();let i=t.dataset.ticketId;s.expandedCardIds.has(i)?s.expandedCardIds.delete(i):s.expandedCardIds.add(i);let d=t.classList.toggle("is-expanded");o.setAttribute("aria-expanded",d?"true":"false")}),t.addEventListener("dragstart",n=>{n.dataTransfer.setData("text/plain",t.dataset.ticketId),n.dataTransfer.effectAllowed="move"}),t.addEventListener("dragend",()=>{r=!0,setTimeout(()=>{r=!1},0)})})}function ga(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">
|
|
6
6
|
<path d="M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z" fill="currentColor" opacity="0.65" />
|
|
7
7
|
<circle cx="12" cy="11.5" r="1.8" fill="#fff" />
|
|
8
8
|
</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">
|
|
@@ -29,7 +29,7 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
29
29
|
<div class="empty-state-title">${c(t.title)}</div>
|
|
30
30
|
<div class="empty-state-subtitle">${c(t.subtitle)}</div>
|
|
31
31
|
</div>
|
|
32
|
-
`}function
|
|
32
|
+
`}function va(e,a){let t=a.filter(i=>i.state_id===e.id),r=t.length===0,o=e.name==="AI Ready",n=["column"];return o&&n.push("column--ai-ready"),`
|
|
33
33
|
<section class="${n.join(" ")}" data-state-id="${e.id}" data-state-name="${c(e.name)}">
|
|
34
34
|
<div class="column-head">
|
|
35
35
|
<h2${o?' title="Agent staging \u2014 cards here are picked up by the claim-next tool when unblocked"':""}>
|
|
@@ -40,10 +40,10 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
40
40
|
<span class="count">${t.length}</span>
|
|
41
41
|
</div>
|
|
42
42
|
</div>
|
|
43
|
-
${r?
|
|
43
|
+
${r?ga(e.name):wa(t,a)}
|
|
44
44
|
<button type="button" class="add-card-phantom" data-add-to-state="${c(e.id)}">+ Add a card</button>
|
|
45
45
|
</section>
|
|
46
|
-
`}function
|
|
46
|
+
`}function wa(e,a){let t=new Map(a.filter(d=>F(d.type)==="epic").map(d=>[d.id,d])),r=new Set(e.filter(d=>F(d.type)==="epic").map(d=>d.id)),o=new Map;for(let d of e)if(d.parent_ticket_id&&t.has(d.parent_ticket_id)){let p=o.get(d.parent_ticket_id)||[];p.push(d),o.set(d.parent_ticket_id,p)}let n=new Set,i=[];for(let d of e)if(!n.has(d.id)){if(F(d.type)==="epic"){let p=o.get(d.id)||[];if(p.length){let l=p.map(b=>Te(b,{asEpicChild:!0})).join("");i.push(`${Te(d)}<div class="epic-children">${l}</div>`),p.forEach(b=>n.add(b.id))}else i.push(Te(d));n.add(d.id);continue}if(d.parent_ticket_id&&t.has(d.parent_ticket_id)&&!r.has(d.parent_ticket_id)){let p=t.get(d.parent_ticket_id),l=o.get(d.parent_ticket_id)||[],b=l.map(u=>Te(u,{asEpicChild:!0})).join("");i.push(`${ka(p)}<div class="epic-children">${b}</div>`),l.forEach(u=>n.add(u.id));continue}i.push(Te(d)),n.add(d.id)}return i.join("")}function ka(e){return`
|
|
47
47
|
<div class="epic-mini-header" data-ticket-id="${c(e.id)}" title="Open epic">
|
|
48
48
|
<div class="card-type-id type-pill-epic">
|
|
49
49
|
${_e("epic")}
|
|
@@ -52,7 +52,7 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
52
52
|
<span class="ticket-number">${c(z(e))}</span>
|
|
53
53
|
<span class="epic-mini-title">${c(e.title)}</span>
|
|
54
54
|
</div>
|
|
55
|
-
`}function
|
|
55
|
+
`}function Ze(e){let a=Se(e),t=qe(e);return`<div class="card-priority-id priority-pill priority-pill-${c(a)}"><span class="card-priority-label">${c(t)}</span></div>`}function _e(e){let a=F(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`
|
|
56
56
|
<svg class="card-type-icon" viewBox="0 0 24 24" style="color: ${r}">
|
|
57
57
|
${t}
|
|
58
58
|
</svg>
|
|
@@ -62,9 +62,9 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
62
62
|
${_e(e.type)}
|
|
63
63
|
<span class="card-type-label">${c(o)}</span>
|
|
64
64
|
</div>
|
|
65
|
-
${s.showPriority?
|
|
65
|
+
${s.showPriority?Ze(e.priority):""}
|
|
66
66
|
${i?'<svg class="card-expand-chevron" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6" /></svg>':""}
|
|
67
|
-
`,p=
|
|
67
|
+
`,p=Ke(e),l=p===0?"":p===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="${p} unread updates">${p>99?"99+":p}</span>`;return`
|
|
68
68
|
<article class="card type-${c(t)} priority-${c(r)}${n?" is-expanded":""}${a?" is-epic-child":""} ${e.id===s.selectedTicketId?"selected":""}" draggable="true" data-ticket-id="${e.id}">
|
|
69
69
|
${l}
|
|
70
70
|
<h3>${c(e.title)}</h3>
|
|
@@ -75,13 +75,13 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
75
75
|
|
|
76
76
|
${i?`
|
|
77
77
|
<div class="card-expandable">
|
|
78
|
-
${
|
|
78
|
+
${At(e.labels)}
|
|
79
79
|
${e.parent_ticket?`<div class="parent-line">-> ${c(z(e.parent_ticket))}</div>`:""}
|
|
80
80
|
${e.child_count?`<div class="child-count">${e.child_count} feature${e.child_count===1?"":"s"} inside</div>`:""}
|
|
81
81
|
</div>
|
|
82
82
|
`:""}
|
|
83
83
|
</article>
|
|
84
|
-
`}function
|
|
84
|
+
`}function Ut(){let t=()=>Math.max(L.clientWidth,1),r=!1,o=!1,n=0,i=0,d=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;L.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)||L.scrollWidth<=L.clientWidth||(u.preventDefault(),L.scrollLeft+=l(g,u.deltaMode))},{passive:!1}),L.addEventListener("pointerdown",u=>{u.button===0&&(p(u.target)||(r=!0,o=!1,d=u.pointerId,n=u.clientX,i=L.scrollLeft,L.classList.add("is-grabbing")))}),L.addEventListener("pointermove",u=>{if(!r||u.pointerId!==d)return;let g=u.clientX-n;if(!o&&Math.abs(g)>4){o=!0;try{L.setPointerCapture(d)}catch{}}o&&(u.preventDefault(),L.scrollLeft=i-g)});let b=u=>{if(!(!r||u&&u.pointerId!==d)){r=!1,L.classList.remove("is-grabbing");try{L.releasePointerCapture(d)}catch{}}};L.addEventListener("pointerup",b),L.addEventListener("pointercancel",b),L.addEventListener("pointerleave",b),L.addEventListener("click",u=>{o&&(u.stopPropagation(),u.preventDefault(),o=!1)},!0)}var Ce=T(()=>{J();R();Y();G();ee();se();X();Ie()});var zt,de,W,Me=T(()=>{zt="full";zt="full";de=zt,W={sse:de==="full",ai:de==="full",multiBoard:de==="full",tokenAuth:de==="full"}});async function ce(){let e=await y(`/api/boards/${s.boardId}/context?include_struck=true`),a=e.board,t=It(),r=[{id:"lanes",label:"Lanes"},{id:"archive",label:"Card Archive"},{id:"notes",label:"Notes"},...W.ai?[{id:"ai",label:"AI"}]:[],{id:"journal",label:"Journal"},{id:"repository",label:"Repository"}],o=t==="ai"&&!W.ai?"lanes":t;Je({eyebrow:"SETTINGS",mode:"settings",title:a.name,tabs:r,activeTab:o,onTabSelect:async n=>{C({boardId:s.boardId,view:"settings",tab:n})},body:$a(e,o)}),ja(e,o)}function $a(e,a){switch(a){case"notes":return Fa(e);case"lanes":return Gt();case"ai":return W.ai?xa(e):Gt();case"journal":return Ba(e);case"archive":return Pa();case"repository":default:return Aa(e)}}function xa(e){let a=e.board,t=a.ai_enabled!==0,r=t?'<div class="ai-section-divider" aria-hidden="true"></div>':"",o=t?La(a):"",n=t?Sa(e):"";return`
|
|
85
85
|
<div class="section">
|
|
86
86
|
<label class="orbit-check" for="aiEnabledToggle">
|
|
87
87
|
<input
|
|
@@ -94,13 +94,13 @@ var na=Object.defineProperty;var T=(e,a)=>()=>(e&&(a=e(e=0)),a);var ia=(e,a)=>{f
|
|
|
94
94
|
</span>
|
|
95
95
|
<span class="orbit-check-label">Enable AI</span>
|
|
96
96
|
</label>
|
|
97
|
-
<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
|
|
97
|
+
<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>
|
|
98
98
|
</div>
|
|
99
99
|
${r}
|
|
100
100
|
${o}
|
|
101
101
|
${r}
|
|
102
102
|
${n}
|
|
103
|
-
`}function
|
|
103
|
+
`}function La(e){return`
|
|
104
104
|
<div class="section ai-subsection ai-context-setup">
|
|
105
105
|
<div class="ai-context-title-row">
|
|
106
106
|
<span class="ai-context-inline-mark" aria-hidden="true">Context</span>
|
|
@@ -114,7 +114,7 @@ How any AI agent should use this board and work in this repo.`)}">${c(e.agent_in
|
|
|
114
114
|
<button type="submit">Save</button>
|
|
115
115
|
</form>
|
|
116
116
|
</div>
|
|
117
|
-
`}function
|
|
117
|
+
`}function Sa(e){let a=Ve(),t="claude-code",r=Ia(e,a),o=yt(t,r),n=gt(a,r),i=tt[t];return`
|
|
118
118
|
<details class="section ai-subsection mcp-setup" data-mcp-setup>
|
|
119
119
|
<summary>
|
|
120
120
|
<div class="mcp-title-row">
|
|
@@ -128,13 +128,13 @@ How any AI agent should use this board and work in this repo.`)}">${c(e.agent_in
|
|
|
128
128
|
<label>
|
|
129
129
|
<span>Operating system</span>
|
|
130
130
|
<select id="mcpOsSelect" class="select-chevron-field">
|
|
131
|
-
${Object.entries(
|
|
131
|
+
${Object.entries(et).map(([d,p])=>`<option value="${d}" ${d===a?"selected":""}>${c(p.label)}</option>`).join("")}
|
|
132
132
|
</select>
|
|
133
133
|
</label>
|
|
134
134
|
<label>
|
|
135
135
|
<span>Agent app</span>
|
|
136
136
|
<select id="mcpClientSelect" class="select-chevron-field">
|
|
137
|
-
${Object.entries(
|
|
137
|
+
${Object.entries(tt).map(([d,p])=>`<option value="${d}" ${d===t?"selected":""}>${c(p.label)}</option>`).join("")}
|
|
138
138
|
</select>
|
|
139
139
|
</label>
|
|
140
140
|
</div>
|
|
@@ -178,21 +178,21 @@ How any AI agent should use this board and work in this repo.`)}">${c(e.agent_in
|
|
|
178
178
|
</div>
|
|
179
179
|
</div>
|
|
180
180
|
</details>
|
|
181
|
-
`}function
|
|
181
|
+
`}function Ve(){let e=String(navigator.userAgentData?.platform||navigator.platform||navigator.userAgent||"").toLowerCase();return e.includes("win")?"windows":e.includes("mac")?"macos":"linux"}function Ea(e){return{serverPath:(et[e]||et.linux).serverPath}}function Ia(e,a){let t=Ea(a);return{serverPath:(e.deployment||{}).mcp_server_path||t.serverPath}}function Jt(){return{serverPath:h("#mcpServerPathInput")?.value||""}}function yt(e,a){if(e==="claude-code")return Ca(a);if(e==="codex")return _a(a);if(e==="opencode")return Ta(a);let t={mcpServers:{"starscape-orbit":{command:"node",args:[a.serverPath]}}};return JSON.stringify(t,null,2)}function Ta(e){return JSON.stringify({$schema:"https://opencode.ai/config.json",mcp:{"starscape-orbit":{type:"local",command:["node",e.serverPath],enabled:!0}}},null,2)}function _a(e){return`[mcp_servers.starscape-orbit]
|
|
182
182
|
command = "node"
|
|
183
|
-
args = ["${
|
|
184
|
-
enabled = true`}function
|
|
183
|
+
args = ["${Ma(e.serverPath)}"]
|
|
184
|
+
enabled = true`}function Ca(e){return["claude mcp add starscape-orbit","--","node",Wt(e.serverPath)].join(" ")}function gt(e,a){return`node ${Wt(a.serverPath)}`}function Wt(e){return`"${String(e||"").replace(/"/g,'\\"')}"`}function Ma(e){return String(e||"").replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Pa(){return`
|
|
185
185
|
<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>
|
|
186
186
|
<div class="section">
|
|
187
187
|
<div id="archiveList" class="archive-list">Loading\u2026</div>
|
|
188
188
|
</div>
|
|
189
|
-
`}function
|
|
189
|
+
`}function Aa(e){let a=e.board;return P.boardId!==a.id&&(P.boardId=a.id,P.step="idle",P.exported=!1),`
|
|
190
190
|
${W.multiBoard?`
|
|
191
191
|
<div class="detail-head project-manual-head">
|
|
192
192
|
<div class="meta-grid">
|
|
193
193
|
<div class="meta meta--repo-path">
|
|
194
194
|
<span>Repo</span>
|
|
195
|
-
<strong>${c(
|
|
195
|
+
<strong>${c(Dt(a.repo_url))}</strong>
|
|
196
196
|
<span>Path</span>
|
|
197
197
|
<strong>${c(a.system_path||e.deployment?.system_path||"Not available")}</strong>
|
|
198
198
|
</div>
|
|
@@ -211,11 +211,11 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
211
211
|
</div>
|
|
212
212
|
</div>
|
|
213
213
|
|
|
214
|
-
${W.multiBoard?
|
|
215
|
-
`}function
|
|
214
|
+
${W.multiBoard?Da(a):""}
|
|
215
|
+
`}function Da(e){let a=c(e.slug||"");if(P.step==="choice")return`
|
|
216
216
|
<div class="section repository-danger-zone">
|
|
217
217
|
<h3>Delete Board</h3>
|
|
218
|
-
<p class="description">Delete this board from Orbit and remove its local
|
|
218
|
+
<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>
|
|
219
219
|
<div class="repository-delete-actions">
|
|
220
220
|
<button type="button" class="ghost" id="deleteBoardExportFirst">Export first</button>
|
|
221
221
|
<button type="button" class="ghost danger-button" id="deleteBoardSkipExport">Delete without exporting</button>
|
|
@@ -239,10 +239,10 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
239
239
|
`}return`
|
|
240
240
|
<div class="section repository-danger-zone">
|
|
241
241
|
<h3>Delete Board</h3>
|
|
242
|
-
<p class="description">Remove this board from Orbit and delete its local
|
|
242
|
+
<p class="description">Remove this board from Orbit and delete its repo-local Orbit files. This cannot be undone without an exported snapshot.</p>
|
|
243
243
|
<button type="button" class="ghost danger-button" id="deleteBoardStart">Delete Board</button>
|
|
244
244
|
</div>
|
|
245
|
-
`}function
|
|
245
|
+
`}function Fa(e){let a=e.board;return`
|
|
246
246
|
<div class="section ai-fields">
|
|
247
247
|
<form id="notesSettingsForm" class="field-form settings-notes-form">
|
|
248
248
|
<label class="settings-notes-field-group">
|
|
@@ -256,7 +256,7 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
256
256
|
<button type="submit" class="settings-notes-save">Save</button>
|
|
257
257
|
</form>
|
|
258
258
|
</div>
|
|
259
|
-
`}function
|
|
259
|
+
`}function Gt(){return`
|
|
260
260
|
<div class="section">
|
|
261
261
|
<label class="orbit-check" for="showPriorityToggle">
|
|
262
262
|
<input
|
|
@@ -270,16 +270,16 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
270
270
|
<span class="orbit-check-label">Show priority label on cards</span>
|
|
271
271
|
</label>
|
|
272
272
|
<p class="description lanes-description">Rename, reorder, add, or remove lanes.</p>
|
|
273
|
-
${
|
|
273
|
+
${Ha()}
|
|
274
274
|
<form id="laneCreateForm" class="lane-create-form">
|
|
275
275
|
<input name="name" placeholder="New lane name..." required />
|
|
276
276
|
<button type="submit">Add Lane</button>
|
|
277
277
|
</form>
|
|
278
278
|
</div>
|
|
279
|
-
`}function
|
|
279
|
+
`}function Ba(e){return`
|
|
280
280
|
${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>':""}
|
|
281
281
|
<div class="section">
|
|
282
|
-
${
|
|
282
|
+
${Oa(e.entries)}
|
|
283
283
|
<form id="projectEntryForm" class="comment-form project-entry-form">
|
|
284
284
|
<select name="type" class="select-chevron-field" aria-label="Entry type">
|
|
285
285
|
<option value="decision">Decision</option>
|
|
@@ -290,7 +290,7 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
290
290
|
<button type="submit">Add Entry</button>
|
|
291
291
|
</form>
|
|
292
292
|
</div>
|
|
293
|
-
`}function
|
|
293
|
+
`}function ja(e,a){let t=e.board;if(a==="repository"){let r=async()=>{let i=await y(`/api/boards/${t.id}/export`);Ft(`${t.slug}.orbit.json`,i)};h("#exportProject")?.addEventListener("click",async()=>{await r()}),h("#importSnapshotFile")?.addEventListener("change",async i=>{let d=i.currentTarget.files?.[0];if(!d)return;let p=await d.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=""}),h("#deleteBoardStart")?.addEventListener("click",async()=>{P.step="choice",P.exported=!1,await ce()}),h("#deleteBoardExportFirst")?.addEventListener("click",async()=>{await r(),P.step="confirm",P.exported=!0,await ce()}),h("#deleteBoardSkipExport")?.addEventListener("click",async()=>{P.step="confirm",P.exported=!1,await ce()}),h("#deleteBoardCancel")?.addEventListener("click",async()=>{P.step="idle",P.exported=!1,await ce()});let o=h("#deleteBoardConfirmInput"),n=h("#deleteBoardConfirm");o?.addEventListener("input",()=>{n&&(n.disabled=o.value.trim()!==t.slug)}),n?.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"&&h("#notesSettingsForm")?.addEventListener("submit",async r=>{r.preventDefault();let o=new FormData(r.currentTarget);await y(`/api/boards/${t.id}`,{method:"PATCH",body:{project_notes:String(o.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 Ua(r)})}),k.querySelectorAll(".lane-row input, .lane-row select").forEach(r=>{r.addEventListener("change",async()=>{await Yt(r.closest(".lane-row"))})}),h("#laneCreateForm")?.addEventListener("submit",async r=>{r.preventDefault();let o=new FormData(r.currentTarget);await y(`/api/boards/${t.id}/states`,{method:"POST",body:Object.fromEntries(o.entries())}),await v(),s.detailMode="settings",m.success("Lane added")}),h("#showPriorityToggle")?.addEventListener("change",r=>{s.showPriority=!!r.currentTarget.checked,localStorage.setItem("mab_show_priority",s.showPriority?"true":"false"),Xe()})),a==="ai"){let r=()=>{let o=h("#mcpOsSelect")?.value||Ve(),n=h("#mcpClientSelect")?.value||"claude-code",i=tt[n]||tt.generic,d=Jt(),p=yt(n,d),l=gt(o,d),b=k.querySelector("[data-mcp-os-note]");b&&(b.textContent=`Detected: ${et[Ve()]?.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 O=k.querySelector("[data-mcp-helper]");O&&(O.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)};h("#mcpOsSelect")?.addEventListener("change",()=>r()),h("#mcpClientSelect")?.addEventListener("change",()=>r()),["#mcpServerPathInput"].forEach(o=>{h(o)?.addEventListener("input",()=>r())}),k.querySelectorAll("[data-copy-mcp]").forEach(o=>{o.addEventListener("click",async()=>{let n=h("#mcpOsSelect")?.value||Ve(),i=h("#mcpClientSelect")?.value||"claude-code",d=Jt(),p=o.dataset.copyMcp==="command"?gt(n,d):yt(i,d);await Ra(p),m.success(o.dataset.copyMcp==="command"?"MCP command copied":"MCP config copied")})}),h("#agentInstructionsForm")?.addEventListener("submit",async o=>{o.preventDefault();let n=new FormData(o.currentTarget);await y(`/api/boards/${t.id}`,{method:"PATCH",body:Object.fromEntries(n.entries())}),await v(),s.detailMode="settings",m.success("Saved")}),h("#aiEnabledToggle")?.addEventListener("change",async o=>{let n=!!o.currentTarget.checked;await y(`/api/boards/${t.id}`,{method:"PATCH",body:{ai_enabled:n}}),await v(),s.detailMode="settings",m.success(n?"AI features enabled \u2014 agent lanes provisioned":"AI features disabled \u2014 AI Ready hidden")})}if(a==="archive"){let r=h("#archiveList");if(r){let o=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(d=>Pe(d,{archive:{id:d.id},disableOpen:!0})).join("")}</div>`}catch(n){r.innerHTML=`<p class="description">Could not load archive: ${c(n?.message||"unknown error")}</p>`}};o(),r.addEventListener("click",async n=>{let i=n.target.closest("[data-archive-restore]"),d=n.target.closest("[data-archive-delete]");if(!i&&!d)return;n.stopPropagation();let l=(i||d).closest("article")?.querySelector("h3")?.textContent||"card";if(i){let b=i.dataset.archiveRestore;await y(E(`/api/tickets/${encodeURIComponent(b)}/restore`),{method:"POST"}),m.success(`Restored: ${l}`),await v(),await o();return}if(d){let b=d.dataset.archiveDelete;if(!confirm(`Permanently delete "${l}"? This cannot be undone.`))return;await y(E(`/api/tickets/${encodeURIComponent(b)}`),{method:"DELETE"}),m.success(`Deleted: ${l}`),await o()}})}}a==="journal"&&(k.querySelectorAll("[data-entry-action='toggle-struck']").forEach(r=>{r.addEventListener("click",async()=>{await y(E(`/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")})}),h("#projectEntryForm")?.addEventListener("submit",async r=>{r.preventDefault();let o=new FormData(r.currentTarget);await y(`/api/boards/${t.id}/entries`,{method:"POST",body:Object.fromEntries(o.entries())}),await v(),s.detailMode="settings",m.success("Project entry added")}))}async function Ra(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 Oa(e=[]){return e.length?e.map(a=>{let t=!!a.struck_at;return`
|
|
294
294
|
<div class="comment project-entry ${c(a.type)} ${t?"is-struck":""}">
|
|
295
295
|
<div class="comment-meta">
|
|
296
296
|
<div>
|
|
@@ -311,9 +311,9 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
311
311
|
</div>
|
|
312
312
|
<div class="comment-body">${c(a.body)}</div>
|
|
313
313
|
</div>
|
|
314
|
-
`}).join(""):'<p class="description">No project entries yet.</p>'}function
|
|
314
|
+
`}).join(""):'<p class="description">No project entries yet.</p>'}function Na(e,a,t){return!!(a.get(e.id)||e.is_default||Kt.has(e.role)||t&&e.role==="ai_ready")}function qa(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)":Kt.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 Ha(){let e=$e(),a=V()?.ai_enabled!==0,t=new Map;for(let r of H())t.set(r.state_id,(t.get(r.state_id)||0)+1);return`
|
|
315
315
|
<div class="lane-list">
|
|
316
|
-
${e.map((r,o)=>{let n=r.role==="ai_ready",i=n?"AI Ready lane name is locked \u2014
|
|
316
|
+
${e.map((r,o)=>{let n=r.role==="ai_ready",i=n?"AI Ready lane name is locked \u2014 disable AI to hide this column":"";return`
|
|
317
317
|
<div class="lane-row${n?" lane-row--locked":""}" data-lane-id="${r.id}">
|
|
318
318
|
<button type="button" class="lane-icon-btn" data-lane-action="up" ${o===0?"disabled":""} title="Move lane left" aria-label="Move lane left">\u2191</button>
|
|
319
319
|
<button type="button" class="lane-icon-btn" data-lane-action="down" ${o===e.length-1?"disabled":""} title="Move lane right" aria-label="Move lane right">\u2193</button>
|
|
@@ -322,25 +322,25 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
322
322
|
<span class="lane-new-sun" aria-hidden="true"></span>
|
|
323
323
|
<span class="lane-new-label">New</span>
|
|
324
324
|
</button>
|
|
325
|
-
<button type="button" class="lane-delete-btn" data-lane-action="delete" ${
|
|
325
|
+
<button type="button" class="lane-delete-btn" data-lane-action="delete" ${Na(r,t,a)?"disabled":""} title="${qa(r,t,a)}" aria-label="Delete lane">\xD7</button>
|
|
326
326
|
</div>
|
|
327
327
|
`}).join("")}
|
|
328
328
|
</div>
|
|
329
|
-
`}async function
|
|
330
|
-
`).length+1):(n.type="text",n.maxLength=500),e.replaceWith(n),n.focus(),o?n.setSelectionRange(n.value.length,n.value.length):n.select();let i=!1,d=async()=>{if(i)return;i=!0;let l=n.value;if(String(l)===String(t)){await N();return}if(a==="title"&&!l.trim()){m.warning("Title cannot be empty"),await N();return}await
|
|
329
|
+
`}async function Ua(e){let a=e.closest(".lane-row"),t=a.dataset.laneId,r=e.dataset.laneAction;if(r==="delete"){await y(E(`/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 Yt(a,{silent:!0}),m.success("Default lane updated");return}let o=$e().map(d=>d.id),n=o.indexOf(t),i=r==="up"?n-1:n+1;i<0||i>=o.length||([o[n],o[i]]=[o[i],o[n]],await y(`/api/boards/${s.boardId}/states`,{method:"PATCH",body:{state_ids:o}}),await v(),s.detailMode="settings",m.success("Lanes reordered"))}async function Yt(e,{silent:a=!1}={}){let t=e.querySelector('input[name="name"]').value,o=e.querySelector('[data-lane-action="toggle-default"]')?.getAttribute("aria-pressed")==="true";await y(E(`/api/states/${e.dataset.laneId}`),{method:"PATCH",body:{name:t,is_default:o}}),await v(),s.detailMode="settings",a||m.success("Lane updated")}var P,et,tt,Kt,Xt=T(()=>{R();J();Y();G();ne();Ge();ee();Ce();vt();X();Me();P={boardId:"",step:"idle",exported:!1};et={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"}},tt={"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."}};Kt=new Set(["in_progress","review"])});async function le(e,a){await y(E(`/api/tickets/${e}`),{method:"PATCH",body:a}),await v(),s.selectedTicketId=e,s.detailMode="ticket",await N()}function at(e,a,t,r){if(!e||e.dataset.editing==="true")return;e.dataset.editing="true";let o=a==="description",n=document.createElement(o?"textarea":"input");n.className=o?"inline-desc-editor":"inline-title-editor",n.value=t,n.setAttribute("data-editing-field",a),o?n.rows=Math.max(3,String(t).split(`
|
|
330
|
+
`).length+1):(n.type="text",n.maxLength=500),e.replaceWith(n),n.focus(),o?n.setSelectionRange(n.value.length,n.value.length):n.select();let i=!1,d=async()=>{if(i)return;i=!0;let l=n.value;if(String(l)===String(t)){await N();return}if(a==="title"&&!l.trim()){m.warning("Title cannot be empty"),await N();return}await le(r,{[a]:l})},p=async()=>{i||(i=!0,await N())};n.addEventListener("blur",d),n.addEventListener("keydown",l=>{if(l.key==="Escape"){l.preventDefault(),p();return}l.key==="Enter"&&(o?(l.metaKey||l.ctrlKey)&&(l.preventDefault(),d()):(l.preventDefault(),d()))})}function za(e){let a=e.id,t=q.querySelector('[data-edit-field="title"]');t&&(t.addEventListener("click",()=>{at(t,"title",e.title||"",a)}),t.addEventListener("keydown",i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),at(t,"title",e.title||"",a))}));let r=k.querySelector('[data-edit-field="description"]');r&&(r.addEventListener("click",()=>{at(r,"description",e.description||"",a)}),r.addEventListener("keydown",i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),at(r,"description",e.description||"",a))})),k.querySelectorAll(".meta-select[data-meta-field]").forEach(i=>{i.addEventListener("change",async()=>{let d=i.dataset.metaField;if(d==="type"){await le(a,{type:i.value});return}if(d==="state_id"){await le(a,{state_id:i.value});return}if(d==="parent_ticket_id"){await le(a,{parent_ticket_id:i.value||null});return}d==="priority"&&await le(a,{priority:Number(i.value)})})});let o=async i=>{await le(a,{labels:i})};k.querySelectorAll("[data-remove-label]").forEach(i=>{i.addEventListener("click",async()=>{let d=i.getAttribute("data-remove-label"),p=(e.labels||[]).map(l=>l.name).filter(l=>l!==d);await o(p)})});let n=async()=>{let i=k.querySelector("[data-label-input]");if(!i)return;let d=i.value.trim();if(!d)return;let p=(e.labels||[]).map(l=>l.name);if(p.includes(d)){i.value="";return}p.push(d),i.value="",await o(p)};k.querySelector("[data-label-add]")?.addEventListener("click",()=>{n()}),k.querySelector("[data-label-input]")?.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),n())})}async function N(){if(s.detailMode==="settings"){await ce(),ft();return}if(!s.selectedTicketId){ze();return}let[e,a]=await Promise.all([y(E(`/api/tickets/${s.selectedTicketId}/context?depth=1`)),y(E(`/api/tickets/${s.selectedTicketId}/history`))]),t=e.ticket;Ye(t.id,t.updated_at),document.querySelector(`.card[data-ticket-id="${CSS.escape(t.id)}"] .card-unread-dot`)?.remove();let r=Ct(t.state_id),o=["epic","feature","task","bug"].map(f=>`<option value="${c(f)}" ${F(t.type)===f?"selected":""}>${c(Pt(f))}</option>`).join(""),n=r.map(f=>`<option value="${c(f.id)}" ${f.id===t.state_id?"selected":""}>${c(f.name)}</option>`).join(""),i=[0,1,2,3,4].map(f=>`<option value="${f}" ${Number(t.priority)===f?"selected":""}>${c(qe(f))}</option>`).join(""),d=(t.labels||[]).map(f=>`
|
|
331
331
|
<span class="label-pill-removable" style="--label-color: ${c(f.color)}">
|
|
332
332
|
${c(f.name)}
|
|
333
333
|
<button type="button" class="label-pill-remove" data-remove-label="${c(f.name)}" title="Remove label">\xD7</button>
|
|
334
|
-
</span>`).join(""),l=
|
|
334
|
+
</span>`).join(""),l=Tt().map(f=>f.name).filter(f=>!t.labels?.some(S=>S.name===f)).map(f=>`<option value="${c(f)}"></option>`).join(""),b=F(t.type),u=Le(t.type).toUpperCase(),g=`
|
|
335
335
|
<span class="ticket-number">${c(z(t))}</span>
|
|
336
336
|
<div class="card-type-id type-pill-${c(b)}">
|
|
337
337
|
${_e(t.type)}
|
|
338
338
|
<span class="card-type-label">${c(u)}</span>
|
|
339
339
|
</div>
|
|
340
|
-
${
|
|
341
|
-
`;
|
|
340
|
+
${Ze(t.priority)}
|
|
341
|
+
`;Je({title:t.title,titleAttrs:{class:"editable-field","data-edit-field":"title",tabindex:"0",title:"Click to edit"},subtitleHtml:g,body:`
|
|
342
342
|
<div class="detail-head">
|
|
343
|
-
<p class="detail-updated" title="Last saved change">Updated ${c(
|
|
343
|
+
<p class="detail-updated" title="Last saved change">Updated ${c(Mt(t.updated_at))}</p>
|
|
344
344
|
<p class="description editable-field ${t.description?"":"is-placeholder"}" data-edit-field="description" tabindex="0" title="Click to edit">${c(t.description||"No description yet.")}</p>
|
|
345
345
|
<dl class="ticket-meta" id="ticketMetaGrid" data-ticket-id="${c(t.id)}">
|
|
346
346
|
<div class="ticket-meta-row">
|
|
@@ -369,17 +369,17 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
369
369
|
</dl>
|
|
370
370
|
</div>
|
|
371
371
|
|
|
372
|
-
${
|
|
372
|
+
${Ya(t,e)}
|
|
373
373
|
|
|
374
|
-
${
|
|
374
|
+
${Xa(t,e)}
|
|
375
375
|
|
|
376
376
|
<div class="section">
|
|
377
377
|
<h3>Related</h3>
|
|
378
|
-
${
|
|
378
|
+
${Ka(e.relations,t)}
|
|
379
379
|
</div>
|
|
380
380
|
|
|
381
|
-
${
|
|
382
|
-
<details class="section ai-fields" data-ai-plan-toggle data-ticket-id="${c(t.id)}"${
|
|
381
|
+
${V()?.ai_enabled!==0?`
|
|
382
|
+
<details class="section ai-fields" data-ai-plan-toggle data-ticket-id="${c(t.id)}"${Ja(t.id)?" open":""}>
|
|
383
383
|
<summary><h3>AI Plan / Implementation Record</h3></summary>
|
|
384
384
|
<form id="aiFieldsForm" class="field-form">
|
|
385
385
|
<label>
|
|
@@ -400,23 +400,23 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
400
400
|
|
|
401
401
|
<div class="section">
|
|
402
402
|
<h3>Status History</h3>
|
|
403
|
-
${
|
|
403
|
+
${Ga(a)}
|
|
404
404
|
</div>
|
|
405
405
|
|
|
406
406
|
<div class="section">
|
|
407
407
|
<h3>Comments</h3>
|
|
408
|
-
${e.comments.map(
|
|
408
|
+
${e.comments.map(Wa).join("")||'<p class="description">No comments yet.</p>'}
|
|
409
409
|
<form class="comment-form" id="detailCommentForm">
|
|
410
410
|
<textarea name="body" placeholder="Add a comment, decision, or instruction..." required></textarea>
|
|
411
411
|
<button type="submit">Comment</button>
|
|
412
412
|
</form>
|
|
413
413
|
</div>
|
|
414
|
-
`}),
|
|
414
|
+
`}),za(t),h("#aiFieldsForm")?.addEventListener("submit",async f=>{f.preventDefault();let S=new FormData(f.currentTarget);await y(E(`/api/tickets/${t.id}`),{method:"PATCH",body:{ai_plan:S.get("ai_plan"),implementation_summary:S.get("implementation_summary"),implementation_updates:S.get("implementation_updates")}}),await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await N(),m.success("AI fields saved")}),h("#detailCommentForm").addEventListener("submit",async f=>{f.preventDefault();let S=new FormData(f.currentTarget).get("body").trim();S&&(await y(E(`/api/tickets/${t.id}/comments`),{method:"POST",body:{body:S}}),await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await N())}),k.querySelectorAll("[data-open-ticket]").forEach(f=>{f.addEventListener("click",async S=>{S.target.closest("[data-detach-child],[data-detach-parent],[data-detach-relation]")||C({boardId:s.boardId,view:"ticket",ticketId:f.dataset.openTicket})})}),k.querySelectorAll("[data-detach-child]").forEach(f=>{f.addEventListener("click",async S=>{S.stopPropagation();let A=f.dataset.detachChild;try{await y(E(`/api/tickets/${A}`),{method:"PATCH",body:{parent_ticket_id:null}})}catch(D){m.error(D.message||"Failed to remove child");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await N(),m.success("Removed from epic")})}),k.querySelectorAll("[data-detach-parent]").forEach(f=>{f.addEventListener("click",async S=>{S.stopPropagation();try{await y(E(`/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 N(),m.success("Parent epic removed")})}),k.querySelectorAll("[data-detach-relation]").forEach(f=>{f.addEventListener("click",async S=>{S.stopPropagation();let A=f.dataset.detachRelation;try{await y(E(`/api/relations/${A}`),{method:"DELETE"})}catch(D){m.error(D.message||"Failed to remove relation");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await N(),m.success("Relation removed")})});let O=k.querySelector("[data-ai-plan-toggle]");O&&O.addEventListener("toggle",()=>{let f=O.dataset.ticketId;O.open?localStorage.setItem(`mab_ai_plan_open:${f}`,"1"):localStorage.removeItem(`mab_ai_plan_open:${f}`)});let x=k.querySelector("#parentEpicForm");if(x){let f=x.querySelector("[name=target]"),S=x.querySelector("[data-parent-epic-clear]"),A=()=>{x.classList.toggle("has-value",f.value.length>0)};f.addEventListener("input",A),A(),S.addEventListener("click",()=>{f.value="",A(),f.focus()}),x.addEventListener("submit",async D=>{D.preventDefault();let w=String(new FormData(D.currentTarget).get("target")||"").trim();if(!w)return;let j=Zt(w,t.id);if(!j){m.warning("Pick an epic from the suggestions");return}let I=H().find(M=>M.id===j);if(!I||F(I.type)!=="epic"){m.warning("Parent must be an epic");return}try{await y(E(`/api/tickets/${t.id}`),{method:"PATCH",body:{parent_ticket_id:j}})}catch(M){m.error(M.message||"Failed to set parent epic");return}await v(),s.selectedTicketId=t.id,s.detailMode="ticket",await N(),m.success("Parent epic set")})}let B=k.querySelector("#relatedAddForm");if(B){let f=B.querySelector("[name=target]"),S=B.querySelector("[data-related-clear]"),A=()=>{B.classList.toggle("has-value",f.value.length>0)};f.addEventListener("input",A),A(),S.addEventListener("click",()=>{f.value="",A(),f.focus()}),B.addEventListener("submit",async D=>{D.preventDefault();let w=new FormData(D.currentTarget),j=String(w.get("target")||"").trim(),I=String(w.get("type")||"relates_to");if(!j)return;let M=Zt(j,t.id);if(!M){m.warning("Pick a ticket from the suggestions");return}try{await y(E("/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 N()})}ft()}function Ja(e){return localStorage.getItem(`mab_ai_plan_open:${e}`)==="1"}function Zt(e,a){let t=e.trim(),r=t.match(/^#?(\d+)\b/),o=H().filter(i=>i.id!==a);if(r){let i=Number(r[1]),d=o.find(p=>p.number===i);if(d)return d.id}let n=o.find(i=>`#${i.number} \u2014 ${i.title}`===t);return n?n.id:""}function Ga(e){return!e||e.length===0?'<p class="description">No status changes yet.</p>':e.map(a=>{let t=a.body,r=t.from?c(t.from):"?",o=c(t.to||t.state||t.next_state||"?"),n=t.actor_type||"human",i=c(a.actor),d=t.actor_id&&t.actor_id!==a.actor?c(t.actor_id):null,p=n==="agent"?`agent \xB7 ${d?`${i} (${d})`:i}`:"you";return`<div class="comment status-change">
|
|
415
415
|
<div class="comment-meta">
|
|
416
416
|
<span class="status-route">${r} \u2192 ${o}</span>
|
|
417
417
|
<span>${p} \xB7 ${xe(a.created_at)}</span>
|
|
418
418
|
</div>
|
|
419
|
-
</div>`}).join("")}function
|
|
419
|
+
</div>`}).join("")}function Wa(e){return`
|
|
420
420
|
<div class="comment ${e.kind==="checkpoint"?"checkpoint":""}">
|
|
421
421
|
<div class="comment-meta">
|
|
422
422
|
<strong>${c(e.author)}</strong>
|
|
@@ -424,7 +424,7 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
424
424
|
</div>
|
|
425
425
|
<div class="comment-body">${c(e.body)}</div>
|
|
426
426
|
</div>
|
|
427
|
-
`}function
|
|
427
|
+
`}function Ka(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 H())p.parent_ticket_id===a.id&&r.add(p.id);let n=H().filter(p=>p.id!==a?.id&&!t.has(p.id)&&!r.has(p.id)).map(p=>`<option value="#${p.number} \u2014 ${c(p.title)}"></option>`).join(""),i=e.length?`<div class="detail-card-grid">${e.map(p=>Za(p)).join("")}</div>`:"",d=`
|
|
428
428
|
<form id="relatedAddForm" class="related-add-row">
|
|
429
429
|
<div class="related-add-input-wrap">
|
|
430
430
|
<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" />
|
|
@@ -438,12 +438,12 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
438
438
|
</select>
|
|
439
439
|
<button type="submit" class="ghost meta-add-btn">Add</button>
|
|
440
440
|
</form>
|
|
441
|
-
`;return i+d}function
|
|
441
|
+
`;return i+d}function Ya(e,a){if(F(e.type)==="epic"){let r=a.child_tickets||[];return`
|
|
442
442
|
<div class="section">
|
|
443
443
|
<h3>Features inside this Epic</h3>
|
|
444
444
|
${r.length?`<div class="detail-card-grid">${r.map(n=>Pe(n,{detach:{mode:"child",id:n.id}})).join("")}</div>`:'<p class="description">No child features yet. Create a feature / task card and set this epic as its parent.</p>'}
|
|
445
445
|
</div>
|
|
446
|
-
`}return""}function
|
|
446
|
+
`}return""}function Xa(e,a){if(F(e.type)==="epic")return"";let r=H().filter(n=>n.type==="epic"&&n.id!==e.id).map(n=>`<option value="#${n.number} \u2014 ${c(n.title)}"></option>`).join("");return`
|
|
447
447
|
<div class="section">
|
|
448
448
|
<h3>Epic</h3>
|
|
449
449
|
${a.parent_ticket?`<div class="detail-card-grid detail-card-grid--single">${Pe(a.parent_ticket,{detach:{mode:"parent"}})}</div>`:`
|
|
@@ -462,7 +462,7 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
462
462
|
<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>
|
|
463
463
|
<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>
|
|
464
464
|
</div>
|
|
465
|
-
`}let d=
|
|
465
|
+
`}let d=Ke(e),p=d===0?"":d===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="${d} unread updates">${d>99?"99+":d}</span>`;return`
|
|
466
466
|
<article class="card card--detail type-${c(t)} priority-${c(r)}"${a.disableOpen?"":` data-open-ticket="${c(e.id)}"`}>
|
|
467
467
|
${p}
|
|
468
468
|
${i}
|
|
@@ -475,11 +475,11 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
475
475
|
${_e(e.type)}
|
|
476
476
|
<span class="card-type-label">${c(o)}</span>
|
|
477
477
|
</div>
|
|
478
|
-
${s.showPriority?
|
|
478
|
+
${s.showPriority?Ze(e.priority):""}
|
|
479
479
|
</div>
|
|
480
480
|
</div>
|
|
481
481
|
</article>
|
|
482
|
-
`}function
|
|
482
|
+
`}function Za(e){let a=String(e.type||"").replace(/_/g," "),t=e.direction==="incoming"?"from":"to";return Pe(e.other_ticket,{eyebrow:`${a} ${t}`,detach:{mode:"relation",id:e.id}})}var vt=T(()=>{R();J();Y();Ce();Ge();ee();G();ne();X();Xt();Ie()});function wt(){pe&&(clearTimeout(pe),pe=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",()=>{rt=1e3,ot&&(m.success("Live updates reconnected"),ot=!1)}),t.addEventListener("board",async r=>{let o;try{o=JSON.parse(r.data)}catch{return}let n=o.type,i=()=>s.data?.tickets?.find(l=>l.id===o.ticket_id),d=s.data?.actor?.name,p=o.actor&&d&&o.actor===d;if(o.ticket_id&&(p?Ye(o.ticket_id,o.timestamp):n==="ticket_deleted"?qt(o.ticket_id):Qa.has(n)&&Nt(o.ticket_id)),n==="ticket_created")m.success(`Card created: ${o.data.title||"New card"}`),te();else if(n==="state_changed"){let l=i(),b=l?`#${l.number} ${l.title}`:"Card";m.info(`${b} \u2192 ${o.data.to}`),te()}else if(n==="ticket_updated"){let l=i(),b=l?`#${l.number}`:"Card",u=o.data.fields?Object.keys(o.data.fields).join(", "):"";m.info(`${b} updated${u?`: ${u}`:""}`),te()}else if(n==="comment_created"){let l=i(),b=l?`#${l.number}`:"ticket";m.info(`New comment on ${b}`),te()}else if(n==="agent_claimed"){let l=i();m.info(`Agent claimed ${l?`#${l.number} ${l.title}`:"a ticket"}`),te()}else if(n==="checkpoint_requested"){let l=i();m.warning(`Checkpoint on ${l?`#${l.number}`:"ticket"} \u2014 needs human input`),te()}else if(n==="agent_completed"){let l=i();m.success(`Agent completed ${l?`#${l.number} ${l.title}`:"a ticket"}`),te()}else(n==="ticket_deleted"||n==="states_reordered"||n==="state_created"||n==="state_deleted"||n==="board_updated"||n==="board_imported")&&te()}),t.onerror=()=>{if(t.readyState!==EventSource.CLOSED||(ot||(m.warning("Live updates disconnected \u2014 retrying\u2026"),ot=!0),pe))return;let r=rt;rt=Math.min(rt*2,3e4),pe=setTimeout(()=>{pe=null,wt()},r)}}var Qa,rt,pe,ot,te,Qt=T(()=>{R();G();ne();X();Ie();Qa=new Set(["ticket_created","state_changed","ticket_updated","comment_created","agent_claimed","checkpoint_requested","agent_completed"]),rt=1e3,pe=null,ot=!1;te=He(async()=>{let e=s.selectedTicketId,a=s.detailMode;s.data=await y(Ue()),ke(),s.selectedTicketId=e,s.detailMode=a,await nt()},300)});var ea={};ca(ea,{load:()=>v,render:()=>nt});async function v(){K(),s.data=await y(Ue()),ke(),Ht(s.boardId,s.data?.tickets||[]),await nt(),W.sse&&s.boardId!==Vt&&(Vt=s.boardId,wt())}async function nt(){ke(),ta(),Xe(),await N()}var Vt,X=T(()=>{R();G();Ce();vt();Ae();Qt();Ie();Me();Vt=null});function $t(){return ie?.classList.contains("is-open")}function Qe(e){clearTimeout(kt),K(),ze(),ct.innerHTML=Va(e||""),er(),h("#createFlyoutClose")?.addEventListener("click",()=>_()),ie.hidden=!1,re.hidden=!1,requestAnimationFrame(()=>{ie.classList.add("is-open"),re.classList.add("is-visible")}),requestAnimationFrame(()=>{h("#createTicketTitle")?.focus()})}function _(){clearTimeout(kt),ie.classList.remove("is-open"),re.classList.remove("is-visible"),kt=setTimeout(()=>{ie.hidden=!0,re.hidden=!0,ct.innerHTML=""},220)}function Va(e){let a=Ne(),t=a.find(i=>i.is_default)||a[0],r=e&&a.some(i=>i.id===e)?e:t?.id||"",o=a.map(i=>`<option value="${c(i.id)}" ${i.id===r?"selected":""}>${c(i.name)}</option>`).join(""),n=H().filter(i=>i.type==="epic").map(i=>`<option value="${c(i.id)}">${c(z(i))}</option>`).join("");return`
|
|
483
483
|
<div class="create-flyout-head">
|
|
484
484
|
<h2>New card</h2>
|
|
485
485
|
<button type="button" class="create-flyout-close ghost" id="createFlyoutClose" aria-label="Close">\xD7</button>
|
|
@@ -522,7 +522,7 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
522
522
|
<input id="createTicketLabels" name="labels" type="text" placeholder="Labels (comma-separated)" />
|
|
523
523
|
<button type="submit">Create card</button>
|
|
524
524
|
</form>
|
|
525
|
-
`}function
|
|
525
|
+
`}function er(){let e=h("#createTicketForm");e&&e.addEventListener("submit",tr)}async function tr(e){e.preventDefault();let a=e.currentTarget,t=new FormData(a),r=String(t.get("labels")||"").split(",").map(n=>n.trim()).filter(Boolean),o=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=o.id,s.detailMode="ticket",await v(),ue()}var kt,se=T(()=>{J();R();Y();G();ee();Ge();Ae();X();kt=0});function De(){U&&(U.hidden=!0,U.innerHTML="",Z?.setAttribute("aria-expanded","false"))}function K(){De()}function ta(){if(!s.data)return;let e=(s.data.boards||[]).find(a=>a.id===s.boardId);Z&&(Z.textContent=e?.name||"Board",Z.title=e?`${e.name} \u2014 slug: ${e.slug}`:"Choose board")}function ar(){let t=(s.data.boards||[]).map(o=>`
|
|
526
526
|
<button type="button" class="menu-flyout-item ${o.id===s.boardId?"is-current":""}" data-pick-board="${c(o.id)}" role="menuitem">
|
|
527
527
|
<span class="menu-flyout-item-title">${c(o.name)}</span>
|
|
528
528
|
<span class="menu-flyout-item-meta">${c(o.slug)}</span>
|
|
@@ -545,10 +545,10 @@ enabled = true`}function Ia(e){return["claude mcp add starscape-orbit","--","nod
|
|
|
545
545
|
<div class="menu-flyout-head">Board</div>
|
|
546
546
|
<div class="menu-flyout-list">${t}</div>
|
|
547
547
|
${r}
|
|
548
|
-
`}function
|
|
548
|
+
`}function rr(){U.querySelectorAll("[data-pick-board]").forEach(a=>{a.addEventListener("click",async t=>{t.stopPropagation();let r=a.getAttribute("data-pick-board");De(),r!==s.boardId&&(_(),await C({boardId:r,view:"board"}))})});let e=U.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 o=await y("/api/system/pick-folder",{method:"POST"});o.path&&(t.value=o.path,t.dispatchEvent(new Event("input",{bubbles:!0})))}catch(o){m.error(o?.message||"Folder picker unavailable")}finally{a.disabled=!1}}),e.addEventListener("submit",async r=>{r.preventDefault();let o=new FormData(e),n=String(o.get("slug")||"").trim(),i=String(o.get("default_branch")||"").trim(),d=String(o.get("repo_url")||"").trim(),p=String(o.get("repo_path")||"").trim();if(!p){t?.reportValidity();return}let l=await y("/api/boards",{method:"POST",body:{name:o.get("name"),repo_path:p,...n?{slug:n}:{},...i?{default_branch:i}:{},...d?{repo_url:d}:{}}});De(),s.boardId=l.id,s.selectedTicketId="",s.detailMode="settings",await v(),ue(),m.success("Board created")})}}function aa(){_(),U.innerHTML=ar(),U.hidden=!1,Z?.setAttribute("aria-expanded","true"),rr()}var Ae=T(()=>{J();R();Y();G();ee();se();ne();X();Me()});function ra(e){st=e}async function C(e,{replace:a=!1}={}){let t=it.build(e);if(location.hash===t){st&&await Fe();return}a?history.replaceState(null,"",t):history.pushState(null,"",t),st&&await Fe()}function ue({replace:e=!1}={}){let a=it.build(it.fromState());location.hash!==a&&(e?history.replaceState(null,"",a):history.pushState(null,"",a))}async function Fe(){let{load:e,render:a}=await Promise.resolve().then(()=>(X(),ea)),t=it.parse(location.hash),r=s.boardId;if(t.boardId&&(s.boardId=t.boardId),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";K(),_(),t.boardId&&t.boardId!==r&&await e(),await a()}var it,st,ee=T(()=>{R();pt();Ae();se();it={parse(e){let a=String(e||"").replace(/^#/,"").replace(/^\/+/,""),t=a?a.split("/"):[],r={boardId:"",view:"board",ticketId:"",tab:""},o=0;if(t[o]==="b"&&t[o+1]&&(r.boardId=decodeURIComponent(t[o+1]),o+=2),t[o]==="t"&&t[o+1])r.view="ticket",r.ticketId=decodeURIComponent(t[o+1]);else if(t[o]==="settings"){r.view="settings";let n=t[o+1];n&&Oe.has(n)&&(r.tab=n)}return r},build({boardId:e="",view:a="board",ticketId:t="",tab:r=""}={}){let o=[];return e&&o.push("b",encodeURIComponent(e)),a==="ticket"&&t?o.push("t",encodeURIComponent(t)):a==="settings"&&(o.push("settings"),r&&Oe.has(r)&&o.push(r)),"#/"+o.join("/")},fromState(){let e="board";return s.detailMode==="ticket"&&s.selectedTicketId?e="ticket":s.detailMode==="settings"&&(e="settings"),{boardId:s.boardId,view:e,ticketId:s.selectedTicketId,tab:e==="settings"?we(s.settingsTab):""}}},st=!1;window.addEventListener("popstate",()=>{st&&Fe()})});J();{let e=localStorage.getItem("mab_theme");e&&document.documentElement.setAttribute("data-theme",e)}var la=pa();lt();{let e=()=>{document.body.classList.toggle("is-scrolled",window.scrollY>4)};window.addEventListener("scroll",e,{passive:!0}),e()}St();xt.addEventListener("click",()=>{let e=document.documentElement.getAttribute("data-theme")==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",e),localStorage.setItem("mab_theme",e),St(),la.sync()});function St(){let e=document.documentElement.getAttribute("data-theme")==="dark";Lt.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 pa(){let e=document.querySelector(".grain");if(!e)return{sync:()=>{}};ua(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"),o=Math.min(window.devicePixelRatio||1,2),n=0,i=0,d=[],p=0,l=!1,b={x:0,y:0,tx:0,ty:0};function u(){n=window.innerWidth,i=window.innerHeight,a.width=Math.round(n*o),a.height=Math.round(i*o),a.style.width=n+"px",a.style.height=i+"px",r.setTransform(o,0,0,o,0,0),g()}function g(){let w=n*i/1296e3,j=[{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=Et(12648430);d=[];for(let M of j)for(let $=0;$<M.count;$++){let me=fa(I(),M.sizes);d.push({x:I()*n,y:I()*i,size:me,depth:M.depth,glow:me>=2?M.glow:0,rgb:O(I()),period:2.2+I()*5.4,phase:I()*Math.PI*2,amp:.25+I()*.5,baseAlpha:me<1.5?.45+I()*.28:.55+I()*.22})}}function O(w){return w<.8?[255,255,255]:w<.93?[255,222,186]:[195,218,255]}function x(w){!n||!i||(b.tx=w.clientX/n-.5,b.ty=w.clientY/i-.5)}function B(w){b.x+=(b.tx-b.x)*.06,b.y+=(b.ty-b.y)*.06,r.clearRect(0,0,n,i),r.globalCompositeOperation="lighter";let j=w/1e3,I=70;for(let M=0;M<d.length;M++){let $=d[M],me=.5+.5*Math.sin(j*(2*Math.PI/$.period)+$.phase),Be=$.baseAlpha*(1-$.amp+$.amp*me),fe=$.x-b.x*$.depth*I,he=$.y-b.y*$.depth*I,[be,ye,ge]=$.rgb;if($.glow>0){let ve=$.size*$.glow,je=r.createRadialGradient(fe,he,0,fe,he,ve);je.addColorStop(0,`rgba(${be},${ye},${ge},${Be*.85})`),je.addColorStop(.35,`rgba(${be},${ye},${ge},${Be*.3})`),je.addColorStop(1,`rgba(${be},${ye},${ge},0)`),r.fillStyle=je,r.beginPath(),r.arc(fe,he,ve,0,Math.PI*2),r.fill(),r.fillStyle=`rgba(${be},${ye},${ge},${Be})`,r.beginPath(),r.arc(fe,he,$.size/2,0,Math.PI*2),r.fill()}else{let ve=$.size/2;r.fillStyle=`rgba(${be},${ye},${ge},${Be})`,r.fillRect(fe-ve,he-ve,$.size,$.size)}}r.globalCompositeOperation="source-over",l&&(p=requestAnimationFrame(B))}function f(){r.clearRect(0,0,n,i),r.globalCompositeOperation="lighter";for(let w of d){let[j,I,M]=w.rgb;if(r.fillStyle=`rgba(${j},${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 S(){l||(l=!0,p=requestAnimationFrame(B))}function A(){l=!1,cancelAnimationFrame(p)}function D(){let w=document.documentElement.getAttribute("data-theme")==="dark",j=window.matchMedia("(prefers-reduced-motion: reduce)").matches;if(!w){A(),r.clearRect(0,0,n,i);return}d.length||u(),j||document.hidden?(A(),f()):S()}return window.addEventListener("resize",()=>{u(),D()},{passive:!0}),window.addEventListener("pointermove",x,{passive:!0}),document.addEventListener("visibilitychange",D),window.matchMedia("(prefers-reduced-motion: reduce)").addEventListener("change",D),u(),D(),{sync:D}}function ua(e){e.querySelectorAll(".signature-star").forEach(r=>r.remove());let a=Et(6070757),t=7;for(let r=0;r<t;r++){let o=document.createElement("div");o.className="signature-star",o.setAttribute("aria-hidden","true"),o.style.left=(6+a()*88).toFixed(2)+"%",o.style.top=(8+a()*78).toFixed(2)+"%",o.style.animationDelay=(-a()*4.8).toFixed(2)+"s",e.appendChild(o)}}function lt(){let e=14e3+Math.random()*28e3;setTimeout(ma,e)}function ma(){let e=document.documentElement.getAttribute("data-theme")==="dark",a=window.matchMedia("(prefers-reduced-motion: reduce)").matches,t=document.querySelector(".grain");if(!e||a||document.hidden||!t){lt();return}let r=window.innerWidth,o=window.innerHeight,n=Math.random()*r*.6,i=Math.random()*o*.55,d=380+Math.random()*520,p=18+Math.random()*26,l=p*Math.PI/180,b=n+Math.cos(l)*d,u=i+Math.sin(l)*d,g=document.createElement("div");g.className="meteor",g.setAttribute("aria-hidden","true"),g.style.setProperty("--from-x",n+"px"),g.style.setProperty("--from-y",i+"px"),g.style.setProperty("--to-x",b+"px"),g.style.setProperty("--to-y",u+"px"),g.style.setProperty("--angle",p+"deg"),t.appendChild(g),g.addEventListener("animationend",()=>g.remove(),{once:!0}),lt()}function fa(e,a){let t=0;for(let[r,o]of a)if(t+=o,e<t)return r;return a[a.length-1][0]}function Et(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();R();G();ne();ee();Ae();se();Ce();J();R();G();ee();Y();se();async function oa(){let e=Re.value.trim();if(e.length<2){dt();return}let a=V();if(!a)return;let t=await y(`/api/search?q=${encodeURIComponent(e)}&board=${encodeURIComponent(a.slug)}`);if(t.results.length===0){Q.hidden=!1,Q.innerHTML='<div class="search-hit">No results</div>';return}Q.hidden=!1,Q.innerHTML=t.results.map(r=>`
|
|
549
549
|
<div class="search-hit" data-ticket-id="${r.id}">
|
|
550
550
|
<strong>${c(z(r))}</strong>
|
|
551
551
|
${c(r.title)}
|
|
552
552
|
</div>
|
|
553
|
-
`).join(""),
|
|
553
|
+
`).join(""),Q.querySelectorAll("[data-ticket-id]").forEach(r=>{r.addEventListener("click",async()=>{_(),dt(),C({boardId:s.boardId,view:"ticket",ticketId:r.dataset.ticketId})})})}function dt(){Q.hidden=!0,Q.innerHTML=""}X();Me();function ia(e){e?.showModal()}function na(e){e?.open&&e.close()}function sa(e){e&&(e.addEventListener("click",a=>{a.target===e&&na(e)}),e.querySelectorAll("[data-modal-close]").forEach(a=>{a.addEventListener("click",()=>na(e))}))}async function or(){let e=document.getElementById("welcomeDialog");sa(e),de==="preview"&&ia(e),h("#settingsBtn").addEventListener("click",async()=>{_(),K(),C({boardId:s.boardId,view:"settings",tab:s.settingsTab||"lanes"})}),Z?.addEventListener("click",t=>{if(t.stopPropagation(),!U.hidden){De();return}aa()}),h("#newTicketBtn").addEventListener("click",()=>{if($t()){_();return}Qe("")}),re.addEventListener("click",()=>{_()}),h("#drawerCloseBtn").addEventListener("click",()=>{C({boardId:s.boardId,view:"board"})}),h("#drawerArchiveBtn").addEventListener("click",async()=>{let t=s.selectedTicketId;if(!t||s.detailMode!=="ticket")return;let o=s.data?.tickets?.find(n=>n.id===t)?.title||"card";await y(E(`/api/tickets/${encodeURIComponent(t)}/archive`),{method:"POST"}),m.error(`Archived: ${o}`),await v(),C({boardId:s.boardId,view:"board"})}),ae.addEventListener("click",()=>{C({boardId:s.boardId,view:"board"})}),document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;if(!U.hidden){K();return}if($t()){_();return}if(!q.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"})}),Re.addEventListener("input",He(oa,220)),document.addEventListener("click",t=>{t.target.closest("#topbarSearch")||dt(),t.target.closest(".topbar-menu")||K()}),Ut(),await v(),ra(!0);let a=location.hash;a&&a!=="#"&&a!=="#/"?await Fe():ue({replace:!0})}or();
|
|
554
554
|
//# sourceMappingURL=app.js.map
|