@zibby/skills 0.1.11 → 0.1.13

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/index.js CHANGED
@@ -129,19 +129,19 @@ AFTER completing the test, you MUST call memory_save_insight at least once:
129
129
  https://docs.dolthub.com/introduction/installation
130
130
 
131
131
  Error: ${e.message}`,{cause:e})}return{command:"node",args:[r,"--db-path",t],description:this.description}},tools:[{name:"memory_get_test_history",description:"Query recent test runs with pass/fail results and timing",input_schema:{type:"object",properties:{specPath:{type:"string",description:"Filter by spec path (substring match)"},limit:{type:"number",description:"Max results (default 10)"}}}},{name:"memory_get_selectors",description:"Query known selectors for a page with stability metrics",input_schema:{type:"object",properties:{pageUrl:{type:"string",description:"Filter by page URL (substring match)"},limit:{type:"number",description:"Max results (default 20)"}}}},{name:"memory_get_page_model",description:"Query page structure \u2014 elements, roles, selectors",input_schema:{type:"object",properties:{url:{type:"string",description:"Filter by page URL (substring match)"},limit:{type:"number",description:"Max results (default 20)"}}}},{name:"memory_get_navigation",description:"Query known page-to-page transitions",input_schema:{type:"object",properties:{fromUrl:{type:"string",description:"Filter by source URL (substring match)"},limit:{type:"number",description:"Max results (default 20)"}}}},{name:"memory_save_insight",description:"Save a useful observation for future runs (selector tips, timing, workarounds)",input_schema:{type:"object",properties:{category:{type:"string",enum:["selector_tip","timing","navigation","workaround","flaky","general"],description:"Type of insight"},content:{type:"string",description:"The insight text \u2014 be specific and actionable"},specPath:{type:"string",description:"Related spec path"},sessionId:{type:"string",description:"Current session ID"}},required:["category","content"]}}]};import{existsSync as hs,readFileSync as _s}from"fs";import{homedir as ks}from"os";import{join as ws}from"path";import{spawn as bs}from"child_process";var B={jira:{description:"Jira issue search, details, comments, transitions",integrationProvider:"jira",envKeys:[],setupInstructions:`To connect Jira:
132
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
132
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
133
133
  2. Click "Connect Jira" and authorize via Atlassian OAuth
134
134
  3. After OAuth completes, ask me to install Jira again`},github:{description:"GitHub issues, PRs, repository management",integrationProvider:"github",envKeys:[],setupInstructions:`To connect GitHub:
135
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
135
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
136
136
  2. Click "Connect GitHub" and authorize
137
137
  3. After OAuth completes, ask me to install GitHub again`},slack:{description:"Slack messages, channels, reactions",integrationProvider:"slack",envKeys:[],setupInstructions:`To connect Slack:
138
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
138
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
139
139
  2. Click "Connect Slack" and authorize
140
140
  3. After OAuth completes, ask me to install Slack again`},sentry:{description:"Sentry error tracking \u2014 projects, issues, events",integrationProvider:"sentry",envKeys:[],setupInstructions:`To connect Sentry:
141
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
141
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
142
142
  2. Click "Connect Sentry" and authorize
143
143
  3. After OAuth completes, ask me to install Sentry again`},runner:{description:"Run zibby test workflows from chat (parallel supported)",envKeys:[],setupInstructions:"Ready to use. Runs zibby test workflows as background processes \u2014 each with its own browser and session."},browser:{description:"Playwright browser automation (navigate, click, fill, screenshot)",envKeys:[],setupInstructions:"Ready to use. Starts a Playwright browser for web automation."},memory:{description:"Test memory database (Dolt) \u2014 history, selectors, insights",envKeys:[],setupInstructions:"Ready to use. Requires Dolt (https://docs.dolthub.com/introduction/installation) and a memory DB via `zibby init --mem`."},"chat-memory":{description:"Persistent chat memory \u2014 remembers facts, decisions, and task history across sessions (Dolt-backed)",envKeys:[],setupInstructions:'Ready to use. Requires Dolt installed. Tables auto-create on first use. Install with: "add chat memory" or "install chat-memory".'},git:{description:"Clone and explore git repositories locally for codebase analysis",envKeys:[],setupInstructions:"Ready to use. Clone repos with git_checkout, explore with git_explore. Auto-authenticates with GitHub/GitLab tokens."}};function Ss(){let r=["## Available Skills"];for(let[t,e]of Object.entries(B)){let s=e.integrationProvider?`integration: ${e.integrationProvider}`:"ready";r.push(`- ${t}: ${e.description} [${s}]`)}return r.push(""),r.push("Use the install_skill / uninstall_skill / list_available_skills tools to manage skills."),r.push(`Zibby third party Integration settings page: ${ye()}`),r.push(""),r.push("## Tool-First Policy (mandatory)"),r.push("CRITICAL RULES \u2014 follow these strictly:"),r.push("1. When user asks to do something and a matching skill is available but not installed, IMMEDIATELY call install_skill. Never ask for credentials or confirmation first."),r.push(`2. If install_skill succeeds, the skill's tools are now available. Use them RIGHT AWAY in the same turn \u2014 don't just say "it's connected", actually call the tools.`),r.push("3. If install_skill reports needsIntegration, tell the user to connect via the integration URL and try again after."),r.push("4. When the relevant skill is already installed, use its tools directly \u2014 don't ask for IDs or keys. Each skill's own instructions explain the workflow."),r.push("5. If a task needs multiple skills (e.g. data from one + execution from another), install all of them, then follow each skill's workflow instructions."),r.join(`
