@zibby/skills 0.2.9 → 0.2.10

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/artifact.js CHANGED
@@ -1,4 +1,4 @@
1
- import{SKILL_META as b}from"@zibby/skill-ids";import{existsSync as y,readFileSync as k}from"node:fs";import{homedir as O}from"node:os";import{join as g,dirname as _,resolve as v}from"node:path";import{fileURLToPath as S}from"node:url";function T(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let i=_(S(import.meta.url)),t=v(i,"..","bin","mcp-skill.mjs");return y(t)?t:null}function l(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let i=g(O(),".zibby","config.json");return y(i)&&JSON.parse(k(i,"utf-8")).sessionToken||null}catch{return null}}function p(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function N(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function h(i){return`${N()}:artifact:${i}`}async function u(i){let t=l();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Artifacts are only available inside a Zibby run.");let e=await fetch(`${p()}/credits/artifacts`,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!e.ok){let r=await e.text().catch(()=>"");throw new Error(`artifact write failed (${e.status}): ${r.slice(0,300)}`)}return e.json()}async function P(i){let t=l();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Artifacts are only available inside a Zibby run.");let e=await fetch(`${p()}/credits/artifacts/${encodeURIComponent(i)}`,{method:"GET",headers:{Authorization:`Bearer ${t}`}});if(!e.ok){let r=await e.text().catch(()=>"");throw new Error(`artifact get failed (${e.status}): ${r.slice(0,300)}`)}return e.json()}async function f(i,t){let e=l();if(!e)return;let r=await fetch(`${p()}/credits/review-memory`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({op:"store",scope:h(i),content:JSON.stringify(t)})});if(!r.ok){let n=await r.text().catch(()=>"");throw new Error(`artifact index write failed (${r.status}): ${n.slice(0,200)}`)}}async function R(i){let t=l();if(!t)return null;let e=await fetch(`${p()}/credits/review-memory`,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify({op:"recall",scope:h(i)})});if(!e.ok)return null;let r=await e.json().catch(()=>null);if(!r?.found||!r?.memory?.content)return null;try{return JSON.parse(r.memory.content)}catch{return null}}function m(i){return typeof i?.html=="string"&&i.html.length>0?{format:"html",content:i.html}:typeof i?.markdown=="string"&&i.markdown.length>0?{format:"markdown",content:i.markdown}:null}var x={id:"artifact",callsBackend:!0,meta:b.artifact,serverName:"artifact",allowedTools:["mcp__artifact__*"],description:"Artifacts \u2014 publish a self-contained, shareable HTML/Markdown page to Zibby and get back a URL; the index of what you published is your memory.",promptFragment:`## Artifacts (publish a shareable page, remember what you made)
1
+ import{SKILL_META as b}from"@zibby/skill-ids";import{existsSync as m,readFileSync as O}from"node:fs";import{homedir as g}from"node:os";import{join as T,dirname as k,resolve as S}from"node:path";import{fileURLToPath as N}from"node:url";function v(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let i=k(N(import.meta.url)),t=S(i,"..","bin","mcp-skill.mjs");return m(t)?t:null}function l(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let i=T(g(),".zibby","config.json");return m(i)&&JSON.parse(O(i,"utf-8")).sessionToken||null}catch{return null}}function p(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function _(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function y(i){return`${_()}:artifact:${i}`}async function u(i){let t=l();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Artifacts are only available inside a Zibby run.");let e=await fetch(`${p()}/credits/artifacts`,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!e.ok){let r=await e.text().catch(()=>"");throw new Error(`artifact write failed (${e.status}): ${r.slice(0,300)}`)}return e.json()}async function I(i){let t=l();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Artifacts are only available inside a Zibby run.");let e=await fetch(`${p()}/credits/artifacts/${encodeURIComponent(i)}`,{method:"GET",headers:{Authorization:`Bearer ${t}`}});if(!e.ok){let r=await e.text().catch(()=>"");throw new Error(`artifact get failed (${e.status}): ${r.slice(0,300)}`)}return e.json()}async function f(i,t){let e=l();if(!e)return;let r=await fetch(`${p()}/credits/review-memory`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({op:"store",scope:y(i),content:JSON.stringify(t)})});if(!r.ok){let n=await r.text().catch(()=>"");throw new Error(`artifact index write failed (${r.status}): ${n.slice(0,200)}`)}}async function E(i){let t=l();if(!t)return null;let e=await fetch(`${p()}/credits/review-memory`,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify({op:"recall",scope:y(i)})});if(!e.ok)return null;let r=await e.json().catch(()=>null);if(!r?.found||!r?.memory?.content)return null;try{return JSON.parse(r.memory.content)}catch{return null}}function h(i){return typeof i?.html=="string"&&i.html.length>0?{format:"html",content:i.html}:typeof i?.markdown=="string"&&i.markdown.length>0?{format:"markdown",content:i.markdown}:null}var B={id:"artifact",callsBackend:!0,meta:b.artifact,serverName:"artifact",allowedTools:["mcp__artifact__*"],description:"Artifacts \u2014 publish a self-contained, shareable HTML/Markdown page to Zibby and get back a URL; the index of what you published is your memory.",promptFragment:`## Artifacts (publish a shareable page, remember what you made)
2
2
  You can PUBLISH a standalone page \u2014 a status report, a plan, a comparison table,
3
3
  a dashboard-y summary, a diagram, a "here's what I found" write-up \u2014 and get back
4
4
  a shareable URL. The page is a self-contained HTML (or Markdown) document; it is
@@ -6,6 +6,22 @@ sandboxed when viewed (no external network, no ambient credentials), so keep all
6
6
  CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 external URLs will
7
7
  be blocked.
8
8
 
9
+ THE CONTENT COMES FROM THIS CONVERSATION \u2014 NEVER FROM YOUR IMAGINATION.
10
+ When someone says "make me a page / an artifact / a report", they mean THE THING
11
+ YOU WERE JUST TALKING ABOUT. Build the page from what is actually in this
12
+ transcript (or from data you fetch with your tools THIS turn for that specific
13
+ subject). The page is about the USER'S subject matter \u2014 their tickets, their
14
+ repos, their incidents, their data.
15
+
16
+ If you do NOT know what the page should be about \u2014 the request is vague and the
17
+ transcript does not tell you \u2014 then ASK ONE SHORT QUESTION ("which part should I
18
+ turn into a page?") and publish NOTHING. Do NOT fall back on a demo, a sample, a
19
+ placeholder, or a "here's an overview of your account" page, and do NOT go
20
+ inventory the account (projects / agents / integrations) just to have something to
21
+ render. A page the user did not ask for is worse than a question: it wastes the
22
+ link, buries the real answer, and reads as if you ignored them. There is no
23
+ situation in which "\u793A\u4F8B / sample / demo" belongs in a title you publish.
24
+
9
25
  Tools:
10
26
  - artifact_publish: Publish a NEW page. Pass a \`title\` and EITHER \`html\` OR
11
27
  \`markdown\` (not both). Optional \`kind\` (e.g. "report", "plan", "dashboard"),
@@ -19,4 +35,4 @@ Tools:
19
35
  To recall WHAT YOU HAVE ALREADY PUBLISHED, use your kv-memory tool
20
36
  kv_recall_prefix with keyPrefix "artifact:" \u2014 each entry is the index record
21
37
  { id, title, url, kind, createdAt, summary } for a page you made. (Publishing
22
- records this automatically; you don't store it yourself.)`,resolve(){let i=T();if(!i)return{command:null,args:[],env:{},description:this.description};let t={};for(let e of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[e]&&(t[e]=process.env[e]);return{type:"stdio",command:"node",args:[i,"../dist/artifact.js","artifactSkill"],env:t,description:this.description,alwaysLoad:!0}},async handleToolCall(i,t){try{switch(i){case"artifact_publish":{let e=typeof t?.title=="string"?t.title.trim():"";if(!e)return JSON.stringify({error:"title is required"});let r=m(t);if(!r)return JSON.stringify({error:"provide exactly one of html or markdown (non-empty string)"});let n={title:e,[r.format]:r.content};typeof t?.kind=="string"&&t.kind.trim()&&(n.kind=t.kind.trim()),typeof t?.favicon=="string"&&t.favicon.trim()&&(n.favicon=t.favicon.trim());let a=await u(n),o=a?.id,s=a?.url;if(!o||!s)return JSON.stringify({error:"artifact write returned no id/url",response:a});let d={id:o,title:e,url:s,kind:n.kind||null,createdAt:a.createdAt||new Date().toISOString(),summary:typeof t?.summary=="string"&&t.summary.trim()?t.summary.trim():e};try{await f(o,d)}catch(c){return JSON.stringify({id:o,url:s,indexWarning:c.message})}return JSON.stringify({id:o,url:s})}case"artifact_update":{let e=typeof t?.id=="string"?t.id.trim():"";if(!e)return JSON.stringify({error:"id is required"});let r=m(t),n=typeof t?.title=="string"?t.title.trim():"";if(!r&&!n)return JSON.stringify({error:"nothing to update \u2014 pass a new title and/or html|markdown"});let a={id:e};n&&(a.title=n),r&&(a[r.format]=r.content),typeof t?.kind=="string"&&t.kind.trim()&&(a.kind=t.kind.trim()),typeof t?.favicon=="string"&&t.favicon.trim()&&(a.favicon=t.favicon.trim());let o=await u(a),s=o?.url;if(!s)return JSON.stringify({error:"artifact update returned no url",response:o});let d=await R(e)||{},c={...d,id:e,url:s,title:n||d.title||"Untitled",kind:a.kind||d.kind||null,createdAt:d.createdAt||o.createdAt||new Date().toISOString(),updatedAt:o.updatedAt||new Date().toISOString()};typeof t?.summary=="string"&&t.summary.trim()?c.summary=t.summary.trim():c.summary||(c.summary=c.title);try{await f(e,c)}catch(w){return JSON.stringify({id:e,url:s,indexWarning:w.message})}return JSON.stringify({id:e,url:s})}case"artifact_get":{let e=typeof t?.id=="string"?t.id.trim():"";if(!e)return JSON.stringify({error:"id is required"});let r=await P(e);return JSON.stringify(r)}default:return JSON.stringify({error:`Unknown tool: ${i}`})}}catch(e){return JSON.stringify({error:e.message})}},tools:[{name:"artifact_publish",description:"Publish a NEW self-contained, shareable page (report/plan/table/dashboard/diagram/write-up) and get back a shareable URL. Pass a title and EITHER html OR markdown. Keep all CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 the page is sandboxed on view and external URLs are blocked. Returns { id, url }.",input_schema:{type:"object",properties:{title:{type:"string",description:"The page title (also the browser tab title)."},html:{type:"string",description:"The page content as a self-contained HTML document (or fragment). Provide this OR markdown, not both."},markdown:{type:"string",description:"The page content as Markdown (rendered to HTML on serve). Provide this OR html, not both."},kind:{type:"string",description:'Optional label for what this is, e.g. "report", "plan", "dashboard", "diagram". Stored in your index.'},favicon:{type:"string",description:'Optional emoji used as the browser-tab icon, e.g. "\u{1F4CA}".'},summary:{type:"string",description:"Optional one-line summary for your own index (defaults to the title). Helps you recall later what this page was."}},required:["title"]}},{name:"artifact_update",description:"Revise an EXISTING artifact by id \u2014 the shareable URL stays the same, the content is replaced (new version). Pass the fields to change (title and/or html|markdown). Returns { id, url }.",input_schema:{type:"object",properties:{id:{type:"string",description:'The id of the artifact to update (from a prior artifact_publish, or your kv-memory "artifact:" index).'},title:{type:"string",description:"New title (optional)."},html:{type:"string",description:"New HTML content (optional). Provide this OR markdown."},markdown:{type:"string",description:"New Markdown content (optional). Provide this OR html."},kind:{type:"string",description:"Optional updated kind label."},favicon:{type:"string",description:"Optional updated emoji favicon."},summary:{type:"string",description:"Optional updated one-line index summary."}},required:["id"]}},{name:"artifact_get",description:'Fetch ONE artifact you published, by id \u2192 { metadata, content }. Use to reuse / edit / re-publish a page. To LIST what you have published, use your kv-memory tool kv_recall_prefix with keyPrefix "artifact:".',input_schema:{type:"object",properties:{id:{type:"string",description:"The artifact id."}},required:["id"]}}]};export{x as artifactSkill};
38
+ records this automatically; you don't store it yourself.)`,resolve(){let i=v();if(!i)return{command:null,args:[],env:{},description:this.description};let t={};for(let e of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[e]&&(t[e]=process.env[e]);return{type:"stdio",command:"node",args:[i,"../dist/artifact.js","artifactSkill"],env:t,description:this.description,alwaysLoad:!0}},async handleToolCall(i,t){try{switch(i){case"artifact_publish":{let e=typeof t?.title=="string"?t.title.trim():"";if(!e)return JSON.stringify({error:"title is required"});let r=h(t);if(!r)return JSON.stringify({error:"provide exactly one of html or markdown (non-empty string)"});let n={title:e,[r.format]:r.content};typeof t?.kind=="string"&&t.kind.trim()&&(n.kind=t.kind.trim()),typeof t?.favicon=="string"&&t.favicon.trim()&&(n.favicon=t.favicon.trim());let a=await u(n),o=a?.id,s=a?.url;if(!o||!s)return JSON.stringify({error:"artifact write returned no id/url",response:a});let d={id:o,title:e,url:s,kind:n.kind||null,createdAt:a.createdAt||new Date().toISOString(),summary:typeof t?.summary=="string"&&t.summary.trim()?t.summary.trim():e};try{await f(o,d)}catch(c){return JSON.stringify({id:o,url:s,indexWarning:c.message})}return JSON.stringify({id:o,url:s})}case"artifact_update":{let e=typeof t?.id=="string"?t.id.trim():"";if(!e)return JSON.stringify({error:"id is required"});let r=h(t),n=typeof t?.title=="string"?t.title.trim():"";if(!r&&!n)return JSON.stringify({error:"nothing to update \u2014 pass a new title and/or html|markdown"});let a={id:e};n&&(a.title=n),r&&(a[r.format]=r.content),typeof t?.kind=="string"&&t.kind.trim()&&(a.kind=t.kind.trim()),typeof t?.favicon=="string"&&t.favicon.trim()&&(a.favicon=t.favicon.trim());let o=await u(a),s=o?.url;if(!s)return JSON.stringify({error:"artifact update returned no url",response:o});let d=await E(e)||{},c={...d,id:e,url:s,title:n||d.title||"Untitled",kind:a.kind||d.kind||null,createdAt:d.createdAt||o.createdAt||new Date().toISOString(),updatedAt:o.updatedAt||new Date().toISOString()};typeof t?.summary=="string"&&t.summary.trim()?c.summary=t.summary.trim():c.summary||(c.summary=c.title);try{await f(e,c)}catch(w){return JSON.stringify({id:e,url:s,indexWarning:w.message})}return JSON.stringify({id:e,url:s})}case"artifact_get":{let e=typeof t?.id=="string"?t.id.trim():"";if(!e)return JSON.stringify({error:"id is required"});let r=await I(e);return JSON.stringify(r)}default:return JSON.stringify({error:`Unknown tool: ${i}`})}}catch(e){return JSON.stringify({error:e.message})}},tools:[{name:"artifact_publish",description:"Publish a NEW self-contained, shareable page (report/plan/table/dashboard/diagram/write-up) and get back a shareable URL. The content MUST come from the current conversation or data you fetched this turn for that subject \u2014 if you are not sure what the page should be about, ASK the user instead of calling this tool; never publish a demo/sample/placeholder or an account-overview page as a stand-in. Pass a title and EITHER html OR markdown. Keep all CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 the page is sandboxed on view and external URLs are blocked. Returns { id, url }.",input_schema:{type:"object",properties:{title:{type:"string",description:"The page title (also the browser tab title)."},html:{type:"string",description:"The page content as a self-contained HTML document (or fragment). Provide this OR markdown, not both."},markdown:{type:"string",description:"The page content as Markdown (rendered to HTML on serve). Provide this OR html, not both."},kind:{type:"string",description:'Optional label for what this is, e.g. "report", "plan", "dashboard", "diagram". Stored in your index.'},favicon:{type:"string",description:'Optional emoji used as the browser-tab icon, e.g. "\u{1F4CA}".'},summary:{type:"string",description:"Optional one-line summary for your own index (defaults to the title). Helps you recall later what this page was."}},required:["title"]}},{name:"artifact_update",description:"Revise an EXISTING artifact by id \u2014 the shareable URL stays the same, the content is replaced (new version). Pass the fields to change (title and/or html|markdown). Returns { id, url }.",input_schema:{type:"object",properties:{id:{type:"string",description:'The id of the artifact to update (from a prior artifact_publish, or your kv-memory "artifact:" index).'},title:{type:"string",description:"New title (optional)."},html:{type:"string",description:"New HTML content (optional). Provide this OR markdown."},markdown:{type:"string",description:"New Markdown content (optional). Provide this OR html."},kind:{type:"string",description:"Optional updated kind label."},favicon:{type:"string",description:"Optional updated emoji favicon."},summary:{type:"string",description:"Optional updated one-line index summary."}},required:["id"]}},{name:"artifact_get",description:'Fetch ONE artifact you published, by id \u2192 { metadata, content }. Use to reuse / edit / re-publish a page. To LIST what you have published, use your kv-memory tool kv_recall_prefix with keyPrefix "artifact:".',input_schema:{type:"object",properties:{id:{type:"string",description:"The artifact id."}},required:["id"]}}]};export{B as artifactSkill};
package/dist/index.js CHANGED
@@ -782,6 +782,22 @@ sandboxed when viewed (no external network, no ambient credentials), so keep all
782
782
  CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 external URLs will
783
783
  be blocked.
784
784
 
785
+ THE CONTENT COMES FROM THIS CONVERSATION \u2014 NEVER FROM YOUR IMAGINATION.
786
+ When someone says "make me a page / an artifact / a report", they mean THE THING
787
+ YOU WERE JUST TALKING ABOUT. Build the page from what is actually in this
788
+ transcript (or from data you fetch with your tools THIS turn for that specific
789
+ subject). The page is about the USER'S subject matter \u2014 their tickets, their
790
+ repos, their incidents, their data.
791
+
792
+ If you do NOT know what the page should be about \u2014 the request is vague and the
793
+ transcript does not tell you \u2014 then ASK ONE SHORT QUESTION ("which part should I
794
+ turn into a page?") and publish NOTHING. Do NOT fall back on a demo, a sample, a
795
+ placeholder, or a "here's an overview of your account" page, and do NOT go
796
+ inventory the account (projects / agents / integrations) just to have something to
797
+ render. A page the user did not ask for is worse than a question: it wastes the
798
+ link, buries the real answer, and reads as if you ignored them. There is no
799
+ situation in which "\u793A\u4F8B / sample / demo" belongs in a title you publish.
800
+
785
801
  Tools:
786
802
  - artifact_publish: Publish a NEW page. Pass a \`title\` and EITHER \`html\` OR
787
803
  \`markdown\` (not both). Optional \`kind\` (e.g. "report", "plan", "dashboard"),
@@ -795,7 +811,7 @@ Tools:
795
811
  To recall WHAT YOU HAVE ALREADY PUBLISHED, use your kv-memory tool
796
812
  kv_recall_prefix with keyPrefix "artifact:" \u2014 each entry is the index record
797
813
  { id, title, url, kind, createdAt, summary } for a page you made. (Publishing
798
- records this automatically; you don't store it yourself.)`,resolve(){let r=gp();if(!r)return{command:null,args:[],env:{},description:this.description};let e={};for(let t of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[r,"../dist/artifact.js","artifactSkill"],env:e,description:this.description,alwaysLoad:!0}},async handleToolCall(r,e){try{switch(r){case"artifact_publish":{let t=typeof e?.title=="string"?e.title.trim():"";if(!t)return JSON.stringify({error:"title is required"});let n=Wi(e);if(!n)return JSON.stringify({error:"provide exactly one of html or markdown (non-empty string)"});let i={title:t,[n.format]:n.content};typeof e?.kind=="string"&&e.kind.trim()&&(i.kind=e.kind.trim()),typeof e?.favicon=="string"&&e.favicon.trim()&&(i.favicon=e.favicon.trim());let s=await zi(i),o=s?.id,a=s?.url;if(!o||!a)return JSON.stringify({error:"artifact write returned no id/url",response:s});let c={id:o,title:t,url:a,kind:i.kind||null,createdAt:s.createdAt||new Date().toISOString(),summary:typeof e?.summary=="string"&&e.summary.trim()?e.summary.trim():t};try{await Yi(o,c)}catch(d){return JSON.stringify({id:o,url:a,indexWarning:d.message})}return JSON.stringify({id:o,url:a})}case"artifact_update":{let t=typeof e?.id=="string"?e.id.trim():"";if(!t)return JSON.stringify({error:"id is required"});let n=Wi(e),i=typeof e?.title=="string"?e.title.trim():"";if(!n&&!i)return JSON.stringify({error:"nothing to update \u2014 pass a new title and/or html|markdown"});let s={id:t};i&&(s.title=i),n&&(s[n.format]=n.content),typeof e?.kind=="string"&&e.kind.trim()&&(s.kind=e.kind.trim()),typeof e?.favicon=="string"&&e.favicon.trim()&&(s.favicon=e.favicon.trim());let o=await zi(s),a=o?.url;if(!a)return JSON.stringify({error:"artifact update returned no url",response:o});let c=await kp(t)||{},d={...c,id:t,url:a,title:i||c.title||"Untitled",kind:s.kind||c.kind||null,createdAt:c.createdAt||o.createdAt||new Date().toISOString(),updatedAt:o.updatedAt||new Date().toISOString()};typeof e?.summary=="string"&&e.summary.trim()?d.summary=e.summary.trim():d.summary||(d.summary=d.title);try{await Yi(t,d)}catch(l){return JSON.stringify({id:t,url:a,indexWarning:l.message})}return JSON.stringify({id:t,url:a})}case"artifact_get":{let t=typeof e?.id=="string"?e.id.trim():"";if(!t)return JSON.stringify({error:"id is required"});let n=await bp(t);return JSON.stringify(n)}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(t){return JSON.stringify({error:t.message})}},tools:[{name:"artifact_publish",description:"Publish a NEW self-contained, shareable page (report/plan/table/dashboard/diagram/write-up) and get back a shareable URL. Pass a title and EITHER html OR markdown. Keep all CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 the page is sandboxed on view and external URLs are blocked. Returns { id, url }.",input_schema:{type:"object",properties:{title:{type:"string",description:"The page title (also the browser tab title)."},html:{type:"string",description:"The page content as a self-contained HTML document (or fragment). Provide this OR markdown, not both."},markdown:{type:"string",description:"The page content as Markdown (rendered to HTML on serve). Provide this OR html, not both."},kind:{type:"string",description:'Optional label for what this is, e.g. "report", "plan", "dashboard", "diagram". Stored in your index.'},favicon:{type:"string",description:'Optional emoji used as the browser-tab icon, e.g. "\u{1F4CA}".'},summary:{type:"string",description:"Optional one-line summary for your own index (defaults to the title). Helps you recall later what this page was."}},required:["title"]}},{name:"artifact_update",description:"Revise an EXISTING artifact by id \u2014 the shareable URL stays the same, the content is replaced (new version). Pass the fields to change (title and/or html|markdown). Returns { id, url }.",input_schema:{type:"object",properties:{id:{type:"string",description:'The id of the artifact to update (from a prior artifact_publish, or your kv-memory "artifact:" index).'},title:{type:"string",description:"New title (optional)."},html:{type:"string",description:"New HTML content (optional). Provide this OR markdown."},markdown:{type:"string",description:"New Markdown content (optional). Provide this OR html."},kind:{type:"string",description:"Optional updated kind label."},favicon:{type:"string",description:"Optional updated emoji favicon."},summary:{type:"string",description:"Optional updated one-line index summary."}},required:["id"]}},{name:"artifact_get",description:'Fetch ONE artifact you published, by id \u2192 { metadata, content }. Use to reuse / edit / re-publish a page. To LIST what you have published, use your kv-memory tool kv_recall_prefix with keyPrefix "artifact:".',input_schema:{type:"object",properties:{id:{type:"string",description:"The artifact id."}},required:["id"]}}]};import{createRequire as wp}from"node:module";import{existsSync as rs,mkdirSync as Sp,writeFileSync as Xi}from"node:fs";import{dirname as ns,join as qe,resolve as is}from"node:path";import{fileURLToPath as ss}from"node:url";var os=wp(import.meta.url),Ir=null;function Ip(){return Ir||(Ir=os("echarts")),Ir}var vr=null;function vp(){return vr||(vr=os("@resvg/resvg-js")),vr}var Np=800,Op=600,Tp=4096,Rp=16,es=60,as="Noto Sans";function Ap(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=ns(ss(import.meta.url)),e=is(r,"..","bin","mcp-skill.mjs");return rs(e)?e:null}function Ep(){let r=ns(ss(import.meta.url)),e=is(r,"..","assets","fonts");return["NotoSans-Regular.ttf","NotoSans-Bold.ttf"].map(t=>qe(e,t)).filter(t=>rs(t))}function xp(){let r=process.env.ZIBBY_NODE_SESSION_PATH,e=process.env.ZIBBY_SESSION_PATH,t=r||(e?qe(e,"chart-render"):qe(process.cwd(),".zibby","output","charts"));return Sp(t,{recursive:!0}),t}function Te(r){return r!=null&&typeof r=="object"&&!Array.isArray(r)}function ts(r,e){let t=Number(r);return Number.isFinite(t)?Math.max(Rp,Math.min(Tp,Math.round(t))):e}function Nr(r){return typeof r!="string"||r.length<=es?r:`${r.slice(0,es-1)}\u2026`}function Ct(r){if(Array.isArray(r))for(let e=0;e<r.length;e++){let t=r[e];typeof t=="string"?r[e]=Nr(t):Te(t)&&typeof t.name=="string"&&(t.name=Nr(t.name))}}function Lp(r){for(let n of["xAxis","yAxis"]){let i=Array.isArray(r[n])?r[n]:r[n]?[r[n]]:[];for(let s of i)Te(s)&&Ct(s.data)}let e=Array.isArray(r.radar)?r.radar:r.radar?[r.radar]:[];for(let n of e)Te(n)&&Ct(n.indicator);Te(r.legend)&&Ct(r.legend.data);let t=Array.isArray(r.series)?r.series:r.series?[r.series]:[];for(let n of t)Te(n)&&(typeof n.name=="string"&&(n.name=Nr(n.name)),Ct(n.data))}function jp(r){let e=JSON.parse(JSON.stringify(r));return e.animation=!1,e.backgroundColor==null&&(e.backgroundColor="#fff"),Te(e.textStyle)||(e.textStyle={}),e.textStyle.fontFamily==null&&(e.textStyle.fontFamily=as),Lp(e),e}function $p(r){return typeof r!="string"?null:r.trim().replace(/\.(svg|png)$/i,"").replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^[.-]+|[.-]+$/g,"")||null}function Pp(r,e,t){let i=Ip().init(null,null,{renderer:"svg",ssr:!0,width:e,height:t});try{return i.setOption(r),i.renderToSVGString()}finally{i.dispose()}}function Cp(r){let{Resvg:e}=vp();return new e(r,{font:{fontFiles:Ep(),loadSystemFonts:!0,defaultFontFamily:as}}).render().asPng()}var cs={id:"chart-render",serverName:"chart_render",allowedTools:["mcp__chart_render__*"],description:"Chart render \u2014 local server-side chart rendering (Apache ECharts SVG SSR + resvg PNG); data never leaves the box",promptFragment:`## Chart Render (local, no external service)
814
+ records this automatically; you don't store it yourself.)`,resolve(){let r=gp();if(!r)return{command:null,args:[],env:{},description:this.description};let e={};for(let t of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[r,"../dist/artifact.js","artifactSkill"],env:e,description:this.description,alwaysLoad:!0}},async handleToolCall(r,e){try{switch(r){case"artifact_publish":{let t=typeof e?.title=="string"?e.title.trim():"";if(!t)return JSON.stringify({error:"title is required"});let n=Wi(e);if(!n)return JSON.stringify({error:"provide exactly one of html or markdown (non-empty string)"});let i={title:t,[n.format]:n.content};typeof e?.kind=="string"&&e.kind.trim()&&(i.kind=e.kind.trim()),typeof e?.favicon=="string"&&e.favicon.trim()&&(i.favicon=e.favicon.trim());let s=await zi(i),o=s?.id,a=s?.url;if(!o||!a)return JSON.stringify({error:"artifact write returned no id/url",response:s});let c={id:o,title:t,url:a,kind:i.kind||null,createdAt:s.createdAt||new Date().toISOString(),summary:typeof e?.summary=="string"&&e.summary.trim()?e.summary.trim():t};try{await Yi(o,c)}catch(d){return JSON.stringify({id:o,url:a,indexWarning:d.message})}return JSON.stringify({id:o,url:a})}case"artifact_update":{let t=typeof e?.id=="string"?e.id.trim():"";if(!t)return JSON.stringify({error:"id is required"});let n=Wi(e),i=typeof e?.title=="string"?e.title.trim():"";if(!n&&!i)return JSON.stringify({error:"nothing to update \u2014 pass a new title and/or html|markdown"});let s={id:t};i&&(s.title=i),n&&(s[n.format]=n.content),typeof e?.kind=="string"&&e.kind.trim()&&(s.kind=e.kind.trim()),typeof e?.favicon=="string"&&e.favicon.trim()&&(s.favicon=e.favicon.trim());let o=await zi(s),a=o?.url;if(!a)return JSON.stringify({error:"artifact update returned no url",response:o});let c=await kp(t)||{},d={...c,id:t,url:a,title:i||c.title||"Untitled",kind:s.kind||c.kind||null,createdAt:c.createdAt||o.createdAt||new Date().toISOString(),updatedAt:o.updatedAt||new Date().toISOString()};typeof e?.summary=="string"&&e.summary.trim()?d.summary=e.summary.trim():d.summary||(d.summary=d.title);try{await Yi(t,d)}catch(l){return JSON.stringify({id:t,url:a,indexWarning:l.message})}return JSON.stringify({id:t,url:a})}case"artifact_get":{let t=typeof e?.id=="string"?e.id.trim():"";if(!t)return JSON.stringify({error:"id is required"});let n=await bp(t);return JSON.stringify(n)}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(t){return JSON.stringify({error:t.message})}},tools:[{name:"artifact_publish",description:"Publish a NEW self-contained, shareable page (report/plan/table/dashboard/diagram/write-up) and get back a shareable URL. The content MUST come from the current conversation or data you fetched this turn for that subject \u2014 if you are not sure what the page should be about, ASK the user instead of calling this tool; never publish a demo/sample/placeholder or an account-overview page as a stand-in. Pass a title and EITHER html OR markdown. Keep all CSS/JS/images INLINE (inline <style>/<script>, data: URIs) \u2014 the page is sandboxed on view and external URLs are blocked. Returns { id, url }.",input_schema:{type:"object",properties:{title:{type:"string",description:"The page title (also the browser tab title)."},html:{type:"string",description:"The page content as a self-contained HTML document (or fragment). Provide this OR markdown, not both."},markdown:{type:"string",description:"The page content as Markdown (rendered to HTML on serve). Provide this OR html, not both."},kind:{type:"string",description:'Optional label for what this is, e.g. "report", "plan", "dashboard", "diagram". Stored in your index.'},favicon:{type:"string",description:'Optional emoji used as the browser-tab icon, e.g. "\u{1F4CA}".'},summary:{type:"string",description:"Optional one-line summary for your own index (defaults to the title). Helps you recall later what this page was."}},required:["title"]}},{name:"artifact_update",description:"Revise an EXISTING artifact by id \u2014 the shareable URL stays the same, the content is replaced (new version). Pass the fields to change (title and/or html|markdown). Returns { id, url }.",input_schema:{type:"object",properties:{id:{type:"string",description:'The id of the artifact to update (from a prior artifact_publish, or your kv-memory "artifact:" index).'},title:{type:"string",description:"New title (optional)."},html:{type:"string",description:"New HTML content (optional). Provide this OR markdown."},markdown:{type:"string",description:"New Markdown content (optional). Provide this OR html."},kind:{type:"string",description:"Optional updated kind label."},favicon:{type:"string",description:"Optional updated emoji favicon."},summary:{type:"string",description:"Optional updated one-line index summary."}},required:["id"]}},{name:"artifact_get",description:'Fetch ONE artifact you published, by id \u2192 { metadata, content }. Use to reuse / edit / re-publish a page. To LIST what you have published, use your kv-memory tool kv_recall_prefix with keyPrefix "artifact:".',input_schema:{type:"object",properties:{id:{type:"string",description:"The artifact id."}},required:["id"]}}]};import{createRequire as wp}from"node:module";import{existsSync as rs,mkdirSync as Sp,writeFileSync as Xi}from"node:fs";import{dirname as ns,join as qe,resolve as is}from"node:path";import{fileURLToPath as ss}from"node:url";var os=wp(import.meta.url),Ir=null;function Ip(){return Ir||(Ir=os("echarts")),Ir}var vr=null;function vp(){return vr||(vr=os("@resvg/resvg-js")),vr}var Np=800,Op=600,Tp=4096,Rp=16,es=60,as="Noto Sans";function Ap(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=ns(ss(import.meta.url)),e=is(r,"..","bin","mcp-skill.mjs");return rs(e)?e:null}function Ep(){let r=ns(ss(import.meta.url)),e=is(r,"..","assets","fonts");return["NotoSans-Regular.ttf","NotoSans-Bold.ttf"].map(t=>qe(e,t)).filter(t=>rs(t))}function xp(){let r=process.env.ZIBBY_NODE_SESSION_PATH,e=process.env.ZIBBY_SESSION_PATH,t=r||(e?qe(e,"chart-render"):qe(process.cwd(),".zibby","output","charts"));return Sp(t,{recursive:!0}),t}function Te(r){return r!=null&&typeof r=="object"&&!Array.isArray(r)}function ts(r,e){let t=Number(r);return Number.isFinite(t)?Math.max(Rp,Math.min(Tp,Math.round(t))):e}function Nr(r){return typeof r!="string"||r.length<=es?r:`${r.slice(0,es-1)}\u2026`}function Ct(r){if(Array.isArray(r))for(let e=0;e<r.length;e++){let t=r[e];typeof t=="string"?r[e]=Nr(t):Te(t)&&typeof t.name=="string"&&(t.name=Nr(t.name))}}function Lp(r){for(let n of["xAxis","yAxis"]){let i=Array.isArray(r[n])?r[n]:r[n]?[r[n]]:[];for(let s of i)Te(s)&&Ct(s.data)}let e=Array.isArray(r.radar)?r.radar:r.radar?[r.radar]:[];for(let n of e)Te(n)&&Ct(n.indicator);Te(r.legend)&&Ct(r.legend.data);let t=Array.isArray(r.series)?r.series:r.series?[r.series]:[];for(let n of t)Te(n)&&(typeof n.name=="string"&&(n.name=Nr(n.name)),Ct(n.data))}function jp(r){let e=JSON.parse(JSON.stringify(r));return e.animation=!1,e.backgroundColor==null&&(e.backgroundColor="#fff"),Te(e.textStyle)||(e.textStyle={}),e.textStyle.fontFamily==null&&(e.textStyle.fontFamily=as),Lp(e),e}function $p(r){return typeof r!="string"?null:r.trim().replace(/\.(svg|png)$/i,"").replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^[.-]+|[.-]+$/g,"")||null}function Pp(r,e,t){let i=Ip().init(null,null,{renderer:"svg",ssr:!0,width:e,height:t});try{return i.setOption(r),i.renderToSVGString()}finally{i.dispose()}}function Cp(r){let{Resvg:e}=vp();return new e(r,{font:{fontFiles:Ep(),loadSystemFonts:!0,defaultFontFamily:as}}).render().asPng()}var cs={id:"chart-render",serverName:"chart_render",allowedTools:["mcp__chart_render__*"],description:"Chart render \u2014 local server-side chart rendering (Apache ECharts SVG SSR + resvg PNG); data never leaves the box",promptFragment:`## Chart Render (local, no external service)
799
815
  You can render charts LOCALLY with the chart_render tool \u2014 pass a standard
800
816
  Apache ECharts option object as \`spec\` (any chart type: bar, line, pie,
801
817
  radar, scatter, heatmap, \u2026). It renders server-side to SVG/PNG files in the
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",