kanbo-cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- (function(){var e=class extends Error{status;code;constructor(e,t,n){super(n),this.status=e,this.code=t}};function t(t){async function r(r,i,a){let o={},s=t();s&&(o.authorization=`Bearer ${s}`),r!==`GET`&&(o[`content-type`]=`application/json`);let c=await fetch(i,{method:r,headers:o,body:a===void 0?void 0:JSON.stringify(a)}),l=await c.text();if(!c.ok){let t=n(l);throw new e(c.status,t?.code??`unknown`,t?.message??`${c.status} ${c.statusText}`)}return JSON.parse(l)}let i=e=>`/issues/${encodeURIComponent(e)}`;return{version:async()=>(await r(`GET`,`/issues/version`)).seq,statuses:async()=>await r(`GET`,`/issues/statuses`),cards:async()=>await r(`GET`,`/issues`),createCard:async e=>await r(`POST`,`/issues`,e),moveCard:async(e,t)=>await r(`PATCH`,`${i(e)}/status/${encodeURIComponent(t)}`),comments:async e=>await r(`GET`,`${i(e)}/comments`),addComment:async(e,t)=>await r(`POST`,`${i(e)}/comments`,{content:t}),activity:async e=>await r(`GET`,`${i(e)}/activity`),runs:async e=>await r(`GET`,`${i(e)}/runs`),approve:async(e,t)=>await r(`POST`,`${i(e)}/approve`,{comment:t}),returnCard:async(e,t)=>await r(`POST`,`${i(e)}/return`,{comment:t})}}function n(e){try{return JSON.parse(e)}catch{return null}}function r(e){return e.title===e.id?i(e.description)??e.title:e.title}function i(e){for(let t of(e??``).split(`
2
- `)){let e=a(t);if(e)return e.length>120?`${e.slice(0,119).trimEnd()}…`:e}return null}function a(e){return e.replace(/^\s*(?:>\s*)+/,``).replace(/^\s*#{1,6}\s+/,``).replace(/^\s*(?:[-*+]|\d+[.)])\s+(?:\[[ x]\]\s+)?/i,``).replace(/!\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/<[^>]+>/g,``).replace(/[*_~`]/g,``).replace(/\s+/g,` `).trim()}function o(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n!==void 0&&(r.textContent=n),r}function s(e,t,n){let r=o(`button`,t,e);return r.type=`button`,r.addEventListener(`click`,n),r}function c(e,t,n){let i=o(`article`,`card`);i.draggable=!0,i.dataset.cardId=e.id;let a=o(`div`,`card-head`);if(a.append(o(`span`,`card-key`,e.id)),e.activeRun?.state===`running`){let t=o(`span`,`run-dot`);t.title=`Running: ${e.activeRun.agentName}`,t.setAttribute(`role`,`img`),t.setAttribute(`aria-label`,t.title),a.append(t)}i.append(a);let s=o(`button`,`card-title`,r(e));s.type=`button`,s.addEventListener(`click`,()=>n(e)),i.append(s);let c=e.statusLine?.trim()??``,l=e.waitingFor===`human`,u=e.attemptCount>1;if(c||l||u){let n=o(`div`,`card-status`);if(c){let e=o(`p`,`status-line`,c);e.title=c,e.dataset.category=t??`unstarted`,n.append(e)}if(l&&n.append(o(`span`,`waiting-badge`,`Waiting for you`)),u){let t=o(`span`,`attempt-chip`,`×${e.attemptCount}`);t.title=`Attempt ${e.attemptCount}`,n.append(t)}i.append(n)}return i}function l(e,t){let n=new Set(t.map(e=>e.statusId)),r=e.filter(e=>e.category!==`canceled`||n.has(e.id)).map(e=>({id:e.id,name:e.name,status:e,cards:[]})),i=new Map(r.map(e=>[e.id,e])),a=new Set(e.map(e=>e.id));for(let e of t){let t=e.statusId??``,n=i.get(t);!n&&!a.has(t)&&(n={id:t,name:e.statusId??`No status`,status:null,cards:[]},i.set(t,n),r.push(n)),n?.cards.push(e)}return r}function u(e,t,n){let{card:i,status:a}=e,c=o(`aside`,`panel`);c.setAttribute(`aria-label`,`Card ${i.id}`);let l=o(`div`,`panel-head`);l.append(o(`span`,`card-key`,i.id),s(`Close`,`ghost`,t.close)),c.append(l),c.append(o(`h2`,`panel-title`,r(i)));let u=o(`p`,`panel-facts`,a?a.name:`No column`);if(i.waitingFor===`human`&&u.append(` `,o(`span`,`waiting-badge`,`Waiting for you`)),c.append(u),i.statusLine?.trim()){let e=o(`p`,`status-line`,i.statusLine.trim());e.dataset.category=a?.category??`unstarted`,c.append(e)}let _=o(`p`,`panel-notice`,n??``);return _.setAttribute(`role`,`alert`),_.hidden=!n,c.append(_),c.append(d(`Description`,i.description?.trim()?o(`div`,`description`,i.description):o(`p`,`empty`,`No description.`))),c.append(f(i,t)),c.append(d(`Comments`,...p(e.comments),m(t))),c.append(d(`Activity`,h(e.activity,e=>[g(e),e.createdAt],`No activity.`))),c.append(d(`Runs`,h(e.runs,e=>[v(e),e.startedAt],`No runs.`))),c}function d(e,...t){let n=o(`section`,`panel-section`);return n.append(o(`h3`,void 0,e),...t),n}function f(e,t){let n=o(`textarea`,`field`);n.rows=2,n.placeholder=e.waitingFor===`human`?`A note for the agent (needed to return)`:`Why it goes back (needed to return)`,n.setAttribute(`aria-label`,`Decision note`);let r=o(`p`,`hint`),i=o(`div`,`row`);return e.waitingFor===`human`&&i.append(s(`Approve`,`primary`,()=>t.approve(n.value.trim()||null))),i.append(s(`Return`,`secondary`,()=>{let e=n.value.trim();if(!e){r.textContent=`Say why in the note to return the card.`,n.focus();return}t.returnCard(e)})),d(`Decision`,n,i,r)}function p(e){if(e.length===0)return[o(`p`,`empty`,`No comments.`)];let t=o(`ul`,`entries`);for(let n of e){let e=o(`li`),r=o(`div`,`entry-meta`);r.append(o(`span`,`entry-author`,n.author.displayName),o(`span`,void 0,y(n.createdAt))),e.append(r,o(`div`,`entry-text`,n.content)),t.append(e)}return[t]}function m(e){let t=o(`div`,`comment-form`),n=o(`textarea`,`field`);return n.rows=2,n.placeholder=`Add a comment`,n.setAttribute(`aria-label`,`New comment`),t.append(n,s(`Comment`,`secondary`,()=>{let t=n.value.trim();t&&e.addComment(t)})),t}function h(e,t,n){if(e.length===0)return o(`p`,`empty`,n);let r=o(`ul`,`entries`);for(let n of e){let[e,i]=t(n),a=o(`li`);a.append(o(`div`,`entry-text`,e),o(`div`,`entry-meta`,y(i))),r.append(a)}return r}function g(e){let t=e.actor.displayName;if(e.kind===`created`)return`${t} created the card`;if(e.kind===`comment`)return`${t}: ${e.comment?.content??``}`;let n=e.fieldChange;if(!n)return`${t} changed the card`;switch(n.action){case`added-description`:return`${t} added the description`;case`updated-description`:return`${t} updated the description`;case`cleared-description`:return`${t} cleared the description`;case`renamed-issue`:return`${t} renamed the card to ${_(n.toValue)}`;case`changed-field`:{let e=n.fromValue?` from ${_(n.fromValue)}`:``;return`${t} changed ${n.field??`a field`}${e} to ${_(n.toValue)}`}}}function _(e){return e?e.kind===`text`?e.text:e.kind===`date`?(/* @__PURE__ */ new Date(e.timestamp*1e3)).toLocaleDateString():e.token===`current-user`?`you`:e.token.replaceAll(`-`,` `):`nothing`}function v(e){return[`Attempt ${e.attempt}`,e.agentName,e.state,e.branch].filter(Boolean).join(` · `)}function y(e){return(/* @__PURE__ */ new Date(e*1e3)).toLocaleString()}let b=`kanbo-serve-token`;function x(){try{return sessionStorage.getItem(b)}catch{return null}}function S(e){try{e?sessionStorage.setItem(b,e):sessionStorage.removeItem(b)}catch{}}function C(){let e=new URLSearchParams(location.hash.slice(1)).get(`token`)?.trim();e&&(S(e),history.replaceState(history.state,``,`${location.pathname}${location.search}`))}C();let w=x(),T=t(()=>w),E=[],D=[],O=null,k=!1,A=!1,j=null,M=null,N=null,P=null,F=null,I=document.querySelector(`#app`)??document.body,L=o(`input`,`field token-input`),R=o(`p`,`notice`),z=o(`main`,`board`),B=o(`div`,`panel-host`);function V(){let e=o(`header`,`topbar`),t=o(`h1`,`topbar-title`,`Kanbo`),n=o(`span`,`workspace`);n.id=`workspace`;let r=o(`form`,`token-form`);L.type=`password`,L.autocomplete=`off`,L.placeholder=`Server token`,L.value=w??``;let i=o(`label`,`token-label`,`Token`);i.append(L);let a=o(`button`,`secondary`,`Save`);a.type=`submit`,r.append(i,a),r.addEventListener(`submit`,e=>{e.preventDefault(),w=L.value.trim()||null,S(w),k=!1,U(null),q()}),e.append(t,n,r),R.setAttribute(`role`,`status`),R.hidden=!0,I.replaceChildren(e,R,z,B)}let H=!1;function U(e,t=`info`){R.textContent=e??``,R.hidden=!e,R.dataset.kind=t,H=!1}function W(t){return t instanceof e?t.status===401?(k=!0,L.focus(),`This server needs its token. Enter it in the Token field above.`):t.message:t instanceof Error?t.message:String(t)}function G(e){U(W(e),`error`),H=!0}function K(){H&&(H=!1,U(null))}async function q(){if(!A){A=!0;try{let e=await T.version(),[t,n]=await Promise.all([T.statuses(),T.cards()]);O=e,E=t,D=n,Y(),K(),M&&await Z()}catch(e){G(e)}finally{A=!1}}}async function J(){if(!(document.visibilityState!==`visible`||k||A))try{await T.version()===O?K():await q()}catch(e){G(e)}}function Y(){let e=document.querySelector(`#workspace`);e&&(e.textContent=E[0]?.workspaceId??``);let t=j!==null&&document.activeElement===j.input,n=document.activeElement?.closest(`.card`)?.dataset.cardId??null;z.replaceChildren(...l(E,D).map(ee)),t?j?.input.focus():n&&X(n)}function X(e){for(let t of z.querySelectorAll(`.card`))t.dataset.cardId===e&&t.querySelector(`.card-title`)?.focus()}function ee(e){let t=o(`section`,`column`);t.setAttribute(`aria-label`,e.name);let n=o(`header`,`column-head`);n.append(o(`span`,`column-name`,e.name),o(`span`,`column-count`,String(e.cards.length)));let r=e.status;if(r){let t=s(`+ New`,`ghost column-add`,()=>ne(r));t.setAttribute(`aria-label`,`New card in ${e.name}`),n.append(t)}let i=o(`div`,`column-cards`);j&&j.statusId===e.id&&i.append(j.form);for(let t of e.cards){let e=c(t,r?.category??null,e=>void re(e.id));e.addEventListener(`dragstart`,n=>{F=t.id,n.dataTransfer?.setData(`text/plain`,t.id),e.classList.add(`dragging`)}),e.addEventListener(`dragend`,()=>{F=null,e.classList.remove(`dragging`)}),i.append(e)}return t.append(n,i),r&&(t.addEventListener(`dragover`,e=>{F&&(e.preventDefault(),t.classList.add(`drop-target`))}),t.addEventListener(`dragleave`,e=>{t.contains(e.relatedTarget)||t.classList.remove(`drop-target`)}),t.addEventListener(`drop`,e=>{e.preventDefault(),t.classList.remove(`drop-target`);let n=F;F=null,n&&te(n,r)})),t}async function te(e,t){if(D.find(t=>t.id===e)?.statusId!==t.id){try{let n=await T.moveCard(e,t.id),r=n.unmetRules??[];U(r.length>0?`${n.id} is in ${t.name}, but still misses: ${r.map(e=>e.detail).join(`; `)}`:null)}catch(e){U(W(e),`error`)}await q()}}function ne(e){let t=o(`div`,`draft`),n=o(`textarea`,`field`);n.rows=3,n.placeholder=`Describe the card`,n.setAttribute(`aria-label`,`New card in ${e.name}`);let r=async()=>{let t=n.value.trim();if(!t){n.focus();return}try{let n=await T.createCard({workspaceId:e.workspaceId,statusId:e.id,description:t});j=null,U(n.unmetRules?.length?`${n.id} is in ${e.name}, but still misses: ${n.unmetRules.map(e=>e.detail).join(`; `)}`:null)}catch(e){U(W(e),`error`)}await q()},i=()=>{j=null,Y()};n.addEventListener(`keydown`,e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)?(e.preventDefault(),r()):e.key===`Escape`&&(e.stopPropagation(),i())});let a=o(`div`,`row`);a.append(s(`Create`,`primary`,()=>void r()),s(`Cancel`,`ghost`,i)),t.append(n,a),j={statusId:e.id,form:t,input:n},Y(),n.focus()}async function re(e){M=e,P=null,await Z()}async function Z(){let e=M,t=D.find(t=>t.id===e);if(!e||!t){$();return}if(!(N?.card.id===e&&ie(B))){try{let[n,r,i]=await Promise.all([T.comments(e),T.activity(e),T.runs(e)]);N={card:t,status:E.find(e=>e.id===t.statusId)??null,comments:n,activity:r,runs:i}}catch(e){P=W(e)}ae()}}function ie(e){return[...e.querySelectorAll(`textarea`)].some(e=>e.value.trim()!==``||document.activeElement===e)}function ae(){if(!N||N.card.id!==M){B.replaceChildren();return}let e=N.card.id,t=u(N,{close:$,addComment:t=>void Q(async()=>{await T.addComment(e,t)}),approve:t=>void Q(async()=>{await T.approve(e,t)}),returnCard:t=>void Q(async()=>{await T.returnCard(e,t)})},P),n=!B.firstChild;B.replaceChildren(t),n&&t.querySelector(`button`)?.focus()}async function Q(t){try{await t(),P=null;for(let e of B.querySelectorAll(`textarea`))e.value=``}catch(t){let n=W(t);P=t instanceof e&&t.status===403?`${n} Needs the server token: only a request holding the token this server was started with acts for a person.`:n;let r=B.querySelector(`.panel-notice`);r&&(r.textContent=P,r.hidden=!1);return}await q()}function $(){let e=M;M=null,N=null,P=null,B.replaceChildren(),e&&X(e)}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&M&&$()}),document.addEventListener(`visibilitychange`,()=>void J()),V(),q(),setInterval(()=>void J(),2e3)})();
1
+ (function(){var e=class extends Error{status;code;constructor(e,t,n){super(n),this.status=e,this.code=t}};function t(t,r=()=>``){async function i(r,i,a){let o={},s=t();s&&(o.authorization=`Bearer ${s}`),r!==`GET`&&(o[`content-type`]=`application/json`);let c;try{c=await fetch(i,{method:r,headers:o,body:a===void 0?void 0:JSON.stringify(a)})}catch{throw new e(0,`server_unreachable`,`The board server has stopped. Run kanbo serve to open it again.`)}let l=await c.text();if(!c.ok){let t=n(l);throw new e(c.status,t?.code??`unknown`,t?.message??`${c.status} ${c.statusText}`)}return JSON.parse(l)}let a=e=>`${r()}${e}`,o=e=>a(`/issues/${encodeURIComponent(e)}`);return{projects:async()=>await i(`GET`,`/projects`),workspace:async()=>await i(`GET`,a(`/issues/workspace`)),version:async()=>(await i(`GET`,a(`/issues/version`))).seq,statuses:async()=>await i(`GET`,a(`/issues/statuses`)),cards:async()=>await i(`GET`,a(`/issues`)),createCard:async e=>await i(`POST`,a(`/issues`),e),moveCard:async(e,t)=>await i(`PATCH`,`${o(e)}/status/${encodeURIComponent(t)}`),comments:async e=>await i(`GET`,`${o(e)}/comments`),addComment:async(e,t)=>await i(`POST`,`${o(e)}/comments`,{content:t}),activity:async e=>await i(`GET`,`${o(e)}/activity`),runs:async e=>await i(`GET`,`${o(e)}/runs`),fieldChanges:async e=>await i(`GET`,`${o(e)}/field-changes`),approve:async(e,t)=>await i(`POST`,`${o(e)}/approve`,{comment:t}),returnCard:async(e,t)=>await i(`POST`,`${o(e)}/return`,{comment:t})}}function n(e){try{return JSON.parse(e)}catch{return null}}function r(e){return e.title===e.id?i(e.description)??e.title:e.title}function i(e){for(let t of(e??``).split(`
2
+ `)){let e=a(t);if(e)return e.length>120?`${e.slice(0,119).trimEnd()}…`:e}return null}function a(e){return e.replace(/^\s*(?:>\s*)+/,``).replace(/^\s*#{1,6}\s+/,``).replace(/^\s*(?:[-*+]|\d+[.)])\s+(?:\[[ x]\]\s+)?/i,``).replace(/!\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/<[^>]+>/g,``).replace(/[*_~`]/g,``).replace(/\s+/g,` `).trim()}function o(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n!==void 0&&(r.textContent=n),r}function s(e,t,n){let r=o(`button`,t,e);return r.type=`button`,r.addEventListener(`click`,n),r}let c={text:``,worker:null,waiting:!1,running:!1,priorities:[],labels:[]},l=[`urgent`,`high`,`medium`,`low`,`none`];function u(e){return e.activeRun?.state===`running`&&e.activeRun.agentName?{key:`agent:${e.activeRun.agentName}`,label:e.activeRun.agentName}:e.delegateAgentId?{key:`agent:${e.delegateAgentId}`,label:e.delegateAgentId}:e.assigneeKind===`user`?{key:`user`,label:`You`}:e.assigneeKind===`agent`&&e.assigneeId?{key:`agent:${e.assigneeId}`,label:e.assigneeId}:null}function d(e,t){let n=t.text.trim().toLowerCase();if(n&&![e.id,e.title,e.description,e.statusLine,...e.labels].some(e=>e?.toLowerCase().includes(n)))return!1;if(t.worker!==null){let n=u(e);if(t.worker===`nobody`?n!==null:n?.key!==t.worker)return!1}return!(t.waiting&&e.waitingFor!==`human`||t.running&&e.activeRun?.state!==`running`||t.priorities.length>0&&!t.priorities.includes(e.priority)||t.labels.length>0&&!e.labels.some(e=>t.labels.includes(e)))}function f(e){let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Set;for(let r of e){let e=u(r);e&&t.set(e.key,e.label);for(let e of r.labels)n.add(e)}return{workers:[...t].map(([e,t])=>({key:e,label:t})).sort((e,t)=>e.label.localeCompare(t.label)),labels:[...n].sort((e,t)=>e.localeCompare(t))}}function p(e){return e.text.trim()!==``||e.worker!==null||e.waiting||e.running||e.priorities.length>0||e.labels.length>0}function m(e){return e?e.split(`,`).filter(e=>e!==``):[]}function h(e){let t=new URLSearchParams(e);return{text:t.get(`q`)??``,worker:t.get(`who`)||null,waiting:t.get(`waiting`)===`1`,running:t.get(`running`)===`1`,priorities:m(t.get(`priority`)).filter(e=>l.includes(e)),labels:m(t.get(`label`))}}function g(e,t){let n=new URLSearchParams(t),r=(e,t)=>{t?n.set(e,t):n.delete(e)};r(`q`,e.text.trim()===``?null:e.text),r(`who`,e.worker),r(`waiting`,e.waiting?`1`:null),r(`running`,e.running?`1`:null),r(`priority`,e.priorities.join(`,`)||null),r(`label`,e.labels.join(`,`)||null);let i=n.toString();return i?`?${i}`:``}function _(e,t){return e.waitingFor===`human`?`waiting`:e.activeRun?.state===`running`?`running`:t===`completed`?`done`:t===`canceled`?`quiet`:`idle`}function v(e){let t=`${e.done} of ${e.total} sub-cards done`;return{chip:e.done===e.total?`All ${e.total} sub-cards done`:`${e.done}/${e.total} sub-cards`,words:t}}function ee(e,t,n,i){let a=o(`article`,`card`);a.draggable=!0,a.dataset.cardId=e.id,a.dataset.state=_(e,t);let s=e.waitingFor===`human`,c=e.activeRun?.state===`running`?e.activeRun:null,l=e.attemptCount>1;if(s||c||l){let t=o(`div`,`card-state`);if(s&&t.append(o(`span`,`waiting-badge`,`Waiting for you`)),c){let e=o(`span`,`run-state`),n=o(`span`,`run-dot`);n.setAttribute(`aria-hidden`,`true`),e.append(n,c.agentName?`Running · ${c.agentName}`:`Running`),t.append(e)}if(l){let n=o(`span`,`attempt-chip`,`×${e.attemptCount}`);n.title=`Attempt ${e.attemptCount}`,t.append(n)}a.append(t)}if(i&&e.parentIssueId){let t=i.parent,n=o(t?`button`:`span`,`parent-link`);if(n.append(o(`span`,`parent-arrow`,`↳ `),o(`span`,`card-key`,e.parentIssueId)),t){let e=n;e.type=`button`,n.append(o(`span`,`parent-title`,r(t))),n.title=`Parent: ${r(t)}`,n.addEventListener(`click`,e=>{e.stopPropagation(),i.onOpenCard(t.id)})}a.append(n)}let d=o(`button`,`card-title`,r(e));d.type=`button`,d.addEventListener(`click`,()=>n(e)),a.append(d);let f=o(`div`,`card-meta`);f.append(o(`span`,`card-key`,e.id));let p=u(e);if(p&&!c?.agentName){let e=o(`span`,`worker`,p.label);e.dataset.kind=p.key===`user`?`user`:`agent`,f.append(e)}if(i?.summary){let{chip:e,words:t}=v(i.summary),n=o(`span`,`subcard-chip`,e);n.title=t,f.append(n)}a.append(f);let m=e.statusLine?.trim()??``;if(m){let e=o(`p`,`status-line`,m);e.title=m,e.dataset.category=t??`unstarted`,a.append(e)}if(e.priority!==`none`||e.labels.length>0){let t=o(`div`,`card-tags`);if(e.priority!==`none`){let n=o(`span`,`priority`,e.priority);n.dataset.priority=e.priority,t.append(n)}t.append(...e.labels.map(e=>o(`span`,`label`,e))),a.append(t)}return a}function te(e){return new Map(e.map(e=>[e.id,{statusId:e.statusId,waiting:e.waitingFor===`human`}]))}function ne(e,t){if(e===null)return null;let n=e.get(t.id);return n?n.statusId===t.statusId?null:`moved`:`new`}function re(e,t){return e!==null&&t.waitingFor===`human`&&e.get(t.id)?.waiting!==!0}let ie={urgent:`Urgent`,high:`High`,medium:`Medium`,low:`Low`,none:`None`};function y(e,t,n,r){let i=s(e,`${t}${n?` active`:``}`,r);return i.setAttribute(`aria-pressed`,String(n)),i}function b(e,t){return e.filter(e=>e!==t)}function ae(e,t,n,r){let i=o(`div`,`filter-bar`);i.setAttribute(`role`,`search`);let a=o(`input`,`field filter-search`);a.type=`search`,a.placeholder=`Search cards`,a.setAttribute(`aria-label`,`Search cards`),a.value=e.text,a.addEventListener(`input`,()=>r({...e,text:a.value})),a.addEventListener(`keydown`,t=>{t.key===`Escape`&&a.value!==``&&(t.stopPropagation(),a.value=``,r({...e,text:``}))});let u=o(`select`,`field filter-worker`);u.setAttribute(`aria-label`,`Worked by`);let d=[{key:``,label:`Anyone`},{key:`nobody`,label:`Nobody`},...t.workers];e.worker!==null&&!d.some(t=>t.key===e.worker)&&d.push({key:e.worker,label:e.worker});for(let e of d){let t=o(`option`,void 0,e.key===``?`Worked by: Anyone`:e.label);t.value=e.key,u.append(t)}u.value=e.worker??``,u.addEventListener(`change`,()=>r({...e,worker:u.value===``?null:u.value}));let f=o(`span`,`filter-group`);f.setAttribute(`role`,`group`),f.setAttribute(`aria-label`,`Priority`);for(let t of l){let n=e.priorities.includes(t);f.append(y(ie[t],`filter-chip`,n,()=>r({...e,priorities:n?b(e.priorities,t):[...e.priorities,t]})))}let m=o(`span`,`select-wrap`);m.append(u);let h=y(`Waiting for you`,`filter-toggle`,e.waiting,()=>r({...e,waiting:!e.waiting}));h.dataset.filter=`waiting`;let g=y(`Running now`,`filter-toggle`,e.running,()=>r({...e,running:!e.running}));g.dataset.filter=`running`,i.append(a,m,h,g,f);let _=[.../* @__PURE__ */ new Set([...t.labels,...e.labels])];if(_.length>0&&_.length<=8){let t=o(`span`,`filter-group`);t.setAttribute(`role`,`group`),t.setAttribute(`aria-label`,`Labels`);for(let n of _){let i=e.labels.includes(n);t.append(y(n,`filter-chip`,i,()=>r({...e,labels:i?b(e.labels,n):[...e.labels,n]})))}i.append(t)}else if(_.length>8){let t=o(`select`,`field filter-labels`);t.multiple=!0,t.setAttribute(`aria-label`,`Labels`);for(let n of _){let r=o(`option`,void 0,n);r.value=n,r.selected=e.labels.includes(n),t.append(r)}t.addEventListener(`change`,()=>r({...e,labels:[...t.selectedOptions].map(e=>e.value)})),i.append(t)}return p(e)&&i.append(o(`span`,`filter-count`,oe(n)),s(`Clear`,`ghost filter-clear`,()=>r(c))),i}function oe(e){return`Showing ${e.shown} of ${e.total}`}function se(e,t){let n=e.querySelector(`.filter-count`);n&&(n.textContent=oe(t))}function ce(e,t){let n=new Set(t.map(e=>e.statusId)),r=e.filter(e=>e.category!==`canceled`||n.has(e.id)).map(e=>({id:e.id,name:e.name,status:e,cards:[]})),i=new Map(r.map(e=>[e.id,e])),a=new Set(e.map(e=>e.id));for(let e of t){let t=e.statusId??``,n=i.get(t);!n&&!a.has(t)&&(n={id:t,name:e.statusId??`No status`,status:null,cards:[]},i.set(t,n),r.push(n)),n?.cards.push(e)}return r}function le(e){switch(e){case`assignee`:return`Assignee`;case`description`:return`Description`;case`due-date`:return`Due date`;case`labels`:return`Labels`;case`metadata`:return`Metadata`;case`milestone`:return`Milestone`;case`parent`:return`Parent card`;case`priority`:return`Priority`;case`status`:return`Column`;case`status-line`:return`Status line`;case`title`:return`Title`;case`workspace`:return`Workspace`}}function ue(e,t){let n=new Map(t.map(e=>[e.id,e])),r=[];for(let t of e){if(t.kind===`comment`)continue;let e={kind:t.actor.kind,name:t.actor.displayName,label:t.actor.label},i={id:t.id,actor:e,field:null,from:null,to:null,text:null,at:t.createdAt},a=t.fieldChange;if(t.kind===`created`)r.push({...i,verb:`created the card`});else if(!a)r.push({...i,verb:`changed the card`});else if(a.action===`added-description`||a.action===`updated-description`||a.action===`cleared-description`){let e=n.get(t.id),o=a.action===`added-description`?`added the description`:a.action===`cleared-description`?`cleared the description`:`updated the description`;r.push({...i,verb:o,text:e?{before:e.fromValue,after:e.toValue}:null})}else if(a.field===`metadata`||a.field===null)r.push({...i,verb:`changed metadata`});else{let e=a.field===`status`?`moved it`:a.action===`renamed-issue`?`renamed it`:`changed`;r.push({...i,verb:e,field:le(a.field),from:de(a.fromValue),to:de(a.toValue)})}}return[...r].sort((e,t)=>t.at-e.at)}function de(e){if(!e)return`nothing`;if(e.kind===`text`)return e.text;if(e.kind===`date`)return(/* @__PURE__ */ new Date(e.timestamp*1e3)).toLocaleDateString();if(e.token.startsWith(`priority-`)){let t=e.token.slice(9);return`${t.charAt(0).toUpperCase()}${t.slice(1)}`}return e.token===`current-user`?`you`:e.token.replaceAll(`-`,` `)}function x(e,t){return e.getFullYear()===t.getFullYear()&&e.getMonth()===t.getMonth()&&e.getDate()===t.getDate()}function fe(e,t){return e.toLocaleDateString(void 0,{day:`numeric`,month:`short`,year:e.getFullYear()===t.getFullYear()?void 0:`numeric`})}function pe(e,t){return x(e,t)?`Today`:x(e,new Date(t.getFullYear(),t.getMonth(),t.getDate()-1))?`Yesterday`:fe(e,t)}function me(e,t){let n=[];for(let r of e){let e=pe(/* @__PURE__ */ new Date(r.at*1e3),t),i=n.at(-1);i&&i.day===e?i.entries.push(r):n.push({day:e,entries:[r]})}return n}function he(e,t){let n=/* @__PURE__ */ new Date(e*1e3);if(!x(n,t))return _e(n);let r=Math.floor(t.getTime()/1e3)-e;return r<60?`just now`:r<3600?`${Math.floor(r/60)} min ago`:`${Math.floor(r/3600)} h ago`}function ge(e,t,{withClock:n=!1}={}){let r=/* @__PURE__ */ new Date(e*1e3);return x(r,t)?he(e,t):n?`${pe(r,t)} ${_e(r)}`:pe(r,t)}function _e(e){return e.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`})}let S=[{tab:`comments`,label:`Comments`},{tab:`history`,label:`History`},{tab:`runs`,label:`Runs`}];function ve(e,t){return e.querySelector(`.panel-head .card-key`)?.textContent===t?e.querySelector(`.panel-scroll`)?.scrollTop??0:0}function ye(e,t,n){let{card:i,status:a}=e,c=o(`div`,`panel`);c.setAttribute(`role`,`dialog`),c.setAttribute(`aria-modal`,`true`);let l=`panel-title`;c.setAttribute(`aria-labelledby`,l);let u=o(`div`,`panel-head`),d=s(`✕`,`icon-button`,t.close);d.setAttribute(`aria-label`,`Close`),d.title=`Close (Esc)`,u.append(o(`span`,`card-key`,i.id),o(`span`,`spacer`),d);let f=o(`div`,`panel-scroll`),p=o(`div`,`panel-top`),m=o(`h2`,`panel-title`,r(i));m.id=l,p.append(m,be(i,a));let h=ue(e.activity,e.fieldChanges),g=/* @__PURE__ */ new Date;if(i.statusLine?.trim()){let e=o(`p`,`status-line`,i.statusLine.trim());e.dataset.category=a?.category??`unstarted`,p.append(e)}let _=o(`p`,`panel-notice`,n??``);_.setAttribute(`role`,`alert`),_.hidden=!n,p.append(_);let v=o(`div`,`panel-main`);v.append(w(`Description`,i.description?.trim()?o(`div`,`description`,i.description):o(`p`,`empty`,`No description.`))),e.children.length>0&&v.append(we(e,t));let ee=[...Oe(e.comments,t,g)],te=[Te(h,g)],ne=[Ae(e.runs,e=>[je(e),e.startedAt,e.state],`No runs.`,g)],re={comments:e.comments.length,history:h.length,runs:e.runs.length},ie={comments:ee,history:te,runs:ne};v.append(xe(e.tab,re,ie,t));let y=o(`div`,`panel-side`);y.append(De(i,t),w(`Details`,Ce(i,e.parent,e.runs,t,h,g)));let b=o(`div`,`panel-body`);return b.append(v,y),f.append(p,b),c.append(u,f),c}function be(e,t){let n=o(`div`,`state-row`);if(n.append(o(`span`,`column-pill`,t?t.name:`No column`)),e.waitingFor===`human`&&n.append(o(`span`,`waiting-badge`,`Waiting for you`)),e.activeRun?.state===`running`){let t=o(`span`,`run-state`),r=o(`span`,`run-dot`);r.setAttribute(`aria-hidden`,`true`),t.append(r,e.activeRun.agentName?`Running · ${e.activeRun.agentName}`:`Running`),n.append(t)}return n}function xe(e,t,n,r){let i=o(`div`,`tabs-wrap`),a=o(`div`,`tabs`);a.setAttribute(`role`,`tablist`);let s=[],c=/* @__PURE__ */ new Map,l=/* @__PURE__ */ new Map,u=e=>{for(let[t,n]of c)n.setAttribute(`aria-selected`,String(t===e)),n.tabIndex=t===e?0:-1,l.get(t).hidden=t!==e;r.selectTab(e)};return S.forEach(({tab:r,label:i},d)=>{let f=o(`button`,`tab`);f.type=`button`,f.id=`tab-${r}`,f.setAttribute(`role`,`tab`),f.setAttribute(`aria-selected`,String(r===e)),f.setAttribute(`aria-controls`,`tab-panel-${r}`),f.tabIndex=r===e?0:-1,f.append(i,o(`span`,`count`,String(t[r]))),f.addEventListener(`click`,()=>u(r)),f.addEventListener(`keydown`,e=>{if(e.key!==`ArrowLeft`&&e.key!==`ArrowRight`)return;e.preventDefault();let t=S[(d+(e.key===`ArrowRight`?1:S.length-1))%S.length].tab;u(t),c.get(t)?.focus()}),c.set(r,f),a.append(f);let p=o(`div`,`tab-panel`);p.id=`tab-panel-${r}`,p.setAttribute(`role`,`tabpanel`),p.setAttribute(`aria-labelledby`,f.id),p.hidden=r!==e,p.append(...n[r]),l.set(r,p),s.push(p)}),i.append(a,...s),i}function Se(e,t){let n=/* @__PURE__ */ new Date(e*1e3),r=o(`time`,`history-time`,t);return r.dateTime=n.toISOString(),r.title=n.toLocaleString(),r}function Ce(e,t,n,i,a,s){let c=o(`dl`,`facts`),l=(e,...t)=>{let n=o(`dd`);n.append(...t),c.append(o(`dt`,void 0,e),n)};if(e.parentIssueId){if(t){let e=o(`button`,`link`);e.type=`button`,e.append(o(`span`,`card-key`,t.id),o(`span`,`link-title`,r(t))),e.addEventListener(`click`,()=>i.openCard(t.id)),l(`Parent`,e)}else l(`Parent`,o(`span`,`card-key`,e.parentIssueId))}let d=a.find(e=>e.verb===`created the card`);l(`Created by`,C(d?{kind:d.actor.kind,name:d.actor.name,label:d.actor.label}:{kind:e.createdByKind,name:e.createdByKind===`user`?`You`:e.createdById??e.createdByKind,label:null}),` `,o(`span`,`muted`,`· ${ge(d?.at??e.createdAt,s)}`));let f=u(e),p=f?null:n.reduce((e,t)=>e===null||t.startedAt>e.startedAt?t:e,null);if(p?l(`Worked by`,C({kind:`agent`,name:p.agentName,label:null}),` `,o(`span`,`muted`,`· ${p.state}`)):l(`Worked by`,f?C({kind:f.key===`user`?`user`:`agent`,name:f.label,label:null}):`Nobody`,...e.activeRun?.state===`running`?[` `,o(`span`,`muted`,`· running`)]:[]),e.priority!==`none`){let t=o(`span`,`priority`,e.priority);t.dataset.priority=e.priority,l(`Priority`,t)}return e.labels.length>0&&l(`Labels`,...e.labels.map(e=>o(`span`,`label`,e))),c}function we(e,t){let n=t=>e.statuses.find(e=>e.id===t.statusId)?.category===`completed`,i=e.children.filter(n).length,a=w(`Sub-cards · ${i} of ${e.children.length} done`),s=o(`ul`,`subcards`);for(let i of e.children){let a=o(`li`),c=o(`button`,`subcard`);c.type=`button`,c.dataset.done=String(n(i)),c.addEventListener(`click`,()=>t.openCard(i.id));let l=o(`span`,`subcard-head`);l.append(o(`span`,`card-key`,i.id),o(`span`,`subcard-title`,r(i)));let d=o(`span`,`subcard-meta`);d.append(o(`span`,`subcard-column`,e.statuses.find(e=>e.id===i.statusId)?.name??`No column`)),i.waitingFor===`human`&&d.append(o(`span`,`waiting-badge`,`Waiting for you`)),i.activeRun?.state===`running`&&d.append(o(`span`,`muted`,i.activeRun.agentName?`Running · ${i.activeRun.agentName}`:`Running`));let f=u(i);f&&d.append(C({kind:f.key===`user`?`user`:`agent`,name:f.label,label:null})),c.append(l,d),a.append(c),s.append(a)}return a.append(s),a}function C(e){let t=o(`span`,`actor-chip`,e.name),n=e.label===`External`;return t.dataset.kind=n||e.kind===`provider-target`?`agent`:e.kind,n?t.title=e.label??``:e.label&&t.append(o(`small`,`actor-label`,` ${e.label}`)),t}function Te(e,t){let n=w(`History`);if(e.length===0)return n.append(o(`p`,`empty`,`No history yet.`)),n;for(let r of me(e,t)){let e=o(`section`,`history-day`);e.append(o(`h4`,void 0,r.day));let i=o(`ol`,`history-list`);for(let e of r.entries)i.append(Ee(e,t));e.append(i),n.append(e)}return n}function Ee(e,t){let n=o(`li`,`history-entry`);n.dataset.kind=e.actor.label===`External`||e.actor.kind===`provider-target`?`agent`:e.actor.kind;let r=o(`span`,`history-what`);if(r.append(C(e.actor),` ${e.verb}`),e.field&&r.append(` `,o(`span`,`history-field`,e.field)),n.append(r,Se(e.at,he(e.at,t))),e.from!==null||e.to!==null){let t=o(`span`,`history-change`);e.from!==null&&t.append(o(`del`,`value-from`,e.from)),e.to!==null&&t.append(o(`ins`,`value-to`,e.to)),n.append(t)}if(e.text){let t=o(`details`,`history-text`);t.append(o(`summary`,void 0,`Show before / after`));let r=o(`div`,`history-text-pair`);for(let[t,n,i]of[[`before`,`Before`,e.text.before],[`after`,`After`,e.text.after]]){let e=o(`p`,`history-text-block`);e.dataset.side=t,e.append(o(`b`,void 0,n),i??``),r.append(e)}t.append(r),n.append(t)}return n}function w(e,...t){let n=o(`section`,`panel-section`);return n.append(o(`h3`,void 0,e),...t),n}function De(e,t){let n=o(`textarea`,`field`);n.rows=2,n.placeholder=e.waitingFor===`human`?`A note for the agent (needed to return)`:`Why it goes back (needed to return)`,n.setAttribute(`aria-label`,`Decision note`);let r=o(`p`,`hint`),i=o(`div`,`row`);e.waitingFor===`human`&&i.append(s(`Approve`,`primary`,()=>t.approve(n.value.trim()||null))),i.append(s(`Return`,`secondary`,()=>{let e=n.value.trim();if(!e){r.textContent=`Say why in the note to return the card.`,n.focus();return}t.returnCard(e)}));let a=w(`Decision`,n,i,r);return e.waitingFor===`human`&&(a.dataset.waiting=``),a}function Oe(e,t,n){if(e.length===0)return[ke(t),o(`p`,`empty`,`No comments.`)];let r=o(`ul`,`entries`);for(let t of[...e].reverse()){let e=o(`li`),i=o(`div`,`entry-meta`);i.append(C({kind:t.author.kind,name:t.author.displayName,label:t.author.label}),Se(t.createdAt,ge(t.createdAt,n,{withClock:!0}))),e.append(i,o(`div`,`entry-text`,t.content)),r.append(e)}return[ke(t),r]}function ke(e){let t=o(`div`,`comment-form`),n=o(`textarea`,`field`);return n.rows=4,n.placeholder=`Add a comment`,n.setAttribute(`aria-label`,`New comment`),t.append(n,s(`Comment`,`secondary`,()=>{let t=n.value.trim();t&&e.addComment(t)})),t}function Ae(e,t,n,r){if(e.length===0)return o(`p`,`empty`,n);let i=o(`ul`,`entries`);for(let n of e){let[e,a,s]=t(n),c=o(`li`);c.dataset.runState=s;let l=o(`div`,`entry-meta`);l.append(Se(a,ge(a,r,{withClock:!0}))),c.append(o(`div`,`entry-text`,e),l),i.append(c)}return i}function je(e){return[`Attempt ${e.attempt}`,e.agentName,e.state,e.branch].filter(Boolean).join(` · `)}function Me(e,t,n){let r=e=>{let n=t.findIndex(t=>t.id===e.statusId);return n===-1?t.length:n};return e.filter(e=>e.parentIssueId===n&&e.id!==n).sort((e,t)=>r(e)-r(t)||e.order-t.order)}function Ne(e,t,n){let r=e=>t.find(t=>t.id===e.statusId)?.category,i=Me(e,t,n).filter(e=>r(e)!==`canceled`);return i.length===0?null:{total:i.length,done:i.filter(e=>r(e)===`completed`).length}}function Pe(e,t){return!t.parentIssueId||t.parentIssueId===t.id?null:e.find(e=>e.id===t.parentIssueId)??null}function Fe(e=globalThis.crypto){return typeof e.randomUUID==`function`?e.randomUUID():Array.from(e.getRandomValues(/* @__PURE__ */ new Uint8Array(16)),e=>e.toString(16).padStart(2,`0`)).join(``)}function Ie(e){let t=Fe(),n=null;function r(r){let i={"content-type":`application/json`},a=e();a&&(i.authorization=`Bearer ${a}`),fetch(`/page/presence`,{method:`POST`,keepalive:!0,headers:i,body:JSON.stringify({tabId:t,state:r})}).then(e=>{(e.status===404||e.status===204)&&n!==null&&(clearInterval(n),n=null)},()=>{})}r(`open`),n=setInterval(()=>r(`open`),2e4),window.addEventListener(`pagehide`,()=>r(`closed`)),window.addEventListener(`pageshow`,e=>{e.persisted&&r(`open`)})}function Le(e,t,n,r=null){let i=o(`label`,`project-switcher select-wrap`);i.append(o(`span`,`visually-hidden`,`Project`));let a=o(`select`,`field project-select`);if(r){let e=o(`option`,void 0,`${r.name?`${r.name} · `:``}the board this server was started on`);e.value=``,e.selected=t===null,a.append(e)}for(let n of e){let e=o(`option`,void 0,`${n.name} · ${n.folder}`);e.value=n.id,e.selected=n.id===t,a.append(e)}return a.addEventListener(`change`,()=>n(a.value)),i.append(a),i}function Re(e,t){let n=o(`span`,`project-where`);if(n.append(o(`span`,`where-key`,t.identifier)),!e)return t.name&&n.append(` · ${t.name}`),n;let r=e.storage.kind===`file`?`board file ${e.storage.path}`:`Postgres at ${e.storage.where}`;return n.append(` · ${e.folder} · ${r}`),n}let ze=`kanbo-serve-token`;function Be(){try{return sessionStorage.getItem(ze)}catch{return null}}function Ve(e){try{e?sessionStorage.setItem(ze,e):sessionStorage.removeItem(ze)}catch{}}function He(){let e=new URLSearchParams(location.hash.slice(1)).get(`token`)?.trim();e&&(Ve(e),history.replaceState(history.state,``,`${location.pathname}${location.search}`))}He();let T=Be(),E=new URLSearchParams(location.search).get(`project`),D=[],O=null,Ue=``,k=t(()=>T,()=>E===null?``:`/projects/${encodeURIComponent(E)}`),A=h(location.search),We=``,j=[],M=[],Ge=null,N=!1,Ke=!1,P=!1,F=null,I=null,L=null,R=null,z=null,B=null,qe=document.querySelector(`#app`)??document.body,V=o(`header`,`topbar`),H=o(`input`,`field token-input`),Je=s(`Token`,`ghost token-toggle`,()=>{q=!q,J(),q&&H.focus()}),U=o(`p`,`notice`),W=o(`main`,`board`),G=o(`div`,`panel-host`),Ye=o(`span`,`project-slot`),K=o(`div`,`filter-slot`),Xe=!1,q=!1;function J(){T===null||N||!Xe?(q=!1,delete V.dataset.token):V.dataset.token=q?`unfolded`:`folded`,Je.setAttribute(`aria-expanded`,String(V.dataset.token!==`folded`))}function Ze(){qe.classList.add(`app`);let e=o(`h1`,`topbar-title`,`Kanbo`),t=o(`span`,`workspace`);t.id=`workspace`,Ye.id=`project-switcher`;let n=o(`form`,`token-form`);n.id=`token-form`,Je.setAttribute(`aria-controls`,n.id),H.type=`password`,H.autocomplete=`off`,H.placeholder=`Server token`,H.value=T??``;let r=o(`label`,`token-label`,`Token`);r.append(H);let i=o(`button`,`secondary`,`Save`);i.type=`submit`,n.append(r,i),n.addEventListener(`submit`,e=>{e.preventDefault(),T=H.value.trim()||null,Ve(T),N=!1,q=!1,X(null),Q()}),V.append(e,Ye,Je,t,n),J(),U.setAttribute(`role`,`status`),U.hidden=!0,qe.replaceChildren(V,U,K,W,G)}let Y=!1;function X(e,t=`info`){U.textContent=e??``,U.hidden=!e,U.dataset.kind=t,Y=!1}function Z(t){return t instanceof e?t.code===`server_unreachable`?(Ke=!0,t.message):t.status===401?(N=!0,J(),H.focus(),`This server needs its token. Enter it in the Token field above.`):t.message:t instanceof Error?t.message:String(t)}function Qe(e){X(Z(e),`error`),Y=!0,Xe=!1,J()}function $e(){Xe=!0,J(),Y&&(Y=!1,X(null))}async function Q(){if(!P){P=!0;try{let e=await k.version(),[t,n,r,i]=await Promise.all([k.statuses(),k.cards(),k.projects(),k.workspace()]);Ge=e,j=t,M=n,D=r,O=i,st(),$e(),I&&await ht()}catch(e){tt(e)||Qe(e)}finally{P=!1}et&&(et=!1,await Q())}}let et=!1;function tt(t){if(!(t instanceof e)||t.code!==`project_not_found`||E===null)return!1;let n=D.find(e=>e.isDefault);return nt(null),X(`That project is no longer on this computer's list; showing ${n?.name??`the board this server was started on`}.`),et=!0,!0}function nt(e){E=e;let t=new URL(location.href);e===null?t.searchParams.delete(`project`):t.searchParams.set(`project`,e),A={...A,worker:null,labels:[]},at(t),Ge=null,F=null,$(),j=[],M=[],B=null,O=null,Ue=``,X(null)}async function rt(){if(!(document.visibilityState!==`visible`||N||Ke||P))try{await k.version()===Ge?$e():await Q()}catch(e){tt(e)?await Q():Qe(e)}}function it(){let e=E===null?D.find(e=>e.isDefault)??null:D.find(e=>e.id===E)??null,t=JSON.stringify([D,E,e?.id,O]);if(t===Ue)return;Ue=t;let n=D.some(e=>e.isDefault);Ye.replaceChildren(...D.length>+!!n?[Le(D,e?.id??null,e=>{nt(e===``?null:e),Q()},n?null:{name:E===null?O?.name??null:null})]:[]);let r=document.querySelector(`#workspace`);r&&r.replaceChildren(...O?[Re(e,O)]:[])}function at(e=new URL(location.href)){history.replaceState(null,``,`${e.pathname}${g(A,e.search)}${e.hash}`)}function ot(e){A=e,at(),st()}function st(){it();let e=F!==null&&document.activeElement===F.input,t=document.activeElement?.closest(`.card`)?.dataset.cardId??null,n=K.querySelector(`.filter-search`),r=n!==null&&document.activeElement===n,i=n?[n.selectionStart,n.selectionEnd,n.selectionDirection]:null,a=M.filter(e=>d(e,A)),o={shown:a.length,total:M.length},s=f(M),c=JSON.stringify([A,s]);if(c!==We||!K.firstElementChild?(We=c,K.replaceChildren(ae(A,s,o,ot))):se(K.firstElementChild,o),W.replaceChildren(...ce(j,a).map(ut)),B=te(M),ct(),r){let e=K.querySelector(`.filter-search`);e?.focus(),e&&i&&e.setSelectionRange(i[0],i[1],i[2]??void 0)}else e?F?.input.focus():t&&lt(t)}function ct(){for(let e of W.querySelectorAll(`.card`))e.toggleAttribute(`data-open`,e.dataset.cardId===I)}function lt(e){for(let t of W.querySelectorAll(`.card`))t.dataset.cardId===e&&t.querySelector(`.card-title`)?.focus()}function ut(e){let t=o(`section`,`column`);t.setAttribute(`aria-label`,e.name);let n=o(`header`,`column-head`);n.append(o(`span`,`column-name`,e.name),o(`span`,`column-count`,String(e.cards.length)));let r=e.status;if(r){let t=s(`+ New`,`ghost column-add`,()=>ft(r));t.setAttribute(`aria-label`,`New card in ${e.name}`),n.append(t)}let i=o(`div`,`column-cards`);F&&F.statusId===e.id&&i.append(F.form);for(let t of e.cards){let e=ee(t,r?.category??null,e=>void mt(e.id),{parent:Pe(M,t),summary:Ne(M,j,t.id),onOpenCard:e=>void mt(e)}),n=ne(B,t);n&&(e.dataset.enter=n),re(B,t)&&e.querySelector(`.waiting-badge`)?.setAttribute(`data-enter`,`waiting`),e.addEventListener(`dragstart`,n=>{z=t.id,n.dataTransfer?.setData(`text/plain`,t.id),e.classList.add(`dragging`)}),e.addEventListener(`dragend`,()=>{z=null,e.classList.remove(`dragging`)}),i.append(e)}return t.append(n,i),r&&(t.addEventListener(`dragover`,e=>{z&&(e.preventDefault(),t.classList.add(`drop-target`))}),t.addEventListener(`dragleave`,e=>{t.contains(e.relatedTarget)||t.classList.remove(`drop-target`)}),t.addEventListener(`drop`,e=>{e.preventDefault(),t.classList.remove(`drop-target`);let n=z;z=null,n&&dt(n,r)})),t}async function dt(e,t){if(M.find(t=>t.id===e)?.statusId!==t.id){try{let n=await k.moveCard(e,t.id),r=n.unmetRules??[];X(r.length>0?`${n.id} is in ${t.name}, but still misses: ${r.map(e=>e.detail).join(`; `)}`:null)}catch(e){X(Z(e),`error`)}await Q()}}function ft(e){let t=o(`div`,`draft`),n=o(`textarea`,`field`);n.rows=3,n.placeholder=`Describe the card`,n.setAttribute(`aria-label`,`New card in ${e.name}`);let r=async()=>{let t=n.value.trim();if(!t){n.focus();return}try{let n=await k.createCard({workspaceId:e.workspaceId,statusId:e.id,description:t});F=null,X(n.unmetRules?.length?`${n.id} is in ${e.name}, but still misses: ${n.unmetRules.map(e=>e.detail).join(`; `)}`:null)}catch(e){X(Z(e),`error`)}await Q()},i=()=>{F=null,st()};n.addEventListener(`keydown`,e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)?(e.preventDefault(),r()):e.key===`Escape`&&(e.stopPropagation(),i())});let a=o(`div`,`row`);a.append(s(`Create`,`primary`,()=>void r()),s(`Cancel`,`ghost`,i)),t.append(n,a),F={statusId:e.id,form:t,input:n},st(),n.focus()}let pt=`comments`;async function mt(e){I=e,R=null,ct(),await ht()}async function ht(){let e=I,t=M.find(t=>t.id===e);if(!e||!t){$();return}if(!(L?.card.id===e&&gt(G))){try{let[n,r,i,a]=await Promise.all([k.comments(e),k.activity(e),k.runs(e),k.fieldChanges(e)]);L={card:t,status:j.find(e=>e.id===t.statusId)??null,comments:n,activity:r,runs:i,fieldChanges:a,parent:Pe(M,t),children:Me(M,j,e),statuses:j,tab:pt}}catch(e){R=Z(e)}_t()}}function gt(e){return[...e.querySelectorAll(`textarea`)].some(e=>e.value.trim()!==``||document.activeElement===e)}function _t(){if(!L||L.card.id!==I){G.replaceChildren(),yt(!1);return}let e=L.card.id,t=ye(L,{close:$,addComment:t=>void vt(async()=>{await k.addComment(e,t)}),approve:t=>void vt(async()=>{await k.approve(e,t)}),returnCard:t=>void vt(async()=>{await k.returnCard(e,t)}),openCard:e=>void mt(e),selectTab:e=>{pt=e,L&&={...L,tab:e}}},R),n=!G.firstChild,r=ve(G,e);G.replaceChildren(t);let i=t.querySelector(`.panel-scroll`);i&&(i.scrollTop=r),n&&(yt(!0),t.classList.add(`panel--opening`),t.querySelector(`button`)?.focus())}async function vt(t){try{await t(),R=null;for(let e of G.querySelectorAll(`textarea`))e.value=``}catch(t){let n=Z(t);R=t instanceof e&&t.status===403?`${n} Needs the server token: only a request holding the token this server was started with acts for a person.`:n;let r=G.querySelector(`.panel-notice`);r&&(r.textContent=R,r.hidden=!1);return}await Q()}function yt(e){for(let t of[V,U,K,W])t.inert=e}G.addEventListener(`click`,e=>{e.target===G&&$()});function $(){let e=I;I=null,L=null,R=null,G.replaceChildren(),yt(!1),ct(),e&&lt(e)}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&I?$():e.key===`/`&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&!bt(e.target)&&(e.preventDefault(),K.querySelector(`.filter-search`)?.focus())});function bt(e){return e instanceof HTMLElement&&(e.isContentEditable||[`INPUT`,`TEXTAREA`,`SELECT`].includes(e.tagName))}document.addEventListener(`visibilitychange`,()=>void rt()),Ze(),Q(),setInterval(()=>void rt(),2e3),Ie(()=>T)})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kanbo-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A Kanban board your AI agents drive through a CLI and an MCP server, and you watch and approve.",
5
5
  "keywords": [
6
6
  "kanban",