144
- `)}function vs(){if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let r=ws(ks(),".zibby","config.json");return hs(r)&&JSON.parse(_s(r,"utf-8")).sessionToken||null}catch{return null}}function Ns(){return(process.env.ZIBBY_API_URL||process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app").replace(/\/$/,"")}function ye(){return`${(process.env.ZIBBY_FRONTEND_URL||process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app").replace(/\/$/,"")}/integrations`}function Os(r){try{let t=process.platform;return bs(t==="darwin"?"open":t==="win32"?"cmd":"xdg-open",t==="win32"?["/c","start","",r]:[r],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}async function $s(){let r=vs();if(!r)return{checked:!1,statuses:null,reason:"no-session-token"};try{let t=await fetch(`${Ns()}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${r}`}});return t.ok?{checked:!0,statuses:await t.json()||{},reason:null}:{checked:!1,statuses:null,reason:`status-${t.status}`}}catch{return{checked:!1,statuses:null,reason:"network-error"}}}function Pe(r,t){if(!t||!r)return{connected:null};let e=r[t];return!e||typeof e.connected!="boolean"?{connected:null,details:e||null}:{connected:e.connected,details:e}}var Be={id:"skill-installer",description:"Live skill installation for chat sessions",envKeys:[],catalog:B,promptFragment:Ss,tools:[{name:"install_skill",description:"Install a skill into the current chat session so its tools become available",input_schema:{type:"object",properties:{skillId:{type:"string",description:'Skill identifier to install (e.g. "jira", "github", "browser", "memory")'}},required:["skillId"]}},{name:"uninstall_skill",description:"Remove a skill from the current chat session",input_schema:{type:"object",properties:{skillId:{type:"string",description:"Skill identifier to remove"}},required:["skillId"]}},{name:"list_available_skills",description:"List all skills that can be installed, with their env-var readiness status",input_schema:{type:"object",properties:{}}}],async handleToolCall(r,t,e){let{activeSkills:s}=e,n=await $s();if(r==="list_available_skills"){let i=Object.entries(B).map(([o,a])=>{let c=s.includes(o),l=Pe(n.statuses,a.integrationProvider);return{id:o,description:a.description,installed:c,integrationProvider:a.integrationProvider||void 0,integrationConnected:l.connected,setupInstructions:l.connected===!1?a.setupInstructions:void 0}});return JSON.stringify({skills:i})}if(r==="install_skill"){let{skillId:i}=t;if(!i)return JSON.stringify({ok:!1,error:"skillId is required"});if(s.includes(i)){let u=B[i],{getSkill:p}=await import("@zibby/agent-workflow"),m=(p(i)?.tools||[]).map(f=>f.name);return JSON.stringify({ok:!0,alreadyInstalled:!0,skillId:i,description:u?.description,availableTools:m,integrationUrl:u?.integrationProvider?ye():void 0,hint:`${i} is already active. Tools available: ${m.join(", ")}. Use them directly.`})}if(!B[i])return JSON.stringify({ok:!1,error:`Unknown skill "${i}". Available: ${Object.keys(B).join(", ")}`});let o=B[i];if(o.integrationProvider){let u=Pe(n.statuses,o.integrationProvider),p=ye();if(n.checked&&u.connected===!1){let y=Os(p);return JSON.stringify({ok:!1,error:`${o.integrationProvider} is not connected for this Zibby account yet`,needsIntegration:!0,integrationUrl:p,openedBrowser:y,setupInstructions:`Please connect ${o.integrationProvider} first at ${p}. After you finish OAuth, ask me to install ${i} again.`})}}s.push(i);let{getSkill:a}=await import("@zibby/agent-workflow"),l=(a(i)?.tools||[]).map(u=>u.name);return JSON.stringify({ok:!0,installed:i,description:o.description,availableTools:l,hint:`${i} is now active. You now have these tools: ${l.join(", ")}. Use them immediately to help the user \u2014 don't just confirm installation.`})}if(r==="uninstall_skill"){let{skillId:i}=t;if(!i)return JSON.stringify({ok:!1,error:"skillId is required"});if(i==="skill-installer")return JSON.stringify({ok:!1,error:"Cannot uninstall the skill installer"});let o=s.indexOf(i);return o===-1?JSON.stringify({ok:!1,error:`${i} is not installed`}):(s.splice(o,1),JSON.stringify({ok:!0,uninstalled:i}))}return JSON.stringify({error:`Unknown tool: ${r}`})},resolve(){return null}};import{readFileSync as Rs,readdirSync as Is,statSync as We,writeFileSync as js,mkdirSync as As}from"fs";import{join as ze,resolve as Ts,relative as Cs}from"path";import{execSync as Ge}from"child_process";var Fe=256*1024,Es=64*1024,He={id:"core-tools",description:"File read/write, directory listing, shell commands, open URLs, wait for async operations",envKeys:[],tools:[{name:"read_file",description:"Read the contents of a file. Returns the text content.",input_schema:{type:"object",properties:{path:{type:"string",description:"File path (relative to cwd or absolute)"}},required:["path"]}},{name:"write_file",description:"Write content to a file. Creates parent directories if needed.",input_schema:{type:"object",properties:{path:{type:"string",description:"File path (relative to cwd or absolute)"},content:{type:"string",description:"Content to write"}},required:["path","content"]}},{name:"list_directory",description:"List files and directories in a path. Returns names with type indicators (/ for dirs).",input_schema:{type:"object",properties:{path:{type:"string",description:"Directory path (relative to cwd or absolute). Defaults to cwd."}}}},{name:"run_command",description:"Run a shell command and return its output. Use for grep, git, npm, etc.",input_schema:{type:"object",properties:{command:{type:"string",description:"Shell command to execute"},cwd:{type:"string",description:"Working directory (optional, defaults to project root)"}},required:["command"]}},{name:"open_url",description:"Open a URL in the user's default browser. Use for OAuth flows, documentation, integration setup pages.",input_schema:{type:"object",properties:{url:{type:"string",description:"URL to open"}},required:["url"]}},{name:"wait",description:"Wait for N seconds. Use this for async operations (tests, builds, deploys) \u2014 wait, then check status again.",input_schema:{type:"object",properties:{seconds:{type:"number",description:"Seconds to wait (default: 5, max: 300)"},reason:{type:"string",description:"Why waiting (for logging/clarity)"}}}}],async handleToolCall(r,t,e){let s=e?.options?.workspace||process.cwd();try{switch(r){case"read_file":return xs(t,s);case"write_file":return Ls(t,s);case"list_directory":return Js(t,s);case"run_command":return Ds(t,s);case"open_url":return Ms(t);case"wait":return await Us(t,e?.options?.signal);default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(n){return JSON.stringify({error:n.message})}},resolve(){return null}};function te(r,t){return Ts(t,r)}function xs(r,t){let e=te(r.path,t),s=We(e);return s.size>Fe?JSON.stringify({error:`File too large (${(s.size/1024).toFixed(0)}KB). Max: ${Fe/1024}KB`}):Rs(e,"utf-8")}function Ls(r,t){let e=te(r.path,t),s=ze(e,"..");return As(s,{recursive:!0}),js(e,r.content,"utf-8"),JSON.stringify({ok:!0,path:Cs(t,e)})}function Js(r,t){let e=te(r.path||".",t);return Is(e).map(n=>{try{return We(ze(e,n)).isDirectory()?`${n}/`:n}catch{return n}}).join(`
144
+ `)}function vs(){if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let r=ws(ks(),".zibby","config.json");return hs(r)&&JSON.parse(_s(r,"utf-8")).sessionToken||null}catch{return null}}function Ns(){return(process.env.ZIBBY_API_URL||process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app").replace(/\/$/,"")}function ye(){return`${(process.env.ZIBBY_FRONTEND_URL||process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.dev").replace(/\/$/,"")}/integrations`}function Os(r){try{let t=process.platform;return bs(t==="darwin"?"open":t==="win32"?"cmd":"xdg-open",t==="win32"?["/c","start","",r]:[r],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}async function $s(){let r=vs();if(!r)return{checked:!1,statuses:null,reason:"no-session-token"};try{let t=await fetch(`${Ns()}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${r}`}});return t.ok?{checked:!0,statuses:await t.json()||{},reason:null}:{checked:!1,statuses:null,reason:`status-${t.status}`}}catch{return{checked:!1,statuses:null,reason:"network-error"}}}function Pe(r,t){if(!t||!r)return{connected:null};let e=r[t];return!e||typeof e.connected!="boolean"?{connected:null,details:e||null}:{connected:e.connected,details:e}}var Be={id:"skill-installer",description:"Live skill installation for chat sessions",envKeys:[],catalog:B,promptFragment:Ss,tools:[{name:"install_skill",description:"Install a skill into the current chat session so its tools become available",input_schema:{type:"object",properties:{skillId:{type:"string",description:'Skill identifier to install (e.g. "jira", "github", "browser", "memory")'}},required:["skillId"]}},{name:"uninstall_skill",description:"Remove a skill from the current chat session",input_schema:{type:"object",properties:{skillId:{type:"string",description:"Skill identifier to remove"}},required:["skillId"]}},{name:"list_available_skills",description:"List all skills that can be installed, with their env-var readiness status",input_schema:{type:"object",properties:{}}}],async handleToolCall(r,t,e){let{activeSkills:s}=e,n=await $s();if(r==="list_available_skills"){let i=Object.entries(B).map(([o,a])=>{let c=s.includes(o),l=Pe(n.statuses,a.integrationProvider);return{id:o,description:a.description,installed:c,integrationProvider:a.integrationProvider||void 0,integrationConnected:l.connected,setupInstructions:l.connected===!1?a.setupInstructions:void 0}});return JSON.stringify({skills:i})}if(r==="install_skill"){let{skillId:i}=t;if(!i)return JSON.stringify({ok:!1,error:"skillId is required"});if(s.includes(i)){let u=B[i],{getSkill:p}=await import("@zibby/agent-workflow"),m=(p(i)?.tools||[]).map(f=>f.name);return JSON.stringify({ok:!0,alreadyInstalled:!0,skillId:i,description:u?.description,availableTools:m,integrationUrl:u?.integrationProvider?ye():void 0,hint:`${i} is already active. Tools available: ${m.join(", ")}. Use them directly.`})}if(!B[i])return JSON.stringify({ok:!1,error:`Unknown skill "${i}". Available: ${Object.keys(B).join(", ")}`});let o=B[i];if(o.integrationProvider){let u=Pe(n.statuses,o.integrationProvider),p=ye();if(n.checked&&u.connected===!1){let y=Os(p);return JSON.stringify({ok:!1,error:`${o.integrationProvider} is not connected for this Zibby account yet`,needsIntegration:!0,integrationUrl:p,openedBrowser:y,setupInstructions:`Please connect ${o.integrationProvider} first at ${p}. After you finish OAuth, ask me to install ${i} again.`})}}s.push(i);let{getSkill:a}=await import("@zibby/agent-workflow"),l=(a(i)?.tools||[]).map(u=>u.name);return JSON.stringify({ok:!0,installed:i,description:o.description,availableTools:l,hint:`${i} is now active. You now have these tools: ${l.join(", ")}. Use them immediately to help the user \u2014 don't just confirm installation.`})}if(r==="uninstall_skill"){let{skillId:i}=t;if(!i)return JSON.stringify({ok:!1,error:"skillId is required"});if(i==="skill-installer")return JSON.stringify({ok:!1,error:"Cannot uninstall the skill installer"});let o=s.indexOf(i);return o===-1?JSON.stringify({ok:!1,error:`${i} is not installed`}):(s.splice(o,1),JSON.stringify({ok:!0,uninstalled:i}))}return JSON.stringify({error:`Unknown tool: ${r}`})},resolve(){return null}};import{readFileSync as Rs,readdirSync as Is,statSync as We,writeFileSync as js,mkdirSync as As}from"fs";import{join as ze,resolve as Ts,relative as Cs}from"path";import{execSync as Ge}from"child_process";var Fe=256*1024,Es=64*1024,He={id:"core-tools",description:"File read/write, directory listing, shell commands, open URLs, wait for async operations",envKeys:[],tools:[{name:"read_file",description:"Read the contents of a file. Returns the text content.",input_schema:{type:"object",properties:{path:{type:"string",description:"File path (relative to cwd or absolute)"}},required:["path"]}},{name:"write_file",description:"Write content to a file. Creates parent directories if needed.",input_schema:{type:"object",properties:{path:{type:"string",description:"File path (relative to cwd or absolute)"},content:{type:"string",description:"Content to write"}},required:["path","content"]}},{name:"list_directory",description:"List files and directories in a path. Returns names with type indicators (/ for dirs).",input_schema:{type:"object",properties:{path:{type:"string",description:"Directory path (relative to cwd or absolute). Defaults to cwd."}}}},{name:"run_command",description:"Run a shell command and return its output. Use for grep, git, npm, etc.",input_schema:{type:"object",properties:{command:{type:"string",description:"Shell command to execute"},cwd:{type:"string",description:"Working directory (optional, defaults to project root)"}},required:["command"]}},{name:"open_url",description:"Open a URL in the user's default browser. Use for OAuth flows, documentation, integration setup pages.",input_schema:{type:"object",properties:{url:{type:"string",description:"URL to open"}},required:["url"]}},{name:"wait",description:"Wait for N seconds. Use this for async operations (tests, builds, deploys) \u2014 wait, then check status again.",input_schema:{type:"object",properties:{seconds:{type:"number",description:"Seconds to wait (default: 5, max: 300)"},reason:{type:"string",description:"Why waiting (for logging/clarity)"}}}}],async handleToolCall(r,t,e){let s=e?.options?.workspace||process.cwd();try{switch(r){case"read_file":return xs(t,s);case"write_file":return Ls(t,s);case"list_directory":return Js(t,s);case"run_command":return Ds(t,s);case"open_url":return Ms(t);case"wait":return await Us(t,e?.options?.signal);default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(n){return JSON.stringify({error:n.message})}},resolve(){return null}};function te(r,t){return Ts(t,r)}function xs(r,t){let e=te(r.path,t),s=We(e);return s.size>Fe?JSON.stringify({error:`File too large (${(s.size/1024).toFixed(0)}KB). Max: ${Fe/1024}KB`}):Rs(e,"utf-8")}function Ls(r,t){let e=te(r.path,t),s=ze(e,"..");return As(s,{recursive:!0}),js(e,r.content,"utf-8"),JSON.stringify({ok:!0,path:Cs(t,e)})}function Js(r,t){let e=te(r.path||".",t);return Is(e).map(n=>{try{return We(ze(e,n)).isDirectory()?`${n}/`:n}catch{return n}}).join(`
145
145
  `)}function Ds(r,t){let e=r.cwd?te(r.cwd,t):t;return Ge(r.command,{cwd:e,encoding:"utf-8",timeout:3e4,maxBuffer:Es,stdio:["pipe","pipe","pipe"]})||"(no output)"}function Ms(r){let{url:t}=r;if(!t||!t.startsWith("http://")&&!t.startsWith("https://"))return JSON.stringify({error:"Invalid URL \u2014 must start with http:// or https://"});let e=process.platform,s=e==="darwin"?"open":e==="win32"?"start":"xdg-open";try{return Ge(`${s} "${t}"`,{stdio:"ignore",timeout:5e3}),JSON.stringify({ok:!0,opened:t})}catch{return JSON.stringify({ok:!1,error:`Could not open browser. Please visit: ${t}`})}}async function Us(r,t){let e=Math.min(Math.max(r.seconds||5,1),300),s=r.reason||"async operation",n=500,i=Date.now()+e*1e3;for(;Date.now()<i;){if(t?.aborted)return JSON.stringify({ok:!0,waited:Math.round((e*1e3-(i-Date.now()))/1e3),reason:s,interrupted:!0});await new Promise(o=>setTimeout(o,Math.min(n,i-Date.now())))}return JSON.stringify({ok:!0,waited:e,reason:s})}import{resolveIntegrationToken as Ze}from"@zibby/core/backend-client.js";async function Ye(r,t={}){let{token:e,organizationSlug:s}=await Ze("sentry"),n=`https://sentry.io/api/0/organizations/${s}${r}`,i=await fetch(n,{method:t.method||"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`Sentry API ${i.status}: ${o.slice(0,300)}`)}return i.json()}var Ve={id:"sentry",description:"Sentry error tracking \u2014 projects, issues, events",envKeys:[],promptFragment:`## Sentry (connected)
146
146
  You have access to the user's Sentry. Use these tools:
147
147
  - sentry_list_projects: List projects in the organization
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Built-in skill definitions for Zibby test automation framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "author": "Zibby",
30
30
  "license": "MIT",
31
- "homepage": "https://zibby.app",
31
+ "homepage": "https://zibby.dev",
32
32
  "repository": {
33
33
  "type": "git",
34
34
  "url": "https://github.com/ZibbyHQ/zibby-agent"
@@ -46,7 +46,7 @@
46
46
  "node": ">=18.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "@zibby/agent-workflow": "^0.1.2"
49
+ "@zibby/agent-workflow": "^0.3.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@zibby/core": ">=0.1.44"
@@ -1,14 +1,14 @@
1
1
  import{existsSync as m,readFileSync as b}from"fs";import{homedir as v}from"os";import{join as I}from"path";import{spawn as w}from"child_process";var r={jira:{description:"Jira issue search, details, comments, transitions",integrationProvider:"jira",envKeys:[],setupInstructions:`To connect Jira:
2
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
2
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
3
3
  2. Click "Connect Jira" and authorize via Atlassian OAuth
4
4
  3. After OAuth completes, ask me to install Jira again`},github:{description:"GitHub issues, PRs, repository management",integrationProvider:"github",envKeys:[],setupInstructions:`To connect GitHub:
5
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
5
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
6
6
  2. Click "Connect GitHub" and authorize
7
7
  3. After OAuth completes, ask me to install GitHub again`},slack:{description:"Slack messages, channels, reactions",integrationProvider:"slack",envKeys:[],setupInstructions:`To connect Slack:
8
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
8
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
9
9
  2. Click "Connect Slack" and authorize
10
10
  3. After OAuth completes, ask me to install Slack again`},sentry:{description:"Sentry error tracking \u2014 projects, issues, events",integrationProvider:"sentry",envKeys:[],setupInstructions:`To connect Sentry:
11
- 1. Go to Settings \u2192 Integrations (https://studio.zibby.app/integrations)
11
+ 1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
12
12
  2. Click "Connect Sentry" and authorize
13
13
  3. After OAuth completes, ask me to install Sentry again`},runner:{description:"Run zibby test workflows from chat (parallel supported)",envKeys:[],setupInstructions:"Ready to use. Runs zibby test workflows as background processes \u2014 each with its own browser and session."},browser:{description:"Playwright browser automation (navigate, click, fill, screenshot)",envKeys:[],setupInstructions:"Ready to use. Starts a Playwright browser for web automation."},memory:{description:"Test memory database (Dolt) \u2014 history, selectors, insights",envKeys:[],setupInstructions:"Ready to use. Requires Dolt (https://docs.dolthub.com/introduction/installation) and a memory DB via `zibby init --mem`."},"chat-memory":{description:"Persistent chat memory \u2014 remembers facts, decisions, and task history across sessions (Dolt-backed)",envKeys:[],setupInstructions:'Ready to use. Requires Dolt installed. Tables auto-create on first use. Install with: "add chat memory" or "install chat-memory".'},git:{description:"Clone and explore git repositories locally for codebase analysis",envKeys:[],setupInstructions:"Ready to use. Clone repos with git_checkout, explore with git_explore. Auto-authenticates with GitHub/GitLab tokens."}};function S(){let t=["## Available Skills"];for(let[s,n]of Object.entries(r)){let o=n.integrationProvider?`integration: ${n.integrationProvider}`:"ready";t.push(`- ${s}: ${n.description} [${o}]`)}return t.push(""),t.push("Use the install_skill / uninstall_skill / list_available_skills tools to manage skills."),t.push(`Zibby third party Integration settings page: ${p()}`),t.push(""),t.push("## Tool-First Policy (mandatory)"),t.push("CRITICAL RULES \u2014 follow these strictly:"),t.push("1. When user asks to do something and a matching skill is available but not installed, IMMEDIATELY call install_skill. Never ask for credentials or confirmation first."),t.push(`2. If install_skill succeeds, the skill's tools are now available. Use them RIGHT AWAY in the same turn \u2014 don't just say "it's connected", actually call the tools.`),t.push("3. If install_skill reports needsIntegration, tell the user to connect via the integration URL and try again after."),t.push("4. When the relevant skill is already installed, use its tools directly \u2014 don't ask for IDs or keys. Each skill's own instructions explain the workflow."),t.push("5. If a task needs multiple skills (e.g. data from one + execution from another), install all of them, then follow each skill's workflow instructions."),t.join(`
14
- `)}function _(){if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let t=I(v(),".zibby","config.json");return m(t)&&JSON.parse(b(t,"utf-8")).sessionToken||null}catch{return null}}function O(){return(process.env.ZIBBY_API_URL||process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app").replace(/\/$/,"")}function p(){return`${(process.env.ZIBBY_FRONTEND_URL||process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app").replace(/\/$/,"")}/integrations`}function P(t){try{let s=process.platform;return w(s==="darwin"?"open":s==="win32"?"cmd":"xdg-open",s==="win32"?["/c","start","",t]:[t],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}async function R(){let t=_();if(!t)return{checked:!1,statuses:null,reason:"no-session-token"};try{let s=await fetch(`${O()}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${t}`}});return s.ok?{checked:!0,statuses:await s.json()||{},reason:null}:{checked:!1,statuses:null,reason:`status-${s.status}`}}catch{return{checked:!1,statuses:null,reason:"network-error"}}}function g(t,s){if(!s||!t)return{connected:null};let n=t[s];return!n||typeof n.connected!="boolean"?{connected:null,details:n||null}:{connected:n.connected,details:n}}var j={id:"skill-installer",description:"Live skill installation for chat sessions",envKeys:[],catalog:r,promptFragment:S,tools:[{name:"install_skill",description:"Install a skill into the current chat session so its tools become available",input_schema:{type:"object",properties:{skillId:{type:"string",description:'Skill identifier to install (e.g. "jira", "github", "browser", "memory")'}},required:["skillId"]}},{name:"uninstall_skill",description:"Remove a skill from the current chat session",input_schema:{type:"object",properties:{skillId:{type:"string",description:"Skill identifier to remove"}},required:["skillId"]}},{name:"list_available_skills",description:"List all skills that can be installed, with their env-var readiness status",input_schema:{type:"object",properties:{}}}],async handleToolCall(t,s,n){let{activeSkills:o}=n,d=await R();if(t==="list_available_skills"){let e=Object.entries(r).map(([i,a])=>{let h=o.includes(i),c=g(d.statuses,a.integrationProvider);return{id:i,description:a.description,installed:h,integrationProvider:a.integrationProvider||void 0,integrationConnected:c.connected,setupInstructions:c.connected===!1?a.setupInstructions:void 0}});return JSON.stringify({skills:e})}if(t==="install_skill"){let{skillId:e}=s;if(!e)return JSON.stringify({ok:!1,error:"skillId is required"});if(o.includes(e)){let l=r[e],{getSkill:u}=await import("@zibby/agent-workflow"),k=(u(e)?.tools||[]).map(y=>y.name);return JSON.stringify({ok:!0,alreadyInstalled:!0,skillId:e,description:l?.description,availableTools:k,integrationUrl:l?.integrationProvider?p():void 0,hint:`${e} is already active. Tools available: ${k.join(", ")}. Use them directly.`})}if(!r[e])return JSON.stringify({ok:!1,error:`Unknown skill "${e}". Available: ${Object.keys(r).join(", ")}`});let i=r[e];if(i.integrationProvider){let l=g(d.statuses,i.integrationProvider),u=p();if(d.checked&&l.connected===!1){let f=P(u);return JSON.stringify({ok:!1,error:`${i.integrationProvider} is not connected for this Zibby account yet`,needsIntegration:!0,integrationUrl:u,openedBrowser:f,setupInstructions:`Please connect ${i.integrationProvider} first at ${u}. After you finish OAuth, ask me to install ${e} again.`})}}o.push(e);let{getSkill:a}=await import("@zibby/agent-workflow"),c=(a(e)?.tools||[]).map(l=>l.name);return JSON.stringify({ok:!0,installed:e,description:i.description,availableTools:c,hint:`${e} is now active. You now have these tools: ${c.join(", ")}. Use them immediately to help the user \u2014 don't just confirm installation.`})}if(t==="uninstall_skill"){let{skillId:e}=s;if(!e)return JSON.stringify({ok:!1,error:"skillId is required"});if(e==="skill-installer")return JSON.stringify({ok:!1,error:"Cannot uninstall the skill installer"});let i=o.indexOf(e);return i===-1?JSON.stringify({ok:!1,error:`${e} is not installed`}):(o.splice(i,1),JSON.stringify({ok:!0,uninstalled:e}))}return JSON.stringify({error:`Unknown tool: ${t}`})},resolve(){return null}};export{j as skillInstallerSkill};
14
+ `)}function _(){if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let t=I(v(),".zibby","config.json");return m(t)&&JSON.parse(b(t,"utf-8")).sessionToken||null}catch{return null}}function O(){return(process.env.ZIBBY_API_URL||process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app").replace(/\/$/,"")}function p(){return`${(process.env.ZIBBY_FRONTEND_URL||process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.dev").replace(/\/$/,"")}/integrations`}function P(t){try{let s=process.platform;return w(s==="darwin"?"open":s==="win32"?"cmd":"xdg-open",s==="win32"?["/c","start","",t]:[t],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}async function R(){let t=_();if(!t)return{checked:!1,statuses:null,reason:"no-session-token"};try{let s=await fetch(`${O()}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${t}`}});return s.ok?{checked:!0,statuses:await s.json()||{},reason:null}:{checked:!1,statuses:null,reason:`status-${s.status}`}}catch{return{checked:!1,statuses:null,reason:"network-error"}}}function g(t,s){if(!s||!t)return{connected:null};let n=t[s];return!n||typeof n.connected!="boolean"?{connected:null,details:n||null}:{connected:n.connected,details:n}}var j={id:"skill-installer",description:"Live skill installation for chat sessions",envKeys:[],catalog:r,promptFragment:S,tools:[{name:"install_skill",description:"Install a skill into the current chat session so its tools become available",input_schema:{type:"object",properties:{skillId:{type:"string",description:'Skill identifier to install (e.g. "jira", "github", "browser", "memory")'}},required:["skillId"]}},{name:"uninstall_skill",description:"Remove a skill from the current chat session",input_schema:{type:"object",properties:{skillId:{type:"string",description:"Skill identifier to remove"}},required:["skillId"]}},{name:"list_available_skills",description:"List all skills that can be installed, with their env-var readiness status",input_schema:{type:"object",properties:{}}}],async handleToolCall(t,s,n){let{activeSkills:o}=n,d=await R();if(t==="list_available_skills"){let e=Object.entries(r).map(([i,a])=>{let h=o.includes(i),c=g(d.statuses,a.integrationProvider);return{id:i,description:a.description,installed:h,integrationProvider:a.integrationProvider||void 0,integrationConnected:c.connected,setupInstructions:c.connected===!1?a.setupInstructions:void 0}});return JSON.stringify({skills:e})}if(t==="install_skill"){let{skillId:e}=s;if(!e)return JSON.stringify({ok:!1,error:"skillId is required"});if(o.includes(e)){let l=r[e],{getSkill:u}=await import("@zibby/agent-workflow"),k=(u(e)?.tools||[]).map(y=>y.name);return JSON.stringify({ok:!0,alreadyInstalled:!0,skillId:e,description:l?.description,availableTools:k,integrationUrl:l?.integrationProvider?p():void 0,hint:`${e} is already active. Tools available: ${k.join(", ")}. Use them directly.`})}if(!r[e])return JSON.stringify({ok:!1,error:`Unknown skill "${e}". Available: ${Object.keys(r).join(", ")}`});let i=r[e];if(i.integrationProvider){let l=g(d.statuses,i.integrationProvider),u=p();if(d.checked&&l.connected===!1){let f=P(u);return JSON.stringify({ok:!1,error:`${i.integrationProvider} is not connected for this Zibby account yet`,needsIntegration:!0,integrationUrl:u,openedBrowser:f,setupInstructions:`Please connect ${i.integrationProvider} first at ${u}. After you finish OAuth, ask me to install ${e} again.`})}}o.push(e);let{getSkill:a}=await import("@zibby/agent-workflow"),c=(a(e)?.tools||[]).map(l=>l.name);return JSON.stringify({ok:!0,installed:e,description:i.description,availableTools:c,hint:`${e} is now active. You now have these tools: ${c.join(", ")}. Use them immediately to help the user \u2014 don't just confirm installation.`})}if(t==="uninstall_skill"){let{skillId:e}=s;if(!e)return JSON.stringify({ok:!1,error:"skillId is required"});if(e==="skill-installer")return JSON.stringify({ok:!1,error:"Cannot uninstall the skill installer"});let i=o.indexOf(e);return i===-1?JSON.stringify({ok:!1,error:`${e} is not installed`}):(o.splice(i,1),JSON.stringify({ok:!0,uninstalled:e}))}return JSON.stringify({error:`Unknown tool: ${t}`})},resolve(){return null}};export{j as skillInstallerSkill};
@@ -1,338 +1,202 @@
1
1
  ---
2
- sidebar_position: 6
2
+ sidebar_position: 4
3
3
  title: CLI Reference
4
4
  ---
5
5
 
6
6
  # CLI Reference
7
7
 
8
- ## Installation
8
+ Every command lives under `zibby workflow <verb>` for consistency. The bare top-level forms (`zibby start`, `zibby deploy`, `zibby trigger`, `zibby logs`, `zibby g workflow`) are kept as backward-compat aliases — they call the same handlers — but new code should use the namespaced forms.
9
9
 
10
- ```bash
11
- npm install -g @zibby/cli
12
- ```
13
-
14
- ---
15
-
16
- ## Commands
17
-
18
- ### `zibby test [spec-path]`
19
-
20
- Run a test specification.
21
-
22
- ```bash
23
- # Run a local test spec
24
- zibby test test-specs/login.txt --agent cursor
25
-
26
- # Run without any project setup
27
- echo "Go to example.com" > test.txt && zibby test test.txt --agent cursor
28
-
29
- # Run with cloud sync
30
- zibby test test-specs/login.txt --sync
10
+ ## Workflow commands
31
11
 
32
- # Run test cases from cloud
33
- zibby test --sources TC001,TC002 --execution abc123
34
- ```
35
-
36
- | Flag | Description |
12
+ | Command | What it does |
37
13
  |---|---|
38
- | `--agent <type>` | AI agent: `cursor`, `claude`, or `codex` |
39
- | `--workflow <name>` | Workflow to use (e.g., `QuickSmokeWorkflow`, `quick-smoke`) |
40
- | `--headless` | Run browser in headless mode |
41
- | `--node <name>` | Run only a specific node (`preflight`, `execute_live`, `generate_script`) |
42
- | `--session <id>` | Reuse an existing session (`last` for most recent) requires `--node` |
43
- | `--sources <ids>` | Comma-separated test case IDs to fetch from cloud |
44
- | `--execution <id>` | Execution ID (required with `--sources`) |
45
- | `--project <id>` | Project ID or API token (auto-detected from `ZIBBY_API_KEY`) |
46
- | `--collection <id-or-name>` | Collection to organize the run into (creates if name is new) |
47
- | `--folder <path>` | Folder within the collection |
48
- | `--sync` | Force upload results to cloud |
49
- | `--no-sync` | Skip cloud upload |
50
- | `--config <path>` | Config file path (default: `.zibby.config.js`) |
51
- | `--auto-approve` | Auto-approve MCP tool calls (for CI/CD) |
52
- | `-o, --open` | Open results in browser after upload |
53
- | `--verbose` | Show info-level logs |
54
- | `--debug` | Show debug-level logs |
55
-
56
- ---
57
-
58
- ### `zibby init [project-name]`
59
-
60
- Initialize a Zibby project with config and workflow files. **Optional** — `zibby test` works without it using the built-in workflow.
61
-
62
- ```bash
63
- zibby init
64
- zibby init my-project --agent cursor --cloud-sync
65
- ```
66
-
67
- | Flag | Description |
14
+ | [`zibby workflow new <name>`](#workflow-new) | Scaffold a new custom workflow under `.zibby/workflows/<name>/`. |
15
+ | [`zibby workflow run <name>`](#workflow-run) | One-shot local execution. Same input flags as `trigger`. |
16
+ | [`zibby workflow list`](#workflow-list) | List local + deployed workflows. |
17
+ | [`zibby workflow deploy [name]`](#workflow-deploy) | Deploy to Zibby Cloud. Interactive picker if name omitted. |
18
+ | [`zibby workflow trigger [uuid]`](#workflow-trigger) | Run a deployed workflow remotely. UUID is canonical. |
19
+ | [`zibby workflow logs [uuid] -t`](#workflow-logs) | Tail logs from a run, Heroku-style. |
20
+ | [`zibby workflow download <uuid>`](#workflow-download) | Pull a deployed workflow back to local. Edit + redeploy. |
21
+ | [`zibby workflow delete <uuid>`](#workflow-delete) | Delete a deployed workflow. |
22
+ | [`zibby workflow start <name>`](#workflow-start) | Long-lived dev server (Studio integration). Most users want `run`. |
23
+ | [`zibby workflow env <verb>`](#workflow-env) | Manage per-workflow encrypted env vars: `list`, `set`, `unset`, `push`. |
24
+
25
+ Plus auth + admin:
26
+
27
+ | Command | What it does |
68
28
  |---|---|
69
- | `--agent <type>` | `cursor`, `claude`, or `codex` |
70
- | `--cloud-sync` | Enable cloud sync |
71
- | `--headless` | Headless browser mode |
72
- | `--headed` | Headed browser mode |
73
- | `--api-key <key>` | Zibby API key |
74
- | `--skip-install` | Skip `npm install` |
75
- | `-f, --force` | Overwrite existing config |
29
+ | `zibby login` | OAuth in browser. Writes session to `~/.zibby/config.json`. |
30
+ | `zibby logout` | Clear session. |
31
+ | `zibby status` | Show current auth state. |
32
+ | `zibby project list` | List projects you have access to. |
76
33
 
77
- ---
78
-
79
- ### `zibby login`
80
-
81
- Authenticate with Zibby (opens browser for OAuth).
34
+ ## workflow new {#workflow-new}
82
35
 
83
36
  ```bash
84
- zibby login
37
+ zibby workflow new [name]
85
38
  ```
86
39
 
87
- ---
40
+ Scaffolds `.zibby/workflows/<name>/` with a starter `graph.mjs`, `nodes/example.mjs`, `package.json`, and `workflow.json` manifest. Auto-runs `npm install` in the new folder unless `--skip-install`.
88
41
 
89
- ### `zibby logout`
42
+ Options:
43
+ - `--skip-install` — skip `npm install`
44
+ - If `name` is omitted, the CLI generates one (`zealous-otter`, etc.)
90
45
 
91
- Clear saved session.
46
+ ## workflow run {#workflow-run}
92
47
 
93
48
  ```bash
94
- zibby logout
49
+ zibby workflow run <workflow-name>
95
50
  ```
96
51
 
97
- ---
98
-
99
- ### `zibby status`
100
-
101
- Show current authentication status.
102
-
103
- ```bash
104
- zibby status
105
- zibby status --json
106
- ```
107
-
108
- ---
52
+ Loads `graph.mjs`, instantiates the entry class, runs the graph **once** in-process, prints results, and exits. Output → `.zibby/output/sessions/<sessionId>/`.
109
53
 
110
- ### `zibby list`
54
+ Mirrors `zibby workflow trigger` so the same input flags work locally and in the cloud — flip the verb and the project, and your local dev loop is exactly the same call shape your CI/CD uses.
111
55
 
112
- List your projects and API tokens.
56
+ Options:
57
+ - `-p, --param <key=value>` — input param (repeatable, highest precedence). Example: `-p ticket=BUG-123 -p priority=high`
58
+ - `--input <json>` — input as JSON string
59
+ - `--input-file <path>` — input as JSON file (lowest precedence)
113
60
 
61
+ Examples:
114
62
  ```bash
115
- zibby list
63
+ zibby workflow run my-pipeline
64
+ zibby workflow run my-pipeline -p ticket=BUG-123
65
+ zibby workflow run my-pipeline --input '{"ticket":"BUG-123","priority":"high"}'
66
+ zibby workflow run my-pipeline --input-file payload.json -p priority=urgent
116
67
  ```
117
68
 
118
- ---
119
-
120
- ### `zibby upload <spec-path>`
121
-
122
- Upload existing test artifacts to Zibby Cloud.
123
-
124
- ```bash
125
- zibby upload test-specs/login.txt --collection "Auth Tests"
126
- ```
127
-
128
- | Flag | Description |
129
- |---|---|
130
- | `--project <id>` | Project ID (required) |
131
- | `--collection <id-or-name>` | Collection to upload into |
132
- | `--folder <path>` | Folder within collection |
133
-
134
- ---
135
-
136
- ### `zibby video`
137
-
138
- Organize test videos — moves videos from `test-results/` to sit next to test files.
69
+ ## workflow start {#workflow-start}
139
70
 
140
71
  ```bash
141
- zibby video
72
+ zibby workflow start <workflow-name>
142
73
  ```
143
74
 
144
- ---
75
+ Long-lived local dev server (default port 3848). Listens on `POST /trigger` for input payloads and runs the workflow in-process. Used today by the Studio desktop app — for plain CLI use, prefer `workflow run`.
145
76
 
146
- ### `zibby setup-playwright`
77
+ Options:
78
+ - `-p, --port <port>` — override the default port (3848)
147
79
 
148
- Configure the Playwright MCP server.
80
+ ## workflow list {#workflow-list}
149
81
 
150
82
  ```bash
151
- zibby setup-playwright
152
- zibby setup-playwright --headed --viewport-width 1920 --viewport-height 1080
83
+ zibby workflow list
153
84
  ```
154
85
 
155
- ---
86
+ Shows both local workflows (folders under `.zibby/workflows/`) and deployed ones (from cloud, scoped to projects you have access to). Output is a table with UUID, Name, Project, Version. `-` in any column means "not applicable" (e.g. local-only workflows have no UUID yet).
156
87
 
157
- ### `zibby ci-setup`
88
+ Options:
89
+ - `--local-only` — skip the cloud query
90
+ - `--remote-only` — skip the local scan
91
+ - `--project <id>` — filter to one project
158
92
 
159
- Configure Cursor Agent for CI/CD pipelines.
93
+ ## workflow deploy {#workflow-deploy}
160
94
 
161
95
  ```bash
162
- zibby ci-setup
163
- zibby ci-setup --get-keys
164
- zibby ci-setup --save
96
+ zibby workflow deploy [workflow-name]
165
97
  ```
166
98
 
167
- ---
168
-
169
- ### `zibby g workflow [name]`
170
-
171
- Scaffold a new custom workflow. Auto-generates a name if omitted.
172
-
173
- ```bash
174
- zibby g workflow ticket-triage
175
- zibby g workflow # auto-generates name
176
- ```
99
+ Two phases:
100
+ 1. Upload sources to S3 (presigned PUT). The CLI also resolves your `.zibby.config.mjs` (if present at project root) and includes it in the bundle as `zibby.config.json` — see [Bundle build](./cloud/bundles).
101
+ 2. CodeBuild downloads, runs `npm install --omit=dev`, packages a tarball, uploads it. The tarball is what each cloud execution downloads at trigger time.
177
102
 
178
- ---
103
+ After success, the CLI writes `.zibby/workflows/<name>/.zibby-deploy.json` with the canonical UUID. Commit this file.
179
104
 
180
- ### `zibby start <workflow-name>`
105
+ Options:
106
+ - `--project <id>` — skip the project picker
107
+ - `--api-key <key>` — auth via API key (or set `ZIBBY_API_KEY`)
108
+ - `--env <path>` — sync a `.env` file into per-workflow env vars after deploy. Repeatable (later files override). See [Per-workflow env vars](./cloud/env-vars).
109
+ - `--verbose` — show raw CodeBuild logs during the bundle build
181
110
 
182
- Start a local dev server for testing a custom workflow.
111
+ ## workflow trigger {#workflow-trigger}
183
112
 
184
113
  ```bash
185
- zibby start ticket-triage
186
- zibby start ticket-triage --port 3850
114
+ zibby workflow trigger <uuid>
187
115
  ```
188
116
 
189
- | Flag | Description |
190
- |---|---|
191
- | `-p, --port <port>` | Server port (default: 3848) |
192
-
193
- ---
117
+ UUID is required (or omit for interactive picker). Names aren't accepted — pass the UUID from `.zibby-deploy.json` or `workflow list`.
194
118
 
195
- ### `zibby deploy <workflow-name>`
119
+ Options:
120
+ - `-p, --param <key=value>` — input param (repeatable, highest precedence)
121
+ - `--input <json>` — input as JSON string
122
+ - `--input-file <path>` — input as JSON/YAML file (lowest precedence)
123
+ - `--idempotency-key <key>` — prevent duplicate executions
124
+ - `--api-key <key>` — auth via API key
196
125
 
197
- Deploy a custom workflow to Zibby Cloud. Returns the trigger URL and workflow UUID.
126
+ ## workflow logs {#workflow-logs}
198
127
 
199
128
  ```bash
200
- zibby deploy ticket-triage --project <id>
129
+ zibby workflow logs <uuid> # dump latest run
130
+ zibby workflow logs <uuid> -t # tail live (Heroku-style)
201
131
  ```
202
132
 
203
- | Flag | Description |
204
- |---|---|
205
- | `--project <id>` | Project ID (or `ZIBBY_PROJECT_ID` env) |
206
- | `--api-key <key>` | API key (or `ZIBBY_API_KEY` env, or session token) |
133
+ When `-t` is set and the workflow finishes, the stream waits for the next trigger of the same workflow and auto-switches to streaming it. Ctrl+C to exit.
207
134
 
208
- ---
135
+ Options:
136
+ - `-t, --follow` — live tail
137
+ - `--lines <n>` — max log lines per fetch (default: 500)
138
+ - `--all --workflow <name>` — interleaved logs from all runs (requires `--workflow`)
139
+ - `--api-key <key>` — auth via API key
209
140
 
210
- ### `zibby trigger <workflow-uuid>`
141
+ **Storage & retention.** Live logs are kept in CloudWatch for 30 days. Beyond that, the per-run session folder (uploaded to S3 at the end of every execution) is the long-term archive — pull it back with `zibby workflow download <uuid>`.
211
142
 
212
- Trigger a deployed workflow by its UUID. The CLI automatically discovers the project.
143
+ ## workflow env {#workflow-env}
213
144
 
214
- ```bash
215
- # Trigger by UUID (project auto-discovered)
216
- zibby trigger 562e48d7-ef67-4900-96b7-0d7b51a33405
217
-
218
- # Trigger by UUID with input data
219
- zibby trigger 562e48d7-ef67-4900-96b7-0d7b51a33405 \
220
- --input '{"ticket":"JIRA-123"}'
221
-
222
- # Trigger by name (requires project)
223
- zibby trigger custom-flow --project <id>
224
-
225
- # With idempotency key (prevents duplicate runs)
226
- zibby trigger 562e48d7-ef67-4900-96b7-0d7b51a33405 \
227
- --idempotency-key "daily-scan-2026-04-27"
228
- ```
229
-
230
- | Flag | Description |
231
- |---|---|
232
- | `--input <json>` | Input data as JSON string |
233
- | `--idempotency-key <key>` | Prevent duplicate executions (same key within 24h) |
234
- | `--project <id>` | Project ID (only needed if triggering by workflow name) |
235
-
236
- **After triggering, stream logs:**
145
+ Per-workflow encrypted env vars — KMS-stored on the workflow record, injected into the Fargate task at trigger time. Workflow env wins over project secrets on conflict.
237
146
 
238
147
  ```bash
239
- zibby logs 562e48d7-ef67-4900-96b7-0d7b51a33405 -t
148
+ zibby workflow env list <uuid> # show key names (no values)
149
+ zibby workflow env set <uuid> ANTHROPIC_API_KEY=sk-… # add or rotate one
150
+ zibby workflow env unset <uuid> OLD_KEY # remove one
151
+ zibby workflow env push <uuid> --file .env [--file .env.prod] # bulk replace from .env files
240
152
  ```
241
153
 
242
- ---
154
+ `push` accepts repeatable `--file` (later files override). `list` only ever returns key names — values never leave the encrypted blob.
243
155
 
244
- ### `zibby logs <workflow-uuid>`
156
+ The shortcut for first-time setup is `zibby workflow deploy --env .env`, which runs `push` automatically against the new UUID. Full guide: [Per-workflow env vars](./cloud/env-vars).
245
157
 
246
- Fetch and display logs from a workflow's latest execution.
158
+ ## workflow download {#workflow-download}
247
159
 
248
160
  ```bash
249
- # Fetch logs for latest execution (simple, one-time fetch)
250
- zibby logs 562e48d7-ef67-4900-96b7-0d7b51a33405
251
-
252
- # Stream logs in real-time (like "heroku logs -t")
253
- zibby logs 562e48d7-ef67-4900-96b7-0d7b51a33405 -t
254
-
255
- # Stream logs by workflow name
256
- zibby logs --workflow custom-flow --project <id> -t
161
+ zibby workflow download <uuid>
257
162
  ```
258
163
 
259
- | Flag | Description |
260
- |---|---|
261
- | `-t, --follow` | Stream logs in real-time via SSE (Server-Sent Events) |
262
- | `--project <id>` | Project ID (optional, auto-discovered from workflow UUID) |
263
- | `--workflow <name>` | Workflow name (fetches latest run) |
264
- | `--all` | Interleaved logs from all runs (requires `--workflow`) |
265
- | `--lines <n>` | Max log lines per fetch (default: 1000) |
266
-
267
- **How it works:**
268
-
269
- - **Without `-t`**: Fetches complete logs from CloudWatch (permanent storage) and exits. Perfect for historical logs and debugging old executions.
270
- - **With `-t`**: Streams logs in real-time via SSE from DynamoDB hot cache (24h TTL). Only works for active/recent executions. Press Ctrl+C to stop.
164
+ Pulls the deployed workflow's sources back into `.zibby/workflows/<name>/`, including the `.zibby-deploy.json` manifest. Useful when collaborators need the source from cloud.
271
165
 
272
- **Architecture:**
166
+ Options:
167
+ - `--type <type>` — for built-in workflows (`analysis`, `implementation`, `run_test`)
168
+ - `--output <dir>` — alternate output base
169
+ - `--include-default` — pull the built-in default graph if no custom one exists
273
170
 
274
- ```
275
- CloudWatch Logs (permanent) ──────────> CLI (without -t)
276
-
277
- └──> Kinesis ──> Lambda ──> DynamoDB (24h TTL) ──> SSE ──> CLI (with -t)
278
- ```
279
-
280
- ---
281
-
282
- ### `zibby workflow download`
283
-
284
- Download a workflow graph from Zibby Cloud.
171
+ ## workflow delete {#workflow-delete}
285
172
 
286
173
  ```bash
287
- zibby workflow download --type run_test
174
+ zibby workflow delete <uuid>
288
175
  ```
289
176
 
290
- ### `zibby workflow list`
177
+ Removes the workflow from cloud (and its trigger URL). Local files are not touched.
291
178
 
292
- List all workflows for a project.
179
+ ## Environment variables
293
180
 
294
- ```bash
295
- zibby workflow list
296
- ```
181
+ | Var | Purpose |
182
+ |---|---|
183
+ | `ZIBBY_API_KEY` | API key for non-interactive auth (CI). Preferred over saved session. |
184
+ | `ZIBBY_PROJECT_ID` | Default project for commands that take `--project` |
185
+ | `AGENT_TYPE` | Default agent strategy when no per-node override and no project default |
186
+ | `ZIBBY_DEPLOY_VERBOSE=1` | Same as `--verbose` on `workflow deploy` |
187
+ | `ZIBBY_SESSION_LOG=1` | Re-enable the diagnostic `[zibby:session]` log line in run output |
188
+ | `ZIBBY_RUN_DIAG=1` | Cloud runtime: dump per-copy `agent-workflow` registry state |
189
+ | `ZIBBY_DEBUG=true` | Verbose debug logs from the framework |
297
190
 
298
- ---
191
+ ## Legacy aliases
299
192
 
300
- ## Environment Variables
193
+ These still work and route to the same handlers, but new code should use the `zibby workflow <verb>` form:
301
194
 
302
- | Variable | Description |
195
+ | Legacy | Canonical |
303
196
  |---|---|
304
- | `CURSOR_API_KEY` | Cursor agent API key (required in CI, optional locally) |
305
- | `ANTHROPIC_API_KEY` | Claude agent API key |
306
- | `OPENAI_API_KEY` | Codex agent API key |
307
- | `ZIBBY_API_KEY` | Project API key for cloud sync (from dashboard Settings) |
308
- | `ZIBBY_USER_TOKEN` | Personal Access Token for CI/CD uploads |
309
- | `ZIBBY_ENV` | Environment override: `local`, `staging`, `prod` |
310
-
311
- ## Configuration File
312
-
313
- `.zibby.config.js` in your project root (ESM):
314
-
315
- ```javascript
316
- export default {
317
- agent: {
318
- cursor: { model: 'auto' },
319
- // claude: { model: 'auto' },
320
- // codex: { model: 'gpt-5.2-codex' },
321
- },
322
-
323
- paths: {
324
- specs: 'test-specs',
325
- generated: 'tests',
326
- output: '.zibby/output',
327
- },
328
-
329
- context: {
330
- filenames: ['CONTEXT.md', 'AGENTS.md'],
331
- },
332
-
333
- video: 'on',
334
- viewport: { width: 1280, height: 720 },
335
- playwrightArtifacts: true,
336
- cloudSync: false,
337
- };
338
- ```
197
+ | `zibby g workflow <name>` | `zibby workflow new <name>` |
198
+ | `zibby start <name>` | `zibby workflow start <name>` |
199
+ | `zibby run <name>` | `zibby workflow run <name>` |
200
+ | `zibby deploy [name]` | `zibby workflow deploy [name]` |
201
+ | `zibby trigger <uuid>` | `zibby workflow trigger <uuid>` |
202
+ | `zibby logs <uuid>` | `zibby workflow logs <uuid>` |
@@ -269,7 +269,7 @@ Common failure reasons:
269
269
 
270
270
  ## Local Development
271
271
 
272
- When running workflows locally (`zibby start`), you'll need to:
272
+ When running workflows locally (`zibby workflow run`), you'll need to:
273
273
  1. Set `REPOS` env var manually (JSON array)
274
274
  2. Provide `GITHUB_TOKEN` or `GITLAB_TOKEN`
275
275
  3. Ensure `git` is installed
@@ -279,7 +279,7 @@ Example for local testing:
279
279
  ```bash
280
280
  export REPOS='[{"name":"myorg/backend","provider":"github","cloneUrl":"https://github.com/myorg/backend.git"}]'
281
281
  export GITHUB_TOKEN="ghp_your_token"
282
- zibby start my-workflow
282
+ zibby workflow run my-workflow
283
283
  ```
284
284
 
285
285
  In production (cloud), these are injected automatically.