@zibby/skills 2.0.5 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/artifact.js +7 -7
  2. package/dist/chat-notify.js +4 -4
  3. package/dist/chatProgress.js +4 -4
  4. package/dist/datasetStore.js +2 -2
  5. package/dist/discord.js +3 -3
  6. package/dist/figma.js +2 -2
  7. package/dist/git-write.js +9 -9
  8. package/dist/github.js +5 -5
  9. package/dist/gitlab.js +5 -5
  10. package/dist/googleDocs.js +9 -9
  11. package/dist/hubspot.js +1 -1
  12. package/dist/index.js +179 -181
  13. package/dist/jira.d.ts +19 -9
  14. package/dist/jira.js +22 -20
  15. package/dist/kvMemory.js +2 -2
  16. package/dist/lark.js +2 -2
  17. package/dist/larkAttendance.js +1 -1
  18. package/dist/larkDocs.js +3 -3
  19. package/dist/lib/http-deadline.d.ts +117 -0
  20. package/dist/lib/http-deadline.js +1 -0
  21. package/dist/lib/markup.d.ts +158 -0
  22. package/dist/lib/markup.js +22 -0
  23. package/dist/linear.js +15 -15
  24. package/dist/linkedin.js +2 -2
  25. package/dist/llm-billing.js +1 -1
  26. package/dist/notion.js +7 -7
  27. package/dist/opendesign.js +2 -2
  28. package/dist/package.json +6 -5
  29. package/dist/report.d.ts +42 -42
  30. package/dist/review.js +4 -4
  31. package/dist/reviewMemoryIo.js +1 -1
  32. package/dist/sentry.js +2 -2
  33. package/dist/skill-installer.js +3 -3
  34. package/dist/slack.js +2 -2
  35. package/dist/trackers/github-adapter.js +5 -5
  36. package/dist/trackers/index.js +46 -44
  37. package/dist/trackers/jira-adapter.js +24 -22
  38. package/dist/trackers/linear-adapter.js +19 -19
  39. package/dist/trackers/plane-adapter.js +1 -1
  40. package/dist/triggerAgent.js +1 -1
  41. package/dist/vikunja.d.ts +8 -1
  42. package/dist/vikunja.js +22 -7
  43. package/docs/templates/catalog-metadata.md +1 -1
  44. package/package.json +6 -5
