kanbo-cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/cli.cjs +96 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/lib/{board-store-B16YarvX.d.mts → board-store-BfszzAJB.d.cts} +2 -2
- package/dist/lib/{board-store-BHHo_ZlR.d.cts → board-store-BvWn9xTB.d.mts} +2 -2
- package/dist/lib/index.cjs +2 -29
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.d.cts +363 -363
- package/dist/lib/index.d.mts +363 -363
- package/dist/lib/index.mjs +1 -28
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/{manifest-C0EcwwgO.mjs → manifest-DfOBqo-Q.mjs} +100 -17
- package/dist/lib/manifest-DfOBqo-Q.mjs.map +1 -0
- package/dist/lib/{manifest-CpZOcB_6.cjs → manifest-wdwFSquz.cjs} +104 -15
- package/dist/lib/manifest-wdwFSquz.cjs.map +1 -0
- package/dist/lib/mcp/index.cjs +1 -1
- package/dist/lib/mcp/index.d.cts +12 -12
- package/dist/lib/mcp/index.d.mts +12 -12
- package/dist/lib/mcp/index.mjs +1 -1
- package/dist/lib/postgres/index.d.cts +151 -151
- package/dist/lib/postgres/index.d.mts +151 -151
- package/dist/lib/{schema-fsHqNAip.d.cts → schema-D0MyXcej.d.cts} +41 -41
- package/dist/lib/{schema-fsHqNAip.d.mts → schema-D0MyXcej.d.mts} +41 -41
- package/dist/lib/sqlite/index.d.cts +12 -12
- package/dist/lib/sqlite/index.d.mts +12 -12
- package/dist/lib/sqlite/schema.d.cts +1 -1
- package/dist/lib/sqlite/schema.d.mts +1 -1
- package/dist/lib/{tool-names-9cmCn0gP.d.cts → tool-names-3q_GEZej.d.mts} +5 -5
- package/dist/lib/{tool-names-Dxg1UTUl.d.mts → tool-names-WfH4IURz.d.cts} +5 -5
- package/dist/page/board.js +1 -1
- package/package.json +4 -4
- package/dist/lib/manifest-C0EcwwgO.mjs.map +0 -1
- package/dist/lib/manifest-CpZOcB_6.cjs.map +0 -1
package/dist/page/board.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
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{}}let C=x(),w=t(()=>C),T=[],E=[],D=null,O=!1,k=!1,A=null,j=null,M=null,N=null,P=null,F=document.querySelector(`#app`)??document.body,I=o(`input`,`field token-input`),L=o(`p`,`notice`),R=o(`main`,`board`),z=o(`div`,`panel-host`);function B(){let e=o(`header`,`topbar`),t=o(`h1`,`topbar-title`,`Kanbo`),n=o(`span`,`workspace`);n.id=`workspace`;let r=o(`form`,`token-form`);I.type=`password`,I.autocomplete=`off`,I.placeholder=`Server token`,I.value=C??``;let i=o(`label`,`token-label`,`Token`);i.append(I);let a=o(`button`,`secondary`,`Save`);a.type=`submit`,r.append(i,a),r.addEventListener(`submit`,e=>{e.preventDefault(),C=I.value.trim()||null,S(C),O=!1,H(null),K()}),e.append(t,n,r),L.setAttribute(`role`,`status`),L.hidden=!0,F.replaceChildren(e,L,R,z)}let V=!1;function H(e,t=`info`){L.textContent=e??``,L.hidden=!e,L.dataset.kind=t,V=!1}function U(t){return t instanceof e?t.status===401?(O=!0,I.focus(),`This server needs its token. Enter it in the Token field above.`):t.message:t instanceof Error?t.message:String(t)}function W(e){H(U(e),`error`),V=!0}function G(){V&&(V=!1,H(null))}async function K(){if(!k){k=!0;try{let e=await w.version(),[t,n]=await Promise.all([w.statuses(),w.cards()]);D=e,T=t,E=n,J(),G(),j&&await Z()}catch(e){W(e)}finally{k=!1}}}async function q(){if(!(document.visibilityState!==`visible`||O||k))try{await w.version()===D?G():await K()}catch(e){W(e)}}function J(){let e=document.querySelector(`#workspace`);e&&(e.textContent=T[0]?.workspaceId??``);let t=A!==null&&document.activeElement===A.input,n=document.activeElement?.closest(`.card`)?.dataset.cardId??null;R.replaceChildren(...l(T,E).map(X)),t?A?.input.focus():n&&Y(n)}function Y(e){for(let t of R.querySelectorAll(`.card`))t.dataset.cardId===e&&t.querySelector(`.card-title`)?.focus()}function X(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`,()=>te(r));t.setAttribute(`aria-label`,`New card in ${e.name}`),n.append(t)}let i=o(`div`,`column-cards`);A&&A.statusId===e.id&&i.append(A.form);for(let t of e.cards){let e=c(t,r?.category??null,e=>void ne(e.id));e.addEventListener(`dragstart`,n=>{P=t.id,n.dataTransfer?.setData(`text/plain`,t.id),e.classList.add(`dragging`)}),e.addEventListener(`dragend`,()=>{P=null,e.classList.remove(`dragging`)}),i.append(e)}return t.append(n,i),r&&(t.addEventListener(`dragover`,e=>{P&&(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=P;P=null,n&&ee(n,r)})),t}async function ee(e,t){if(E.find(t=>t.id===e)?.statusId!==t.id){try{let n=await w.moveCard(e,t.id),r=n.unmetRules??[];H(r.length>0?`${n.id} is in ${t.name}, but still misses: ${r.map(e=>e.detail).join(`; `)}`:null)}catch(e){H(U(e),`error`)}await K()}}function te(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 w.createCard({workspaceId:e.workspaceId,statusId:e.id,description:t});A=null,H(n.unmetRules?.length?`${n.id} is in ${e.name}, but still misses: ${n.unmetRules.map(e=>e.detail).join(`; `)}`:null)}catch(e){H(U(e),`error`)}await K()},i=()=>{A=null,J()};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),A={statusId:e.id,form:t,input:n},J(),n.focus()}async function ne(e){j=e,N=null,await Z()}async function Z(){let e=j,t=E.find(t=>t.id===e);if(!e||!t){$();return}if(!(M?.card.id===e&&re(z))){try{let[n,r,i]=await Promise.all([w.comments(e),w.activity(e),w.runs(e)]);M={card:t,status:T.find(e=>e.id===t.statusId)??null,comments:n,activity:r,runs:i}}catch(e){N=U(e)}ie()}}function re(e){return[...e.querySelectorAll(`textarea`)].some(e=>e.value.trim()!==``||document.activeElement===e)}function ie(){if(!M||M.card.id!==j){z.replaceChildren();return}let e=M.card.id,t=u(M,{close:$,addComment:t=>void Q(async()=>{await w.addComment(e,t)}),approve:t=>void Q(async()=>{await w.approve(e,t)}),returnCard:t=>void Q(async()=>{await w.returnCard(e,t)})},N),n=!z.firstChild;z.replaceChildren(t),n&&t.querySelector(`button`)?.focus()}async function Q(t){try{await t(),N=null;for(let e of z.querySelectorAll(`textarea`))e.value=``}catch(t){let n=U(t);N=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=z.querySelector(`.panel-notice`);r&&(r.textContent=N,r.hidden=!1);return}await K()}function $(){let e=j;j=null,M=null,N=null,z.replaceChildren(),e&&Y(e)}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&j&&$()}),document.addEventListener(`visibilitychange`,()=>void q()),B(),K(),setInterval(()=>void q(),2e3)})();
|
|
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)})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kanbo-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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",
|
|
@@ -139,9 +139,9 @@
|
|
|
139
139
|
"better-sqlite3": "^13.0.3",
|
|
140
140
|
"drizzle-kit": "^0.31.10",
|
|
141
141
|
"jsdom": "^30.0.1",
|
|
142
|
-
"tsdown": "^0.
|
|
142
|
+
"tsdown": "^0.23.0",
|
|
143
143
|
"tsx": "^4.23.13",
|
|
144
|
-
"typescript": "^
|
|
145
|
-
"vitest": "^
|
|
144
|
+
"typescript": "^7.0.2",
|
|
145
|
+
"vitest": "^5.0.2"
|
|
146
146
|
}
|
|
147
147
|
}
|