@zibby/cli 0.1.42 → 0.1.45
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/bin/zibby.js +1 -1
- package/dist/commands/chat.js +61 -51
- package/dist/commands/init.js +46 -45
- package/dist/commands/setup-scripts.js +16 -11
- package/dist/commands/workflows/deploy.js +15 -16
- package/dist/commands/workflows/logs.js +21 -0
- package/dist/package.json +5 -4
- package/package.json +5 -4
package/dist/bin/zibby.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.stdout.on("error",o=>{o.code}),process.stderr.on("error",o=>{o.code}),process.env.DOTENV_CONFIG_QUIET="true";import"@zibby/skills";import{Command as s}from"commander";import{initCommand as c}from"../commands/init.js";import{runCommand as d}from"../commands/run.js";import{videoCommand as p}from"../commands/video.js";import{uploadCommand as m}from"../commands/upload.js";import{ciSetupCommand as l}from"../commands/ci-setup.js";import{setupPlaywrightMcpCommand as u,setupCiCommand as f,testWithVideoCommand as w}from"../commands/setup-scripts.js";import{readFileSync as y}from"fs";import{fileURLToPath as g}from"url";import{dirname as h,join as b}from"path";const k=g(import.meta.url),C=h(k),v=JSON.parse(y(b(C,"../package.json"),"utf-8")),i=process.argv.slice(2),I=i.includes("-h")||i.includes("--help"),P=i.includes("-V")||i.includes("--version"),S=i[0]==="chat",D=["--verbose","-v","--agent","--stream","-s"],_=i.length>0&&i.every(o=>D.includes(o)||i[i.indexOf(o)-1]==="--agent"),E=i.length===0||S||_;if(E&&!I&&!P){const o={},t=i.indexOf("--agent");t!==-1&&i[t+1]&&(o.agent=i[t+1]),(i.includes("--verbose")||i.includes("-v"))&&(o.verbose=!0),(i.includes("--stream")||i.includes("-s"))&&(o.stream=!0);const{chatCommand:n}=await import("../commands/chat.js");await n(o),process.exit(0)}const e=new s;e.name("zibby").description("Zibby Test Automation - AI-powered test generation").version(v.version),e.command("init").description("Initialize a new Zibby test project (like rails new)").argument("[project-name]","Project name (optional, uses current directory if not provided)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini)").option("--memory-backend <backend>","Memory backend to configure (dolt, mem0)","dolt").option("--skip-install","Skip npm install").option("--skip-memory","Skip test memory setup during initialization").option("-f, --force","Force reinitialize (overwrite existing config)").option("--headed","Run MCP browser in headed mode (visible browser)").option("--headless","Run MCP browser in headless mode (hidden browser)").option("--api-key <key>","Zibby API key for cloud sync").option("--cloud-sync","Enable cloud sync and install Zibby MCP").action(c),e.command("test").description("Run a test specification").argument("[spec-path]","Path to test spec file or inline test description in quotes").option("--sources <ids>","Comma-separated test case IDs to fetch from cloud").option("--execution <id>","Execution ID containing the test cases (required with --sources)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini) - overrides config").option("--workflow <name>","Workflow to use (e.g., QuickSmokeWorkflow, quick-smoke)").option("--headless","Run browser in headless mode").option("--node <name>","Run only a specific node (e.g., execute_live, generate_script)").option("--session <id>",'Use existing session (e.g., 1768974629717 or "last") - requires --node').option("--session-path <dir>","Use this session folder (absolute or relative to cwd); Studio pins artifacts here").option("--project <id>","Project ID (optional, auto-detected from ZIBBY_API_KEY)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional, requires --collection)").option("--sync","Force upload to cloud (overrides cloudSync: false)").option("--no-sync","Skip upload to cloud (overrides cloudSync: true)").option("--config <path>","Path to config file",".zibby.config.mjs").option("--auto-approve","Auto-approve MCP tools (for CI/CD)").option("-o, --open","Open test results in browser after completion").option("--verbose","Show info level logs").option("--debug","Show debug level logs (most verbose)").option("-m, --mem","Enable test memory (Dolt-backed knowledge from previous runs)").action((o,t)=>(t.debug?process.env.ZIBBY_DEBUG="true":t.verbose&&(process.env.ZIBBY_VERBOSE="true"),d(o,t))),e.command("implement").description("Implement a Jira ticket using AI agent (runs in ECS container)").action(async(...o)=>{const{implementCommand:t}=await import("../commands/implement.js");return t(...o)}),e.command("analyze").description("Analyze a Jira ticket against the codebase (runs in ECS container)").option("--workflow <path>","Path to a local workflow JSON file (e.g., .zibby/workflow-analysis.json)").action(async(...o)=>{const{analyzeCommand:t}=await import("../commands/analyze-graph.js");return t(...o)}),e.command("video").description("Organize test videos next to test files").action(p),e.command("upload <spec-path>").description("Upload existing test artifacts to Zibby Cloud").option("--project <id>","Project ID (REQUIRED - use flag or ZIBBY_PROJECT_ID env)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional)").option("--agent <type>","Agent used (for metadata)").action(m),e.command("login").description("Log in to Zibby (opens browser for authentication)").action(async()=>{const{loginCli:o}=await import("../auth/cli-login.js");await o(),process.exit(0)}),e.command("logout").description("Log out from Zibby (clears saved session)").action(async()=>{const{logoutCli:o}=await import("../auth/cli-login.js");o(),process.exit(0)}),e.command("status").description("Show current authentication status and token details").option("--json","Output in JSON format (for scripts)").action(async o=>{const{showLoginStatus:t}=await import("../auth/cli-login.js");await t(o),process.exit(0)}),e.command("list").description("List your projects and API tokens").action(async()=>{const{listProjectsCommand:o}=await import("../commands/list-projects.js");await o()}),e.command("ci-setup").description("Setup Cursor Agent for CI/CD (patch and configure)").option("--get-keys","Get MCP approval keys").option("--save","Save approval keys to project").action(l),e.command("setup-playwright").description("Setup official Playwright MCP (from cursor-agent-package)").option("--headed","Configure MCP in headed mode (visible browser)").option("--viewport-width <width>","Viewport width (default: 1280)","1280").option("--viewport-height <height>","Viewport height (default: 720)","720").action(o=>{const t={width:parseInt(o.viewportWidth,10)||1280,height:parseInt(o.viewportHeight,10)||720};return u({...o,viewport:t})}),e.command("setup-ci-full").description("Complete CI/CD setup from scratch").action(f),e.command("test-video").description("Run Playwright tests with video recording").argument("[test-file]","Test file to run (default: tests/)").option("--headed","Run in headed mode (visible browser)").action(w),e.command("generate").description("Generate test specs from a ticket + codebase (local analysis using real AI agent)").option("-t, --ticket <key>","Jira ticket key (fetches automatically)").option("-i, --input <file>","Input file with ticket description/requirements").option("-d, --description <text>","Inline ticket description").option("--repo <path>","Path to the codebase (default: current directory)").option("--agent <type>","Agent to use (codex, claude, cursor, gemini)").option("--model <model>","Model override").option("-o, --output <dir>","Output directory for spec files (default: test-specs)").action(async o=>{const{generateCommand:t}=await import("../commands/generate.js");return t(o)}),e.command("studio").description("Launch Zibby Studio desktop (installs from CDN if needed). Uses this folder as the Zibby project.").option("-p, --port <port>","Port for the Studio API bridge (default: 3847)").option("--no-open","Start the API only; do not launch desktop app").option("--update","Force re-download of the latest Studio binary").action(async o=>{const{studioCommand:t}=await import("../commands/studio.js");return t(o)});const j=e.command("g").description("Generate scaffolds");j.command("workflow [name]").description("Scaffold a new custom workflow in .zibby/workflows/<name>/ (auto-generates name if omitted)").action(async o=>{const{generateWorkflowCommand:t}=await import("../commands/workflows/generate.js");return t(o)}),e.command("start <workflow-name>").description("Start a local dev server for a custom workflow").option("-p, --port <port>","Port for the workflow server (default: 3848)").action(async(o,t)=>{const{startWorkflowCommand:n}=await import("../commands/workflows/start.js");return n(o,t)}),e.command("deploy <workflow-name>").description("Deploy a custom workflow to Zibby Cloud").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").action(async(o,t)=>{const{deployWorkflowCommand:n}=await import("../commands/workflows/deploy.js");return n(o,t)}),e.command("run-workflow").description("Run a deployed workflow from S3 sources (used by ECS containers)").action(async()=>{const{runWorkflowCommand:o}=await import("../commands/workflows/run.js");return o()});const a=e.command("memory").description("Test memory database \u2014 version-controlled knowledge from runs");a.command("stats").description("Show memory database statistics").action(async()=>{const{memoryStatsCommand:o}=await import("../commands/memory.js");return o()}),a.command("init").description("Initialize the memory database (Dolt)").action(async()=>{const{memoryInitCommand:o}=await import("../commands/memory.js");return o()}),a.command("compact").description("Prune old data and run Dolt GC to reclaim storage").option("--max-runs <n>","Keep last N runs per spec (default: 50)",parseInt).option("--max-age <days>","Remove data older than N days (default: 90)",parseInt).action(async o=>{const{memoryCompactCommand:t}=await import("../commands/memory.js");return t(o)}),a.command("reset").description("Wipe the memory database").option("-f, --force","Confirm reset").action(async o=>{const{memoryResetCommand:t}=await import("../commands/memory.js");return t(o)});const r=e.command("workflow").description("Manage workflow graphs (download, upload, list)");r.command("download").description("Download a workflow graph from Zibby Cloud to .zibby/").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--type <type>","Workflow type: analysis, implementation, run_test").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").option("--output <dir>","Output directory (default: .zibby/)").option("--include-default","Download the built-in default graph if no custom one exists").action(async o=>{const{workflowDownloadCommand:t}=await import("../commands/workflow.js");return t(o)}),r.command("list").description("List all workflows for a project").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").action(async o=>{const{workflowListCommand:t}=await import("../commands/workflow.js");return t(o)});const x=e.command("run-queue").description("Parallel capacity \u2014 on-disk wait queue (see parallel.waitWhenAtCapacity in .zibby.config.mjs)");x.command("list").description("List CLI processes waiting for a run slot").option("--config <path>","Path to config file",".zibby.config.mjs").action(async o=>{const{runCapacityQueueListCommand:t}=await import("../commands/run-capacity-queue-cli.js");await t(o),process.exit(0)}),e.parse();
|
|
2
|
+
process.stdout.on("error",o=>{o.code}),process.stderr.on("error",o=>{o.code}),process.env.DOTENV_CONFIG_QUIET="true";import"@zibby/skills";import{Command as s}from"commander";import{initCommand as c}from"../commands/init.js";import{runCommand as d}from"../commands/run.js";import{videoCommand as p}from"../commands/video.js";import{uploadCommand as m}from"../commands/upload.js";import{ciSetupCommand as l}from"../commands/ci-setup.js";import{setupPlaywrightMcpCommand as u,setupCiCommand as f,testWithVideoCommand as w}from"../commands/setup-scripts.js";import{readFileSync as y}from"fs";import{fileURLToPath as g}from"url";import{dirname as h,join as k}from"path";const b=g(import.meta.url),C=h(b),I=JSON.parse(y(k(C,"../package.json"),"utf-8")),i=process.argv.slice(2),v=i.includes("-h")||i.includes("--help"),P=i.includes("-V")||i.includes("--version"),S=i[0]==="chat",_=["--verbose","-v","--agent","--stream","-s"],j=i.length>0&&i.every(o=>_.includes(o)||i[i.indexOf(o)-1]==="--agent"),D=i.length===0||S||j;if(D&&!v&&!P){const o={},t=i.indexOf("--agent");t!==-1&&i[t+1]&&(o.agent=i[t+1]),(i.includes("--verbose")||i.includes("-v"))&&(o.verbose=!0),(i.includes("--stream")||i.includes("-s"))&&(o.stream=!0);const{chatCommand:n}=await import("../commands/chat.js");await n(o),process.exit(0)}const e=new s;e.name("zibby").description("Zibby Test Automation - AI-powered test generation").version(I.version),e.command("init").description("Initialize a new Zibby test project (like rails new)").argument("[project-name]","Project name (optional, uses current directory if not provided)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini)").option("--memory-backend <backend>","Memory backend to configure (dolt, mem0)","dolt").option("--skip-install","Skip npm install").option("--skip-memory","Skip test memory setup during initialization").option("-f, --force","Force reinitialize (overwrite existing config)").option("--headed","Run MCP browser in headed mode (visible browser)").option("--headless","Run MCP browser in headless mode (hidden browser)").option("--api-key <key>","Zibby API key for cloud sync").option("--cloud-sync","Enable cloud sync and install Zibby MCP").action(c),e.command("test").description("Run a test specification").argument("[spec-path]","Path to test spec file or inline test description in quotes").option("--sources <ids>","Comma-separated test case IDs to fetch from cloud").option("--execution <id>","Execution ID containing the test cases (required with --sources)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini) - overrides config").option("--workflow <name>","Workflow to use (e.g., QuickSmokeWorkflow, quick-smoke)").option("--headless","Run browser in headless mode").option("--node <name>","Run only a specific node (e.g., execute_live, generate_script)").option("--session <id>",'Use existing session (e.g., 1768974629717 or "last") - requires --node').option("--session-path <dir>","Use this session folder (absolute or relative to cwd); Studio pins artifacts here").option("--project <id>","Project ID (optional, auto-detected from ZIBBY_API_KEY)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional, requires --collection)").option("--sync","Force upload to cloud (overrides cloudSync: false)").option("--no-sync","Skip upload to cloud (overrides cloudSync: true)").option("--config <path>","Path to config file",".zibby.config.mjs").option("--auto-approve","Auto-approve MCP tools (for CI/CD)").option("-o, --open","Open test results in browser after completion").option("--verbose","Show info level logs").option("--debug","Show debug level logs (most verbose)").option("-m, --mem","Enable test memory (Dolt-backed knowledge from previous runs)").action((o,t)=>(t.debug?process.env.ZIBBY_DEBUG="true":t.verbose&&(process.env.ZIBBY_VERBOSE="true"),d(o,t))),e.command("implement").description("Implement a Jira ticket using AI agent (runs in ECS container)").action(async(...o)=>{const{implementCommand:t}=await import("../commands/implement.js");return t(...o)}),e.command("analyze").description("Analyze a Jira ticket against the codebase (runs in ECS container)").option("--workflow <path>","Path to a local workflow JSON file (e.g., .zibby/workflow-analysis.json)").action(async(...o)=>{const{analyzeCommand:t}=await import("../commands/analyze-graph.js");return t(...o)}),e.command("video").description("Organize test videos next to test files").action(p),e.command("upload <spec-path>").description("Upload existing test artifacts to Zibby Cloud").option("--project <id>","Project ID (REQUIRED - use flag or ZIBBY_PROJECT_ID env)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional)").option("--agent <type>","Agent used (for metadata)").action(m),e.command("login").description("Log in to Zibby (opens browser for authentication)").action(async()=>{const{loginCli:o}=await import("../auth/cli-login.js");await o(),process.exit(0)}),e.command("logout").description("Log out from Zibby (clears saved session)").action(async()=>{const{logoutCli:o}=await import("../auth/cli-login.js");o(),process.exit(0)}),e.command("status").description("Show current authentication status and token details").option("--json","Output in JSON format (for scripts)").action(async o=>{const{showLoginStatus:t}=await import("../auth/cli-login.js");await t(o),process.exit(0)}),e.command("list").description("List your projects and API tokens").action(async()=>{const{listProjectsCommand:o}=await import("../commands/list-projects.js");await o()}),e.command("ci-setup").description("Setup Cursor Agent for CI/CD (patch and configure)").option("--get-keys","Get MCP approval keys").option("--save","Save approval keys to project").action(l),e.command("setup-playwright").description("Setup official Playwright MCP (from cursor-agent-package)").option("--headed","Configure MCP in headed mode (visible browser)").option("--viewport-width <width>","Viewport width (default: 1280)","1280").option("--viewport-height <height>","Viewport height (default: 720)","720").action(o=>{const t={width:parseInt(o.viewportWidth,10)||1280,height:parseInt(o.viewportHeight,10)||720};return u({...o,viewport:t})}),e.command("setup-ci-full").description("Complete CI/CD setup from scratch").action(f),e.command("test-video").description("Run Playwright tests with video recording").argument("[test-file]","Test file to run (default: tests/)").option("--headed","Run in headed mode (visible browser)").action(w),e.command("generate").description("Generate test specs from a ticket + codebase (local analysis using real AI agent)").option("-t, --ticket <key>","Jira ticket key (fetches automatically)").option("-i, --input <file>","Input file with ticket description/requirements").option("-d, --description <text>","Inline ticket description").option("--repo <path>","Path to the codebase (default: current directory)").option("--agent <type>","Agent to use (codex, claude, cursor, gemini)").option("--model <model>","Model override").option("-o, --output <dir>","Output directory for spec files (default: test-specs)").action(async o=>{const{generateCommand:t}=await import("../commands/generate.js");return t(o)}),e.command("studio").description("Launch Zibby Studio desktop (installs from CDN if needed). Uses this folder as the Zibby project.").option("-p, --port <port>","Port for the Studio API bridge (default: 3847)").option("--no-open","Start the API only; do not launch desktop app").option("--update","Force re-download of the latest Studio binary").action(async o=>{const{studioCommand:t}=await import("../commands/studio.js");return t(o)});const E=e.command("g").description("Generate scaffolds");E.command("workflow [name]").description("Scaffold a new custom workflow in .zibby/workflows/<name>/ (auto-generates name if omitted)").action(async o=>{const{generateWorkflowCommand:t}=await import("../commands/workflows/generate.js");return t(o)}),e.command("start <workflow-name>").description("Start a local dev server for a custom workflow").option("-p, --port <port>","Port for the workflow server (default: 3848)").action(async(o,t)=>{const{startWorkflowCommand:n}=await import("../commands/workflows/start.js");return n(o,t)}),e.command("deploy <workflow-name>").description("Deploy a custom workflow to Zibby Cloud").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").action(async(o,t)=>{const{deployWorkflowCommand:n}=await import("../commands/workflows/deploy.js");return n(o,t)}),e.command("logs [jobId]").description("Tail logs from a workflow job (use --workflow to auto-pick latest)").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--workflow <name>","Workflow name (tails the latest run)").option("--all","Show interleaved logs from all runs (requires --workflow)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").option("--no-follow","Fetch logs once and exit (default: tail)").option("--lines <n>","Max log lines per fetch (default: 200)").action(async(o,t)=>{const{logsCommand:n}=await import("../commands/workflows/logs.js");return n(o,t)}),e.command("run-workflow").description("Run a deployed workflow from S3 sources (used by ECS containers)").action(async()=>{const{runWorkflowCommand:o}=await import("../commands/workflows/run.js");return o()});const a=e.command("memory").description("Test memory database \u2014 version-controlled knowledge from runs");a.command("stats").description("Show memory database statistics").action(async()=>{const{memoryStatsCommand:o}=await import("../commands/memory.js");return o()}),a.command("init").description("Initialize the memory database (Dolt)").action(async()=>{const{memoryInitCommand:o}=await import("../commands/memory.js");return o()}),a.command("compact").description("Prune old data and run Dolt GC to reclaim storage").option("--max-runs <n>","Keep last N runs per spec (default: 50)",parseInt).option("--max-age <days>","Remove data older than N days (default: 90)",parseInt).action(async o=>{const{memoryCompactCommand:t}=await import("../commands/memory.js");return t(o)}),a.command("reset").description("Wipe the memory database").option("-f, --force","Confirm reset").action(async o=>{const{memoryResetCommand:t}=await import("../commands/memory.js");return t(o)});const r=e.command("workflow").description("Manage workflow graphs (download, upload, list)");r.command("download").description("Download a workflow graph from Zibby Cloud to .zibby/").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--type <type>","Workflow type: analysis, implementation, run_test").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").option("--output <dir>","Output directory (default: .zibby/)").option("--include-default","Download the built-in default graph if no custom one exists").action(async o=>{const{workflowDownloadCommand:t}=await import("../commands/workflow.js");return t(o)}),r.command("list").description("List all workflows for a project").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").action(async o=>{const{workflowListCommand:t}=await import("../commands/workflow.js");return t(o)});const x=e.command("run-queue").description("Parallel capacity \u2014 on-disk wait queue (see parallel.waitWhenAtCapacity in .zibby.config.mjs)");x.command("list").description("List CLI processes waiting for a run slot").option("--config <path>","Path to config file",".zibby.config.mjs").action(async o=>{const{runCapacityQueueListCommand:t}=await import("../commands/run-capacity-queue-cli.js");await t(o),process.exit(0)}),e.parse();
|
package/dist/commands/chat.js
CHANGED
|
@@ -1,79 +1,89 @@
|
|
|
1
|
-
import{invokeAgent as
|
|
2
|
-
`)}function
|
|
1
|
+
import{invokeAgent as _e,getAgentStrategy as ve,getSkill as kt}from"@zibby/core";import{existsSync as $t,readFileSync as oe,readdirSync as Te}from"fs";import{resolve as mt,join as Dt,dirname as Ce,basename as Ie}from"path";import{createInterface as Pe,moveCursor as M,cursorTo as O,clearLine as q,emitKeypressEvents as Ae}from"readline";import{fileURLToPath as Ee}from"url";import e from"chalk";import{highlight as ne}from"cli-highlight";import Le from"dotenv";import{getSessionToken as Wt,getUserInfo as Me,getProjects as Be,saveSessionToken as Ne,saveUserInfo as Oe,clearSession as Re,saveProxyUrl as Ue,getProxyUrl as Fe,getMem0ProxyUrl as je,saveMem0ProxyUrl as De}from"../config/config.js";import{getApiUrl as re}from"../config/environments.js";import{loadActiveSkills as We,loadChatHistory as Ye,saveActiveSkills as It,saveChatHistory as Pt}from"./chat-session-store.js";import{buildReliabilityInstruction as He}from"./agent-reliability.js";const ze=Ee(import.meta.url),Je=Ce(ze),qe=JSON.parse(oe(Dt(Je,"../../package.json"),"utf-8")),ie=30,Ze=54,Ge=18e3,ce=12e3,ae=42e3;function Ke(o){return new Promise(t=>setTimeout(t,o))}const At=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Yt=[{cmd:"/help",desc:"Show this help"},{cmd:"/skills",desc:"List active & available skills"},{cmd:"/history",desc:"Show conversation history (--all or -n 50)"},{cmd:"/clear",desc:"Clear conversation history"},{cmd:"/memory",desc:"View stored memories, tasks, sessions"},{cmd:"/exit",desc:"Exit the chat"},{cmd:"/quit",desc:"Exit the chat"}];function le(){let o=0,t="thinking...";const s=setInterval(()=>{const h=e.cyan(At[o%At.length]),k=o%3,v=k===0?e.white(".")+e.gray(".")+e.dim("."):k===1?e.dim(".")+e.white(".")+e.gray("."):e.gray(".")+e.dim(".")+e.white("."),C=t.replace(/\.+$/,""),I=` ${h} ${e.gray(C)}${v}`;process.stdout.write(`\r${" ".repeat(80)}\r${I}`),o++},300),r=()=>{clearInterval(s),process.stdout.write(`\r${" ".repeat(80)}\r`)};return r.setLabel=h=>{t=h},r}function Os(o){const t=o?.agent;return t?t.provider?t.provider:t.gemini?"gemini":t.codex?"codex":t.claude?"claude":t.cursor?"cursor":process.env.AGENT_TYPE||"cursor":process.env.AGENT_TYPE||"cursor"}function Ve(o){return o.slice(-ie).map(t=>`${t.role==="human"?"H":"AI"}: ${t.content}`).join(`
|
|
2
|
+
`)}function Rs(o,t,s){let r=o;return t.length>0&&(r+=`
|
|
3
3
|
|
|
4
|
-
${
|
|
4
|
+
${Ve(t)}`),r+=`
|
|
5
5
|
H: ${s}
|
|
6
|
-
AI:`,r}function
|
|
6
|
+
AI:`,r}function Xe(o){const t=o.filter(s=>!process.env[s]);return{ok:t.length===0,missing:t}}function Qe(o){const t=mt(o,".zibby.config.mjs");if(!$t(t))return{};try{return import(t).then(s=>s.default||{})}catch{return{}}}async function ts(o){const t=mt(o,".zibby","chat.mjs");if($t(t)){const s=await import(t);return s.CHAT_CONFIG||s.default||{}}try{const s=await import("@zibby/core/templates/browser-test-automation/chat.mjs");return s.CHAT_CONFIG||s.default||{}}catch{return{systemPrompt:"You are Zibby, a friendly AI assistant for test automation.",skills:[]}}}function ue(o){try{const t=mt(o,".zibby","commands");return $t(t)?Te(t).filter(s=>s.toLowerCase().endsWith(".md")).sort((s,r)=>s.localeCompare(r)):[]}catch{return[]}}function es(o,t){const s=String(t||"").trim();if(!s.startsWith("/"))return s;const[r,...h]=s.split(/\s+/),k=h.join(" ").trim(),v=r.slice(1);if(!v)return s;const C=v.toLowerCase().endsWith(".md")?[v]:[v,`${v}.md`],I=mt(o,".zibby","commands"),U=C.find(R=>$t(Dt(I,R)));if(!U)return s;try{const R=oe(Dt(I,U),"utf-8").trim();return k?`${R}
|
|
7
7
|
|
|
8
|
-
${
|
|
8
|
+
${k}`:R}catch{return s}}function ss(o){const t=o.slice(-ie),s=[];let r=0;for(let h=t.length-1;h>=0;h--){const k=t[h],v=String(k?.content||""),C=k?.role==="human"?"user":"assistant",I=v.length;if(s.length>=6&&r+I>Ge)break;s.push({role:C,content:v}),r+=I}return s.reverse()}function xt(o,t){const s=String(o||"");return s.length<=t?s:`${s.slice(0,Math.max(0,t-24))}
|
|
9
9
|
|
|
10
|
-
[truncated for proxy size]`}function Ht(o){return o.reduce((t,s)=>t+String(s?.content||"").length+64,0)}function
|
|
10
|
+
[truncated for proxy size]`}function Ht(o){return o.reduce((t,s)=>t+String(s?.content||"").length+64,0)}function os(o){let t=[...o];if(t.length===0||(t[0]?.role==="system"&&(t[0]={...t[0],content:xt(t[0].content,ce)}),Ht(t)<=ae))return t;const s=t[0],r=t[t.length-1],h=t.slice(1,-1).slice(-4).map(k=>({...k,content:xt(k.content,2500)}));return t=[s,...h,r],Ht(t)<=ae||(t=[{...s,content:xt(s?.content,6e3)},{...r,content:xt(r?.content,8e3)}]),t}function ns(o){const t=[];for(const s of o){const r=kt(s),h=String(r?.description||"").trim();if(!h){t.push(`- ${s}`);continue}t.push(`- ${s}: ${Et(h,80)}`)}return t.length===0?"":`## Active skills (call get_skill_context before first use)
|
|
11
11
|
${t.join(`
|
|
12
|
-
`)}`}const
|
|
13
|
-
`)};function
|
|
14
|
-
|
|
12
|
+
`)}`}const pe={cli_plain:["## Response format for this channel","- Output plain terminal text with optional fenced code blocks.","- Use fenced code blocks (```language) when showing code or config. Always include the language tag.","- Outside of code blocks, do NOT use Markdown syntax (no **bold**, __underline__, headings, inline backticks, or markdown tables).","- Keep responses concise and readable in a terminal.","- Write in natural, conversational English. Avoid dumping raw JSON, run IDs, or technical jargon.",'- When reporting test results: summarize in plain language (e.g. "Both tests finished \u2014 the checkbox test passed but the login test failed because..."). Include ticket keys but skip internal run IDs unless the user asks.',"- When something fails, explain the root cause simply and suggest a fix."].join(`
|
|
13
|
+
`)};function rs(o={},t={}){const s=String(t.outputProfile||process.env.ZIBBY_OUTPUT_PROFILE||o.outputProfile||"cli_plain").trim(),r=o?.outputProfiles?.[s];return typeof r=="string"&&r.trim()?r.trim():r&&typeof r.instruction=="string"&&r.instruction.trim()?r.instruction.trim():pe[s]||pe.cli_plain}function Et(o,t){const s=String(o??"");return s.length<=t?s:t<=1?s.slice(0,t):`${s.slice(0,t-1)}\u2026`}function is(){return!1}function Us(o){return o}function cs(o){const t=/^```(\w*)\n([\s\S]*?)^```$/gm;return o.replace(t,(s,r,h)=>{const k=h.replace(/\n$/,"");try{const v=r?ne(k,{language:r,ignoreIllegals:!0}):ne(k,{ignoreIllegals:!0}),C=e.gray("\u2500".repeat(Math.min(process.stdout.columns-6||54,72))),I=r?e.dim(` ${r}`):"";return`${C}${I}
|
|
14
|
+
${v}
|
|
15
|
+
${C}`}catch{return k}})}function zt(){const o=Number(process.stdout?.columns)||0,t=o>8?Math.max(30,o-4):Ze;return` ${"\u2500".repeat(t)}`}function de(o=[]){const t=Yt.map(r=>({cmd:r.cmd,source:"builtin",name:r.cmd.slice(1),desc:r.desc})),s=o.map(r=>({cmd:`/${r}`,source:"template",name:r,desc:"Command template"}));return[...t,...s]}function as(o,t){const s=String(o||""),r=Number.isFinite(t)?t:s.length;return!(!s.startsWith("/")||r!==s.length||s.includes(" "))}function ls({userName:o,cwd:t,projectName:s,restoredCount:r,skillsLine:h}){const k=Number(process.stdout?.columns)||0,v=Math.max(40,Math.min(k-8,100)),C=Math.max(20,Math.floor((v-3)*.55)),I=v-C-3,U=o||"there",R=s||"No project linked",gt=Ie(t||process.cwd()),W=[`Restored ${r} messages from previous session.`,"",h],rt=["Workspace details","",`v${qe.version} | Hi, ${U}`,`Company: ${R}`,`Directory: ~/${gt}`,`Path: ${t}`,"","Use /help for commands"],E=Math.max(W.length,rt.length),V=(()=>{if(W.length>=E)return W;const F=Math.floor((E-W.length)/2),st=E-W.length-F;return[...Array(F).fill(""),...W,...Array(st).fill("")]})(),H="\u2500",L=` \u250C${H.repeat(C+2)}\u252C${H.repeat(I+2)}\u2510`,et=` \u2514${H.repeat(C+2)}\u2534${H.repeat(I+2)}\u2518`;console.log(e.gray(L));for(let F=0;F<E;F++){const st=Et(V[F]||"",C),it=Et(rt[F]||"",I),ht=" ".repeat(Math.max(0,C-st.length)),l=" ".repeat(Math.max(0,I-it.length)),w=` \u2502 ${st}${ht} \u2502 ${it}${l} \u2502`;console.log(e.gray(w))}console.log(e.gray(et)),console.log("")}function us(){process.stdout?.isTTY&&(M(process.stdout,0,-2),O(process.stdout,4))}function ps(o){const t=!!(process.stdout?.isTTY&&process.stdin?.isTTY);let s=!1,r=!1,h=!1,k=null,v=0,C=0,I=0;function U(){return e.gray(zt())}function R(){k&&(clearInterval(k),k=null)}function gt(l){!t||!s||!r||!h||(process.stdout.write("\x1B7"),M(process.stdout,0,-2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(` ${l}`),process.stdout.write("\x1B8"))}function W(){if(!(!t||!s)&&C!==0){process.stdout.write("\x1B7"),M(process.stdout,0,2);for(let l=0;l<C;l++)O(process.stdout,0),q(process.stdout,0),l<C-1&&M(process.stdout,0,1);process.stdout.write("\x1B8"),C=0,r&&rt()}}function rt(){!t||!s||!r||(process.stdout.write("\x1B7"),M(process.stdout,0,1),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),process.stdout.write("\x1B8"))}function E(l,w){if(!t||!s||!r)return;W();const c=l.slice(0,6);if(c.length!==0){M(process.stdout,0,1);for(let y=0;y<c.length;y++)process.stdout.write(`
|
|
16
|
+
`);M(process.stdout,0,-(1+c.length)),process.stdout.write("\x1B7"),M(process.stdout,0,2);for(let y=0;y<c.length;y++){O(process.stdout,0),q(process.stdout,0);const Z=y===w?e.cyan("\u203A"):" ",f=y===w?e.white(c[y]):e.gray(c[y]);process.stdout.write(` ${Z} /${f}`),y<c.length-1&&M(process.stdout,0,1)}process.stdout.write("\x1B8"),C=c.length,rt()}}function V(){if(!t||!s||!r)return;W();const l=process.stdout.columns||80,w=I>0?Math.ceil(I/l):1;O(process.stdout,0),M(process.stdout,0,-w),h&&M(process.stdout,0,-2),process.stdout.write("\x1B[J"),r=!1}function H(l={}){const w=l.preserveInput===!0;if(!t){o.prompt();return}w||(o.line="",o.cursor=0),I=zt().length;const c=U();process.stdout.write(`${c}
|
|
15
17
|
`),o.prompt(),process.stdout.write(`
|
|
16
18
|
${c}
|
|
17
|
-
`),
|
|
18
|
-
`);for(;
|
|
19
|
-
`);
|
|
20
|
-
`)}function it(){R();const l=()=>e.gray(`${At[
|
|
21
|
-
`);for(;c.length>0&&c[c.length-1]==="";)c.pop();for(const
|
|
19
|
+
`),us(),r=!0}function L(){if(!t||!s||!r)return;const l=process.stdout.columns||80,w=I>0?Math.ceil(I/l):1,c=U();process.stdout.write("\x1B7"),M(process.stdout,0,-w);for(let y=0;y<w;y++)O(process.stdout,0),q(process.stdout,0),y<w-1&&M(process.stdout,0,1);O(process.stdout,0),process.stdout.write(c),M(process.stdout,0,2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(c);for(let y=1;y<w;y++)M(process.stdout,0,1),O(process.stdout,0),q(process.stdout,0);process.stdout.write("\x1B8"),I=zt().length}function et(){if(!t||!s||!r)return;const l=(()=>{if(typeof o.getCursorPos!="function")return 0;try{return Math.max(0,Number(o.getCursorPos()?.rows||0))}catch{return 0}})();process.stdout.write("\x1B7"),M(process.stdout,0,-(l+1)),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),M(process.stdout,0,l+2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),process.stdout.write("\x1B8")}function F(l){R(),V(),console.log();const w=String(l??"").replace(/\r/g,"").split(`
|
|
20
|
+
`);for(;w.length>0&&w[w.length-1]==="";)w.pop();for(const c of w)console.log(c?` ${c}`:"");h=!1}function st(l){const w=String(l??"").replace(/\r/g,"").split(`
|
|
21
|
+
`);w.length===0&&w.push("");const c=[];for(const y of w)c.push(e.bgGray.white(` ${y||" "} `));return c.join(`
|
|
22
|
+
`)}function it(){R();const l=()=>e.gray(`${At[v%At.length]} thinking`);if(!t){console.log(` ${l()}`),h=!0;return}W(),V(),console.log(),console.log(` ${l()}`),H({preserveInput:!0}),h=!0,v+=1,k=setInterval(()=>{h&&(gt(l()),v+=1)},120)}function ht(l){R();const w=String(l??"").replace(/\r/g,"").replace(/⎿/g,"");if(!h){F(w);return}V(),console.log();const c=w.split(`
|
|
23
|
+
`);for(;c.length>0&&c[c.length-1]==="";)c.pop();for(const y of c)console.log(y?` ${y}`:"");console.log(),h=!1}return{enabled:t,mount(){if(!s){if(!t){o.prompt(),s=!0;return}s=!0,H()}},refreshPrompt(l={}){if(t&&s){r&&V(),H(l);return}o.prompt()},pushSystem(l){F(l)},pushUser(l){F(st(l))},pushAssistant(l){ht(l)},showAssistantLoading:it,dismissTransientLoading(){R(),h&&t&&s&&r&&(process.stdout.write("\x1B7"),M(process.stdout,0,-2),O(process.stdout,0),q(process.stdout,0),M(process.stdout,0,-1),O(process.stdout,0),q(process.stdout,0),process.stdout.write("\x1B8")),h=!1},touchInputFrame:et,handleResize:L,showCommandDropdown:E,clearCommandDropdown:W}}function ds(){console.log(""),console.log(e.cyan(" Available commands:"));for(const o of Yt)console.log(e.white(` ${o.cmd.padEnd(10)} `)+e.gray(o.desc));console.log(""),console.log(e.cyan(" Chat options:")),console.log(e.white(" --stream, -s ")+e.gray("Enable typewriter effect (default: instant)")),console.log(""),console.log(e.gray(" To install/uninstall skills, just ask naturally:")),console.log(e.gray(' "connect to Jira" \u2022 "add GitHub" \u2022 "remove Slack"')),console.log("")}const fs=Xe;async function Fs(o={}){const t=process.cwd();o.verbose&&(process.env.ZIBBY_VERBOSE="true");const s=o.stream||!1;[mt(t,".env.local"),mt(t,".env")].forEach(c=>{$t(c)&&Le.config({path:c,override:!1})});try{await import("@zibby/skills")}catch{}function h(){const c=Wt();if(!c)return!1;try{const y=JSON.parse(atob(c.split(".")[1]));return y.exp&&y.exp*1e3>Date.now()}catch{return!1}}if(!h()){Re();const c=re(),{spawn:y}=await import("child_process"),Z=await fetch(`${c}/cli/login/initiate`,{method:"POST",headers:{"Content-Type":"application/json"}});Z.ok||(console.log(e.red("\n Could not start login. Try `zibby login`.\n")),process.exit(1));const{deviceCode:f,verificationUrl:n,expiresIn:N,interval:at}=await Z.json(),ot=process.platform;y(ot==="darwin"?"open":ot==="win32"?"cmd":"xdg-open",ot==="win32"?["/c","start","",n]:[n],{detached:!0,stdio:"ignore"}).unref();const lt=le(),ut=(at||3)*1e3,pt=Math.floor(N/(at||3));let X=!1;for(let nt=0;nt<pt;nt++){await Ke(ut);try{const Q=await fetch(`${c}/cli/login/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:f})});if(Q.status===202)continue;if(!Q.ok)break;const z=await Q.json();if(z.status==="authorized"){Ne(z.token),Oe(z.user),z.proxyUrl&&Ue(z.proxyUrl),z.mem0ProxyUrl&&De(z.mem0ProxyUrl),X=!0;break}if(z.status==="denied")break}catch{break}}lt(),X||(console.log(e.red("\n Login failed or timed out. Run `zibby login` to try again.\n")),process.exit(1))}const k=await Qe(t),v=await ts(t),C=o.agent||"assistant",I=Wt();I&&!process.env.ZIBBY_USER_TOKEN&&(process.env.ZIBBY_USER_TOKEN=I);const U=je()||Fe();U&&!process.env.ZIBBY_MEM0_OPENAI_BASE_URL&&(process.env.ZIBBY_MEM0_OPENAI_BASE_URL=U),process.env.AGENT_TYPE=C,process.env.ZIBBY_CHAT_OWNER_PID=String(process.pid);try{const{cleanupStalePidFiles:c}=await import("../utils/chat-run-lifecycle.js");c(t,k)}catch{}let R;try{R=ve({state:{agentType:C}})}catch(c){console.log(e.red(`
|
|
22
24
|
${c.message}
|
|
23
|
-
`)),process.exit(1)}const gt=
|
|
25
|
+
`)),process.exit(1)}const gt=Me(),rt=Be()?.[0]?.name,E=Ye(t),V=v.skills||[],H=We(t),L=H?[...new Set([...V,...H])]:[...V];let et={data:null,timestamp:0};const F=300*1e3,st={jira:"jira",github:"github",slack:"slack",sentry:"sentry"};try{const c=Wt();if(c){const y=re(),Z=await fetch(`${y}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${c}`}});if(Z.ok){const f=await Z.json();for(const[n,N]of Object.entries(st))f[n]?.connected&&!L.includes(N)&&kt(N)&&L.push(N);It(t,L)}}}catch{}const it=L.filter(c=>c!=="skill-installer"&&c!=="core-tools"),ht=it.length>0?`Skills: ${it.join(", ")}`:"Skills: (none)";ls({userName:gt?.name?.split(" ")[0],cwd:t,projectName:rt,restoredCount:E.length,skillsLine:ht});let l=ue(t),w=de(l);return new Promise(c=>{const y=process.env.ZIBBY_CHAT_TAB_COMPLETION==="1",Z={input:process.stdin,output:process.stdout,prompt:e.green(" > "),terminal:!0};y&&(Z.completer=u=>{const i=String(u||"");if(!i.startsWith("/"))return[[],i];const m=w.map(P=>P.cmd),$=m.filter(P=>P.startsWith(i));return[$.length>0?$:m,i]});const f=Pe(Z),n=ps(f);let N=null,at=!1;const ot=[],fe=0,me=1200;let lt=!1,ut=!1,pt=!1,X=!1,nt="",Q=0;const z=typeof f._ttyWrite=="function"?f._ttyWrite.bind(f):null;z&&(f._ttyWrite=(...u)=>{if(!(X||Date.now()<Q))return z(...u)});function ge(){pt||!process.stdout?.isTTY||typeof process.stdout.write!="function"||(process.stdout.write("\x1B[?2004h"),pt=!0)}function Jt(){pt&&(!process.stdout?.isTTY||typeof process.stdout.write!="function"||(process.stdout.write("\x1B[?2004l"),pt=!1))}function he(u){const i="\x1B[200~",m="\x1B[201~";if(!X&&!u.includes(i))return!1;let $=u,P=!1;for(;$.length>0;){if(!X){const A=$.indexOf(i);if(A===-1)break;P=!0,Kt(),X=!0,nt="",$=$.slice(A+i.length);continue}const J=$.indexOf(m);if(J===-1){P=!0,nt+=$;break}P=!0,nt+=$.slice(0,J);const tt=String(nt||"").replace(/\r\n/g,`
|
|
24
26
|
`).replace(/\r/g,`
|
|
25
|
-
`);if(
|
|
26
|
-
`);for(const G of
|
|
27
|
-
`)||
|
|
28
|
-
`&&
|
|
29
|
-
`,P=
|
|
30
|
-
`);Bt.push({placeholder:i,text:
|
|
31
|
-
Active skills:`)),g.length===0&&console.log(e.gray(" (none)"));for(const
|
|
32
|
-
Available:`));for(const
|
|
27
|
+
`);if(tt.length>0){const A=tt.split(`
|
|
28
|
+
`);for(const G of A)Rt(G)}vt(),nt="",X=!1,$=$.slice(J+m.length)}return P}function qt(){if(!lt){lt=!0;try{Pt(t,E),It(t,L)}catch{}try{Jt()}catch{}try{f.close()}catch{}process.exit(0)}}async function Lt(){if(!lt){lt=!0,typeof R?.cleanup=="function"&&await R.cleanup().catch(()=>{});try{const{killAllChatOrchestratedRuns:u}=await import("../utils/chat-run-lifecycle.js"),{postCliInterruptedRunIndex:i}=await import("@zibby/core/utils/run-index-post-cli.js");u(t,process.pid,k),i({cwd:t,config:k})}catch{}Pt(t,E),It(t,L),n.pushSystem(e.gray("Session saved. Goodbye!")),Jt(),f.close(),process.exit(0)}}if(n.mount(),ge(),process.stdout?.isTTY){let u;process.stdout.on("resize",()=>{clearTimeout(u),u=setTimeout(()=>{n.handleResize()},80)})}let Mt=0;const _t=u=>{if(typeof u=="string"?u==="\x1B":u&&typeof u.length=="number"?u.length===1&&u[0]===27:!1){N&&N.abort(),qt();return}const m=typeof u=="string"?u:u&&typeof u.length=="number"?Buffer.from(u).toString("utf8"):"";if(!m)return;if(he(m)){Mt=Date.now()+1200,Q=Date.now()+1200,Ot();return}const $=(m.includes(`
|
|
29
|
+
`)||m.includes("\r"))&&m!=="\r"&&m!==`
|
|
30
|
+
`&&m!==`\r
|
|
31
|
+
`,P=m.includes("\x1B[200~")||m.includes("\x1B[201~"),J=m.length>=16&&/\s/.test(m)&&!m.startsWith("\x1B");($||P||J)&&(Mt=Date.now()+1200,Q=Date.now()+1200,Kt(),Ot())},B={query:"",matches:[],selected:0},Y={prefix:"",matches:[],nextIndex:0},_={active:!1,prefix:"",lines:[],timer:null},Bt=[];let Zt=0,Nt="";const ye=new Set(Yt.map(u=>u.cmd));function dt(u,{preserveFrame:i=!1}={}){const m=String(u||"");f.line=m,f.cursor=m.length,Nt=m,typeof f._refreshLine=="function"?f._refreshLine():f.prompt(),i&&n.touchInputFrame()}function Gt(){Y.prefix="",Y.matches=[],Y.nextIndex=0}function vt(){if(_.timer&&(clearTimeout(_.timer),_.timer=null),_.active&&_.lines.length>0){Zt+=1;const u=_.lines.length,i=`[Pasted text #${Zt} +${u} lines]`,m=_.lines.join(`
|
|
32
|
+
`);Bt.push({placeholder:i,text:m});const $=String(_.prefix||"").trimEnd(),P=$?`${$} ${i}`:i;dt(P,{preserveFrame:!0}),ft(f.line)}_.active=!1,_.prefix="",_.lines=[],Q=0}function Ot(){_.timer&&clearTimeout(_.timer),_.timer=setTimeout(()=>{vt()},180)}function Kt(){_.active||(_.active=!0,_.prefix=String(Nt||f.line||""),_.lines=[],dt(_.prefix,{preserveFrame:!0}))}function Rt(u){return _.active?(_.lines.push(String(u||"")),dt(_.prefix,{preserveFrame:!0}),Ot(),!0):!1}function we(u){let i=String(u||"");for(const m of Bt)i=i.split(m.placeholder).join(m.text);return i}function ft(u){const i=String(u||"");if(!i.startsWith("/")||i.includes(" ")||i.length===0){B.query="",B.matches=[],B.selected=0,n.clearCommandDropdown();return}l=ue(t),w=de(l);const m=i.slice(1).toLowerCase(),$=l.filter(P=>P.toLowerCase().startsWith(m));B.query=m,B.matches=$,B.selected=Math.min(B.selected,Math.max(0,$.length-1)),n.showCommandDropdown($,B.selected)}const Ut=(u,i)=>{if(i?.name==="escape"||i?.sequence==="\x1B"){N&&N.abort(),qt();return}if((i?.name==="return"||i?.name==="enter")&&(ut=!0),(i?.name==="backspace"||i?.name==="delete")&&n.touchInputFrame(),i?.name==="tab"&&!i?.shift){const P=String(f.line||""),J=Number(f.cursor||P.length);if(!as(P,J)){Gt(),ft(f.line);return}const tt=P.slice(1).toLowerCase();if(Y.prefix!==tt&&(Y.prefix=tt,Y.matches=w.map(G=>G.cmd).filter(G=>G.toLowerCase().startsWith(`/${tt}`)),Y.nextIndex=0),Y.matches.length===0)return;const A=Y.nextIndex%Y.matches.length;Y.nextIndex+=1,dt(Y.matches[A]),ft(f.line);return}const m=String(f.line||""),$=m.startsWith("/")&&!m.includes(" ")&&B.matches.length>0;if(i?.name==="up"||i?.name==="down"){if(!$){ft(f.line);return}const P=i.name==="up"?-1:1,J=B.matches.length;B.selected=(B.selected+P+J)%J;const tt=B.matches[B.selected];dt(`/${tt}`,{preserveFrame:!0}),n.showCommandDropdown(B.matches,B.selected);return}i?.name!=="tab"&&Gt(),setTimeout(()=>{ft(f.line),_.active||(Nt=String(f.line||""))},50)};process.stdin?.on&&(Ae(process.stdin,f),process.stdin.on("keypress",Ut)),n.enabled&&process.stdin?.on&&(typeof process.stdin.prependListener=="function"?process.stdin.prependListener("data",_t):process.stdin.on("data",_t)),f.on("line",async u=>{try{let i=String(u||"");const m=ut;if(ut=!1,!m&&(_.active||X||Date.now()<Mt||Date.now()<Q)){if(_.active&&i.length>0){Rt(i);return}_.active&&(vt(),n.refreshPrompt());return}if(_.active&&(vt(),i=String(f.line||i||"")),Rt(i))return;const $=i.trim(),P=B.matches[B.selected];if($.startsWith("/")&&!$.includes(" ")&&B.matches.length>0&&!ye.has($)&&$!==`/${P}`){n.clearCommandDropdown(),n.refreshPrompt(),dt(`/${P}`),ft(`/${P}`);return}n.clearCommandDropdown();const A=String(i||"").replace(/[\u0000-\u001F\u007F-\u009F]/g,"").trim();if(!A){n.enabled&&process.stdout?.isTTY&&(M(process.stdout,0,-1),O(process.stdout,4));return}if(at&&A!=="/exit"&&A!=="/quit"){N&&N.abort(),ot.push(A),n.pushSystem(e.gray("Processing your message...")),n.refreshPrompt({preserveInput:!0});return}const G=1e4;if(A.length>G){n.pushSystem(e.red(`\u26A0 Input too long (${A.length} chars). Maximum: ${G} characters.`)),n.pushSystem(e.gray("Tip: If you need to share logs, use a file instead:")),n.pushSystem(e.gray(" 1. Save to file: pbpaste > debug.log")),n.pushSystem(e.gray(' 2. Ask: "analyze debug.log in current directory"')),n.refreshPrompt();return}if(A==="/exit"||A==="/quit"){Lt();return}if(A==="/help"){ds(),n.refreshPrompt();return}if(A==="/skills"){const x=kt("skill-installer")?.catalog||{},g=L.filter(b=>b!=="skill-installer");console.log(e.cyan(`
|
|
33
|
+
Active skills:`)),g.length===0&&console.log(e.gray(" (none)"));for(const b of g){const S=x[b]||{};console.log(e.green(` \u2713 ${b}`)+e.gray(S.description?` \u2014 ${S.description}`:""))}const T=Object.keys(x).filter(b=>!L.includes(b));if(T.length>0){console.log(e.cyan(`
|
|
34
|
+
Available:`));for(const b of T){const S=x[b],d=S.envKeys?.length>0?fs(S.envKeys).ok?e.green(" \u2713 configured"):e.yellow(` \u26A0 needs: ${S.envKeys.join(", ")}`):"";console.log(e.white(` - ${b}`)+e.gray(` \u2014 ${S.description}`)+d)}}console.log(e.gray(`
|
|
33
35
|
Just ask to install: "connect to Jira", "add GitHub", etc.
|
|
34
|
-
`)),n.refreshPrompt();return}if(
|
|
36
|
+
`)),n.refreshPrompt();return}if(A.startsWith("/history")){if(E.length===0)console.log(e.gray(`
|
|
35
37
|
No conversation history.
|
|
36
|
-
`));else{const a=
|
|
37
|
-
Showing ${S.length} of ${
|
|
38
|
-
`));for(const
|
|
38
|
+
`));else{const a=A.split(/\s+/).slice(1),x=a.includes("--all"),g=a.indexOf("-n"),T=g>=0&&a[g+1]?parseInt(a[g+1],10):NaN,b=x?E.length:isNaN(T)?10:T,S=E.slice(-b);console.log(e.gray(`
|
|
39
|
+
Showing ${S.length} of ${E.length} messages${x?" (all)":""}:
|
|
40
|
+
`));for(const d of S){const p=d.role==="human"?e.green(" You"):e.cyan(" Zibby"),j=x||T>10?500:100,D=d.content.length>j?`${d.content.substring(0,j)}...`:d.content;console.log(`${p}: ${e.white(D)}`)}console.log("")}n.refreshPrompt();return}if(A==="/clear"){E.length=0,Pt(t,E),console.log(e.gray(`
|
|
39
41
|
History cleared.
|
|
40
|
-
`)),n.refreshPrompt();return}if(
|
|
42
|
+
`)),n.refreshPrompt();return}if(A.startsWith("/memory")){const a=L.includes("chat-memory")?kt("chat-memory"):null;if(!a?.handleToolCall){console.log(e.yellow(`
|
|
41
43
|
Chat memory not active. Install with: "add chat memory"
|
|
42
|
-
`)),n.refreshPrompt();return}const
|
|
43
|
-
Stored memories (${
|
|
44
|
-
`)),
|
|
45
|
-
`));else{for(const p of
|
|
46
|
-
Task history (${
|
|
47
|
-
`)),
|
|
48
|
-
`));else{for(const p of
|
|
44
|
+
`)),n.refreshPrompt();return}const x=A.split(/\s+/).slice(1),g=x[0]||"brief",T={options:{workspace:t}};try{if(g==="facts"||g==="all"){const b=parseInt(x[1],10)||30,S=await a.handleToolCall("memory_recall",{limit:b},T),d=JSON.parse(S);if(console.log(e.cyan(`
|
|
45
|
+
Stored memories (${d.total}):
|
|
46
|
+
`)),d.total===0)console.log(e.gray(` (empty \u2014 memories are saved as the agent learns things)
|
|
47
|
+
`));else{for(const p of d.memories){const j=e.yellow(`[${p.category}]`),D=Number(p.relevance)<1?e.gray(` (${(Number(p.relevance)*100).toFixed(0)}%)`):"",bt=p.ticket_key?e.magenta(` ${p.ticket_key}`):"",St=p.source?e.gray(` via ${p.source}`):"";console.log(` ${j}${bt} ${e.white(p.content)}${D}${St}`)}console.log("")}}else if(g==="tasks"){const b=parseInt(x[1],10)||20,S=await a.handleToolCall("task_history",{limit:b},T),d=JSON.parse(S);if(console.log(e.cyan(`
|
|
48
|
+
Task history (${d.total}):
|
|
49
|
+
`)),d.total===0)console.log(e.gray(` (no tasks logged yet)
|
|
50
|
+
`));else{for(const p of d.tasks){const j=p.status==="passed"?e.green("\u2713"):p.status==="failed"?e.red("\u2717"):e.yellow("\u25CB"),D=p.ticket_key?e.magenta(` ${p.ticket_key}`):"",bt=e.gray(`[${p.type}]`),St=p.result_summary?e.gray(` \u2014 ${p.result_summary.slice(0,80)}`):"";console.log(` ${j} ${bt}${D} ${e.white(p.title)}${St}`)}console.log("")}}else if(g==="sessions"){const b=await a.handleToolCall("memory_brief",{},T),S=JSON.parse(b);if(console.log(e.cyan(`
|
|
49
51
|
Recent sessions (${S.recentSessions?.length||0}):
|
|
50
52
|
`)),!S.recentSessions?.length)console.log(e.gray(` (no sessions saved yet)
|
|
51
|
-
`));else{for(const
|
|
53
|
+
`));else{for(const d of S.recentSessions){const p=d.tickets?e.magenta(` [${d.tickets}]`):"",j=d.tasks_run>0?e.gray(` \u2014 ${d.tasks_run} tasks (${d.tasks_passed} passed, ${d.tasks_failed} failed)`):"",D=d.created_at?e.gray(` ${d.created_at.split("T")[0]}`):"";if(console.log(` ${e.white(d.summary)}${p}${j}${D}`),d.key_facts)for(const bt of d.key_facts.split(";").map(St=>St.trim()).filter(Boolean))console.log(e.gray(` \u2192 ${bt}`))}console.log("")}}else if(g==="search"){const b=x.slice(1).join(" ");if(!b)console.log(e.yellow(`
|
|
52
54
|
Usage: /memory search <keyword>
|
|
53
|
-
`));else{const S=await a.handleToolCall("memory_recall",{query:
|
|
54
|
-
Search "${
|
|
55
|
-
`));for(const p of
|
|
55
|
+
`));else{const S=await a.handleToolCall("memory_recall",{query:b,limit:20},T),d=JSON.parse(S);console.log(e.cyan(`
|
|
56
|
+
Search "${b}" \u2014 ${d.total} results:
|
|
57
|
+
`));for(const p of d.memories){const j=e.yellow(`[${p.category}]`),D=p.ticket_key?e.magenta(` ${p.ticket_key}`):"";console.log(` ${j}${D} ${e.white(p.content)}`)}d.total===0&&console.log(e.gray(" (no matches)")),console.log("")}}else{const b=await a.handleToolCall("memory_brief",{},T),S=JSON.parse(b),d=S.topMemories?.length||0,p=S.recentSessions?.length||0,j=(S.taskStats||[]).map(D=>`${D.type}:${D.status}=${D.cnt}`).join(", ");console.log(e.cyan(`
|
|
56
58
|
Memory overview:
|
|
57
|
-
`)),console.log(e.white(` Facts stored: ${
|
|
58
|
-
Subcommands:`)),console.log(e.gray(" /memory facts [n] \u2014 List all stored memories")),console.log(e.gray(" /memory tasks [n] \u2014 List task history")),console.log(e.gray(" /memory sessions \u2014 List session summaries")),console.log(e.gray(" /memory search <keyword> \u2014 Search memories")),console.log("")}}catch(
|
|
59
|
-
Memory error: ${
|
|
60
|
-
`))}n.refreshPrompt();return}n.enabled&&process.stdout?.isTTY&&(
|
|
59
|
+
`)),console.log(e.white(` Facts stored: ${d>0?e.cyan(d):e.gray("0")}`)),console.log(e.white(` Sessions saved: ${p>0?e.cyan(p):e.gray("0")}`)),j&&console.log(e.white(` Task history: ${e.gray(j)}`)),console.log(e.gray(`
|
|
60
|
+
Subcommands:`)),console.log(e.gray(" /memory facts [n] \u2014 List all stored memories")),console.log(e.gray(" /memory tasks [n] \u2014 List task history")),console.log(e.gray(" /memory sessions \u2014 List session summaries")),console.log(e.gray(" /memory search <keyword> \u2014 Search memories")),console.log("")}}catch(b){console.log(e.red(`
|
|
61
|
+
Memory error: ${b.message}
|
|
62
|
+
`))}n.refreshPrompt();return}n.enabled&&process.stdout?.isTTY&&(M(process.stdout,0,-1),O(process.stdout,0)),n.pushUser(A),n.refreshPrompt(),n.showAssistantLoading();const Vt=we(A),Tt=es(t,Vt);if(Bt.length=0,!String(Tt||"").trim()){n.dismissTransientLoading(),n.refreshPrompt();return}if(Tt.length>G){n.pushAssistant(e.red(`Input too long after command expansion (${Tt.length} chars).`)),n.pushSystem(e.gray(`Try shortening the command template or user text. Limit: ${G} chars.`)),n.refreshPrompt();return}at=!0;let K=v.systemPrompt||"You are Zibby, a helpful AI assistant.";const Xt=rs(v,o);Xt&&(K+=`
|
|
61
63
|
|
|
62
|
-
${Xt}`);const Qt=
|
|
64
|
+
${Xt}`);const Qt=He({activeSkills:L,chatConfig:v,options:o});Qt&&(K+=`
|
|
63
65
|
|
|
64
|
-
${Qt}`);const te=
|
|
66
|
+
${Qt}`);const te=ns(L);if(te&&(K+=`
|
|
65
67
|
|
|
66
|
-
${te}`),
|
|
68
|
+
${te}`),K+=`
|
|
67
69
|
|
|
68
|
-
Use provided tools when external data/actions are required. Do not claim actions without tool calls. Before using a skill's tools for the first time in a conversation, call get_skill_context(skillId) to load its full guidance.`,
|
|
70
|
+
Use provided tools when external data/actions are required. Do not claim actions without tool calls. Before using a skill's tools for the first time in a conversation, call get_skill_context(skillId) to load its full guidance.`,L.includes("chat-memory")&&(K+=`
|
|
69
71
|
|
|
70
72
|
### Memory Tool Usage (chat-memory)
|
|
71
73
|
- At conversation start: call memory_brief to load recent context.
|
|
72
74
|
- Before answering memory-dependent questions: call memory_recall with focused query terms.
|
|
73
75
|
- When learning durable user/project facts or decisions: call memory_store.
|
|
74
76
|
- Avoid storing transient chatter, filler text, or duplicate facts.
|
|
75
|
-
- Prefer updating strong existing facts over creating near-duplicates when possible.`),
|
|
77
|
+
- Prefer updating strong existing facts over creating near-duplicates when possible.`),L.includes("workflow-builder")&&(K+=`
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
### Workflow Builder (workflow-builder)
|
|
80
|
+
- When users want to create, build, or scaffold an AI workflow, use the workflow-builder tools.
|
|
81
|
+
- FIRST call get_skill_context("workflow-builder") to load the full framework reference.
|
|
82
|
+
- Conversation flow: ask about purpose \u2192 input data \u2192 processing steps \u2192 output format \u2192 conditional logic.
|
|
83
|
+
- Then call design_workflow to create a spec, review with user, then build_workflow to generate code.
|
|
84
|
+
- After building: remind user about \`zibby start <name>\` (test), \`zibby deploy <name>\` (deploy), \`zibby logs\` (logs).
|
|
85
|
+
- Use list_workflows to show existing workflows, add_node to extend them, deploy_workflow to ship.`),L.includes("chat-memory"))try{const a=kt("chat-memory");if(typeof a?.buildPromptContext=="function"){const x=Date.now();let g;et.data&&x-et.timestamp<F?(g=et.data,process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray("Using cached memory context"))):(g=await a.buildPromptContext({options:{workspace:t}},{}),et={data:g,timestamp:x},process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray("Refreshed memory context cache")));const T=String(g?.backend||"dolt");process.env.ZIBBY_VERBOSE==="true"&&(n.pushSystem(e.gray(`memory backend: ${T}`)),n.pushSystem(e.gray(`memory retrieval output: ${Et(JSON.stringify(g?.debugPreview||{}),1400)}`)),g?.error&&n.pushSystem(e.yellow(`memory backend warning: ${g.error}`))),g?.promptContext&&(K+=`
|
|
86
|
+
|
|
87
|
+
${g.promptContext}`)}}catch(a){process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.yellow(`memory backend warning: ${String(a?.message||a)}`))}K=xt(K,ce);const Se=ss(E),Ft=os([{role:"system",content:K},...Se,{role:"user",content:Tt}]),ee=Ht(Ft),ke=Buffer.byteLength(JSON.stringify(Ft),"utf8");process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray(`payload estimate: ${ee} chars, ${ke} bytes (~${Math.round(ee/4)} tokens)`)),E.push({role:"human",content:Vt});const yt=n.enabled?(()=>{const a=()=>{};return a.setLabel=()=>{},a})():le();let ct=!0;const Ct=[];let se="",wt="";const gs=50,hs=500,ys=3,ws=60,bs=500,Ss=15,ks=25,$s=4,xs=new Set([".","!","?",",",";",":"]),$e=a=>{ct&&(yt(),ct=!1),wt+=a},xe=(a,x)=>{if(!a){ct&&yt.setLabel("thinking...");return}Ct.push(a);const g=70;let T=a;if(x&&typeof x=="object"){const S=Object.values(x).map(p=>typeof p=="string"?p:JSON.stringify(p)).join(", "),d=`${a}(${S})`;d.length<=g?T=d:T=`${a}(${S.slice(0,g-a.length-4)}...)`}T!==se&&(se=T,n.pushSystem(e.gray(`\u23BF ${T}`)),n.refreshPrompt({preserveInput:!0}),ct&&n.showAssistantLoading()),ct&&yt.setLabel(T)},jt=new AbortController;N=jt;try{const a=await _e("",{state:{agentType:C,config:k,cwd:t,workspace:t}},{model:k?.agent?.assistant?.model||v.model||"auto",workspace:t,skills:L,activeSkills:L,config:k,timeout:v.timeout||3e5,messages:Ft,skipPromptFragments:!0,stream:!0,onToken:$e,onToolCall:xe,signal:jt.signal});ct&&yt();const x=typeof a=="string"?a:a?.structured?JSON.stringify(a.structured,null,2):a?.raw||String(a),g=wt&&wt.trim().length>0?wt.trim():x.trim(),T=is(g,Ct)?g:cs(g);n.pushAssistant(T);const b=Ct.length>0?`[tools used: ${Ct.join(", ")}]
|
|
88
|
+
${g}`:g;E.push({role:"ai",content:b}),Pt(t,E),It(t,L)}catch(a){if(ct&&yt(),n.dismissTransientLoading(),jt.signal.aborted){ot.length===0&&n.pushAssistant(e.gray("[cancelled]"));let x="";try{const{testRunnerSkill:T}=await import("../../skills/index.js"),b=await T.handleToolCall("run_status",{runId:"all"},{options:{workspace:t}}),S=JSON.parse(b);S.runs?.length>0&&(x=`
|
|
89
|
+
[Active test runs: ${S.runs.map(p=>`${p.runId}: ${p.ticketKey||p.spec} (${p.status})`).join(", ")}. Use run_status("all") to check progress.]`)}catch{}const g=wt.trim();g?E.push({role:"ai",content:g+x}):E.push({role:"ai",content:`[interrupted \u2014 new message]${x}`})}else{const x=String(a?.message||a||"Unknown error");/413|payload too large|request payload too large/i.test(x)?(n.pushAssistant(e.yellow("Request became too large for the proxy (413).")),n.pushSystem(e.gray("Try: /clear, then retry your command; or shorten command/context."))):n.pushAssistant(e.red(`Error: ${x}`)),E.push({role:"ai",content:`[Error: ${a.message}]`})}}finally{N=null,at=!1}if(n.refreshPrompt(),ot.length>0){const a=ot.shift();ut=!0,setImmediate(()=>f.emit("line",a))}}catch(i){n.pushSystem(e.red(`Input handling error: ${i?.message||String(i)}`)),n.refreshPrompt()}}),f.on("SIGINT",()=>{if(N){N.abort();return}Lt()}),f.on("close",Lt);const be=()=>{process.stdin?.off?(process.stdin.off("data",_t),process.stdin.off("keypress",Ut)):process.stdin?.removeListener&&(process.stdin.removeListener("data",_t),process.stdin.removeListener("keypress",Ut))};f.on("close",be)})}export{Rs as _buildPrompt,Xe as _checkEnvKeys,Ve as _formatHistory,Os as _inferAgentType,Fs as chatCommand};
|
package/dist/commands/init.js
CHANGED
|
@@ -1,51 +1,52 @@
|
|
|
1
|
-
import{mkdir as A,writeFile as u,readFile as w}from"fs/promises";import{existsSync as
|
|
2
|
-
\u{1F4A1} To add manually on Windows:`)),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${
|
|
1
|
+
import{mkdir as A,writeFile as u,readFile as w}from"fs/promises";import{existsSync as f,readdirSync as j}from"fs";import{join as i,resolve as L,dirname as N}from"path";import{homedir as E}from"os";import D from"inquirer";import e from"chalk";import x from"ora";import{spawn as S,execSync as Y}from"child_process";import{fileURLToPath as G}from"url";import{createRequire as O}from"module";const H=G(import.meta.url),F=N(H),Z=O(import.meta.url);async function W(){try{const d=process.platform==="win32",n=Y("npm config get prefix",{encoding:"utf-8"}).trim(),g=d?n:`${n}/bin`,m=g.replace(/^~/,E()),a=d?";":":";if(process.env.PATH.split(a).some(I=>{const $=I.replace(/^~/,E());return $===m||$===g}))return;console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${m}`)),console.log();const{shouldAddPath:s}=await D.prompt([{type:"confirm",name:"shouldAddPath",message:"Add npm global bin to your shell PATH automatically?",default:!0}]);if(!s){d?(console.log(e.gray(`
|
|
2
|
+
\u{1F4A1} To add manually on Windows:`)),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${m}
|
|
3
3
|
`))):(console.log(e.gray(`
|
|
4
|
-
\u{1F4A1} To add manually, run:`)),console.log(e.gray(` echo 'export PATH="${
|
|
5
|
-
`)));return}if(
|
|
6
|
-
`));return}const
|
|
4
|
+
\u{1F4A1} To add manually, run:`)),console.log(e.gray(` echo 'export PATH="${m}:$PATH"' >> ~/.zshrc`)),console.log(e.gray(` source ~/.zshrc
|
|
5
|
+
`)));return}if(d){console.log(e.yellow("\u26A0\uFE0F Cannot auto-add PATH on Windows")),console.log(e.gray(" Please add manually:")),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${m}
|
|
6
|
+
`));return}const v=process.env.SHELL||"";let p="";if(v.includes("zsh"))p=i(E(),".zshrc");else if(v.includes("bash"))p=f(i(E(),".bashrc"))?i(E(),".bashrc"):i(E(),".bash_profile");else{console.log(e.yellow(`\u26A0\uFE0F Unknown shell: ${v}`)),console.log(e.gray(" Please add manually:")),console.log(e.gray(` export PATH="${m}:$PATH"`));return}if(f(p)){const I=await w(p,"utf-8");if(I.includes(m)||I.includes("npm")&&I.includes("global")&&I.includes("bin")){console.log(e.yellow(`\u26A0\uFE0F PATH entry found in ${p} but not active`)),console.log(e.gray(` Run: source ${p}
|
|
7
7
|
`));return}}const b=`
|
|
8
8
|
# npm global bin (added by zibby)
|
|
9
|
-
export PATH="${
|
|
10
|
-
`;await u(p,(
|
|
9
|
+
export PATH="${m}:$PATH"
|
|
10
|
+
`;await u(p,(f(p)?await w(p,"utf-8"):"")+b),console.log(e.green(`\u2705 Added to ${p}`)),console.log(e.yellow(`
|
|
11
11
|
\u{1F4A1} Run this to activate in current session:`)),console.log(e.gray(` source ${p}
|
|
12
|
-
`))}catch{}}async function
|
|
12
|
+
`))}catch{}}async function ue(d,n){console.log(e.bold.cyan(`
|
|
13
13
|
\u{1F3AD} Welcome to Zibby Test Automation!
|
|
14
|
-
`));const g=!n.skipMemory,
|
|
15
|
-
\u274C Directory "${
|
|
16
|
-
`)),process.exit(1)),!f
|
|
14
|
+
`));const g=!n.skipMemory,m=["dolt","mem0"].includes(String(n.memoryBackend||"").toLowerCase())?String(n.memoryBackend).toLowerCase():"dolt";await W();const a=d?L(process.cwd(),d):process.cwd(),_=d||"zibby-tests",h=!!d;h&&f(a)&&(console.log(e.red(`
|
|
15
|
+
\u274C Directory "${d}" already exists!
|
|
16
|
+
`)),process.exit(1)),!h&&f(i(a,".zibby.config.mjs"))&&!n.force&&(console.log(e.yellow(`
|
|
17
17
|
\u26A0\uFE0F Zibby is already initialized in this directory!
|
|
18
18
|
`)),console.log(e.white("Config file found: .zibby.config.mjs")),console.log(e.gray(`Use --force or -f to reinitialize
|
|
19
|
-
`)),process.exit(0)),n.force&&!
|
|
19
|
+
`)),process.exit(0)),n.force&&!h&&console.log(e.cyan(`
|
|
20
20
|
Reinitializing Zibby configuration...
|
|
21
|
-
`));let
|
|
22
|
-
`)),
|
|
21
|
+
`));let s;if(n.agent&&(n.headed||n.headless))console.log(e.cyan(`Setting up with provided options...
|
|
22
|
+
`)),s={agent:n.agent,browserMode:n.headless?"headless":"headed",apiKey:n.apiKey||null,cloudSync:!!(n.cloudSync||n.apiKey)};else{const b=[];n.agent||b.push({type:"select",name:"agent",message:"Which AI agent do you prefer?",choices:[{name:"Cursor",value:"cursor"},{name:"Claude (Anthropic)",value:"claude"},{name:"Codex (OpenAI)",value:"codex"},{name:"Gemini (Google)",value:"gemini"}],default:"cursor"}),!n.headed&&!n.headless&&b.push({type:"select",name:"browserMode",message:"Browser mode during live AI execution?",choices:[{name:"Headed - Visible browser (recommended for development)",value:"headed"},{name:"Headless - Hidden browser (for CI/CD)",value:"headless"}],default:"headed"}),n.apiKey||b.push({type:"input",name:"apiKey",message:"Enable cloud sync? Enter project ZIBBY_API_KEY (or press Enter to skip):"}),s=b.length>0?await D.prompt(b):{},s.agent=n.agent||s.agent,s.browserMode=n.headless?"headless":n.headed?"headed":s.browserMode,s.apiKey=n.apiKey||s.apiKey,s.cloudSync=!!(n.cloudSync||n.apiKey||s.apiKey&&s.apiKey.trim())}s.mcp="playwright",s.setupMcp=s.agent==="cursor";const p=x("Setting up Zibby...").start();try{if(h&&await A(a,{recursive:!0}),await A(i(a,"test-specs/examples"),{recursive:!0}),await A(i(a,"tests"),{recursive:!0}),await A(i(a,".zibby/output"),{recursive:!0}),await A(i(a,".zibby/commands"),{recursive:!0}),g&&m==="dolt")try{const{initMemory:t,DoltDB:r}=await import("@zibby/memory");if(r.isAvailable()){const{created:o}=t(a);o&&(p.text="Initialized test memory database (Dolt)...")}else p.text="Dolt not found \u2014 skipping memory database (brew install dolt)"}catch{}p.text="Scaffolding workflow graph...";const{TemplateFactory:b}=await import("@zibby/core/templates"),I=n.template||"browser-test-automation";try{const{graphPath:t,nodesPath:r,readmePath:o,resultHandlerPath:c,template:l}=b.getTemplateFiles(I),y=i(a,".zibby"),k=await w(t,"utf-8");if(await u(i(y,"graph.mjs"),k),c){const P=await w(c,"utf-8");await u(i(y,"result-handler.mjs"),P)}const B=await w(o,"utf-8");await u(i(y,"README.md"),B),await A(i(y,"nodes"),{recursive:!0});const{readdirSync:C}=await import("fs"),z=C(r);for(const P of z){let K=await w(i(r,P),"utf-8");!g&&P==="execute-live.mjs"&&(K=K.replace("skills: [SKILLS.BROWSER, SKILLS.MEMORY],","skills: [SKILLS.BROWSER],")),await u(i(y,"nodes",P),K)}const T=i(l.path,"chat.mjs");if(f(T)){const P=await w(T,"utf-8");await u(i(y,"chat.mjs"),P)}}catch(t){throw p.fail(`Failed to scaffold template: ${t.message}`),t}p.text="Generating configuration files...";const $=U(s,n,{memoryBackend:m});if(await u(i(a,".zibby.config.mjs"),$),await u(i(a,".env.example"),V(s,m)),s.apiKey&&s.apiKey.trim()){const t=i(a,".env"),r=s.apiKey.trim();if(f(t)){let o=await w(t,"utf8");/^ZIBBY_API_KEY=/m.test(o)?o=o.replace(/^ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${r}`):/^#\s*ZIBBY_API_KEY=/m.test(o)?o=o.replace(/^#\s*ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${r}`):o=`${o.trimEnd()}
|
|
23
23
|
|
|
24
24
|
# Zibby Cloud Sync
|
|
25
25
|
ZIBBY_API_KEY=${r}
|
|
26
|
-
`,await u(t,
|
|
27
|
-
|
|
28
|
-
`));
|
|
26
|
+
`,await u(t,o)}else await u(t,q(s,r,m))}if(h){const t=X(_,s,{memoryBackend:m});await u(i(a,"package.json"),t)}if(!f(i(a,".gitignore"))){const t=J();await u(i(a,".gitignore"),t)}if(!f(i(a,"playwright.config.js"))){const t=Q("on");await u(i(a,"playwright.config.js"),t)}if(!f(i(a,"test-specs/examples/example-domain.txt"))){const t=ee();await u(i(a,"test-specs/examples/example-domain.txt"),t)}const R=L(F,"../../../../examples/.zibby/commands");if(f(R)){const t=j(R).filter(r=>r.toLowerCase().endsWith(".md"));for(const r of t){const o=i(a,".zibby/commands",r);if(n.force||!f(o)){const c=await w(i(R,r),"utf-8");await u(o,c)}}}if(!f(i(a,".zibby/commands/example.md"))){const t=te();await u(i(a,".zibby/commands/example.md"),t)}if(h){const t=ne(_,s);await u(i(a,"README.md"),t)}if(p.succeed(h?"Project created!":"Zibby initialized!"),h&&!n.skipInstall){const t=x("Installing dependencies...").start();await new Promise((r,o)=>{S("npm",["install"],{cwd:a,stdio:"pipe"}).on("close",l=>{l===0?(t.succeed("Dependencies installed!"),r()):(t.fail("Failed to install dependencies"),o(new Error("npm install failed")))})})}else if(!h){const t=["@zibby/cli","@zibby/core"],r=[];for(const o of t)try{O(i(a,"package.json")).resolve(`${o}/package.json`)}catch{r.push(o)}if(r.length>0){const o=Z("../../package.json"),c=r.map(l=>l==="@zibby/cli"?`${l}@latest`:l==="@zibby/core"?`${l}@${o.dependencies?.["@zibby/core"]||"^0.1.29"}`:l);if(n.skipInstall)console.log(e.yellow(`
|
|
27
|
+
Missing required Zibby dependencies in this project:`)),console.log(e.white(` ${r.join(", ")}`)),console.log(e.gray("Install them manually to avoid runtime errors:")),console.log(e.white(` npm install --save-dev ${c.join(" ")}
|
|
28
|
+
`));else{const l=x("Installing missing Zibby dependencies for this project...").start();await new Promise(k=>{S("npm",["install","--save-dev",...c],{cwd:a,stdio:"pipe"}).on("close",C=>k(C??1))})===0?l.succeed("Installed missing Zibby dependencies"):(l.warn("Could not auto-install Zibby dependencies"),console.log(e.gray("Run this manually:")),console.log(e.white(` npm install --save-dev ${c.join(" ")}
|
|
29
|
+
`)))}}}if(!h&&g&&m==="mem0"&&(console.log(e.yellow(`
|
|
29
30
|
Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(e.gray("Run this manually in your project when ready:")),console.log(e.white(` npm install mem0ai
|
|
30
|
-
`))),!n.skipInstall){const t=
|
|
31
|
+
`))),!n.skipInstall){const t=x("Installing Playwright browsers...").start();await new Promise(r=>{const o=S("npx",["playwright","install","chromium"],{cwd:a,stdio:"pipe"});let c="";o.stdout.on("data",l=>{c+=l.toString()}),o.stderr.on("data",l=>{c+=l.toString()}),o.on("close",l=>{l===0?(c.includes("already installed")||c.includes("up to date")?t.succeed("Playwright browsers already installed"):t.succeed("Playwright browsers installed!"),r()):(t.warn("Could not verify Playwright browsers"),console.log(e.yellow(`
|
|
31
32
|
\u26A0\uFE0F If tests fail, run: npx playwright install
|
|
32
|
-
`)),r())})})}if(
|
|
33
|
-
`))}}}if(
|
|
34
|
-
`))}}}if(
|
|
35
|
-
`))}}const r=
|
|
36
|
-
`,"utf-8");let
|
|
37
|
-
`))}}if(
|
|
33
|
+
`)),r())})})}if(s.agent==="cursor"&&!n.skipInstall){const t=x("Checking cursor-agent CLI...").start();try{Y("cursor-agent --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),t.succeed("cursor-agent CLI already installed")}catch{t.text="Installing cursor-agent CLI...";try{await new Promise((r,o)=>{S("bash",["-c","curl https://cursor.com/install -fsS | bash"],{stdio:"pipe"}).on("close",l=>{l===0?(t.succeed("cursor-agent CLI installed!"),r()):o(new Error("cursor-agent install failed"))})})}catch{t.fail("Could not install cursor-agent CLI"),console.log(e.yellow(` Install manually: curl https://cursor.com/install -fsS | bash
|
|
34
|
+
`))}}}if(s.agent==="codex"&&!n.skipInstall){const t=x("Checking Codex CLI...").start();try{Y("codex --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),t.succeed("Codex CLI already installed")}catch{t.text="Installing Codex CLI...";try{await new Promise((r,o)=>{S("npm",["install","-g","@openai/codex"],{stdio:"pipe"}).on("close",l=>{l===0?(t.succeed("Codex CLI installed!"),r()):o(new Error("npm install -g @openai/codex failed"))})})}catch{t.fail("Could not install Codex CLI"),console.log(e.yellow(` Install manually: npm install -g @openai/codex
|
|
35
|
+
`))}}}if(s.agent==="gemini"&&!n.skipInstall){const t=x("Checking Gemini CLI...").start();try{Y("gemini --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),t.succeed("Gemini CLI already installed")}catch{t.text="Installing Gemini CLI...";try{await new Promise((o,c)=>{S("npm",["install","-g","@google/gemini-cli"],{stdio:"pipe"}).on("close",y=>{y===0?(t.succeed("Gemini CLI installed!"),o()):c(new Error("npm install -g @google/gemini-cli failed"))})})}catch{t.fail("Could not install Gemini CLI"),console.log(e.yellow(` Install manually: npm install -g @google/gemini-cli
|
|
36
|
+
`))}}const r=x("Configuring Gemini MCP servers...").start();try{const o=i(E(),".gemini"),c=i(o,"settings.json");f(o)||await A(o,{recursive:!0});let l={mcpServers:{}};if(f(c))try{const z=await w(c,"utf-8");l=JSON.parse(z),l.mcpServers||(l.mcpServers={})}catch{}let y;try{const{createRequire:z}=await import("module");y=z(import.meta.url).resolve("@zibby/mcp-browser/bin/mcp-browser-zibby.js")}catch{y="@playwright/mcp"}const k=s.browserMode!=="headless",B=y==="@playwright/mcp"?["-y","@playwright/mcp","--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir","test-results"]:[y,"--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir=test-results"];k||B.push("--headless"),l.mcpServers["playwright-official"]={command:y==="@playwright/mcp"?"npx":"node",args:B},await u(c,`${JSON.stringify(l,null,2)}
|
|
37
|
+
`,"utf-8");let C="Gemini MCP configured";k?C+=" (headed mode - visible browser)":C+=" (headless mode - hidden browser)",r.succeed(C)}catch(o){r.fail("MCP setup failed"),console.log(e.yellow(" You may need to configure ~/.gemini/settings.json manually")),console.log(e.gray(` Error: ${o.message}
|
|
38
|
+
`))}}if(s.agent==="cursor"&&s.setupMcp){const t=x("Setting up Playwright MCP...").start();try{const{setupPlaywrightMcpCommand:r}=await import("./setup-scripts.js"),o=s.cloudSync||!1,c=s.browserMode!=="headless";await r({headed:c,cloudSync:o,video:"on",viewport:{width:1280,height:720}});let l="Playwright MCP configured";c?l+=" (headed mode - visible browser)":l+=" (headless mode - hidden browser)",o&&(l+=" + Zibby MCP (cloud sync)"),t.succeed(l),o&&!(s.apiKey&&s.apiKey.trim())&&console.log(e.gray(`
|
|
38
39
|
Copy .env.example to .env and set ZIBBY_API_KEY to enable uploads
|
|
39
40
|
`))}catch(r){t.fail("MCP setup script failed"),console.log(e.yellow(" Check if MCP is already configured:")),console.log(e.gray(' \u2022 Open Cursor settings \u2192 Check "playwright-official" MCP')),console.log(e.gray(" \u2022 Run: cursor-agent mcp list")),console.log(e.gray(` \u2022 Or run manually: zibby setup-playwright
|
|
40
41
|
`)),console.log(e.gray(` Error: ${r.message}
|
|
41
42
|
`))}}console.log(e.bold.green(`
|
|
42
43
|
\u{1F389} All set!
|
|
43
|
-
`)),console.log(e.cyan("Start the Zibby Chat Agent:")),
|
|
44
|
+
`)),console.log(e.cyan("Start the Zibby Chat Agent:")),h&&console.log(e.white(` cd ${d}`)),console.log(e.white(` zibby
|
|
44
45
|
`)),console.log(e.cyan("Or run a test directly:")),console.log(e.white(` zibby run test-specs/examples/example-domain.txt
|
|
45
|
-
`)),console.log(e.cyan("Next steps:"));let
|
|
46
|
+
`)),console.log(e.cyan("Next steps:"));let M=1;console.log(e.white(` ${M++}. cp .env.example .env ${e.gray("# then add your API keys")}`)),g&&console.log(e.white(` ${M++}. Set ${e.bold("ZIBBY_MEMORY_BACKEND")} in .env ${e.gray(`# currently: ${m}`)}`)),console.log(e.white(` ${M++}. Type ${e.bold("zibby")} to chat with the AI testing assistant`)),console.log(e.white(` ${M++}. Write test specs in test-specs/`)),console.log(e.white(` ${M++}. Run: npx zibby run <spec-file>
|
|
46
47
|
`))}catch(b){p.fail("Failed to create project"),console.error(e.red(`
|
|
47
48
|
\u274C Error: ${b.message}
|
|
48
|
-
`)),process.exit(1)}}function
|
|
49
|
+
`)),process.exit(1)}}function U(d,n={},g={}){const m=["dolt","mem0"].includes(String(g.memoryBackend||"").toLowerCase())?String(g.memoryBackend).toLowerCase():"dolt",a={claude:`
|
|
49
50
|
claude: {
|
|
50
51
|
model: 'auto', // Options: 'auto', 'sonnet-4.6', 'opus-4.6', 'sonnet-4.5', 'opus-4.5'
|
|
51
52
|
maxTokens: 4096,
|
|
@@ -58,13 +59,13 @@ Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(
|
|
|
58
59
|
},`,gemini:`
|
|
59
60
|
gemini: {
|
|
60
61
|
model: 'gemini-2.5-pro', // Options: 'auto', 'gemini-2.5-pro', 'gemini-2.5-flash'
|
|
61
|
-
},`},
|
|
62
|
-
`).map(
|
|
62
|
+
},`},_=d.agent,h=Object.entries(a).filter(([s])=>s!==_).map(([,s])=>s.split(`
|
|
63
|
+
`).map(v=>v.trim()?` // ${v.trimStart()}`:v).join(`
|
|
63
64
|
`)).join(`
|
|
64
65
|
`);return`export default {
|
|
65
66
|
// AI agent settings
|
|
66
|
-
agent: {${a[
|
|
67
|
-
${
|
|
67
|
+
agent: {${a[_]}
|
|
68
|
+
${h}
|
|
68
69
|
strictMode: false,
|
|
69
70
|
},
|
|
70
71
|
|
|
@@ -72,12 +73,12 @@ ${f}
|
|
|
72
73
|
// and workflow config. Runtime strategies attach MCP per run (no global Gemini settings mutation).
|
|
73
74
|
browser: {
|
|
74
75
|
mcp: 'playwright',
|
|
75
|
-
headless: ${
|
|
76
|
+
headless: ${d.browserMode==="headless"},
|
|
76
77
|
},
|
|
77
78
|
|
|
78
79
|
// Chat memory backend adapter (dolt | mem0)
|
|
79
80
|
memory: {
|
|
80
|
-
backend: '${
|
|
81
|
+
backend: '${m}',
|
|
81
82
|
},
|
|
82
83
|
|
|
83
84
|
// Advanced: Override models per node (optional)
|
|
@@ -125,13 +126,13 @@ ${f}
|
|
|
125
126
|
},
|
|
126
127
|
|
|
127
128
|
// Cloud sync - auto-upload test results & videos (requires ZIBBY_API_KEY in .env)
|
|
128
|
-
cloudSync: ${
|
|
129
|
+
cloudSync: ${d.cloudSync||!1}
|
|
129
130
|
};
|
|
130
|
-
`}function
|
|
131
|
+
`}function V(d,n="dolt"){return`# Zibby Test Automation - Environment Variables
|
|
131
132
|
|
|
132
133
|
# AI Provider Keys
|
|
133
134
|
${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:`# Cursor Agent uses cursor-agent CLI \u2014 no API key needed
|
|
134
|
-
# Install: curl https://cursor.com/install -fsS | bash`,codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[
|
|
135
|
+
# Install: curl https://cursor.com/install -fsS | bash`,codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[d.agent]||""}
|
|
135
136
|
|
|
136
137
|
# Zibby Cloud Sync (for uploading test results & videos)
|
|
137
138
|
# Get your API key from: https://zibby.app/settings/tokens
|
|
@@ -144,10 +145,10 @@ ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:`# Cursor Agent uses c
|
|
|
144
145
|
|
|
145
146
|
# Chat memory backend
|
|
146
147
|
ZIBBY_MEMORY_BACKEND=${n}
|
|
147
|
-
`}function
|
|
148
|
+
`}function q(d,n,g="dolt"){return`# Zibby Test Automation - Environment Variables
|
|
148
149
|
|
|
149
150
|
# AI Provider Keys
|
|
150
|
-
${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:"# Cursor Agent uses cursor-agent CLI \u2014 no API key needed",codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[
|
|
151
|
+
${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:"# Cursor Agent uses cursor-agent CLI \u2014 no API key needed",codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[d.agent]||""}
|
|
151
152
|
|
|
152
153
|
# Zibby Cloud Sync
|
|
153
154
|
ZIBBY_API_KEY=${n}
|
|
@@ -159,7 +160,7 @@ ZIBBY_API_KEY=${n}
|
|
|
159
160
|
|
|
160
161
|
# Chat memory backend
|
|
161
162
|
ZIBBY_MEMORY_BACKEND=${g}
|
|
162
|
-
`}function
|
|
163
|
+
`}function X(d,n,g={}){const a={"@zibby/cli":"latest","@zibby/core":Z("../../package.json").dependencies?.["@zibby/core"]||"^0.1.29"};return g.memoryBackend==="mem0"&&(a.mem0ai="^2.4.6"),JSON.stringify({name:d,version:"1.0.0",type:"module",private:!0,scripts:{"test:spec":"zibby run",test:"playwright test","test:headed":"playwright test --headed"},dependencies:a,devDependencies:{"@playwright/test":"^1.49.0",dotenv:"^17.2.3"}},null,2)}function J(){return`# Dependencies
|
|
163
164
|
node_modules/
|
|
164
165
|
|
|
165
166
|
# Test artifacts
|
|
@@ -187,7 +188,7 @@ Thumbs.db
|
|
|
187
188
|
# Zibby memory (Dolt DB synced separately via dolt remote, not git)
|
|
188
189
|
.zibby/memory/
|
|
189
190
|
.zibby/memory-context.md
|
|
190
|
-
`}function
|
|
191
|
+
`}function Q(d="off",n=null){return`import { defineConfig} from '@playwright/test';
|
|
191
192
|
|
|
192
193
|
export default defineConfig({
|
|
193
194
|
testDir: './tests',
|
|
@@ -209,7 +210,7 @@ ${n?` outputDir: '${n}',
|
|
|
209
210
|
['list']
|
|
210
211
|
],
|
|
211
212
|
});
|
|
212
|
-
`}function
|
|
213
|
+
`}function ee(){return`Test Specification: Example Domain Navigation
|
|
213
214
|
==============================================
|
|
214
215
|
|
|
215
216
|
Application: Example Domain
|
|
@@ -246,7 +247,7 @@ Notes:
|
|
|
246
247
|
- Uses a stable, public domain (example.com) maintained by IANA
|
|
247
248
|
- No authentication required
|
|
248
249
|
- Suitable for CI/CD smoke testing
|
|
249
|
-
`}function
|
|
250
|
+
`}function te(){return`# Example command template
|
|
250
251
|
|
|
251
252
|
Use this command when the user asks for a concise testing task breakdown.
|
|
252
253
|
|
|
@@ -257,7 +258,7 @@ Required output format:
|
|
|
257
258
|
4. Expected result
|
|
258
259
|
|
|
259
260
|
Keep the response actionable and short.
|
|
260
|
-
`}function
|
|
261
|
+
`}function ne(d,n){return`# ${d}
|
|
261
262
|
|
|
262
263
|
AI-powered test automation with Zibby.
|
|
263
264
|
|
|
@@ -328,7 +329,7 @@ Edit \`.zibby.config.mjs\` to customize:
|
|
|
328
329
|
## Project Structure
|
|
329
330
|
|
|
330
331
|
\`\`\`
|
|
331
|
-
${
|
|
332
|
+
${d}/
|
|
332
333
|
\u251C\u2500\u2500 .zibby/
|
|
333
334
|
\u2502 \u251C\u2500\u2500 graph.mjs # Workflow definition
|
|
334
335
|
\u2502 \u251C\u2500\u2500 nodes/ # Custom nodes
|
|
@@ -346,4 +347,4 @@ ${l}/
|
|
|
346
347
|
|
|
347
348
|
- Documentation: https://docs.zibby.dev
|
|
348
349
|
- Examples: https://github.com/zibby/examples
|
|
349
|
-
`}export{
|
|
350
|
+
`}export{ue as initCommand};
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as y,execSync as w}from"child_process";import{join as l,dirname as v,resolve as P}from"path";import{readFileSync as C,writeFileSync as S,existsSync as u,mkdirSync as x}from"fs";import{homedir as j}from"os";import{createRequire as A}from"module";import c from"chalk";const b=A(import.meta.url);function B(){try{return v(b.resolve("@zibby/core/package.json"))}catch{return null}}function $(e){try{return w(`command -v ${e}`,{stdio:"pipe"}),!0}catch{return!1}}function E(){try{const e=b.resolve("@zibby/mcp-browser/bin/mcp-browser-zibby.js");if(u(e))return e}catch{}try{const e=b.resolve("@playwright/mcp/package.json"),r=v(e),o=JSON.parse(C(e,"utf-8")),n=typeof o.bin=="string"?o.bin:o.bin?.["playwright-mcp"];if(n){const s=l(r,n);if(u(s))return s}const t=l(r,"cli.js");if(u(t))return t}catch{}return null}function k(e,r,o={}){return new Promise((n,t)=>{const s=y(e,r,{stdio:"inherit",...o});s.on("close",p=>n(p??1)),s.on("error",t)})}async function N(e){return $("playwright")?await k("playwright",["install","ffmpeg"],{cwd:e})===0:await k("npx",["--yes","playwright","install","ffmpeg"],{cwd:e})===0}function O({headed:e=!1,video:r="on",viewport:o=null}){const n=process.execPath,t=v(n),s=E(),p=Number(o?.width)||1280,d=Number(o?.height)||720,f=`${p}x${d}`,i=[];r!=="off"&&i.push(`--save-video=${f}`),i.push(`--viewport-size=${f}`,"--output-dir=test-results"),e||i.push("--headless");let g;s?g={command:n,args:[s,...i],env:{PATH:`${t}:/usr/bin:/bin:/usr/sbin:/sbin`}}:g={command:"npx",args:["-y","@playwright/mcp",...i],env:{PATH:`${t}:/usr/bin:/bin:/usr/sbin:/sbin`}},g.description="Zibby MCP Browser - Playwright MCP with Zibby defaults";const h=l(j(),".cursor"),m=l(h,"mcp.json");u(h)||x(h,{recursive:!0});let a={mcpServers:{}};if(u(m))try{a=JSON.parse(C(m,"utf-8")),(!a.mcpServers||typeof a.mcpServers!="object")&&(a.mcpServers={})}catch{a={mcpServers:{}}}a.mcpServers["playwright-official"]=g,S(m,`${JSON.stringify(a,null,2)}
|
|
2
|
+
`,"utf-8")}async function R(){const e=B();if(!e)return;const r=l(e,"scripts","patch-cursor-mcp.js");if(u(r))try{await new Promise((o,n)=>{const t=y(process.execPath,[r],{cwd:process.cwd(),stdio:"ignore"});t.on("close",s=>o(s??0)),t.on("error",n)})}catch{}}function z(e){return P(e).replace(/^\/+/,"").replace(/\//g,"-")}function J(e){const r=String(e||""),o=r.split(`
|
|
3
|
+
`).find(s=>/playwright-official/i.test(s)&&/APPROVAL|🔑/i.test(s));if(o){const s=o.match(/=>\s*(\S+)/);if(s)return s[1]}const n=r.match(/playwright-official[^=]*=>\s*(\S+)/);if(n)return n[1];const t=r.match(/playwright-official-[a-f0-9]+/i);return t?t[0]:null}function T(e,r){const o=z(e),n=l(j(),".cursor","projects",o);x(n,{recursive:!0});const t=l(n,"mcp-approvals.json");return S(t,`${JSON.stringify([r],null,2)}
|
|
4
|
+
`,"utf-8"),t}function M(e){try{return w("cursor-agent mcp list",{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","pipe"],env:process.env,maxBuffer:2*1024*1024})}catch(r){const o=r.stdout!=null?String(r.stdout):"",n=r.stderr!=null?String(r.stderr):"";return o+n}}function D(e){try{return w("cursor-agent mcp enable playwright-official",{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","pipe"],env:process.env,maxBuffer:1024*1024}),!0}catch{return!1}}async function F(e={}){const r=!!e.headed,o=e.video||"on",n=e.viewport||{width:1280,height:720};if(!process.execPath)throw new Error("Node.js runtime not found");const t=await N(process.cwd());console.log(t?c.gray(" \u2713 ffmpeg installed for Playwright video"):c.yellow(" \u26A0 Could not install ffmpeg (video may be unavailable)")),O({headed:r,video:o,viewport:n}),await R();const s=P(process.cwd());if($("cursor-agent")){M(s);const p=D(s);p&&console.log(c.gray(" \u2713 cursor-agent: mcp enable playwright-official"));const d=M(s),f=J(d);if(f)try{const i=T(s,f);console.log(c.gray(` \u2713 MCP auto-approval key saved (${i})`))}catch(i){console.log(c.yellow(` \u26A0 Could not write mcp-approvals.json: ${i.message}`))}else p||(console.log(c.yellow(" \u26A0 Could not auto-approve MCP (mcp enable failed and no approval key in cursor-agent output)")),console.log(c.gray(" Try: cursor-agent mcp enable playwright-official")))}else console.log(c.yellow(" \u26A0 cursor-agent not found; install it to use Cursor MCP tools"))}async function L(e){try{console.log(c.cyan(`
|
|
5
|
+
\u{1F680} Running CI setup...
|
|
6
|
+
`)),await F({headed:!1,cloudSync:!0,video:"on",viewport:{width:1280,height:720}}),console.log(c.green(`
|
|
2
7
|
\u2705 CI/CD setup complete!
|
|
3
|
-
`))}catch(
|
|
4
|
-
\u274C Error: ${
|
|
5
|
-
`)),process.exit(1)}}async function
|
|
8
|
+
`))}catch(r){console.log(c.red(`
|
|
9
|
+
\u274C Error: ${r.message}
|
|
10
|
+
`)),process.exit(1)}}async function Z(e,r){try{const o=["playwright","test",e||"tests/","--project=chromium"];r.headed&&o.push("--headed"),console.log(c.cyan(`
|
|
6
11
|
\u{1F3A5} Running tests with video recording...
|
|
7
|
-
`)),console.log(
|
|
12
|
+
`)),console.log(c.gray("\u2501".repeat(50)));const n=y("npx",o,{cwd:process.cwd(),stdio:"inherit"});n.on("close",t=>{t===0?console.log(c.green(`
|
|
8
13
|
\u2705 Tests complete!
|
|
9
|
-
`)):(console.log(
|
|
10
|
-
\u274C Tests failed with code ${
|
|
11
|
-
`)),process.exit(
|
|
12
|
-
\u274C Error: ${r.message}
|
|
13
|
-
`)),process.exit(1)})}catch(t){console.log(o.red(`
|
|
14
|
+
`)):(console.log(c.red(`
|
|
15
|
+
\u274C Tests failed with code ${t}
|
|
16
|
+
`)),process.exit(t))}),n.on("error",t=>{console.log(c.red(`
|
|
14
17
|
\u274C Error: ${t.message}
|
|
15
|
-
`)),process.exit(1)}}
|
|
18
|
+
`)),process.exit(1)})}catch(o){console.log(c.red(`
|
|
19
|
+
\u274C Error: ${o.message}
|
|
20
|
+
`)),process.exit(1)}}export{L as setupCiCommand,F as setupPlaywrightMcpCommand,Z as testWithVideoCommand};
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
|
|
1
|
+
import{existsSync as m}from"fs";import{readFile as B,readdir as P}from"fs/promises";import{join as y,resolve as T,relative as x}from"path";import{pathToFileURL as z}from"url";import o from"chalk";import h from"ora";import C from"dotenv";import{getApiUrl as I,getCurrentEnvironment as E}from"../../config/environments.js";import{getSessionToken as S}from"../../config/config.js";C.config();function A(r){const t=r.apiKey||process.env.ZIBBY_API_KEY||S();t||(console.log(o.red(`
|
|
2
|
+
Not authenticated`)),console.log(o.gray(` Run: zibby login
|
|
3
3
|
`)),process.exit(1));const e=r.project||process.env.ZIBBY_PROJECT_ID;return e||(console.log(o.red(`
|
|
4
4
|
--project or ZIBBY_PROJECT_ID is required`)),console.log(o.gray(` Example: zibby deploy my-workflow --project <id>
|
|
5
|
-
`)),process.exit(1)),{apiKey:t,projectId:e}}function
|
|
5
|
+
`)),process.exit(1)),{apiKey:t,projectId:e}}function O(r){const t=process.cwd();return y(t,".zibby","workflows",r)}async function U(r,t){const e=y(r,"workflow.json");if(!m(e))return{name:t,triggers:{api:!0}};const l=await B(e,"utf-8");return JSON.parse(l)}async function D(r){const t={};async function e(l){const u=await P(l,{withFileTypes:!0});for(const g of u){const i=y(l,g.name);if(g.isDirectory())await e(i);else if(/\.(mjs|js|json)$/.test(g.name)){const f=x(r,i);t[f]=await B(i,"utf-8")}}}return await e(r),t}async function Z(r,t){r||(console.log(o.red(`
|
|
6
6
|
Workflow name is required`)),console.log(o.gray(" Usage: zibby deploy <workflow-name>")),console.log(o.gray(` Example: zibby deploy ticket-triage
|
|
7
|
-
`)),process.exit(1));const e=r.toLowerCase(),l=
|
|
7
|
+
`)),process.exit(1));const e=r.toLowerCase(),l=O(e);m(l)||(console.log(o.red(`
|
|
8
8
|
Workflow not found: .zibby/workflows/${e}/`)),console.log(o.gray(" Create one first:")),console.log(o.cyan(` zibby g workflow ${e}
|
|
9
|
-
`)),process.exit(1));const
|
|
9
|
+
`)),process.exit(1));const u=E(),{apiKey:g,projectId:i}=A(t);console.log(o.bold.cyan(`
|
|
10
10
|
Zibby Workflow Deploy
|
|
11
|
-
`)),console.log(o.gray(" ".padEnd(56,"-"))),console.log(o.white(` Environment: ${o.cyan(
|
|
11
|
+
`)),console.log(o.gray(" ".padEnd(56,"-"))),console.log(o.white(` Environment: ${o.cyan(u.name)}`)),console.log(o.white(` Project: ${o.cyan(i)}`)),console.log(o.white(` Workflow: ${o.cyan(e)}`)),console.log(o.gray(" ".padEnd(56,"-")));const f=h(" Loading workflow module...").start();let b,$;try{$=await U(l,e);const n=y(l,"graph.mjs");if(!m(n))throw new Error(`graph.mjs not found in .zibby/workflows/${e}/`);const s=await import(z(T(n)).href),a=$.entryClass,c=a&&s[a]||s.default||Object.values(s).find(v=>typeof v=="function"&&v.prototype?.buildGraph);if(!c)throw new Error("No WorkflowAgent class found in graph.mjs");const j=new c().buildGraph();b=j.serialize(),f.succeed(` Loaded ${c.name} (${j.nodes.size} nodes)`)}catch(n){f.fail(" Failed to load workflow"),console.log(o.red(`
|
|
12
12
|
${n.message}
|
|
13
|
-
`)),process.exit(1)}const k=
|
|
13
|
+
`)),process.exit(1)}const k=h(" Bundling source files...").start();let p;try{p=await D(l);const n=Object.keys(p).length,s=(Buffer.byteLength(JSON.stringify(p),"utf-8")/1024).toFixed(1);k.succeed(` Bundled ${n} files (${s} KB)`)}catch(n){k.fail(" Failed to bundle sources"),console.log(o.red(`
|
|
14
14
|
${n.message}
|
|
15
|
-
`)),process.exit(1)}const
|
|
16
|
-
|
|
17
|
-
`)),process.exit(1)}v.succeed(" Graph is valid");const h=u(" Deploying to cloud...").start();try{const n=T(),s=await fetch(`${n}/projects/${i}/workflows/${e}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${g}`},body:JSON.stringify({graph:m,sources:d})});if(!s.ok){const p=await s.text();h.fail(` API error: ${s.status}`),console.log(o.red(` ${p}
|
|
18
|
-
`)),process.exit(1)}const a=await s.json();h.succeed(` Deployed successfully (v${a.version})`);const c=`${n}/projects/${i}/workflows/${e}/trigger`;if(console.log(o.green(`
|
|
15
|
+
`)),process.exit(1)}const w=h(" Deploying to cloud...").start();try{const n=I(),s=await fetch(`${n}/projects/${i}/workflows/${e}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${g}`},body:JSON.stringify({graph:b,sources:p})});if(!s.ok){const d=await s.text();w.fail(` API error: ${s.status}`),console.log(o.red(` ${d}
|
|
16
|
+
`)),process.exit(1)}const a=await s.json();w.succeed(` Deployed successfully (v${a.version})`);const c=`${n}/projects/${i}/workflows/${e}/trigger`;if(console.log(o.green(`
|
|
19
17
|
Workflow "${e}" deployed to version ${a.version}`)),console.log(o.white(`
|
|
20
|
-
Trigger URL (API):`)),console.log(o.cyan(` POST ${c}`)),a.subdomain){const
|
|
21
|
-
Trigger URL (subdomain):`)),console.log(o.cyan(` POST ${
|
|
22
|
-
Test with:`)),console.log(o.gray(` curl -X POST ${c} \\`)),console.log(o.gray(' -H "Authorization: Bearer $ZIBBY_API_KEY" \\')),console.log(o.gray(' -H "Content-Type: application/json" \\')),console.log(o.gray(` -d '{"input": {"key": "value"}}'
|
|
23
|
-
|
|
18
|
+
Trigger URL (API):`)),console.log(o.cyan(` POST ${c}`)),a.subdomain){const d=`https://${a.subdomain}.workflows.zibby.app`;console.log(o.white(`
|
|
19
|
+
Trigger URL (subdomain):`)),console.log(o.cyan(` POST ${d}`))}console.log(o.white(`
|
|
20
|
+
Test with:`)),console.log(o.gray(` curl -X POST ${c} \\`)),console.log(o.gray(' -H "Authorization: Bearer $ZIBBY_API_KEY" \\')),console.log(o.gray(' -H "Content-Type: application/json" \\')),console.log(o.gray(` -d '{"input": {"key": "value"}}'`)),console.log(o.white(`
|
|
21
|
+
Tail logs:`)),console.log(o.gray(` zibby logs <jobId> --project ${i}
|
|
22
|
+
`))}catch(n){w.fail(" Deploy failed"),console.log(o.red(`
|
|
24
23
|
${n.message}
|
|
25
|
-
`)),process.exit(1)}}export{
|
|
24
|
+
`)),process.exit(1)}}export{Z as deployWorkflowCommand};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import o from"chalk";import{getSessionToken as k}from"../../config/config.js";import h from"dotenv";h.config();const w="https://logs.workflows.zibby.app";function j(e){const r=e.apiKey||process.env.ZIBBY_API_KEY||k();r||(console.log(o.red(`
|
|
2
|
+
Not authenticated`)),console.log(o.gray(` Run: zibby login
|
|
3
|
+
`)),process.exit(1));const t=e.project||process.env.ZIBBY_PROJECT_ID;return t||(console.log(o.red(`
|
|
4
|
+
--project or ZIBBY_PROJECT_ID is required`)),console.log(o.gray(` Example: zibby logs <jobId> --project <id>
|
|
5
|
+
`)),process.exit(1)),{token:r,projectId:t}}function $(e){return new Date(e).toISOString().replace("T"," ").replace("Z","")}function I(e){return e==="running"?o.yellow(e):e==="completed"?o.green(e):o.red(e||"unknown")}function b(e){return e?.length>16?e.slice(0,16):e}async function p(e,r){const t=await fetch(e,{headers:{Authorization:`Bearer ${r}`}});if(!t.ok){const i=await t.text();throw new Error(`API ${t.status}: ${i}`)}return t.json()}async function x(e,r,t,i){if(e)return e;const g=r.workflow;g||(console.log(o.red(`
|
|
6
|
+
Job ID or --workflow is required`)),console.log(o.gray(" Usage: zibby logs <jobId> --project <id>")),console.log(o.gray(" zibby logs --workflow ticket-triage --project <id>")),console.log(o.gray(` zibby logs --workflow ticket-triage --all --project <id>
|
|
7
|
+
`)),process.exit(1));const m=new URLSearchParams({workflow:g,limit:"10"}),{jobs:l}=await p(`${w}/jobs/${i}?${m}`,t);(!l||l.length===0)&&(console.log(o.yellow(`
|
|
8
|
+
No jobs found for workflow "${g}".`)),process.exit(0)),console.log(o.gray(`
|
|
9
|
+
Recent runs for ${o.cyan(g)}:
|
|
10
|
+
`));for(const f of l.slice(0,5))console.log(o.gray(` ${b(f.jobId)} ${I(f.status)} ${f.createdAt||""}`));const a=l[0];return console.log(o.gray(`
|
|
11
|
+
Tailing latest: ${o.cyan(b(a.jobId))}
|
|
12
|
+
`)),a.jobId}async function T({token:e,projectId:r,jobId:t,follow:i,limit:g}){const m=`${w}/logs/${r}/${t}`;let l=null,a=0;const f=new Set;for(console.log(o.gray(` Tailing logs for job ${o.cyan(b(t))}...`)),console.log(i?o.gray(` Press Ctrl+C to stop.
|
|
13
|
+
`):"");;)try{const u=new URLSearchParams({limit:String(g)});l&&u.set("nextToken",l);const n=await p(`${m}?${u}`,e);n.message&&n.lines?.length===0&&a===0&&console.log(o.gray(` ${n.message}`));for(const s of n.lines||[]){const d=`${s.timestamp}:${s.message}`;if(f.has(d))continue;f.add(d);const y=o.gray($(s.timestamp));console.log(`${y} ${s.message.replace(/\n$/,"")}`)}if(a=n.lines?.length>0?0:a+1,l=n.nextForwardToken||null,n.status==="completed"||n.status==="failed"){const s=n.status==="completed"?o.green:o.red;console.log(s(`
|
|
14
|
+
Job ${n.status}.`)),process.exit(n.status==="completed"?0:1)}if(!i){n.status&&console.log(o.gray(`
|
|
15
|
+
Status: ${n.status}`));break}await new Promise(s=>setTimeout(s,a>5?5e3:2e3))}catch(u){if(u.name==="AbortError")break;console.error(o.red(` Error: ${u.message}`)),i||process.exit(1),await new Promise(n=>setTimeout(n,3e3))}}async function P({token:e,projectId:r,workflow:t,follow:i,limit:g}){const m=`${w}/all/${r}`;let l=null,a=0;const f=new Set;let u=null;for(console.log(o.gray(`
|
|
16
|
+
Tailing all runs for ${o.cyan(t)}...`)),console.log(i?o.gray(` Press Ctrl+C to stop.
|
|
17
|
+
`):"");;)try{const n=new URLSearchParams({workflow:t,limit:String(g)});l&&n.set("nextToken",l);const c=await p(`${m}?${n}`,e);c.message&&c.lines?.length===0&&a===0&&console.log(o.gray(` ${c.message}`));for(const s of c.lines||[]){const d=`${s.timestamp}:${s.jobId}:${s.message}`;if(f.has(d))continue;f.add(d),s.jobId!==u&&(u!==null&&console.log(""),console.log(o.dim(` \u2500\u2500 ${b(s.jobId)} \u2500\u2500`)),u=s.jobId);const y=o.gray($(s.timestamp));console.log(`${y} ${s.message.replace(/\n$/,"")}`)}if(a=c.lines?.length>0?0:a+1,l=c.nextToken||null,!i){l&&console.log(o.gray(`
|
|
18
|
+
... more logs available. Run again or use --follow to stream.`)),c.jobCount&&console.log(o.gray(` ${c.jobCount} job(s) found.`));break}if(!c.hasRunning&&!l&&a>2){console.log(o.gray(`
|
|
19
|
+
No running jobs. All caught up.`));break}await new Promise(s=>setTimeout(s,a>5?5e3:2e3))}catch(n){if(n.name==="AbortError")break;console.error(o.red(` Error: ${n.message}`)),i||process.exit(1),await new Promise(c=>setTimeout(c,3e3))}}async function C(e,r){const{token:t,projectId:i}=j(r),g=r.follow!==!1,m=r.lines?parseInt(r.lines,10):200;if(r.all){const a=r.workflow;return a||(console.log(o.red(`
|
|
20
|
+
--workflow is required with --all`)),console.log(o.gray(` Example: zibby logs --workflow ticket-triage --all --project <id>
|
|
21
|
+
`)),process.exit(1)),P({token:t,projectId:i,workflow:a,follow:g,limit:m})}const l=await x(e,r,t,i);return T({token:t,projectId:i,jobId:l,follow:g,limit:m})}export{C as logsCommand};
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.45",
|
|
4
4
|
"description": "Zibby CLI - Test automation generator and runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,11 +33,12 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@aws-sdk/client-sqs": "^3.1029.0",
|
|
36
|
-
"@zibby/core": "^0.1.
|
|
37
|
-
"@zibby/memory": "^0.1.
|
|
38
|
-
"@zibby/skills": "^0.1.
|
|
36
|
+
"@zibby/core": "^0.1.30",
|
|
37
|
+
"@zibby/memory": "^0.1.5",
|
|
38
|
+
"@zibby/skills": "^0.1.6",
|
|
39
39
|
"adm-zip": "^0.5.17",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
|
+
"cli-highlight": "^2.1.11",
|
|
41
42
|
"commander": "^12.0.0",
|
|
42
43
|
"dotenv": "^17.4.1",
|
|
43
44
|
"express": "^4.18.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.45",
|
|
4
4
|
"description": "Zibby CLI - Test automation generator and runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,11 +33,12 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@aws-sdk/client-sqs": "^3.1029.0",
|
|
36
|
-
"@zibby/core": "^0.1.
|
|
37
|
-
"@zibby/memory": "^0.1.
|
|
38
|
-
"@zibby/skills": "^0.1.
|
|
36
|
+
"@zibby/core": "^0.1.30",
|
|
37
|
+
"@zibby/memory": "^0.1.5",
|
|
38
|
+
"@zibby/skills": "^0.1.6",
|
|
39
39
|
"adm-zip": "^0.5.17",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
|
+
"cli-highlight": "^2.1.11",
|
|
41
42
|
"commander": "^12.0.0",
|
|
42
43
|
"dotenv": "^17.4.1",
|
|
43
44
|
"express": "^4.18.2",
|