@zibby/skills 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/slack.js CHANGED
@@ -1,4 +1,4 @@
1
- import{existsSync as h}from"fs";import{fileURLToPath as g}from"url";import{dirname as k,resolve as f}from"path";import{resolveIntegrationToken as y}from"@zibby/core/backend-client.js";var _=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),S=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",connectPath:"/integrations?provider=lark"},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"},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"}});function b(){if(process.env.MCP_SLACK_PATH)return process.env.MCP_SLACK_PATH;let a=k(g(import.meta.url)),t=f(a,"..","bin","mcp-slack.mjs");return h(t)?t:null}async function n(a,t={}){let{token:e}=await y("slack"),i=["conversations.list","users.list","users.profile.get","users.lookupByEmail","usergroups.list","usergroups.users.list","conversations.history","conversations.replies"].includes(a),c=`https://slack.com/api/${a}`,o={Authorization:`Bearer ${e}`},d;if(i){let s=new URLSearchParams(t).toString();s&&(c+=`?${s}`)}else o["Content-Type"]="application/json; charset=utf-8",d=JSON.stringify(t);let r=await(await fetch(c,{method:i?"GET":"POST",headers:o,body:d})).json();if(!r.ok)throw new Error(`Slack API error: ${r.error}`);return r}var w={id:"slack",serverName:"slack",allowedTools:["mcp__slack__*"],requiresIntegration:_.SLACK,envKeys:["SLACK_BOT_TOKEN","SLACK_TEAM_ID"],description:"Slack MCP Server",promptFragment:`## Slack
1
+ import{existsSync as h}from"fs";import{fileURLToPath as g}from"url";import{dirname as k,resolve as f}from"path";import{resolveIntegrationToken as y}from"@zibby/core/backend-client.js";var _=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),S=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",connectPath:"/integrations?provider=lark"},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"},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"}});function b(){if(process.env.MCP_SLACK_PATH)return process.env.MCP_SLACK_PATH;let a=k(g(import.meta.url)),t=f(a,"..","bin","mcp-slack.mjs");return h(t)?t:null}async function n(a,t={}){let{token:e}=await y("slack"),i=["conversations.list","users.list","users.profile.get","users.lookupByEmail","usergroups.list","usergroups.users.list","conversations.history","conversations.replies"].includes(a),c=`https://slack.com/api/${a}`,o={Authorization:`Bearer ${e}`},d;if(i){let s=new URLSearchParams(t).toString();s&&(c+=`?${s}`)}else o["Content-Type"]="application/json; charset=utf-8",d=JSON.stringify(t);let r=await(await fetch(c,{method:i?"GET":"POST",headers:o,body:d})).json();if(!r.ok)throw new Error(`Slack API error: ${r.error}`);return r}var w={id:"slack",callsBackend:!0,serverName:"slack",allowedTools:["mcp__slack__*"],requiresIntegration:_.SLACK,envKeys:["SLACK_BOT_TOKEN","SLACK_TEAM_ID"],description:"Slack MCP Server",promptFragment:`## Slack
2
2
  You have access to the user's Slack workspace. Use these tools:
3
3
  - slack_list_channels, slack_post_message, slack_reply_to_thread
4
4
  - slack_add_reaction, slack_get_channel_history, slack_get_thread_replies