package/dist/vikunja.js CHANGED
@@ -1,9 +1,24 @@
1
- import{existsSync as j}from"fs";import{fileURLToPath as I}from"url";import{dirname as w,resolve as N}from"path";var y=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",LARK_DOCS:"lark_docs",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",VIKUNJA:"vikunja",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),A=Object.freeze({sentry:{id:"sentry",name:"Sentry",connectPath:"/integrations?provider=sentry"},jira:{id:"jira",name:"Jira",connectPath:"/integrations?provider=jira"},github:{id:"github",name:"GitHub",connectPath:"/integrations?provider=github"},gitlab:{id:"gitlab",name:"GitLab",connectPath:"/integrations?provider=gitlab"},slack:{id:"slack",name:"Slack",connectPath:"/integrations?provider=slack"},lark:{id:"lark",name:"Lark Chat",connectPath:"/integrations?provider=lark"},lark_docs:{id:"lark_docs",name:"Lark App",connectPath:"/integrations?provider=lark_docs"},openai_billing:{id:"openai_billing",name:"OpenAI Admin",connectPath:"/integrations?provider=openai_billing"},anthropic_billing:{id:"anthropic_billing",name:"Anthropic Admin",connectPath:"/integrations?provider=anthropic_billing"},cursor_admin:{id:"cursor_admin",name:"Cursor Admin",connectPath:"/integrations?provider=cursor_admin"},notion:{id:"notion",name:"Notion",connectPath:"/integrations?provider=notion"},google:{id:"google",name:"Google Docs",connectPath:"/integrations?provider=google"},plane:{id:"plane",name:"Plane",connectPath:"/integrations?provider=plane"},linear:{id:"linear",name:"Linear",connectPath:"/integrations?provider=linear"},vikunja:{id:"vikunja",name:"Vikunja",connectPath:"/integrations?provider=vikunja"},figma:{id:"figma",name:"Figma",connectPath:"/integrations?provider=figma"},hubspot:{id:"hubspot",name:"HubSpot",connectPath:"/integrations?provider=hubspot"},open_design:{id:"open_design",name:"OpenDesign",connectPath:"/integrations?provider=open_design"},linkedin_personal:{id:"linkedin_personal",name:"LinkedIn (Personal)",connectPath:"/integrations?provider=linkedin_personal"},linkedin_business:{id:"linkedin_business",name:"LinkedIn (Business)",connectPath:"/integrations?provider=linkedin_business"},discord:{id:"discord",name:"Discord",connectPath:"/integrations?provider=discord"}});import{resolveIntegrationToken as S}from"@zibby/core/backend-client.js";function O(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let t=w(I(import.meta.url)),a=N(t,"..","bin","mcp-skill.mjs");return j(a)?a:null}function b(t){return String(t||"").trim().replace(/\/+$/,"").replace(/\/api\/v1$/,"")}var u=null;async function p(){if(u)return u;let t=b(process.env.VIKUNJA_URL),a=(process.env.VIKUNJA_TOKEN||"").trim();try{let e=await S("vikunja"),n=String(e?.token||"").trim(),i=b(e?.instanceUrl);if(n&&i)return u={origin:i,token:n},u;if(n&&!i)throw new Error("The connected Vikunja integration has no instance URL \u2014 reconnect it in Integrations \u2192 Vikunja.")}catch(e){if(!(t&&a))throw e}if(!(t&&a))throw new Error("No Vikunja credentials. Connect the board under Integrations \u2192 Vikunja (instance URL + an API token minted in the board's Settings \u2192 API Tokens).");return u={origin:t,token:a},u}function $(){u=null}async function s(t,a,e={}){let{origin:n,token:i}=await p(),r=`${n}/api/v1${a}`;if(e.query&&Object.keys(e.query).length){let l=new URLSearchParams;for(let[f,k]of Object.entries(e.query))k!=null&&k!==""&&l.set(f,String(k));let d=l.toString();d&&(r+=`?${d}`)}let o=await fetch(r,{method:t,headers:{Authorization:`Bearer ${i}`,...e.body?{"Content-Type":"application/json"}:{}},...e.body?{body:JSON.stringify(e.body)}:{}}),c=await o.text();if(!o.ok)throw new Error(`Vikunja ${t} ${a} \u2192 ${o.status}: ${c.slice(0,300)}`);if(!c)return null;try{return JSON.parse(c)}catch{return c}}function v(t){return typeof t!="string"||!t?"":t.replace(/<br\s*\/?>/gi,`
2
- `).replace(/<\/p>/gi,`
3
-
4
- `).replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\n{3,}/g,`
5
-
6
- `).trim()}function h(t){if(t==null||t==="")return null;if(typeof t=="number"&&Number.isFinite(t))return Math.max(0,Math.min(5,Math.round(t)));let a=String(t).trim().toLowerCase(),e={unset:0,none:0,low:1,medium:2,normal:2,high:3,urgent:4,now:5,critical:5,blocker:5,do_now:5,"do now":5};return Object.prototype.hasOwnProperty.call(e,a)?e[a]:null}function m(t,a){return t?{id:String(t.id),identifier:t.identifier||null,projectId:t.project_id??null,title:t.title||"",description:v(t.description),done:!!t.done,priority:t.priority??0,labels:(Array.isArray(t.labels)?t.labels:[]).map(e=>e?.title).filter(Boolean),assignees:(Array.isArray(t.assignees)?t.assignees:[]).map(e=>e?.username).filter(Boolean),dueDate:t.due_date&&!String(t.due_date).startsWith("0001-")?t.due_date:null,url:a?`${a}/tasks/${t.id}`:void 0}:null}async function g(t,{create:a=!1}={}){let e=String(t||"").trim();if(!e)return null;let n=await s("GET","/labels",{query:{s:e}}),i=(Array.isArray(n)?n:[]).find(o=>(o?.title||"").trim().toLowerCase()===e.toLowerCase());return i?.id?i.id:a?(await s("PUT","/labels",{body:{title:e}}))?.id??null:null}async function _(t){let a=encodeURIComponent(String(t)),e=await s("GET",`/projects/${a}/views`),n=(Array.isArray(e)?e:[]).find(r=>r?.view_kind==="kanban");if(!n?.id)throw new Error(`Project ${t} has no kanban view \u2014 there are no columns to move between.`);let i=await s("GET",`/projects/${a}/views/${n.id}/buckets`);return{viewId:n.id,buckets:Array.isArray(i)?i:[]}}var R={id:"vikunja",serverName:"vikunja",allowedTools:["mcp__vikunja__*"],requiresIntegration:y.VIKUNJA,callsBackend:!0,envKeys:["VIKUNJA_URL","VIKUNJA_TOKEN"],description:"Vikunja \u2014 kanban board: tasks, columns, labels, comments (API token)",promptFragment:`## Vikunja
1
+ import{existsSync as Rt}from"fs";var lt={NOTE:"info",TIP:"success",IMPORTANT:"note",WARNING:"warning",CAUTION:"error"},B={info:"NOTE",success:"TIP",note:"IMPORTANT",warning:"WARNING",error:"CAUTION"},ut=2e5,Q=6,dt=/^```([A-Za-z0-9_+.-]{0,32})\s*$/,pt=/^(#{1,6})[ \t]+(.*?)\s*$/,kt=/^(?:-{3,}|\*{3,}|_{3,})\s*$/,J=/^>(?: ?(.*))?$/,U=/^[-*][ \t]+\[([ xX])\][ \t]+(.*)$/,V=/^[-*][ \t]+(.*)$/,F=/^(\d{1,3})[.)][ \t]+(.*)$/,H=/^\|.*\|\s*$/,ht=/^\|?\s*:?-{1,}:?\s*(?:\|\s*:?-{1,}:?\s*)*\|?\s*$/,gt=/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/i;function W(n){let e=n.trim().replace(/^\|/,"").replace(/\|$/,""),t=[],r="";for(let i=0;i<e.length;i++){let s=e[i];if(s==="\\"&&e[i+1]==="|"){r+="|",i++;continue}if(s==="|"){t.push(r.trim()),r="";continue}r+=s}return t.push(r.trim()),t}function tt(n){let t=String(n??"").slice(0,ut).replace(/\r\n?/g,`
2
+ `).split(`
3
+ `);return D(t,0)}function D(n,e){let t=[],r=0;for(;r<n.length;){let i=n[r];if(i.trim()===""){r++;continue}if(/^[ \t]/.test(i)){t.push({t:"paragraph",c:f(i)}),r++;continue}let s;if(s=dt.exec(i)){let a=s[1]||"",o=[];for(r++;r<n.length&&!/^```\s*$/.test(n[r]);)o.push(n[r]),r++;r++,t.push({t:"code",lang:a,v:o.join(`
4
+ `)});continue}if(kt.test(i)){t.push({t:"rule"}),r++;continue}if(s=pt.exec(i)){let a=Math.min(Q,s[1].length);t.push({t:"heading",level:a,c:f(s[2])}),r++;continue}if(J.test(i)&&e<3){let a=[];for(;r<n.length&&(s=J.exec(n[r]));)a.push(s[1]??""),r++;let o=a.findIndex(c=>c.trim()!==""),d=o>=0?gt.exec(a[o].trim()):null;if(d){let c=lt[d[1].toUpperCase()];t.push({t:"panel",kind:c,c:D(a.slice(o+1),e+1)})}else t.push({t:"quote",c:D(a,e+1)});continue}if(U.test(i)){let a=[];for(;r<n.length&&(s=U.exec(n[r]));)a.push({checked:s[1]!==" ",c:f(s[2])}),r++;t.push({t:"task",items:a});continue}if(V.test(i)){let a=[];for(;r<n.length&&!U.test(n[r])&&(s=V.exec(n[r]));)a.push([{t:"paragraph",c:f(s[1])}]),r++;t.push({t:"bullet",items:a});continue}if(s=F.exec(i)){let a=Math.max(1,parseInt(s[1],10)||1),o=[];for(;r<n.length&&(s=F.exec(n[r]));)o.push([{t:"paragraph",c:f(s[2])}]),r++;t.push({t:"ordered",start:a,items:o});continue}if(H.test(i)&&r+1<n.length&&ht.test(n[r+1])){let a=W(i).map(f);r+=2;let o=[];for(;r<n.length&&H.test(n[r]);)o.push(W(n[r]).map(f)),r++;t.push({t:"table",header:a,rows:o});continue}t.push({t:"paragraph",c:f(i)}),r++}return t}var mt=/^https?:\/\/[^\s<>()[\]]+/,ft=/^\[([^\]\n]{1,300})\]\((https?:\/\/[^\s)]{1,2000})\)/,bt=/[.,;:!?'"]+$/;function yt(n,e){return e<=0?!0:/[\s([{"'“‘>:—–-]/.test(n[e-1])}function _t(n,e){return e>=n.length?!0:/[\s)\]}"'”’.,;:!?—–-]/.test(n[e])}function vt(n,e,t){let r=e;for(;r<n.length;){let i=n.indexOf(t,r);if(i<0)return-1;let s=n[i-1],a=n[i+t.length],o=t.length===1&&(s===t||a===t);if(i>e&&s&&!/\s/.test(s)&&!o&&_t(n,i+t.length))return i;r=i+1}return-1}function f(n){let e=String(n??""),t=[],r="",i=()=>{r&&(t.push({t:"text",v:r}),r="")},s=0;for(;s<e.length;){let a=e[s];if(a==="`"){let o=1;for(;e[s+o]==="`";)o++;let d="`".repeat(o),c=e.indexOf(d,s+o);if(c>s+o-1&&c!==-1){let l=e.slice(s+o,c);if(l.trim()){i(),t.push({t:"code",v:l.length>1&&l.startsWith(" ")&&l.endsWith(" ")?l.slice(1,-1):l}),s=c+o;continue}}r+=d,s+=o;continue}if(a==="["){let o=ft.exec(e.slice(s));if(o){i(),t.push({t:"link",href:o[2],c:f(o[1])}),s+=o[0].length;continue}}if((a==="*"||a==="_"||a==="~")&&yt(e,s)){let o=e[s+1]===a;if(a==="~"&&!o){r+=a,s++;continue}let d=o?a+a:a,c=s+d.length;if(c<e.length&&!/\s/.test(e[c])){let l=vt(e,c,d);if(l>c){i();let u=f(e.slice(c,l));t.push(a==="~"?{t:"strike",c:u}:o?{t:"strong",c:u}:{t:"em",c:u}),s=l+d.length;continue}}}if(a==="h"&&(s===0||/[\s(<]/.test(e[s-1]))){let o=mt.exec(e.slice(s));if(o){let d=o[0],c=bt.exec(d);if(c&&(d=d.slice(0,-c[0].length)),d.length>8){i(),t.push({t:"link",href:d,c:[{t:"text",v:d}]}),s+=d.length;continue}}}r+=a,s++}return i(),t}function N(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function v(n){let e="";for(let t of n)switch(t.t){case"text":e+=N(t.v);break;case"br":e+="<br>";break;case"code":e+=`<code>${N(t.v)}</code>`;break;case"strong":e+=`<strong>${v(t.c)}</strong>`;break;case"em":e+=`<em>${v(t.c)}</em>`;break;case"strike":e+=`<s>${v(t.c)}</s>`;break;case"link":e+=`<a href="${N(t.href)}" target="_blank" rel="noopener noreferrer">${v(t.c)}</a>`;break}return e}function It(n){return n.length&&n[0].t==="text"&&/^ /.test(n[0].v)?[{t:"text",v:`\xA0${n[0].v.slice(1)}`},...n.slice(1)]:n}function E(n){let e="";for(let t of n)switch(t.t){case"paragraph":e+=`<p>${v(It(t.c))}</p>`;break;case"heading":e+=`<h${t.level}>${v(t.c)}</h${t.level}>`;break;case"bullet":e+=`<ul>${t.items.map(r=>`<li>${E(r)}</li>`).join("")}</ul>`;break;case"ordered":e+=`<ol${t.start!==1?` start="${t.start}"`:""}>${t.items.map(r=>`<li>${E(r)}</li>`).join("")}</ol>`;break;case"task":e+=`<ul data-type="taskList">${t.items.map(r=>`<li data-type="taskItem" data-checked="${r.checked?"true":"false"}"><label><input type="checkbox"${r.checked?' checked="checked"':""}><span></span></label><div><p>${v(r.c)}</p></div></li>`).join("")}</ul>`;break;case"code":e+=`<pre><code${t.lang?` class="language-${N(t.lang)}"`:""}>${N(t.v)}</code></pre>`;break;case"quote":e+=`<blockquote>${E(t.c)}</blockquote>`;break;case"panel":e+=`<blockquote><p><strong>${B[t.kind][0]}${B[t.kind].slice(1).toLowerCase()}</strong></p>${E(t.c)}</blockquote>`;break;case"rule":e+="<hr>";break;case"table":{let r="<table><tbody>";t.header&&(r+=`<tr>${t.header.map(i=>`<th><p>${v(i)}</p></th>`).join("")}</tr>`);for(let i of t.rows)r+=`<tr>${i.map(s=>`<td><p>${v(s)}</p></td>`).join("")}</tr>`;e+=`${r}</tbody></table>`;break}}return e}function et(n){try{return E(tt(n))||`<p>${N(String(n??""))}</p>`}catch{return String(n??"").split(`
5
+ `).map(e=>`<p>${N(e)}</p>`).join("")}}function I(n){let e="";for(let t of n)switch(t.t){case"text":e+=t.v;break;case"br":e+=`
6
+ `;break;case"code":e+=`\`${t.v}\``;break;case"strong":e+=`**${I(t.c)}**`;break;case"em":e+=`_${I(t.c)}_`;break;case"strike":e+=`~~${I(t.c)}~~`;break;case"link":{let r=I(t.c);e+=!r||r===t.href?t.href:`[${r}](${t.href})`;break}}return e}function w(n){let e="";for(let t of n)switch(t.t){case"paragraph":e+=`${I(t.c)}
7
+ `;break;case"heading":e+=`${"#".repeat(Math.max(1,Math.min(Q,t.level)))} ${I(t.c)}
8
+ `;break;case"bullet":for(let r of t.items)e+=`- ${w(r).trim()}
9
+ `;break;case"ordered":t.items.forEach((r,i)=>{e+=`${t.start+i}. ${w(r).trim()}
10
+ `});break;case"task":for(let r of t.items)e+=`- [${r.checked?"x":" "}] ${I(r.c)}
11
+ `;break;case"code":e+=`\`\`\`${t.lang}
12
+ ${t.v}
13
+ \`\`\`
14
+ `;break;case"quote":e+=z(w(t.c));break;case"panel":e+=`> [!${B[t.kind]}]
15
+ ${z(w(t.c))}`;break;case"rule":e+=`---
16
+ `;break;case"table":{let r=i=>`| ${i.map(s=>I(s).replace(/\|/g,"\\|")).join(" | ")} |
17
+ `;t.header&&(e+=r(t.header)+`|${t.header.map(()=>" --- |").join("")}
18
+ `);for(let i of t.rows)e+=r(i);break}}return e}function wt(n){return n.replace(/^\n+/,"").replace(/\s+$/,"")}function z(n){return n.replace(/\n$/,"").split(`
19
+ `).map(e=>e?`> ${e}`:">").join(`
20
+ `)+`
21
+ `}var Tt={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:"\xA0",hellip:"\u2026",mdash:"\u2014",ndash:"\u2013",lsquo:"\u2018",rsquo:"\u2019",ldquo:"\u201C",rdquo:"\u201D",copy:"\xA9",reg:"\xAE",trade:"\u2122"};function X(n){return n.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi,(e,t)=>{if(t[0]==="#"){let i=t[1]==="x"||t[1]==="X"?parseInt(t.slice(2),16):parseInt(t.slice(1),10);return Number.isFinite(i)&&i>0&&i<1114112?String.fromCodePoint(i):e}let r=Tt[t.toLowerCase()];return r===void 0?e:r})}function xt(n){let e=[],t=/<!--[\s\S]*?-->|<\/([A-Za-z][\w:-]*)\s*>|<([A-Za-z][\w:-]*)((?:\s+[^\s=>/]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*)\s*(\/?)>|([^<]+)|(<)/g,r;for(;r=t.exec(n);)if(r[1])e.push({kind:"close",name:r[1].toLowerCase()});else if(r[2]){let i={},s=/([^\s=>/]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g,a;for(;a=s.exec(r[3]||"");)i[a[1].toLowerCase()]=X(a[2]??a[3]??a[4]??"");let o=r[2].toLowerCase();e.push({kind:"open",name:o,attrs:i,selfClose:!!r[4]||o==="br"||o==="hr"||o==="img"||o==="input"})}else r[5]!==void 0?e.push({kind:"text",v:X(r[5])}):r[6]&&e.push({kind:"text",v:"<"});return e}var Y=new Set(["p","div","h1","h2","h3","h4","h5","h6","ul","ol","li","blockquote","pre","hr","table","thead","tbody","tfoot","tr","td","th","section","article","header","footer","details","summary","figure","figcaption"]),jt=new Set(["script","style","label","input","button","svg","head","title"]);function A(n){let e=[],t=0,r=[],i=[],s=c=>{let l=At(r);r=[],l.length&&e.push(c?c(l):{t:"paragraph",c:l})},a=c=>{if(!c)return;let l={t:"text",v:c};for(let u=i.length-1;u>=0;u--){let p=i[u];p==="strong"?l={t:"strong",c:[l]}:p==="em"?l={t:"em",c:[l]}:p==="strike"?l={t:"strike",c:[l]}:l={t:"link",href:p.link,c:[l]}}r.push(l)},o=c=>{let l=[],u=1;for(;t<n.length;){let p=n[t++];if(p.kind==="open"&&p.name===c&&!p.selfClose&&u++,p.kind==="close"&&p.name===c&&(u--,u===0))break;l.push(p)}return l},d=c=>c.filter(l=>l.kind==="text").map(l=>l.v).join("");for(;t<n.length;){let c=n[t++];if(c.kind==="text"){a(c.v.replace(/\s+/g," "));continue}if(c.kind==="close"){if(c.name==="strong"||c.name==="b")q(i,"strong");else if(c.name==="em"||c.name==="i")q(i,"em");else if(c.name==="s"||c.name==="del"||c.name==="strike")q(i,"strike");else if(c.name==="a"){let u=i.map(p=>typeof p=="object").lastIndexOf(!0);u>=0&&i.splice(u,1)}else Y.has(c.name)&&s();continue}let l=c.name;if(jt.has(l)){c.selfClose||o(l);continue}if(l==="br"){r.push({t:"br"});continue}if(l==="hr"){s(),e.push({t:"rule"});continue}if(l==="strong"||l==="b"){i.push("strong");continue}if(l==="em"||l==="i"){i.push("em");continue}if(l==="s"||l==="del"||l==="strike"){i.push("strike");continue}if(l==="a"){c.attrs.href?i.push({link:c.attrs.href}):i.push({link:""});continue}if(l==="code"){let u=d(o("code"));u&&r.push({t:"code",v:u});continue}if(l==="pre"){s();let u=o("pre"),p=u.find(_=>_.kind==="open"&&_.name==="code"),y=p&&/language-([\w+.-]+)/.exec(p.attrs.class||"")?.[1]||"";e.push({t:"code",lang:y,v:d(u).replace(/\n$/,"")});continue}if(/^h[1-6]$/.test(l)){s();let u=Number(l[1]),p=A(o(l));e.push({t:"heading",level:u,c:f(w(p).trim().replace(/\n+/g," "))});continue}if(l==="blockquote"){s(),e.push({t:"quote",c:A(o(l))});continue}if(l==="ul"||l==="ol"){s();let u=o(l),p=(c.attrs["data-type"]||"")==="tasklist",y=[],_=[],T=0;for(;T<u.length;){let h=u[T++];if(h.kind==="open"&&h.name==="li"){let b=[],x=1;for(;T<u.length;){let g=u[T++];if(g.kind==="open"&&g.name==="li"&&!g.selfClose&&x++,g.kind==="close"&&g.name==="li"&&(x--,x===0))break;b.push(g)}y.push(b);let j=(h.attrs["data-checked"]||"")==="true"||b.some(g=>g.kind==="open"&&g.name==="input"&&"checked"in g.attrs);_.push(j)}}p||y.some(h=>h.some(b=>b.kind==="open"&&b.name==="input"&&(b.attrs.type||"")==="checkbox"))?e.push({t:"task",items:y.map((h,b)=>({checked:_[b],c:f(w(A(h)).trim().replace(/\n+/g," "))}))}):l==="ul"?e.push({t:"bullet",items:y.map(h=>Z(A(h)))}):e.push({t:"ordered",start:Math.max(1,parseInt(c.attrs.start||"1",10)||1),items:y.map(h=>Z(A(h)))});continue}if(l==="table"){s();let u=o("table"),p=[],y=[],_=0;for(;_<u.length;){let P=u[_++];if(P.kind==="open"&&P.name==="tr"){let h=[],b=!0,x=1,j=[];for(;_<u.length;){let m=u[_++];if(m.kind==="open"&&m.name==="tr"&&!m.selfClose&&x++,m.kind==="close"&&m.name==="tr"&&(x--,x===0))break;j.push(m)}let g=0;for(;g<j.length;){let m=j[g++];if(m.kind==="open"&&(m.name==="td"||m.name==="th")){m.name!=="th"&&(b=!1);let G=[],M=1;for(;g<j.length;){let $=j[g++];if($.kind==="open"&&$.name===m.name&&!$.selfClose&&M++,$.kind==="close"&&$.name===m.name&&(M--,M===0))break;G.push($)}h.push(f(w(A(G)).trim().replace(/\n+/g," ")))}}h.length&&(p.push(h),y.push(b))}}let T=p.length&&y[0]?p[0]:null;e.push({t:"table",header:T,rows:p.slice(T?1:0)});continue}if(Y.has(l)){s();continue}}return s(),e}function q(n,e){let t=n.lastIndexOf(e);t>=0&&n.splice(t,1)}function Z(n){return n.length?n:[{t:"paragraph",c:[]}]}function At(n){let e=[...n];for(;e.length&&e[0].t==="text"&&!e[0].v.trim();)e.shift();for(;e.length&&e[e.length-1].t==="text"&&!e[e.length-1].v.trim();)e.pop();e.length&&e[0].t==="text"&&(e[0]={t:"text",v:e[0].v.replace(/^\s+/," ")});let t=e.length-1;return t>=0&&e[t].t==="text"&&(e[t]={t:"text",v:e[t].v.replace(/\s+$/,"")}),e}function Nt(n){try{let e=String(n??"");return/<[a-z][\s\S]*>/i.test(e)?A(xt(e)):tt(e)}catch{return[]}}function nt(n){try{return wt(w(Nt(n)))}catch{return""}}import{fileURLToPath as Ct}from"url";import{dirname as Pt,resolve as Mt}from"path";var rt=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",LARK_DOCS:"lark_docs",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",VIKUNJA:"vikunja",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),Dt=Object.freeze({sentry:{id:"sentry",name:"Sentry",connectPath:"/integrations?provider=sentry"},jira:{id:"jira",name:"Jira",connectPath:"/integrations?provider=jira"},github:{id:"github",name:"GitHub",connectPath:"/integrations?provider=github"},gitlab:{id:"gitlab",name:"GitLab",connectPath:"/integrations?provider=gitlab"},slack:{id:"slack",name:"Slack",connectPath:"/integrations?provider=slack"},lark:{id:"lark",name:"Lark Chat",connectPath:"/integrations?provider=lark"},lark_docs:{id:"lark_docs",name:"Lark App",connectPath:"/integrations?provider=lark_docs"},openai_billing:{id:"openai_billing",name:"OpenAI Admin",connectPath:"/integrations?provider=openai_billing"},anthropic_billing:{id:"anthropic_billing",name:"Anthropic Admin",connectPath:"/integrations?provider=anthropic_billing"},cursor_admin:{id:"cursor_admin",name:"Cursor Admin",connectPath:"/integrations?provider=cursor_admin"},notion:{id:"notion",name:"Notion",connectPath:"/integrations?provider=notion"},google:{id:"google",name:"Google Docs",connectPath:"/integrations?provider=google"},plane:{id:"plane",name:"Plane",connectPath:"/integrations?provider=plane"},linear:{id:"linear",name:"Linear",connectPath:"/integrations?provider=linear"},vikunja:{id:"vikunja",name:"Vikunja",connectPath:"/integrations?provider=vikunja"},figma:{id:"figma",name:"Figma",connectPath:"/integrations?provider=figma"},hubspot:{id:"hubspot",name:"HubSpot",connectPath:"/integrations?provider=hubspot"},open_design:{id:"open_design",name:"OpenDesign",connectPath:"/integrations?provider=open_design"},linkedin_personal:{id:"linkedin_personal",name:"LinkedIn (Personal)",connectPath:"/integrations?provider=linkedin_personal"},linkedin_business:{id:"linkedin_business",name:"LinkedIn (Business)",connectPath:"/integrations?provider=linkedin_business"},discord:{id:"discord",name:"Discord",connectPath:"/integrations?provider=discord"}});import{resolveIntegrationToken as Ut}from"@zibby/core/backend-client.js";var O={api:{knob:"SKILL_API_TIMEOUT_MS",fallback:3e4},transfer:{knob:"SKILL_TRANSFER_TIMEOUT_MS",fallback:12e4},job:{knob:"SKILL_JOB_TIMEOUT_MS",fallback:3e5}};function St(n,e,t=process.env){let r=Number(t?.[n]);return Number.isFinite(r)&&r>0?Math.min(6e5,Math.max(1e3,Math.floor(r))):e}function $t(n="api",e=process.env){let t=O[n]||O.api;return St(t.knob,t.fallback,e)}function Et(n){return n?.name==="TimeoutError"||n?.name==="AbortError"}function Lt(n){try{return new URL(String(n?.url??n)).host||"unknown host"}catch{return"unknown host"}}function Ot(n,e){if(!n)return e;let t=new AbortController,r=a=>{t.signal.aborted||t.abort(a)},i=()=>r(n.reason),s=()=>r(e.reason);return t.signal.addEventListener("abort",()=>{n.removeEventListener("abort",i),e.removeEventListener("abort",s)},{once:!0}),n.aborted?r(n.reason):e.aborted?r(e.reason):(n.addEventListener("abort",i,{once:!0}),e.addEventListener("abort",s,{once:!0})),t.signal}async function it(n,e={},t={}){let r=t.kind||"api",i=(O[r]||O.api).knob,s=t.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(t.timeoutMs))):$t(r),a=e?.signal;if(a?.aborted)throw a.reason??new DOMException("This operation was aborted","AbortError");let o=AbortSignal.timeout(s),d=Ot(a,o);try{return await fetch(n,{...e,signal:d})}catch(c){throw o.aborted&&Et(c)?new Error(`${t.what||"request"} TIMED OUT after ${s}ms against ${Lt(n)} (${i})`):c}}function qt(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let n=Pt(Ct(import.meta.url)),e=Mt(n,"..","bin","mcp-skill.mjs");return Rt(e)?e:null}function st(n){return String(n||"").trim().replace(/\/+$/,"").replace(/\/api\/v1$/,"")}var S=null;async function L(){if(S)return S;let n=st(process.env.VIKUNJA_URL),e=(process.env.VIKUNJA_TOKEN||"").trim();try{let t=await Ut("vikunja"),r=String(t?.token||"").trim(),i=st(t?.instanceUrl);if(r&&i)return S={origin:i,token:r},S;if(r&&!i)throw new Error("The connected Vikunja integration has no instance URL \u2014 reconnect it in Integrations \u2192 Vikunja.")}catch(t){if(!(n&&e))throw t}if(!(n&&e))throw new Error("No Vikunja credentials. Connect the board under Integrations \u2192 Vikunja (instance URL + an API token minted in the board's Settings \u2192 API Tokens).");return S={origin:n,token:e},S}function Yt(){S=null}async function k(n,e,t={}){let{origin:r,token:i}=await L(),s=`${r}/api/v1${e}`;if(t.query&&Object.keys(t.query).length){let d=new URLSearchParams;for(let[l,u]of Object.entries(t.query))u!=null&&u!==""&&d.set(l,String(u));let c=d.toString();c&&(s+=`?${c}`)}let a=await it(s,{method:n,headers:{Authorization:`Bearer ${i}`,...t.body?{"Content-Type":"application/json"}:{}},...t.body?{body:JSON.stringify(t.body)}:{}},{kind:"api",what:`Vikunja ${n} ${e}`}),o=await a.text();if(!a.ok)throw new Error(`Vikunja ${n} ${e} \u2192 ${a.status}: ${o.slice(0,300)}`);if(!o)return null;try{return JSON.parse(o)}catch{return o}}function ct(n){return typeof n!="string"||!n?"":nt(n)}function K(n){return et(n)}function ot(n){if(n==null||n==="")return null;if(typeof n=="number"&&Number.isFinite(n))return Math.max(0,Math.min(5,Math.round(n)));let e=String(n).trim().toLowerCase(),t={unset:0,none:0,low:1,medium:2,normal:2,high:3,urgent:4,now:5,critical:5,blocker:5,do_now:5,"do now":5};return Object.prototype.hasOwnProperty.call(t,e)?t[e]:null}function R(n,e){return n?{id:String(n.id),identifier:n.identifier||null,projectId:n.project_id??null,title:n.title||"",description:ct(n.description),done:!!n.done,priority:n.priority??0,labels:(Array.isArray(n.labels)?n.labels:[]).map(t=>t?.title).filter(Boolean),assignees:(Array.isArray(n.assignees)?n.assignees:[]).map(t=>t?.username).filter(Boolean),dueDate:n.due_date&&!String(n.due_date).startsWith("0001-")?n.due_date:null,url:e?`${e}/tasks/${n.id}`:void 0}:null}async function C(n,{create:e=!1}={}){let t=String(n||"").trim();if(!t)return null;let r=await k("GET","/labels",{query:{s:t}}),i=(Array.isArray(r)?r:[]).find(a=>(a?.title||"").trim().toLowerCase()===t.toLowerCase());return i?.id?i.id:e?(await k("PUT","/labels",{body:{title:t}}))?.id??null:null}async function at(n){let e=encodeURIComponent(String(n)),t=await k("GET",`/projects/${e}/views`),r=(Array.isArray(t)?t:[]).find(s=>s?.view_kind==="kanban");if(!r?.id)throw new Error(`Project ${n} has no kanban view \u2014 there are no columns to move between.`);let i=await k("GET",`/projects/${e}/views/${r.id}/buckets`);return{viewId:r.id,buckets:Array.isArray(i)?i:[]}}var Zt={id:"vikunja",serverName:"vikunja",allowedTools:["mcp__vikunja__*"],requiresIntegration:rt.VIKUNJA,callsBackend:!0,envKeys:["VIKUNJA_URL","VIKUNJA_TOKEN"],description:"Vikunja \u2014 kanban board: tasks, columns, labels, comments (API token)",promptFragment:`## Vikunja
7
22
  You can operate the user's Vikunja board directly. Tools:
8
23
 
9
24
  ### Discovery
@@ -24,4 +39,4 @@ You can operate the user's Vikunja board directly. Tools:
24
39
  ### Notes
25
40
  - Address tasks by their NUMERIC id. The '#1' identifier shown in the UI is per-project and not unique.
26
41
  - Descriptions may come back as plain text converted from HTML \u2014 that is expected.
27
- - Priority accepts a number 0-5 or a word: low, medium, high, urgent, now.`,resolve(){let t={};for(let e of this.envKeys)process.env[e]&&(t[e]=process.env[e]);let a=O();return a?{type:"stdio",command:"node",args:[a,"../dist/vikunja.js","vikunjaSkill"],env:t,description:this.description,alwaysLoad:!0}:{command:null,args:[],env:t,description:this.description}},async handleToolCall(t,a){try{let e=a||{};switch(t){case"vikunja_list_projects":{let n=await s("GET","/projects"),i=(Array.isArray(n)?n:[]).map(r=>({id:String(r.id),title:r.title||"",description:v(r.description)}));return JSON.stringify({count:i.length,projects:i})}case"vikunja_list_buckets":{let{viewId:n,buckets:i}=await _(e.projectId);return JSON.stringify({viewId:n,count:i.length,buckets:i.map(r=>({id:r.id,title:r.title,taskCount:r.count??null}))})}case"vikunja_list_labels":{let n=await s("GET","/labels",{query:{s:e.search}}),i=(Array.isArray(n)?n:[]).map(r=>({id:r.id,title:r.title}));return JSON.stringify({count:i.length,labels:i})}case"vikunja_list_tasks":{let{origin:n}=await p(),i=[];if(e.label){let c=await g(e.label);if(!c)return JSON.stringify({count:0,tasks:[],note:`No label named "${e.label}" exists.`});i.push(`labels in ${c}`)}(e.done===!0||e.done===!1)&&i.push(`done = ${e.done}`);let r=await s("GET",`/projects/${encodeURIComponent(String(e.projectId))}/tasks`,{query:{...i.length?{filter:i.join(" && ")}:{},sort_by:"updated",order_by:"desc",per_page:Math.min(Number(e.limit)||25,50)}}),o=(Array.isArray(r)?r:[]).map(c=>m(c,n));return JSON.stringify({count:o.length,tasks:o})}case"vikunja_get_task":{let{origin:n}=await p(),i=await s("GET",`/tasks/${encodeURIComponent(String(e.taskId))}`);return JSON.stringify({task:m(i,n)})}case"vikunja_create_task":{let{origin:n}=await p(),i=h(e.priority),r=await s("PUT",`/projects/${encodeURIComponent(String(e.projectId))}/tasks`,{body:{title:e.title,...e.description?{description:e.description}:{},...i!==null?{priority:i}:{},...e.dueDate?{due_date:e.dueDate}:{}}});if(!r?.id)throw new Error("Vikunja created no task (no id in the response)");let o=[];for(let l of Array.isArray(e.labels)?e.labels:[])try{let d=await g(l,{create:!0});d&&await s("PUT",`/tasks/${r.id}/labels`,{body:{label_id:d}})}catch(d){o.push(`${l}: ${d?.message||d}`)}let c=await s("GET",`/tasks/${r.id}`);return JSON.stringify({created:m(c||r,n),...o.length?{labelErrors:o}:{}})}case"vikunja_update_task":{let{origin:n}=await p(),i=encodeURIComponent(String(e.taskId)),r=await s("GET",`/tasks/${i}`);if(!r?.id)throw new Error(`No task ${e.taskId}`);let o=h(e.priority),c=await s("POST",`/tasks/${i}`,{body:{...r,...e.title!==void 0?{title:e.title}:{},...e.description!==void 0?{description:e.description}:{},...o!==null?{priority:o}:{},...e.done!==void 0?{done:!!e.done}:{},...e.dueDate!==void 0?{due_date:e.dueDate}:{}}});return JSON.stringify({updated:m(c,n)})}case"vikunja_move_task":{let n=await s("GET",`/tasks/${encodeURIComponent(String(e.taskId))}`);if(!n?.id)throw new Error(`No task ${e.taskId}`);let i=e.projectId??n.project_id,r=String(e.column||"").trim().toLowerCase();if(!r)throw new Error("No target column given.");let{viewId:o,buckets:c}=await _(i),l=c.find(d=>(d?.title||"").trim().toLowerCase()===r);return l?.id?(await s("POST",`/projects/${encodeURIComponent(String(i))}/views/${o}/buckets/${l.id}/tasks`,{body:{task_id:Number(n.id)}}),JSON.stringify({moved:!0,taskId:String(n.id),column:l.title})):JSON.stringify({moved:!1,error:`No column named "${e.column}".`,availableColumns:c.map(d=>d.title)})}case"vikunja_add_label":{let n=await g(e.label,{create:e.create!==!1});return n?(await s("PUT",`/tasks/${encodeURIComponent(String(e.taskId))}/labels`,{body:{label_id:n}}),JSON.stringify({ok:!0,taskId:String(e.taskId),label:e.label})):JSON.stringify({ok:!1,error:`No label named "${e.label}" and creating it was declined.`})}case"vikunja_remove_label":{let n=await g(e.label);return n?(await s("DELETE",`/tasks/${encodeURIComponent(String(e.taskId))}/labels/${n}`),JSON.stringify({ok:!0,taskId:String(e.taskId),label:e.label})):JSON.stringify({ok:!1,error:`No label named "${e.label}".`})}case"vikunja_add_comment":{let n=await s("PUT",`/tasks/${encodeURIComponent(String(e.taskId))}/comments`,{body:{comment:e.comment}});return JSON.stringify({ok:!0,commentId:n?.id??null})}case"vikunja_assign":{let n=await s("GET","/users",{query:{s:e.username}}),i=(Array.isArray(n)?n:[]).find(r=>(r?.username||"").toLowerCase()===String(e.username||"").toLowerCase());return i?.id?(await s("PUT",`/tasks/${encodeURIComponent(String(e.taskId))}/assignees`,{body:{user_id:i.id}}),JSON.stringify({ok:!0,taskId:String(e.taskId),assignee:i.username})):JSON.stringify({ok:!1,error:`No user "${e.username}".`})}default:return JSON.stringify({error:`Unknown vikunja tool: ${t}`})}}catch(e){return JSON.stringify({error:e?.message||String(e)})}},tools:[{name:"vikunja_list_projects",description:"List Vikunja projects/boards (id, title). Everything else is project-scoped \u2014 start here when you do not already have a project id.",input_schema:{type:"object",properties:{}}},{name:"vikunja_list_buckets",description:"List a project's kanban COLUMNS (bucket id + title). Call this before moving a card so you use a column that exists.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"}},required:["projectId"]}},{name:"vikunja_list_labels",description:"List labels (id, title). Optionally narrow with a search string.",input_schema:{type:"object",properties:{search:{type:"string",description:"Optional server-side search on the label title"}}}},{name:"vikunja_list_tasks",description:"List a project's tasks, newest-updated first. Optionally filter by label title and/or done-state.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"},label:{type:"string",description:"Only tasks carrying this label title"},done:{type:"boolean",description:"Filter on completion state"},limit:{type:"number",description:"Max tasks (default 25, max 50)"}},required:["projectId"]}},{name:"vikunja_get_task",description:'Get one task by its NUMERIC id (the "#1" identifier shown in the UI is per-project and not unique).',input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"}},required:["taskId"]}},{name:"vikunja_create_task",description:"Create a task in a project. Labels are attached after creation and fail soft \u2014 the task survives a label error.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"},title:{type:"string",description:"Task title"},description:{type:"string",description:"Task body"},priority:{type:"string",description:"A number 0-5 or a word: low, medium, high, urgent, now"},labels:{type:"array",items:{type:"string"},description:"Label titles; created if missing"},dueDate:{type:"string",description:"RFC3339 timestamp"}},required:["projectId","title"]}},{name:"vikunja_update_task",description:"Change a task's title, description, priority, due date, or done state. To move it to another COLUMN use vikunja_move_task \u2014 a column is not a field on the task.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},title:{type:"string"},description:{type:"string"},priority:{type:"string",description:"A number 0-5 or a word: low, medium, high, urgent, now"},done:{type:"boolean"},dueDate:{type:"string",description:"RFC3339 timestamp"}},required:["taskId"]}},{name:"vikunja_move_task",description:`Move a card to a kanban COLUMN by name (e.g. "Doing"). Vikunja has no task.status: a column is a bucket on the project's kanban view, so this resolves the view and puts the task in the matching bucket. Returns the available column names when the name does not match.`,input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},column:{type:"string",description:"Target column (bucket) title"},projectId:{type:"string",description:"Optional; defaults to the task's own project"}},required:["taskId","column"]}},{name:"vikunja_add_label",description:"Attach a label to a task by title. Creates the label when it does not exist (pass create=false to refuse instead).",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},label:{type:"string",description:"Label title"},create:{type:"boolean",description:"Create the label if missing (default true)"}},required:["taskId","label"]}},{name:"vikunja_remove_label",description:"Detach a label from a task by title.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},label:{type:"string",description:"Label title"}},required:["taskId","label"]}},{name:"vikunja_add_comment",description:"Add a comment to a task.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},comment:{type:"string",description:"Comment body"}},required:["taskId","comment"]}},{name:"vikunja_assign",description:"Assign a user to a task by username.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},username:{type:"string",description:"Vikunja username"}},required:["taskId","username"]}}]};export{$ as clearVikunjaCredsCache,R as vikunjaSkill,v as vkPlainText,h as vkPriority};
42
+ - Priority accepts a number 0-5 or a word: low, medium, high, urgent, now.`,resolve(){let n={};for(let t of this.envKeys)process.env[t]&&(n[t]=process.env[t]);let e=qt();return e?{type:"stdio",command:"node",args:[e,"../dist/vikunja.js","vikunjaSkill"],env:n,description:this.description,alwaysLoad:!0}:{command:null,args:[],env:n,description:this.description}},async handleToolCall(n,e){try{let t=e||{};switch(n){case"vikunja_list_projects":{let r=await k("GET","/projects"),i=(Array.isArray(r)?r:[]).map(s=>({id:String(s.id),title:s.title||"",description:ct(s.description)}));return JSON.stringify({count:i.length,projects:i})}case"vikunja_list_buckets":{let{viewId:r,buckets:i}=await at(t.projectId);return JSON.stringify({viewId:r,count:i.length,buckets:i.map(s=>({id:s.id,title:s.title,taskCount:s.count??null}))})}case"vikunja_list_labels":{let r=await k("GET","/labels",{query:{s:t.search}}),i=(Array.isArray(r)?r:[]).map(s=>({id:s.id,title:s.title}));return JSON.stringify({count:i.length,labels:i})}case"vikunja_list_tasks":{let{origin:r}=await L(),i=[];if(t.label){let o=await C(t.label);if(!o)return JSON.stringify({count:0,tasks:[],note:`No label named "${t.label}" exists.`});i.push(`labels in ${o}`)}(t.done===!0||t.done===!1)&&i.push(`done = ${t.done}`);let s=await k("GET",`/projects/${encodeURIComponent(String(t.projectId))}/tasks`,{query:{...i.length?{filter:i.join(" && ")}:{},sort_by:"updated",order_by:"desc",per_page:Math.min(Number(t.limit)||25,50)}}),a=(Array.isArray(s)?s:[]).map(o=>R(o,r));return JSON.stringify({count:a.length,tasks:a})}case"vikunja_get_task":{let{origin:r}=await L(),i=await k("GET",`/tasks/${encodeURIComponent(String(t.taskId))}`);return JSON.stringify({task:R(i,r)})}case"vikunja_create_task":{let{origin:r}=await L(),i=ot(t.priority),s=await k("PUT",`/projects/${encodeURIComponent(String(t.projectId))}/tasks`,{body:{title:t.title,...t.description?{description:K(t.description)}:{},...i!==null?{priority:i}:{},...t.dueDate?{due_date:t.dueDate}:{}}});if(!s?.id)throw new Error("Vikunja created no task (no id in the response)");let a=[];for(let d of Array.isArray(t.labels)?t.labels:[])try{let c=await C(d,{create:!0});c&&await k("PUT",`/tasks/${s.id}/labels`,{body:{label_id:c}})}catch(c){a.push(`${d}: ${c?.message||c}`)}let o=await k("GET",`/tasks/${s.id}`);return JSON.stringify({created:R(o||s,r),...a.length?{labelErrors:a}:{}})}case"vikunja_update_task":{let{origin:r}=await L(),i=encodeURIComponent(String(t.taskId)),s=await k("GET",`/tasks/${i}`);if(!s?.id)throw new Error(`No task ${t.taskId}`);let a=ot(t.priority),o=await k("POST",`/tasks/${i}`,{body:{...s,...t.title!==void 0?{title:t.title}:{},...t.description!==void 0?{description:K(t.description)}:{},...a!==null?{priority:a}:{},...t.done!==void 0?{done:!!t.done}:{},...t.dueDate!==void 0?{due_date:t.dueDate}:{}}});return JSON.stringify({updated:R(o,r)})}case"vikunja_move_task":{let r=await k("GET",`/tasks/${encodeURIComponent(String(t.taskId))}`);if(!r?.id)throw new Error(`No task ${t.taskId}`);let i=t.projectId??r.project_id,s=String(t.column||"").trim().toLowerCase();if(!s)throw new Error("No target column given.");let{viewId:a,buckets:o}=await at(i),d=o.find(c=>(c?.title||"").trim().toLowerCase()===s);return d?.id?(await k("POST",`/projects/${encodeURIComponent(String(i))}/views/${a}/buckets/${d.id}/tasks`,{body:{task_id:Number(r.id)}}),JSON.stringify({moved:!0,taskId:String(r.id),column:d.title})):JSON.stringify({moved:!1,error:`No column named "${t.column}".`,availableColumns:o.map(c=>c.title)})}case"vikunja_add_label":{let r=await C(t.label,{create:t.create!==!1});return r?(await k("PUT",`/tasks/${encodeURIComponent(String(t.taskId))}/labels`,{body:{label_id:r}}),JSON.stringify({ok:!0,taskId:String(t.taskId),label:t.label})):JSON.stringify({ok:!1,error:`No label named "${t.label}" and creating it was declined.`})}case"vikunja_remove_label":{let r=await C(t.label);return r?(await k("DELETE",`/tasks/${encodeURIComponent(String(t.taskId))}/labels/${r}`),JSON.stringify({ok:!0,taskId:String(t.taskId),label:t.label})):JSON.stringify({ok:!1,error:`No label named "${t.label}".`})}case"vikunja_add_comment":{let r=await k("PUT",`/tasks/${encodeURIComponent(String(t.taskId))}/comments`,{body:{comment:K(t.comment)}});return JSON.stringify({ok:!0,commentId:r?.id??null})}case"vikunja_assign":{let r=await k("GET","/users",{query:{s:t.username}}),i=(Array.isArray(r)?r:[]).find(s=>(s?.username||"").toLowerCase()===String(t.username||"").toLowerCase());return i?.id?(await k("PUT",`/tasks/${encodeURIComponent(String(t.taskId))}/assignees`,{body:{user_id:i.id}}),JSON.stringify({ok:!0,taskId:String(t.taskId),assignee:i.username})):JSON.stringify({ok:!1,error:`No user "${t.username}".`})}default:return JSON.stringify({error:`Unknown vikunja tool: ${n}`})}}catch(t){return JSON.stringify({error:t?.message||String(t)})}},tools:[{name:"vikunja_list_projects",description:"List Vikunja projects/boards (id, title). Everything else is project-scoped \u2014 start here when you do not already have a project id.",input_schema:{type:"object",properties:{}}},{name:"vikunja_list_buckets",description:"List a project's kanban COLUMNS (bucket id + title). Call this before moving a card so you use a column that exists.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"}},required:["projectId"]}},{name:"vikunja_list_labels",description:"List labels (id, title). Optionally narrow with a search string.",input_schema:{type:"object",properties:{search:{type:"string",description:"Optional server-side search on the label title"}}}},{name:"vikunja_list_tasks",description:"List a project's tasks, newest-updated first. Optionally filter by label title and/or done-state.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"},label:{type:"string",description:"Only tasks carrying this label title"},done:{type:"boolean",description:"Filter on completion state"},limit:{type:"number",description:"Max tasks (default 25, max 50)"}},required:["projectId"]}},{name:"vikunja_get_task",description:'Get one task by its NUMERIC id (the "#1" identifier shown in the UI is per-project and not unique).',input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"}},required:["taskId"]}},{name:"vikunja_create_task",description:"Create a task in a project. Labels are attached after creation and fail soft \u2014 the task survives a label error.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project id"},title:{type:"string",description:"Task title"},description:{type:"string",description:"Task body. Markdown is rendered (headings, **bold**, `code`, lists, - [ ] tasks, links, tables, > quotes)."},priority:{type:"string",description:"A number 0-5 or a word: low, medium, high, urgent, now"},labels:{type:"array",items:{type:"string"},description:"Label titles; created if missing"},dueDate:{type:"string",description:"RFC3339 timestamp"}},required:["projectId","title"]}},{name:"vikunja_update_task",description:"Change a task's title, description, priority, due date, or done state. To move it to another COLUMN use vikunja_move_task \u2014 a column is not a field on the task.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},title:{type:"string"},description:{type:"string"},priority:{type:"string",description:"A number 0-5 or a word: low, medium, high, urgent, now"},done:{type:"boolean"},dueDate:{type:"string",description:"RFC3339 timestamp"}},required:["taskId"]}},{name:"vikunja_move_task",description:`Move a card to a kanban COLUMN by name (e.g. "Doing"). Vikunja has no task.status: a column is a bucket on the project's kanban view, so this resolves the view and puts the task in the matching bucket. Returns the available column names when the name does not match.`,input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},column:{type:"string",description:"Target column (bucket) title"},projectId:{type:"string",description:"Optional; defaults to the task's own project"}},required:["taskId","column"]}},{name:"vikunja_add_label",description:"Attach a label to a task by title. Creates the label when it does not exist (pass create=false to refuse instead).",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},label:{type:"string",description:"Label title"},create:{type:"boolean",description:"Create the label if missing (default true)"}},required:["taskId","label"]}},{name:"vikunja_remove_label",description:"Detach a label from a task by title.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},label:{type:"string",description:"Label title"}},required:["taskId","label"]}},{name:"vikunja_add_comment",description:"Add a comment to a task.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},comment:{type:"string",description:"Comment body. Markdown is rendered (headings, **bold**, `code`, lists, - [ ] tasks, links, tables, > quotes)."}},required:["taskId","comment"]}},{name:"vikunja_assign",description:"Assign a user to a task by username.",input_schema:{type:"object",properties:{taskId:{type:"string",description:"Numeric task id"},username:{type:"string",description:"Vikunja username"}},required:["taskId","username"]}}]};export{Yt as clearVikunjaCredsCache,Zt as vikunjaSkill,ct as vkPlainText,ot as vkPriority,K as vkRichHtml};
@@ -18,7 +18,7 @@ pops an "Update available" badge on somebody's deployed agent for nothing.
18
18
  | `tags` | string[] | No | catalog sections; the card is grouped by the first one in section order | `[]` | Card only |
19
19
  | `browseRank` | number | No | lower sorts first; no rank sorts last | none | Card only |
20
20
  | `capabilities` | string[] | No | around five bullets, each one thing, each starting with a verb | `[]` | Card only |
21
- | `conversationStarters` | string[] | No | example prompts | `[]` | Card only |
21
+ | `conversationStarters` | string[] | No | example prompts — the first five appear as "Try asking" on the detail card | `[]` | Card only |
22
22
  | `icon` | string | No | `./icon.png` beside your graph, or an `https://` URL | the Zibby mark | Card only |
23
23
  | `iconPrompt` / `iconBackground` | string | No | inputs to the offline icon generator | none | Card only |
24
24
  | `releaseNotes` | string | No | markdown — see below | `''` | Card only |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -73,7 +73,8 @@
73
73
  "./review": {
74
74
  "types": "./dist/review.d.ts",
75
75
  "default": "./dist/review.js"
76
- }
76
+ },
77
+ "./markup": {"types": "./dist/lib/markup.d.ts", "default": "./dist/lib/markup.js"}
77
78
  },
78
79
  "scripts": {
79
80
  "build": "node ../scripts/build.mjs && npm run build:types",
@@ -116,10 +117,10 @@
116
117
  "dependencies": {
117
118
  "@modelcontextprotocol/sdk": "^1.29.0",
118
119
  "@resvg/resvg-js": "^2.6.2",
119
- "@zibby/agent-workflow": "2.0.5",
120
+ "@zibby/agent-workflow": "2.0.7",
120
121
  "@zibby/bin-oxlint": "^1.73.0",
121
122
  "@zibby/bin-semgrep": "^1.169.0",
122
- "@zibby/skill-ids": "2.0.5",
123
+ "@zibby/skill-ids": "2.0.7",
123
124
  "echarts": "^6.1.0",
124
125
  "mem0ai": "npm:@zibby/mem0ai@^3.0.5",
125
126
  "zod": "^3.23.0 || ^4.0.0"
@@ -134,7 +135,7 @@
134
135
  }
135
136
  },
136
137
  "optionalDependencies": {
137
- "@zibby/mcp-browser": "2.0.5",
138
+ "@zibby/mcp-browser": "2.0.7",
138
139
  "@zibby/mcp-memory": "*"
139
140
  },
140
141
  "devDependencies": {