@@ -2,7 +2,7 @@ import{existsSync as X}from"fs";import{fileURLToPath as ee}from"url";import{dirn
2
2
 
3
3
  <!-- zbfp:${p} -->`}var x=`
4
4
 
5
- <!-- zbreview-summary -->`;function H(p){let o=q.exec(String(p||""));return o?o[1].toLowerCase():null}function J(p){return L.test(String(p||""))}function U(p,o){let t=new Set([...o||[]].map(e=>String(e).toLowerCase())),r=[],i=0;for(let e of Array.isArray(p)?p:[]){if(!e||!e.body)continue;let n=V(e.path,e.body);if(t.has(n)){i+=1;continue}t.add(n),r.push({...e,_fp:n,body:`${String(e.body)}${Z(n)}`})}return{toPost:r,skipped:i}}function ne(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let p=te(ee(import.meta.url)),o=re(p,"..","bin","mcp-skill.mjs");return X(o)?o:null}async function u(p,o={}){let{token:t}=await j("github"),r=p.startsWith("https://")?p:`https://api.github.com${p}`,i={Authorization:`Bearer ${t}`,Accept:o.accept||"application/vnd.github.v3+json","User-Agent":"Zibby-App",...o.body?{"Content-Type":"application/json"}:{}},e=await fetch(r,{method:o.method||"GET",headers:i,body:o.body?JSON.stringify(o.body):void 0});if(!e.ok){let n=await e.text().catch(()=>"");throw new Error(`GitHub API ${e.status}: ${n.slice(0,300)}`)}return o.raw?e.text():e.json()}var R={id:"github",serverName:"github",allowedTools:["mcp__github__*"],requiresIntegration:I.GITHUB,envKeys:["GITHUB_TOKEN","PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV"],description:"GitHub \u2014 issues, PRs, commits, code search, file reading",promptFragment:`## GitHub
5
+ <!-- zbreview-summary -->`;function H(p){let o=q.exec(String(p||""));return o?o[1].toLowerCase():null}function J(p){return L.test(String(p||""))}function U(p,o){let t=new Set([...o||[]].map(e=>String(e).toLowerCase())),r=[],i=0;for(let e of Array.isArray(p)?p:[]){if(!e||!e.body)continue;let n=V(e.path,e.body);if(t.has(n)){i+=1;continue}t.add(n),r.push({...e,_fp:n,body:`${String(e.body)}${Z(n)}`})}return{toPost:r,skipped:i}}function ne(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let p=te(ee(import.meta.url)),o=re(p,"..","bin","mcp-skill.mjs");return X(o)?o:null}async function u(p,o={}){let{token:t}=await j("github"),r=p.startsWith("https://")?p:`https://api.github.com${p}`,i={Authorization:`Bearer ${t}`,Accept:o.accept||"application/vnd.github.v3+json","User-Agent":"Zibby-App",...o.body?{"Content-Type":"application/json"}:{}},e=await fetch(r,{method:o.method||"GET",headers:i,body:o.body?JSON.stringify(o.body):void 0});if(!e.ok){let n=await e.text().catch(()=>"");throw new Error(`GitHub API ${e.status}: ${n.slice(0,300)}`)}return o.raw?e.text():e.json()}var R={id:"github",callsBackend:!0,serverName:"github",allowedTools:["mcp__github__*"],requiresIntegration:I.GITHUB,envKeys:["GITHUB_TOKEN","PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV"],description:"GitHub \u2014 issues, PRs, commits, code search, file reading",promptFragment:`## GitHub
6
6
  You have access to the user's GitHub repositories. Available tools:
7
7
 
8
8
  ### Discovery
@@ -16,7 +16,7 @@ ${"#".repeat(i)} ${n.trim()}
16
16
  ${n}
17
17
  `):e.push(n)}return e.join("").replace(/\n{3,}/g,`
18
18
 
19
- `)}function T(r){return String(r||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function H(r){return T(r).replace(/[a-z0-9]+/g,"")}function D(r,s){let e=T(r),t=T(s);if(!e||!t)return 0;if(e===t)return 1;if(e.length===1||t.length===1)return e===t?1:0;let n=l=>{let p=new Map;for(let m=0;m<l.length-1;m++){let g=l.slice(m,m+2);p.set(g,(p.get(g)||0)+1)}return p},i=n(e),o=n(t),a=0,c=0,u=0;for(let l of i.values())c+=l;for(let l of o.values())u+=l;for(let[l,p]of i.entries()){let m=o.get(l)||0;a+=Math.min(p,m)}return 2*a/Math.max(1,c+u)}function I(r){return String(r||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function qe(r,s=[]){let e=Array.isArray(s)?s:[];if(e.length===0)return{requested:r||null,resolved:null,strategy:"none"};let t=e.filter(a=>!a.subtask),n=t.length>0?t:e,i=I(r);if(i){let a=n.find(l=>I(l.name)===i);if(a)return{requested:r,resolved:a,strategy:"exact"};let c={task:["task","\u4EFB\u52A1","\u4E8B\u9879","to do","todo"],story:["story","\u7528\u6237\u6545\u4E8B","\u9700\u6C42"],bug:["bug","\u7F3A\u9677","\u95EE\u9898"],improvement:["improvement","\u4F18\u5316","\u6539\u8FDB"],epic:["epic","\u53F2\u8BD7"]};for(let l of Object.values(c)){if(!l.some(m=>I(m)===i))continue;let p=n.find(m=>l.some(g=>I(g)===I(m.name)));if(p)return{requested:r,resolved:p,strategy:"alias"}}let u=n.map(l=>({t:l,score:D(r,l.name)})).sort((l,p)=>p.score-l.score);if(u[0]&&u[0].score>=.5)return{requested:r,resolved:u[0].t,strategy:"fuzzy"}}let o=["task","story","bug","improvement","epic"];for(let a of o){let c=n.find(u=>I(u.name)===a);if(c)return{requested:r||null,resolved:c,strategy:"default-preferred"}}return{requested:r||null,resolved:n[0],strategy:"default-first"}}async function ae(r){let s=`projectKeys=${encodeURIComponent(r)}&expand=projects.issuetypes`,e=await w(`/rest/api/3/issue/createmeta?${s}`),t=Array.isArray(e?.projects)?e.projects:[],i=t.find(a=>String(a?.key||"").toUpperCase()===String(r||"").toUpperCase())||t[0]||null;return(Array.isArray(i?.issuetypes)?i.issuetypes:[]).map(a=>({id:a.id,name:a.name,subtask:!!a.subtask,description:a.description||null}))}async function ce(r,s){if(!r)throw new Error("projectKey is required");let e="sprint is not EMPTY";s==="active"?e="sprint in openSprints()":s==="closed"?e="sprint in closedSprints()":s==="future"&&(e="sprint in futureSprints()");let t=`project = ${r} AND ${e} ORDER BY updated DESC`,n=`jql=${encodeURIComponent(t)}&maxResults=100&fields=customfield_10020`,i=await w(`/rest/api/3/search/jql?${n}`),o=new Map;for(let a of i.issues||[])for(let c of a.fields?.customfield_10020||[])c&&!o.has(c.id)&&o.set(c.id,{id:c.id,name:c.name,state:c.state,boardId:c.boardId||null,startDate:c.startDate||null,endDate:c.endDate||null,goal:c.goal||null});return[...o.values()].sort((a,c)=>{let u={active:0,future:1,closed:2},l=(u[a.state]??3)-(u[c.state]??3);return l!==0?l:String(c.startDate||"").localeCompare(String(a.startDate||""))})}function Je(r,{sprintId:s,sprintName:e,target:t}={}){let n=Array.isArray(r)?r:[];if(!n.length)return{sprint:null,selectedBy:"none"};if(s!=null&&String(s).trim()!=="")return{sprint:n.find(a=>String(a.id)===String(s))||null,selectedBy:"id"};if(e&&String(e).trim()){let o=String(e).trim(),a=n.find(u=>String(u.name||"").toLowerCase()===o.toLowerCase());if(a)return{sprint:a,selectedBy:"name-exact"};let c=n.map(u=>({s:u,score:D(o,u.name||"")})).sort((u,l)=>l.score-u.score);return c[0]&&c[0].score>=.5?{sprint:c[0].s,selectedBy:"name-fuzzy"}:{sprint:null,selectedBy:"name-none"}}let i=String(t||"current").trim().toLowerCase();return i==="active"||i==="current"||i==="latest"?{sprint:n[0],selectedBy:i}:{sprint:n[0],selectedBy:"default"}}function xe(r,s){let e=r?.fields?.customfield_10020;return Array.isArray(e)?e.some(t=>String(t?.id)===String(s)):!1}async function Ue({issueKey:r,projectKey:s,sprintId:e,attempts:t=3,delayMs:n=450}){let i=[];for(let o=0;o<t;o++){try{let a=`project = ${s} AND key = ${r} AND sprint = ${e}`,c=`jql=${encodeURIComponent(a)}&maxResults=1&fields=key,status`,u=await w(`/rest/api/3/search/jql?${c}`);if(Number(u?.total||0)>0)return i.push({attempt:o+1,jql:!0,issueField:null}),{ok:!0,method:"jql",traces:i};let p=await w(`/rest/api/3/issue/${r}?fields=customfield_10020,status`),m=xe(p,e);if(i.push({attempt:o+1,jql:!1,issueField:m}),m)return{ok:!0,method:"issue_field",traces:i}}catch(a){i.push({attempt:o+1,error:String(a?.message||a)})}o<t-1&&await new Promise(a=>setTimeout(a,n))}return{ok:!1,method:"none",traces:i}}async function B({issueKey:r,projectKey:s,sprintId:e,sprintName:t,target:n}){if(!r)return{ok:!1,error:"issueKey is required"};let i=s;if(!i&&(i=(await w(`/rest/api/3/issue/${r}?fields=project`))?.fields?.project?.key||null,!i))return{ok:!1,error:`Could not resolve project for ${r}`};let o=await ce(i,"active");if(!o.length)return{ok:!1,error:`No assignable active sprint found for project ${i}`};let{sprint:a,selectedBy:c}=Je(o,{sprintId:e,sprintName:t,target:n});if(!a)return{ok:!1,error:`No matching sprint found in ${i}`,requested:{sprintId:e??null,sprintName:t??null,target:n??"current"},availableSprints:o.map(p=>({id:p.id,name:p.name,state:p.state}))};await w(`/rest/api/3/issue/${r}`,{method:"PUT",body:{fields:{customfield_10020:Number(a.id)}}});let u=await Ue({issueKey:r,projectKey:i,sprintId:a.id}),l=u.ok;return{ok:l,issueKey:r,projectKey:i,sprintId:a.id,sprintName:a.name,selectedBy:c,verifiedBy:u.method,verified:l,verificationTrace:u.traces,warning:l?null:`Sprint assignment attempted but verification did not find ${r} in sprint ${a.id}`}}async function w(r,s={}){let e=async()=>{let{token:t,cloudId:n}=await je("jira");if(typeof t!="string"||!t)throw new Error(`Invalid jira token type: ${typeof t}`);if(!n)throw new Error("Invalid jira cloudId: missing");let i=`https://api.atlassian.com/ex/jira/${n}${r}`,o=await fetch(i,{method:s.method||"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/json",...s.body?{"Content-Type":"application/json"}:{},...s.headers},body:s.body?JSON.stringify(s.body):void 0});if(!o.ok){let c=await o.text().catch(()=>"");throw new Error(`Jira API ${o.status}: ${c.slice(0,300)}`)}let a=await o.text().catch(()=>"");if(!a||!a.trim())return{};try{return JSON.parse(a)}catch{return{raw:a}}};try{return await e()}catch(t){let n=String(t?.message||t||"").toLowerCase();if(!(n.includes("token")||n.includes("401")||n.includes("403")||n.includes("substring")))throw t;return Ee("jira"),e()}}var q={id:"jira",serverName:"jira",allowedTools:["mcp__jira__*"],requiresIntegration:E.JIRA,envKeys:["ATLASSIAN_ACCESS_TOKEN","ATLASSIAN_CLOUD_ID"],description:"Zibby Jira MCP Server (OAuth Bearer)",promptFragment:`## Jira
19
+ `)}function T(r){return String(r||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function H(r){return T(r).replace(/[a-z0-9]+/g,"")}function D(r,s){let e=T(r),t=T(s);if(!e||!t)return 0;if(e===t)return 1;if(e.length===1||t.length===1)return e===t?1:0;let n=l=>{let p=new Map;for(let m=0;m<l.length-1;m++){let g=l.slice(m,m+2);p.set(g,(p.get(g)||0)+1)}return p},i=n(e),o=n(t),a=0,c=0,u=0;for(let l of i.values())c+=l;for(let l of o.values())u+=l;for(let[l,p]of i.entries()){let m=o.get(l)||0;a+=Math.min(p,m)}return 2*a/Math.max(1,c+u)}function I(r){return String(r||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function qe(r,s=[]){let e=Array.isArray(s)?s:[];if(e.length===0)return{requested:r||null,resolved:null,strategy:"none"};let t=e.filter(a=>!a.subtask),n=t.length>0?t:e,i=I(r);if(i){let a=n.find(l=>I(l.name)===i);if(a)return{requested:r,resolved:a,strategy:"exact"};let c={task:["task","\u4EFB\u52A1","\u4E8B\u9879","to do","todo"],story:["story","\u7528\u6237\u6545\u4E8B","\u9700\u6C42"],bug:["bug","\u7F3A\u9677","\u95EE\u9898"],improvement:["improvement","\u4F18\u5316","\u6539\u8FDB"],epic:["epic","\u53F2\u8BD7"]};for(let l of Object.values(c)){if(!l.some(m=>I(m)===i))continue;let p=n.find(m=>l.some(g=>I(g)===I(m.name)));if(p)return{requested:r,resolved:p,strategy:"alias"}}let u=n.map(l=>({t:l,score:D(r,l.name)})).sort((l,p)=>p.score-l.score);if(u[0]&&u[0].score>=.5)return{requested:r,resolved:u[0].t,strategy:"fuzzy"}}let o=["task","story","bug","improvement","epic"];for(let a of o){let c=n.find(u=>I(u.name)===a);if(c)return{requested:r||null,resolved:c,strategy:"default-preferred"}}return{requested:r||null,resolved:n[0],strategy:"default-first"}}async function ae(r){let s=`projectKeys=${encodeURIComponent(r)}&expand=projects.issuetypes`,e=await w(`/rest/api/3/issue/createmeta?${s}`),t=Array.isArray(e?.projects)?e.projects:[],i=t.find(a=>String(a?.key||"").toUpperCase()===String(r||"").toUpperCase())||t[0]||null;return(Array.isArray(i?.issuetypes)?i.issuetypes:[]).map(a=>({id:a.id,name:a.name,subtask:!!a.subtask,description:a.description||null}))}async function ce(r,s){if(!r)throw new Error("projectKey is required");let e="sprint is not EMPTY";s==="active"?e="sprint in openSprints()":s==="closed"?e="sprint in closedSprints()":s==="future"&&(e="sprint in futureSprints()");let t=`project = ${r} AND ${e} ORDER BY updated DESC`,n=`jql=${encodeURIComponent(t)}&maxResults=100&fields=customfield_10020`,i=await w(`/rest/api/3/search/jql?${n}`),o=new Map;for(let a of i.issues||[])for(let c of a.fields?.customfield_10020||[])c&&!o.has(c.id)&&o.set(c.id,{id:c.id,name:c.name,state:c.state,boardId:c.boardId||null,startDate:c.startDate||null,endDate:c.endDate||null,goal:c.goal||null});return[...o.values()].sort((a,c)=>{let u={active:0,future:1,closed:2},l=(u[a.state]??3)-(u[c.state]??3);return l!==0?l:String(c.startDate||"").localeCompare(String(a.startDate||""))})}function Je(r,{sprintId:s,sprintName:e,target:t}={}){let n=Array.isArray(r)?r:[];if(!n.length)return{sprint:null,selectedBy:"none"};if(s!=null&&String(s).trim()!=="")return{sprint:n.find(a=>String(a.id)===String(s))||null,selectedBy:"id"};if(e&&String(e).trim()){let o=String(e).trim(),a=n.find(u=>String(u.name||"").toLowerCase()===o.toLowerCase());if(a)return{sprint:a,selectedBy:"name-exact"};let c=n.map(u=>({s:u,score:D(o,u.name||"")})).sort((u,l)=>l.score-u.score);return c[0]&&c[0].score>=.5?{sprint:c[0].s,selectedBy:"name-fuzzy"}:{sprint:null,selectedBy:"name-none"}}let i=String(t||"current").trim().toLowerCase();return i==="active"||i==="current"||i==="latest"?{sprint:n[0],selectedBy:i}:{sprint:n[0],selectedBy:"default"}}function xe(r,s){let e=r?.fields?.customfield_10020;return Array.isArray(e)?e.some(t=>String(t?.id)===String(s)):!1}async function Ue({issueKey:r,projectKey:s,sprintId:e,attempts:t=3,delayMs:n=450}){let i=[];for(let o=0;o<t;o++){try{let a=`project = ${s} AND key = ${r} AND sprint = ${e}`,c=`jql=${encodeURIComponent(a)}&maxResults=1&fields=key,status`,u=await w(`/rest/api/3/search/jql?${c}`);if(Number(u?.total||0)>0)return i.push({attempt:o+1,jql:!0,issueField:null}),{ok:!0,method:"jql",traces:i};let p=await w(`/rest/api/3/issue/${r}?fields=customfield_10020,status`),m=xe(p,e);if(i.push({attempt:o+1,jql:!1,issueField:m}),m)return{ok:!0,method:"issue_field",traces:i}}catch(a){i.push({attempt:o+1,error:String(a?.message||a)})}o<t-1&&await new Promise(a=>setTimeout(a,n))}return{ok:!1,method:"none",traces:i}}async function B({issueKey:r,projectKey:s,sprintId:e,sprintName:t,target:n}){if(!r)return{ok:!1,error:"issueKey is required"};let i=s;if(!i&&(i=(await w(`/rest/api/3/issue/${r}?fields=project`))?.fields?.project?.key||null,!i))return{ok:!1,error:`Could not resolve project for ${r}`};let o=await ce(i,"active");if(!o.length)return{ok:!1,error:`No assignable active sprint found for project ${i}`};let{sprint:a,selectedBy:c}=Je(o,{sprintId:e,sprintName:t,target:n});if(!a)return{ok:!1,error:`No matching sprint found in ${i}`,requested:{sprintId:e??null,sprintName:t??null,target:n??"current"},availableSprints:o.map(p=>({id:p.id,name:p.name,state:p.state}))};await w(`/rest/api/3/issue/${r}`,{method:"PUT",body:{fields:{customfield_10020:Number(a.id)}}});let u=await Ue({issueKey:r,projectKey:i,sprintId:a.id}),l=u.ok;return{ok:l,issueKey:r,projectKey:i,sprintId:a.id,sprintName:a.name,selectedBy:c,verifiedBy:u.method,verified:l,verificationTrace:u.traces,warning:l?null:`Sprint assignment attempted but verification did not find ${r} in sprint ${a.id}`}}async function w(r,s={}){let e=async()=>{let{token:t,cloudId:n}=await je("jira");if(typeof t!="string"||!t)throw new Error(`Invalid jira token type: ${typeof t}`);if(!n)throw new Error("Invalid jira cloudId: missing");let i=`https://api.atlassian.com/ex/jira/${n}${r}`,o=await fetch(i,{method:s.method||"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/json",...s.body?{"Content-Type":"application/json"}:{},...s.headers},body:s.body?JSON.stringify(s.body):void 0});if(!o.ok){let c=await o.text().catch(()=>"");throw new Error(`Jira API ${o.status}: ${c.slice(0,300)}`)}let a=await o.text().catch(()=>"");if(!a||!a.trim())return{};try{return JSON.parse(a)}catch{return{raw:a}}};try{return await e()}catch(t){let n=String(t?.message||t||"").toLowerCase();if(!(n.includes("token")||n.includes("401")||n.includes("403")||n.includes("substring")))throw t;return Ee("jira"),e()}}var q={id:"jira",callsBackend:!0,serverName:"jira",allowedTools:["mcp__jira__*"],requiresIntegration:E.JIRA,envKeys:["ATLASSIAN_ACCESS_TOKEN","ATLASSIAN_CLOUD_ID"],description:"Zibby Jira MCP Server (OAuth Bearer)",promptFragment:`## Jira
20
20
  You have direct access to the user's Jira. Use these tools proactively:
21
21
 
22
22
  ### Issue tools
@@ -185,7 +185,7 @@ You have direct access to the user's Linear workspace (GraphQL API). Tools:
185
185
 
186
186
  <!-- zbfp:${r} -->`}var me=`
187
187
 
188
- <!-- zbreview-summary -->`;function ye(r){let s=ue.exec(String(r||""));return s?s[1].toLowerCase():null}function fe(r){return de.test(String(r||""))}function ge(r,s){let e=new Set([...s||[]].map(i=>String(i).toLowerCase())),t=[],n=0;for(let i of Array.isArray(r)?r:[]){if(!i||!i.body)continue;let o=rt(i.path,i.body);if(e.has(o)){n+=1;continue}e.add(o),t.push({...i,_fp:o,body:`${String(i.body)}${st(o)}`})}return{toPost:t,skipped:n}}function ct(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=ot(nt(import.meta.url)),s=at(r,"..","bin","mcp-skill.mjs");return it(s)?s:null}async function _(r,s={}){let{token:e}=await he("github"),t=r.startsWith("https://")?r:`https://api.github.com${r}`,n={Authorization:`Bearer ${e}`,Accept:s.accept||"application/vnd.github.v3+json","User-Agent":"Zibby-App",...s.body?{"Content-Type":"application/json"}:{}},i=await fetch(t,{method:s.method||"GET",headers:n,body:s.body?JSON.stringify(s.body):void 0});if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`GitHub API ${i.status}: ${o.slice(0,300)}`)}return s.raw?i.text():i.json()}var R={id:"github",serverName:"github",allowedTools:["mcp__github__*"],requiresIntegration:E.GITHUB,envKeys:["GITHUB_TOKEN","PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV"],description:"GitHub \u2014 issues, PRs, commits, code search, file reading",promptFragment:`## GitHub
188
+ <!-- zbreview-summary -->`;function ye(r){let s=ue.exec(String(r||""));return s?s[1].toLowerCase():null}function fe(r){return de.test(String(r||""))}function ge(r,s){let e=new Set([...s||[]].map(i=>String(i).toLowerCase())),t=[],n=0;for(let i of Array.isArray(r)?r:[]){if(!i||!i.body)continue;let o=rt(i.path,i.body);if(e.has(o)){n+=1;continue}e.add(o),t.push({...i,_fp:o,body:`${String(i.body)}${st(o)}`})}return{toPost:t,skipped:n}}function ct(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=ot(nt(import.meta.url)),s=at(r,"..","bin","mcp-skill.mjs");return it(s)?s:null}async function _(r,s={}){let{token:e}=await he("github"),t=r.startsWith("https://")?r:`https://api.github.com${r}`,n={Authorization:`Bearer ${e}`,Accept:s.accept||"application/vnd.github.v3+json","User-Agent":"Zibby-App",...s.body?{"Content-Type":"application/json"}:{}},i=await fetch(t,{method:s.method||"GET",headers:n,body:s.body?JSON.stringify(s.body):void 0});if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`GitHub API ${i.status}: ${o.slice(0,300)}`)}return s.raw?i.text():i.json()}var R={id:"github",callsBackend:!0,serverName:"github",allowedTools:["mcp__github__*"],requiresIntegration:E.GITHUB,envKeys:["GITHUB_TOKEN","PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV"],description:"GitHub \u2014 issues, PRs, commits, code search, file reading",promptFragment:`## GitHub
189
189
  You have access to the user's GitHub repositories. Available tools:
190
190
 
191
191
  ### Discovery
@@ -16,7 +16,7 @@ ${"#".repeat(n)} ${a.trim()}
16
16
  ${a}
17
17
  `):e.push(a)}return e.join("").replace(/\n{3,}/g,`
18
18
 
19
- `)}function S(s){return String(s||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function A(s){return S(s).replace(/[a-z0-9]+/g,"")}function I(s,r){let e=S(s),t=S(r);if(!e||!t)return 0;if(e===t)return 1;if(e.length===1||t.length===1)return e===t?1:0;let a=u=>{let d=new Map;for(let m=0;m<u.length-1;m++){let g=u.slice(m,m+2);d.set(g,(d.get(g)||0)+1)}return d},n=a(e),o=a(t),i=0,c=0,p=0;for(let u of n.values())c+=u;for(let u of o.values())p+=u;for(let[u,d]of n.entries()){let m=o.get(u)||0;i+=Math.min(d,m)}return 2*i/Math.max(1,c+p)}function b(s){return String(s||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function M(s,r=[]){let e=Array.isArray(r)?r:[];if(e.length===0)return{requested:s||null,resolved:null,strategy:"none"};let t=e.filter(i=>!i.subtask),a=t.length>0?t:e,n=b(s);if(n){let i=a.find(u=>b(u.name)===n);if(i)return{requested:s,resolved:i,strategy:"exact"};let c={task:["task","\u4EFB\u52A1","\u4E8B\u9879","to do","todo"],story:["story","\u7528\u6237\u6545\u4E8B","\u9700\u6C42"],bug:["bug","\u7F3A\u9677","\u95EE\u9898"],improvement:["improvement","\u4F18\u5316","\u6539\u8FDB"],epic:["epic","\u53F2\u8BD7"]};for(let u of Object.values(c)){if(!u.some(m=>b(m)===n))continue;let d=a.find(m=>u.some(g=>b(g)===b(m.name)));if(d)return{requested:s,resolved:d,strategy:"alias"}}let p=a.map(u=>({t:u,score:I(s,u.name)})).sort((u,d)=>d.score-u.score);if(p[0]&&p[0].score>=.5)return{requested:s,resolved:p[0].t,strategy:"fuzzy"}}let o=["task","story","bug","improvement","epic"];for(let i of o){let c=a.find(p=>b(p.name)===i);if(c)return{requested:s||null,resolved:c,strategy:"default-preferred"}}return{requested:s||null,resolved:a[0],strategy:"default-first"}}async function P(s){let r=`projectKeys=${encodeURIComponent(s)}&expand=projects.issuetypes`,e=await y(`/rest/api/3/issue/createmeta?${r}`),t=Array.isArray(e?.projects)?e.projects:[],n=t.find(i=>String(i?.key||"").toUpperCase()===String(s||"").toUpperCase())||t[0]||null;return(Array.isArray(n?.issuetypes)?n.issuetypes:[]).map(i=>({id:i.id,name:i.name,subtask:!!i.subtask,description:i.description||null}))}async function q(s,r){if(!s)throw new Error("projectKey is required");let e="sprint is not EMPTY";r==="active"?e="sprint in openSprints()":r==="closed"?e="sprint in closedSprints()":r==="future"&&(e="sprint in futureSprints()");let t=`project = ${s} AND ${e} ORDER BY updated DESC`,a=`jql=${encodeURIComponent(t)}&maxResults=100&fields=customfield_10020`,n=await y(`/rest/api/3/search/jql?${a}`),o=new Map;for(let i of n.issues||[])for(let c of i.fields?.customfield_10020||[])c&&!o.has(c.id)&&o.set(c.id,{id:c.id,name:c.name,state:c.state,boardId:c.boardId||null,startDate:c.startDate||null,endDate:c.endDate||null,goal:c.goal||null});return[...o.values()].sort((i,c)=>{let p={active:0,future:1,closed:2},u=(p[i.state]??3)-(p[c.state]??3);return u!==0?u:String(c.startDate||"").localeCompare(String(i.startDate||""))})}function G(s,{sprintId:r,sprintName:e,target:t}={}){let a=Array.isArray(s)?s:[];if(!a.length)return{sprint:null,selectedBy:"none"};if(r!=null&&String(r).trim()!=="")return{sprint:a.find(i=>String(i.id)===String(r))||null,selectedBy:"id"};if(e&&String(e).trim()){let o=String(e).trim(),i=a.find(p=>String(p.name||"").toLowerCase()===o.toLowerCase());if(i)return{sprint:i,selectedBy:"name-exact"};let c=a.map(p=>({s:p,score:I(o,p.name||"")})).sort((p,u)=>u.score-p.score);return c[0]&&c[0].score>=.5?{sprint:c[0].s,selectedBy:"name-fuzzy"}:{sprint:null,selectedBy:"name-none"}}let n=String(t||"current").trim().toLowerCase();return n==="active"||n==="current"||n==="latest"?{sprint:a[0],selectedBy:n}:{sprint:a[0],selectedBy:"default"}}function Y(s,r){let e=s?.fields?.customfield_10020;return Array.isArray(e)?e.some(t=>String(t?.id)===String(r)):!1}async function F({issueKey:s,projectKey:r,sprintId:e,attempts:t=3,delayMs:a=450}){let n=[];for(let o=0;o<t;o++){try{let i=`project = ${r} AND key = ${s} AND sprint = ${e}`,c=`jql=${encodeURIComponent(i)}&maxResults=1&fields=key,status`,p=await y(`/rest/api/3/search/jql?${c}`);if(Number(p?.total||0)>0)return n.push({attempt:o+1,jql:!0,issueField:null}),{ok:!0,method:"jql",traces:n};let d=await y(`/rest/api/3/issue/${s}?fields=customfield_10020,status`),m=Y(d,e);if(n.push({attempt:o+1,jql:!1,issueField:m}),m)return{ok:!0,method:"issue_field",traces:n}}catch(i){n.push({attempt:o+1,error:String(i?.message||i)})}o<t-1&&await new Promise(i=>setTimeout(i,a))}return{ok:!1,method:"none",traces:n}}async function N({issueKey:s,projectKey:r,sprintId:e,sprintName:t,target:a}){if(!s)return{ok:!1,error:"issueKey is required"};let n=r;if(!n&&(n=(await y(`/rest/api/3/issue/${s}?fields=project`))?.fields?.project?.key||null,!n))return{ok:!1,error:`Could not resolve project for ${s}`};let o=await q(n,"active");if(!o.length)return{ok:!1,error:`No assignable active sprint found for project ${n}`};let{sprint:i,selectedBy:c}=G(o,{sprintId:e,sprintName:t,target:a});if(!i)return{ok:!1,error:`No matching sprint found in ${n}`,requested:{sprintId:e??null,sprintName:t??null,target:a??"current"},availableSprints:o.map(d=>({id:d.id,name:d.name,state:d.state}))};await y(`/rest/api/3/issue/${s}`,{method:"PUT",body:{fields:{customfield_10020:Number(i.id)}}});let p=await F({issueKey:s,projectKey:n,sprintId:i.id}),u=p.ok;return{ok:u,issueKey:s,projectKey:n,sprintId:i.id,sprintName:i.name,selectedBy:c,verifiedBy:p.method,verified:u,verificationTrace:p.traces,warning:u?null:`Sprint assignment attempted but verification did not find ${s} in sprint ${i.id}`}}async function y(s,r={}){let e=async()=>{let{token:t,cloudId:a}=await E("jira");if(typeof t!="string"||!t)throw new Error(`Invalid jira token type: ${typeof t}`);if(!a)throw new Error("Invalid jira cloudId: missing");let n=`https://api.atlassian.com/ex/jira/${a}${s}`,o=await fetch(n,{method:r.method||"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/json",...r.body?{"Content-Type":"application/json"}:{},...r.headers},body:r.body?JSON.stringify(r.body):void 0});if(!o.ok){let c=await o.text().catch(()=>"");throw new Error(`Jira API ${o.status}: ${c.slice(0,300)}`)}let i=await o.text().catch(()=>"");if(!i||!i.trim())return{};try{return JSON.parse(i)}catch{return{raw:i}}};try{return await e()}catch(t){let a=String(t?.message||t||"").toLowerCase();if(!(a.includes("token")||a.includes("401")||a.includes("403")||a.includes("substring")))throw t;return L("jira"),e()}}var v={id:"jira",serverName:"jira",allowedTools:["mcp__jira__*"],requiresIntegration:C.JIRA,envKeys:["ATLASSIAN_ACCESS_TOKEN","ATLASSIAN_CLOUD_ID"],description:"Zibby Jira MCP Server (OAuth Bearer)",promptFragment:`## Jira
19
+ `)}function S(s){return String(s||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function A(s){return S(s).replace(/[a-z0-9]+/g,"")}function I(s,r){let e=S(s),t=S(r);if(!e||!t)return 0;if(e===t)return 1;if(e.length===1||t.length===1)return e===t?1:0;let a=u=>{let d=new Map;for(let m=0;m<u.length-1;m++){let g=u.slice(m,m+2);d.set(g,(d.get(g)||0)+1)}return d},n=a(e),o=a(t),i=0,c=0,p=0;for(let u of n.values())c+=u;for(let u of o.values())p+=u;for(let[u,d]of n.entries()){let m=o.get(u)||0;i+=Math.min(d,m)}return 2*i/Math.max(1,c+p)}function b(s){return String(s||"").toLowerCase().replace(/\s+/g,"").replace(/[()\-_::"'`]/g,"")}function M(s,r=[]){let e=Array.isArray(r)?r:[];if(e.length===0)return{requested:s||null,resolved:null,strategy:"none"};let t=e.filter(i=>!i.subtask),a=t.length>0?t:e,n=b(s);if(n){let i=a.find(u=>b(u.name)===n);if(i)return{requested:s,resolved:i,strategy:"exact"};let c={task:["task","\u4EFB\u52A1","\u4E8B\u9879","to do","todo"],story:["story","\u7528\u6237\u6545\u4E8B","\u9700\u6C42"],bug:["bug","\u7F3A\u9677","\u95EE\u9898"],improvement:["improvement","\u4F18\u5316","\u6539\u8FDB"],epic:["epic","\u53F2\u8BD7"]};for(let u of Object.values(c)){if(!u.some(m=>b(m)===n))continue;let d=a.find(m=>u.some(g=>b(g)===b(m.name)));if(d)return{requested:s,resolved:d,strategy:"alias"}}let p=a.map(u=>({t:u,score:I(s,u.name)})).sort((u,d)=>d.score-u.score);if(p[0]&&p[0].score>=.5)return{requested:s,resolved:p[0].t,strategy:"fuzzy"}}let o=["task","story","bug","improvement","epic"];for(let i of o){let c=a.find(p=>b(p.name)===i);if(c)return{requested:s||null,resolved:c,strategy:"default-preferred"}}return{requested:s||null,resolved:a[0],strategy:"default-first"}}async function P(s){let r=`projectKeys=${encodeURIComponent(s)}&expand=projects.issuetypes`,e=await y(`/rest/api/3/issue/createmeta?${r}`),t=Array.isArray(e?.projects)?e.projects:[],n=t.find(i=>String(i?.key||"").toUpperCase()===String(s||"").toUpperCase())||t[0]||null;return(Array.isArray(n?.issuetypes)?n.issuetypes:[]).map(i=>({id:i.id,name:i.name,subtask:!!i.subtask,description:i.description||null}))}async function q(s,r){if(!s)throw new Error("projectKey is required");let e="sprint is not EMPTY";r==="active"?e="sprint in openSprints()":r==="closed"?e="sprint in closedSprints()":r==="future"&&(e="sprint in futureSprints()");let t=`project = ${s} AND ${e} ORDER BY updated DESC`,a=`jql=${encodeURIComponent(t)}&maxResults=100&fields=customfield_10020`,n=await y(`/rest/api/3/search/jql?${a}`),o=new Map;for(let i of n.issues||[])for(let c of i.fields?.customfield_10020||[])c&&!o.has(c.id)&&o.set(c.id,{id:c.id,name:c.name,state:c.state,boardId:c.boardId||null,startDate:c.startDate||null,endDate:c.endDate||null,goal:c.goal||null});return[...o.values()].sort((i,c)=>{let p={active:0,future:1,closed:2},u=(p[i.state]??3)-(p[c.state]??3);return u!==0?u:String(c.startDate||"").localeCompare(String(i.startDate||""))})}function G(s,{sprintId:r,sprintName:e,target:t}={}){let a=Array.isArray(s)?s:[];if(!a.length)return{sprint:null,selectedBy:"none"};if(r!=null&&String(r).trim()!=="")return{sprint:a.find(i=>String(i.id)===String(r))||null,selectedBy:"id"};if(e&&String(e).trim()){let o=String(e).trim(),i=a.find(p=>String(p.name||"").toLowerCase()===o.toLowerCase());if(i)return{sprint:i,selectedBy:"name-exact"};let c=a.map(p=>({s:p,score:I(o,p.name||"")})).sort((p,u)=>u.score-p.score);return c[0]&&c[0].score>=.5?{sprint:c[0].s,selectedBy:"name-fuzzy"}:{sprint:null,selectedBy:"name-none"}}let n=String(t||"current").trim().toLowerCase();return n==="active"||n==="current"||n==="latest"?{sprint:a[0],selectedBy:n}:{sprint:a[0],selectedBy:"default"}}function Y(s,r){let e=s?.fields?.customfield_10020;return Array.isArray(e)?e.some(t=>String(t?.id)===String(r)):!1}async function F({issueKey:s,projectKey:r,sprintId:e,attempts:t=3,delayMs:a=450}){let n=[];for(let o=0;o<t;o++){try{let i=`project = ${r} AND key = ${s} AND sprint = ${e}`,c=`jql=${encodeURIComponent(i)}&maxResults=1&fields=key,status`,p=await y(`/rest/api/3/search/jql?${c}`);if(Number(p?.total||0)>0)return n.push({attempt:o+1,jql:!0,issueField:null}),{ok:!0,method:"jql",traces:n};let d=await y(`/rest/api/3/issue/${s}?fields=customfield_10020,status`),m=Y(d,e);if(n.push({attempt:o+1,jql:!1,issueField:m}),m)return{ok:!0,method:"issue_field",traces:n}}catch(i){n.push({attempt:o+1,error:String(i?.message||i)})}o<t-1&&await new Promise(i=>setTimeout(i,a))}return{ok:!1,method:"none",traces:n}}async function N({issueKey:s,projectKey:r,sprintId:e,sprintName:t,target:a}){if(!s)return{ok:!1,error:"issueKey is required"};let n=r;if(!n&&(n=(await y(`/rest/api/3/issue/${s}?fields=project`))?.fields?.project?.key||null,!n))return{ok:!1,error:`Could not resolve project for ${s}`};let o=await q(n,"active");if(!o.length)return{ok:!1,error:`No assignable active sprint found for project ${n}`};let{sprint:i,selectedBy:c}=G(o,{sprintId:e,sprintName:t,target:a});if(!i)return{ok:!1,error:`No matching sprint found in ${n}`,requested:{sprintId:e??null,sprintName:t??null,target:a??"current"},availableSprints:o.map(d=>({id:d.id,name:d.name,state:d.state}))};await y(`/rest/api/3/issue/${s}`,{method:"PUT",body:{fields:{customfield_10020:Number(i.id)}}});let p=await F({issueKey:s,projectKey:n,sprintId:i.id}),u=p.ok;return{ok:u,issueKey:s,projectKey:n,sprintId:i.id,sprintName:i.name,selectedBy:c,verifiedBy:p.method,verified:u,verificationTrace:p.traces,warning:u?null:`Sprint assignment attempted but verification did not find ${s} in sprint ${i.id}`}}async function y(s,r={}){let e=async()=>{let{token:t,cloudId:a}=await E("jira");if(typeof t!="string"||!t)throw new Error(`Invalid jira token type: ${typeof t}`);if(!a)throw new Error("Invalid jira cloudId: missing");let n=`https://api.atlassian.com/ex/jira/${a}${s}`,o=await fetch(n,{method:r.method||"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/json",...r.body?{"Content-Type":"application/json"}:{},...r.headers},body:r.body?JSON.stringify(r.body):void 0});if(!o.ok){let c=await o.text().catch(()=>"");throw new Error(`Jira API ${o.status}: ${c.slice(0,300)}`)}let i=await o.text().catch(()=>"");if(!i||!i.trim())return{};try{return JSON.parse(i)}catch{return{raw:i}}};try{return await e()}catch(t){let a=String(t?.message||t||"").toLowerCase();if(!(a.includes("token")||a.includes("401")||a.includes("403")||a.includes("substring")))throw t;return L("jira"),e()}}var v={id:"jira",callsBackend:!0,serverName:"jira",allowedTools:["mcp__jira__*"],requiresIntegration:C.JIRA,envKeys:["ATLASSIAN_ACCESS_TOKEN","ATLASSIAN_CLOUD_ID"],description:"Zibby Jira MCP Server (OAuth Bearer)",promptFragment:`## Jira
20
20
  You have direct access to the user's Jira. Use these tools proactively:
21
21
 
22
22
  ### Issue tools
@@ -1 +1 @@
1
- import{dirname as f,resolve as d}from"path";import{fileURLToPath as u}from"url";import{existsSync as h}from"fs";function T(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=f(u(import.meta.url)),e=d(r,"..","bin","mcp-skill.mjs");return h(e)?e:null}function y(){return process.env.PROJECT_API_TOKEN||process.env.ZIBBY_USER_TOKEN||null}function _(){return((process.env.PROGRESS_API_URL||"").replace(/\/executions\/?$/,"")||process.env.ZIBBY_ACCOUNT_API_URL||process.env.ZIBBY_PROD_ACCOUNT_API_URL||(process.env.ZIBBY_ENV==="local"?"http://localhost:3001":"https://api-prod.zibby.app")).replace(/\/+$/,"")}var w={name:"trigger_agent",description:"Trigger another Zibby workflow/agent run in THIS project (fire-and-forget). Call it once per run you want to start \u2014 the agent decides which and how many. Omit workflowType to re-run THIS same agent (self-dispatch, e.g. with a different trigger input). Returns the started run's executionId; does NOT wait for it to finish.",input_schema:{type:"object",properties:{workflowType:{type:"string",description:"Which workflow to trigger (its type/slug in this project). Omit to trigger THIS same agent (self-dispatch)."},input:{type:"object",description:"The trigger payload passed to the target workflow (validated against its state schema)."}},required:[]}},k={id:"trigger-agent",serverName:"trigger",allowedTools:["mcp__trigger__*"],envKeys:[],description:"Trigger another Zibby workflow/agent run in this project (agent-driven, fire-and-forget; cloud + self-hosted).",promptFragment:"## Trigger another agent (agent-driven)\nYou can start another Zibby agent run yourself with the `trigger_agent`\ntool \u2014 and YOU decide when and how many times to call it. Each call starts ONE\nindependent run (fire-and-forget) and returns its executionId; it does NOT wait for\nthat run to finish.\n- To re-run THIS same agent (self-dispatch) \u2014 e.g. to hand an item to another of\n this agent's scenarios \u2014 OMIT `workflowType` and pass the `input` for that run.\n- To trigger a DIFFERENT agent in the project, pass its `workflowType` + `input`.\nCall it once per run you want to start (loop over your items and call it for each).\nIt never throws \u2014 a failure comes back as { ok:false, error }; log it and move on.",resolve(){let r=T();if(!r)return{command:null,args:[],env:{},description:this.description};let e={};for(let t of["PROJECT_API_TOKEN","PROJECT_ID","WORKFLOW_TYPE","PROGRESS_API_URL","ZIBBY_ACCOUNT_API_URL","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_USER_TOKEN"])process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[r,"../dist/triggerAgent.js","triggerAgentSkill"],env:e,description:this.description,alwaysLoad:!1}},async handleToolCall(r,e={}){if(r!=="trigger_agent")return JSON.stringify({ok:!1,error:`unknown tool: ${r}`});try{let t=process.env.PROJECT_ID,a=y(),s=typeof e.workflowType=="string"&&e.workflowType.trim()?e.workflowType.trim():(process.env.WORKFLOW_TYPE||"").trim();if(!t)return JSON.stringify({ok:!1,error:"PROJECT_ID not set \u2014 cannot resolve the target project."});if(!a)return JSON.stringify({ok:!1,error:"PROJECT_API_TOKEN not set \u2014 cannot authenticate the trigger."});if(!s)return JSON.stringify({ok:!1,error:"No workflowType given and WORKFLOW_TYPE is unset \u2014 nothing to trigger."});let l=`${_()}/projects/${encodeURIComponent(t)}/workflows/${encodeURIComponent(s)}/trigger`,c=new AbortController,g=setTimeout(()=>c.abort(),2e4),n;try{n=await fetch(l,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${a}`},body:JSON.stringify({input:e.input&&typeof e.input=="object"?e.input:{}}),signal:c.signal})}finally{clearTimeout(g)}let i=await n.text().catch(()=>""),o;try{o=i?JSON.parse(i):{}}catch{o={raw:i}}if(!n.ok)return JSON.stringify({ok:!1,error:`trigger failed (HTTP ${n.status})`,detail:o&&(o.error||o.message)||i.slice(0,300)});let p=o.executionId||o.execution?.id||o.id||null;return JSON.stringify({ok:!0,workflowType:s,executionId:p,note:"run started (fire-and-forget)"})}catch(t){return JSON.stringify({ok:!1,error:`trigger_agent failed: ${t?.message||String(t)}`})}},tools:[w]};export{k as triggerAgentSkill};
1
+ import{dirname as f,resolve as d}from"path";import{fileURLToPath as u}from"url";import{existsSync as h}from"fs";function T(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=f(u(import.meta.url)),e=d(r,"..","bin","mcp-skill.mjs");return h(e)?e:null}function y(){return process.env.PROJECT_API_TOKEN||process.env.ZIBBY_USER_TOKEN||null}function _(){return((process.env.PROGRESS_API_URL||"").replace(/\/executions\/?$/,"")||process.env.ZIBBY_ACCOUNT_API_URL||process.env.ZIBBY_PROD_ACCOUNT_API_URL||(process.env.ZIBBY_ENV==="local"?"http://localhost:3001":"https://api-prod.zibby.app")).replace(/\/+$/,"")}var w={name:"trigger_agent",description:"Trigger another Zibby workflow/agent run in THIS project (fire-and-forget). Call it once per run you want to start \u2014 the agent decides which and how many. Omit workflowType to re-run THIS same agent (self-dispatch, e.g. with a different trigger input). Returns the started run's executionId; does NOT wait for it to finish.",input_schema:{type:"object",properties:{workflowType:{type:"string",description:"Which workflow to trigger (its type/slug in this project). Omit to trigger THIS same agent (self-dispatch)."},input:{type:"object",description:"The trigger payload passed to the target workflow (validated against its state schema)."}},required:[]}},k={id:"trigger-agent",callsBackend:!0,serverName:"trigger",allowedTools:["mcp__trigger__*"],envKeys:[],description:"Trigger another Zibby workflow/agent run in this project (agent-driven, fire-and-forget; cloud + self-hosted).",promptFragment:"## Trigger another agent (agent-driven)\nYou can start another Zibby agent run yourself with the `trigger_agent`\ntool \u2014 and YOU decide when and how many times to call it. Each call starts ONE\nindependent run (fire-and-forget) and returns its executionId; it does NOT wait for\nthat run to finish.\n- To re-run THIS same agent (self-dispatch) \u2014 e.g. to hand an item to another of\n this agent's scenarios \u2014 OMIT `workflowType` and pass the `input` for that run.\n- To trigger a DIFFERENT agent in the project, pass its `workflowType` + `input`.\nCall it once per run you want to start (loop over your items and call it for each).\nIt never throws \u2014 a failure comes back as { ok:false, error }; log it and move on.",resolve(){let r=T();if(!r)return{command:null,args:[],env:{},description:this.description};let e={};for(let t of["PROJECT_API_TOKEN","PROJECT_ID","WORKFLOW_TYPE","PROGRESS_API_URL","ZIBBY_ACCOUNT_API_URL","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_USER_TOKEN"])process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[r,"../dist/triggerAgent.js","triggerAgentSkill"],env:e,description:this.description,alwaysLoad:!1}},async handleToolCall(r,e={}){if(r!=="trigger_agent")return JSON.stringify({ok:!1,error:`unknown tool: ${r}`});try{let t=process.env.PROJECT_ID,a=y(),s=typeof e.workflowType=="string"&&e.workflowType.trim()?e.workflowType.trim():(process.env.WORKFLOW_TYPE||"").trim();if(!t)return JSON.stringify({ok:!1,error:"PROJECT_ID not set \u2014 cannot resolve the target project."});if(!a)return JSON.stringify({ok:!1,error:"PROJECT_API_TOKEN not set \u2014 cannot authenticate the trigger."});if(!s)return JSON.stringify({ok:!1,error:"No workflowType given and WORKFLOW_TYPE is unset \u2014 nothing to trigger."});let l=`${_()}/projects/${encodeURIComponent(t)}/workflows/${encodeURIComponent(s)}/trigger`,c=new AbortController,g=setTimeout(()=>c.abort(),2e4),n;try{n=await fetch(l,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${a}`},body:JSON.stringify({input:e.input&&typeof e.input=="object"?e.input:{}}),signal:c.signal})}finally{clearTimeout(g)}let i=await n.text().catch(()=>""),o;try{o=i?JSON.parse(i):{}}catch{o={raw:i}}if(!n.ok)return JSON.stringify({ok:!1,error:`trigger failed (HTTP ${n.status})`,detail:o&&(o.error||o.message)||i.slice(0,300)});let p=o.executionId||o.execution?.id||o.id||null;return JSON.stringify({ok:!0,workflowType:s,executionId:p,note:"run started (fire-and-forget)"})}catch(t){return JSON.stringify({ok:!1,error:`trigger_agent failed: ${t?.message||String(t)}`})}},tools:[w]};export{k as triggerAgentSkill};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -78,6 +78,7 @@
78
78
  "scripts": {
79
79
  "build": "node ../scripts/build.mjs && npm run build:types",
80
80
  "build:types": "tsc -p tsconfig.types.json",
81
+ "test": "vitest run",
81
82
  "prepack": "node scripts/copy-docs.mjs",
82
83
  "lint": "eslint .",
83
84
  "lint:fix": "eslint --fix ."
@@ -138,10 +139,11 @@
138
139
  },
139
140
  "devDependencies": {
140
141
  "@eslint/js": "^10.0.1",
142
+ "@types/node": "^20.14.0",
141
143
  "esbuild": "^0.28.0",
142
144
  "eslint": "^10.0.2",
143
145
  "globals": "^17.4.0",
144
146
  "typescript": "^5.9.3",
145
- "@types/node": "^20.14.0"
147
+ "vitest": "^4.1.4"
146
148
  }
147
149
  }