@zibby/skills 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +2 -2
- package/dist/chat-memory.js +15 -15
- package/dist/core-tools.js +2 -2
- package/dist/function-skill.js +1 -1
- package/dist/git.js +2 -2
- package/dist/github.js +3 -3
- package/dist/index.js +646 -1
- package/dist/jira.js +6 -6
- package/dist/memory.js +4 -4
- package/dist/package.json +15 -10
- package/dist/sentry.js +2 -2
- package/dist/skill-installer.js +3 -3
- package/dist/slack.js +2 -2
- package/dist/test-runner.js +13 -13
- package/dist/workflow-builder.js +146 -82
- package/docs/analysis.md +109 -0
- package/docs/cli-reference.md +338 -0
- package/docs/cloning-repositories.md +285 -0
- package/docs/custom-workflows.md +358 -0
- package/docs/getting-started.md +108 -0
- package/docs/installation.md +127 -0
- package/docs/integrations/github.md +73 -0
- package/docs/integrations/jira.md +71 -0
- package/docs/intro.md +87 -0
- package/docs/packages/cli.md +238 -0
- package/docs/packages/core.md +256 -0
- package/docs/packages/mcp-browser.md +110 -0
- package/docs/packages/memory.md +223 -0
- package/docs/packages/skills.md +216 -0
- package/docs/reviewing-results.md +114 -0
- package/docs/running-tests.md +134 -0
- package/docs/triggering-workflows.md +552 -0
- package/docs/workflow-artifact-layout-evaluation.md +119 -0
- package/docs/workflow.md +558 -0
- package/package.json +6 -1
package/dist/workflow-builder.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as u,readFileSync as y,readdirSync as N,mkdirSync as J,writeFileSync as m,statSync as _}from"fs";import{join as l,resolve as j,relative as C,dirname as x}from"path";import{fileURLToPath as R}from"url";import{createRequire as P}from"module";var F=P(import.meta.url),T=`## Workflow Builder
|
|
2
2
|
|
|
3
3
|
You can help users build custom AI workflows using the Zibby workflow framework.
|
|
4
4
|
|
|
5
|
+
### What makes Zibby workflows different
|
|
6
|
+
Each node invokes a **real AI agent** (Cursor, Claude, Codex, or Gemini) \u2014 not a thin LLM API wrapper.
|
|
7
|
+
That means every node has full agent capabilities: tool use, MCP servers (browser, GitHub, Jira, Slack),
|
|
8
|
+
multi-turn reasoning, and structured output validation via Zod schemas.
|
|
9
|
+
|
|
10
|
+
Key differentiators:
|
|
11
|
+
- **Agent-powered nodes** \u2014 each step runs a full AI agent (cursor-agent, claude, codex, gemini CLI) with tool access and MCP skills, not a simple chat completion call.
|
|
12
|
+
- **Structured output** \u2014 every node declares a Zod schema; the framework validates and parses the agent's response automatically.
|
|
13
|
+
- **Conditional routing** \u2014 edges can branch on agent-produced fields (e.g., \`state.triage.priority === 'critical'\`), enabling intelligent decision graphs.
|
|
14
|
+
- **MCP skill injection** \u2014 nodes declare \`skills: [SKILLS.BROWSER, SKILLS.GITHUB]\` and the framework spins up the right MCP servers automatically.
|
|
15
|
+
- **Deploy anywhere** \u2014 \`zibby deploy\` pushes to Zibby Cloud with an API trigger; or self-host with \`zibby start\`.
|
|
16
|
+
- **State accumulation** \u2014 each node's validated output is stored under its name in \`state\` (e.g., \`state.classify_ticket\`), so downstream nodes can reference upstream results.
|
|
17
|
+
|
|
5
18
|
### What is a workflow?
|
|
6
|
-
A directed graph of nodes (AI steps) connected by edges. Each node has:
|
|
19
|
+
A directed graph of nodes (AI agent steps) connected by edges. Each node has:
|
|
7
20
|
- \`name\` \u2014 unique identifier (snake_case)
|
|
8
|
-
- \`prompt\` \u2014 function that receives state and returns the
|
|
9
|
-
- \`outputSchema\` \u2014 Zod schema defining the structured output
|
|
10
|
-
- \`skills\` (optional) \u2014 array of MCP skill IDs the node needs (e.g.,
|
|
21
|
+
- \`prompt\` \u2014 function that receives state and returns the prompt string sent to the agent
|
|
22
|
+
- \`outputSchema\` \u2014 Zod schema defining the structured output the agent must return
|
|
23
|
+
- \`skills\` (optional) \u2014 array of MCP skill IDs the node needs (e.g., \`SKILLS.BROWSER\`, \`SKILLS.GITHUB\`)
|
|
24
|
+
- \`timeout\` (optional) \u2014 max execution time in ms (default: 300000)
|
|
25
|
+
- \`model\` (optional) \u2014 override the model for this node (e.g., \`'claude-opus-4'\`)
|
|
11
26
|
|
|
12
27
|
### File structure
|
|
13
28
|
\`\`\`
|
|
@@ -21,17 +36,24 @@ A directed graph of nodes (AI steps) connected by edges. Each node has:
|
|
|
21
36
|
|
|
22
37
|
### Node pattern
|
|
23
38
|
\`\`\`javascript
|
|
24
|
-
import { z } from '@zibby/core';
|
|
39
|
+
import { z, SKILLS } from '@zibby/core';
|
|
25
40
|
|
|
26
41
|
const OutputSchema = z.object({
|
|
27
42
|
summary: z.string().describe('Brief summary'),
|
|
28
|
-
items: z.array(z.string()).describe('List of items'),
|
|
43
|
+
items: z.array(z.string()).describe('List of extracted items'),
|
|
44
|
+
needsReview: z.boolean().describe('Whether a human should review this'),
|
|
29
45
|
});
|
|
30
46
|
|
|
31
47
|
export const myNode = {
|
|
32
48
|
name: 'my_node',
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
skills: [SKILLS.GITHUB], // optional \u2014 framework injects MCP servers
|
|
50
|
+
timeout: 120000, // optional \u2014 2 min timeout
|
|
51
|
+
prompt: (state) => \\\`You are analyzing a pull request.
|
|
52
|
+
|
|
53
|
+
Input:
|
|
54
|
+
\\\${JSON.stringify(state.input || {}, null, 2)}
|
|
55
|
+
|
|
56
|
+
Return a JSON object matching the schema.\\\`,
|
|
35
57
|
outputSchema: OutputSchema,
|
|
36
58
|
};
|
|
37
59
|
\`\`\`
|
|
@@ -51,41 +73,110 @@ export class MyWorkflow extends WorkflowAgent {
|
|
|
51
73
|
graph.addEdge('route', 'END');
|
|
52
74
|
return graph;
|
|
53
75
|
}
|
|
76
|
+
|
|
77
|
+
async onComplete(result) {
|
|
78
|
+
// Post-execution hook \u2014 save artifacts, notify, etc.
|
|
79
|
+
console.log('Workflow complete:', result.success);
|
|
80
|
+
}
|
|
54
81
|
}
|
|
55
82
|
\`\`\`
|
|
56
83
|
|
|
57
84
|
Conditional edges: \`graph.addConditionalEdges('node', (state) => state.node.priority === 'high' ? 'escalate' : 'notify')\`
|
|
58
85
|
|
|
86
|
+
### Available SKILLS constants
|
|
87
|
+
Import from \`@zibby/core\`: \`SKILLS.BROWSER\`, \`SKILLS.MEMORY\`, \`SKILLS.GITHUB\`, \`SKILLS.JIRA\`, \`SKILLS.SLACK\`, \`SKILLS.RUNNER\`
|
|
88
|
+
|
|
89
|
+
### Deep documentation
|
|
90
|
+
Call \`explore_framework_docs\` to read detailed framework docs on demand. Use it for:
|
|
91
|
+
- Advanced patterns (middleware, parallel nodes, state schemas)
|
|
92
|
+
- Deployment & cloud triggers
|
|
93
|
+
- CLI commands reference
|
|
94
|
+
- Integration details (Jira, GitHub, etc.)
|
|
95
|
+
Call with no arguments to see all available topics.
|
|
96
|
+
|
|
59
97
|
### How to use the builder tools
|
|
60
|
-
1.
|
|
61
|
-
2.
|
|
62
|
-
3.
|
|
63
|
-
4.
|
|
98
|
+
1. For complex workflows, call \`explore_framework_docs("custom-workflows")\` first to learn advanced patterns.
|
|
99
|
+
2. Ask the user what their workflow should do, what input it receives, and what steps are needed.
|
|
100
|
+
3. Call \`design_workflow\` with the structured spec for the user to review.
|
|
101
|
+
4. Once approved, call \`build_workflow\` to generate real code on disk (uses the configured agent for high-quality code generation).
|
|
102
|
+
5. Remind the user: \`zibby start <name>\` to test locally, \`zibby deploy <name> --project <id>\` to deploy to cloud, \`zibby logs --workflow <name>\` to tail logs.
|
|
64
103
|
|
|
65
104
|
### Important
|
|
66
|
-
- Each node prompt should be detailed and specific \u2014 tell the AI exactly what to do and what format to return.
|
|
67
|
-
- Zod schemas
|
|
105
|
+
- Each node prompt should be detailed and specific \u2014 tell the AI agent exactly what to do and what format to return.
|
|
106
|
+
- Zod schemas MUST use .describe() on every field so the agent knows what each field means.
|
|
68
107
|
- Node names must be snake_case (e.g., classify_ticket, generate_report).
|
|
69
108
|
- Workflow names must be kebab-case (e.g., ticket-triage, pr-review).
|
|
70
|
-
- State flows through: each node's output is stored under its name in state (e.g., state.classify_ticket).
|
|
71
|
-
- Downstream nodes
|
|
72
|
-
`),
|
|
73
|
-
`)
|
|
109
|
+
- State flows through: each node's validated output is stored under its name in state (e.g., state.classify_ticket).
|
|
110
|
+
- Downstream nodes reference upstream outputs in their prompt function (e.g., \\\`\\\${JSON.stringify(state.classify_ticket, null, 2)}\\\`).
|
|
111
|
+
- Nodes can declare skills to get MCP tool access \u2014 the framework handles server lifecycle automatically.`,O=/^[a-z][a-z0-9-]{0,62}[a-z0-9]$/;function W(r){return`${r.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("")}Workflow`}function h(r){return`${r.replace(/_([a-z])/g,(e,n)=>n.toUpperCase())}Node`}function K(r){let e=r?.agent;return e?e.provider?e.provider:e.gemini?"gemini":e.codex?"codex":e.claude?"claude":e.cursor?"cursor":process.env.AGENT_TYPE||"cursor":process.env.AGENT_TYPE||"cursor"}async function G(r){let e=j(r,".zibby.config.mjs");if(!u(e))return{};try{return(await import(e)).default||{}}catch{return{}}}function M(){try{let r=x(F.resolve("@zibby/core/package.json")),e=l(r,"templates","browser-test-automation"),n=y(l(e,"nodes","preflight.mjs"),"utf-8"),i=y(l(e,"graph.mjs"),"utf-8");return{preflight:n,graph:i}}catch{return null}}var v=x(R(import.meta.url));function z(){let r=j(v,"..","..","..","docsite","docs");if(u(r))return r;let e=j(v,"..","docs");return u(e)?e:null}function I(){let r=z();if(!r)return[];try{let e=(n,i="")=>{let o=[];for(let s of N(n)){let t=l(n,s);try{if(_(t).isDirectory())o=o.concat(e(t,`${i}${s}/`));else if(s.endsWith(".md")){let d=`${i}${s.replace(/\.md$/,"")}`;o.push(d)}}catch{}}return o};return e(r)}catch{return[]}}function A(r){let e=z();if(!e)return null;let n=l(e,`${r}.md`);if(!u(n))return null;try{return y(n,"utf-8")}catch{return null}}function U(r){let e=r.nodes.map(t=>{let d=t.inputFields?.length?`Input fields: ${t.inputFields.join(", ")}`:"Input: receives full state",a=t.outputFields?.length?`Output fields: ${t.outputFields.join(", ")}`:"Output: determined by task",p=t.skills?.length?`Skills: ${t.skills.join(", ")}`:"";return`- ${t.name}: ${t.description}. ${d}. ${a}.${p?` ${p}`:""}`}).join(`
|
|
112
|
+
`),n=r.edges.map(t=>t.condition?`- ${t.from} \u2192 ${t.to} (conditional: ${t.condition})`:`- ${t.from} \u2192 ${t.to}`).join(`
|
|
113
|
+
`),i=M(),o=A("custom-workflows"),s="";return i&&(s+=`
|
|
114
|
+
## Real working examples from the Zibby framework
|
|
115
|
+
|
|
116
|
+
### Example node (preflight.mjs) \u2014 a prompt-only node with Zod schema and onComplete hook:
|
|
117
|
+
\`\`\`javascript
|
|
118
|
+
${i.preflight}
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
### Example graph (graph.mjs) \u2014 WorkflowAgent subclass with conditional routing:
|
|
122
|
+
\`\`\`javascript
|
|
123
|
+
${i.graph}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
Study these examples carefully. Your generated code must follow the same patterns exactly.
|
|
127
|
+
`),o&&(s+=`
|
|
128
|
+
## Full framework documentation (Custom Workflows)
|
|
129
|
+
${o}
|
|
130
|
+
`),`Generate the code for a Zibby workflow called "${r.name}".
|
|
131
|
+
|
|
132
|
+
## Zibby Workflow Framework Reference
|
|
133
|
+
|
|
134
|
+
Zibby workflows are directed graphs where each node invokes a **real AI agent** (Cursor, Claude, Codex, or Gemini)
|
|
135
|
+
with full tool access, MCP server integration, and Zod-validated structured output.
|
|
136
|
+
This is NOT a simple LLM API wrapper \u2014 each node runs a full agent with tool-calling capabilities.
|
|
137
|
+
|
|
138
|
+
### Architecture
|
|
139
|
+
- The framework calls the configured AI agent for each node.
|
|
140
|
+
- Each node's \`prompt\` function receives the accumulated \`state\` object and returns a prompt string.
|
|
141
|
+
- The agent's response is parsed and validated against the node's \`outputSchema\` (Zod).
|
|
142
|
+
- The validated output is stored in \`state\` under the node's name (e.g., \`state.classify_ticket\`).
|
|
143
|
+
- Downstream nodes access upstream results via \`state.<upstream_node_name>\`.
|
|
144
|
+
|
|
145
|
+
### Node properties
|
|
146
|
+
- \`name\` (string, required) \u2014 snake_case identifier
|
|
147
|
+
- \`prompt\` (function, required) \u2014 \`(state) => \\\`...\\\`\` returns the prompt string
|
|
148
|
+
- \`outputSchema\` (Zod schema, required) \u2014 every field MUST have \`.describe()\`
|
|
149
|
+
- \`skills\` (array, optional) \u2014 MCP skills: \`[SKILLS.BROWSER]\`, \`[SKILLS.GITHUB]\`, etc.
|
|
150
|
+
- \`timeout\` (number, optional) \u2014 ms, default 300000
|
|
151
|
+
- \`onComplete\` (async function, optional) \u2014 \`(state, result) => {}\` post-processing hook
|
|
152
|
+
|
|
153
|
+
### Available SKILLS constants (import from '@zibby/core')
|
|
154
|
+
SKILLS.BROWSER, SKILLS.MEMORY, SKILLS.GITHUB, SKILLS.JIRA, SKILLS.SLACK, SKILLS.RUNNER
|
|
155
|
+
|
|
156
|
+
### Graph API
|
|
157
|
+
- \`graph.addNode(name, nodeObject)\` \u2014 register a node
|
|
158
|
+
- \`graph.setEntryPoint(name)\` \u2014 set the first node
|
|
159
|
+
- \`graph.addEdge(from, to)\` \u2014 connect nodes (use \`'END'\` to terminate)
|
|
160
|
+
- \`graph.addConditionalEdges(from, (state) => 'nextNode' | 'END')\` \u2014 conditional routing
|
|
161
|
+
|
|
162
|
+
### Rules
|
|
163
|
+
- Import: \`import { z } from '@zibby/core';\` (add \`SKILLS\` only if the node uses skills)
|
|
164
|
+
- Export name: camelCase + "Node" (e.g., \`classifyTicketNode\` for name \`classify_ticket\`)
|
|
165
|
+
- Prompt function: template literal referencing \`state.input\` and upstream \`state.<node_name>\`
|
|
166
|
+
- Prompts must be detailed \u2014 tell the agent exactly what to analyze/produce
|
|
167
|
+
${s}
|
|
168
|
+
## Workflow to generate: "${r.name}"
|
|
74
169
|
|
|
75
|
-
|
|
76
|
-
${
|
|
170
|
+
### Description
|
|
171
|
+
${r.description}
|
|
77
172
|
|
|
78
|
-
|
|
173
|
+
### Nodes
|
|
79
174
|
${e}
|
|
80
175
|
|
|
81
|
-
|
|
82
|
-
${
|
|
176
|
+
### Edges (flow)
|
|
177
|
+
${n}
|
|
83
178
|
|
|
84
|
-
##
|
|
85
|
-
For EACH node, generate a complete ESM module with:
|
|
86
|
-
1. A Zod output schema with .describe() on every field
|
|
87
|
-
2. A prompt function that takes state and returns a detailed, specific prompt string
|
|
88
|
-
3. The prompt should reference upstream node outputs from state when applicable
|
|
179
|
+
## Output format
|
|
89
180
|
|
|
90
181
|
Return a JSON object with this exact structure:
|
|
91
182
|
{
|
|
@@ -96,80 +187,53 @@ Return a JSON object with this exact structure:
|
|
|
96
187
|
}
|
|
97
188
|
}
|
|
98
189
|
|
|
99
|
-
|
|
100
|
-
- Start with: import { z } from '@zibby/core';
|
|
101
|
-
- Define a const schema (e.g., ClassifyOutputSchema)
|
|
102
|
-
- Export a const node object with name, prompt (function), and outputSchema
|
|
103
|
-
- The export name should be camelCase + "Node" (e.g., classifyTicketNode)
|
|
104
|
-
|
|
105
|
-
Example node code:
|
|
106
|
-
\`\`\`
|
|
107
|
-
import { z } from '@zibby/core';
|
|
108
|
-
|
|
109
|
-
const ClassifyOutputSchema = z.object({
|
|
110
|
-
priority: z.enum(['critical', 'high', 'medium', 'low']).describe('Ticket priority level'),
|
|
111
|
-
category: z.string().describe('Issue category'),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
export const classifyTicketNode = {
|
|
115
|
-
name: 'classify_ticket',
|
|
116
|
-
prompt: (state) => \`You are a ticket classifier.
|
|
117
|
-
|
|
118
|
-
Input ticket:
|
|
119
|
-
\${JSON.stringify(state.input || {}, null, 2)}
|
|
120
|
-
|
|
121
|
-
Classify this ticket by priority and category.\`,
|
|
122
|
-
outputSchema: ClassifyOutputSchema,
|
|
123
|
-
};
|
|
124
|
-
\`\`\`
|
|
125
|
-
|
|
126
|
-
IMPORTANT: Return ONLY valid JSON. No markdown fences, no explanation outside the JSON.`}async function x(n,e){const s=await E(e),o=A(s);try{const{invokeAgent:t}=await import("@zibby/core"),i=D(n),r=await t(i,{state:{agentType:o,config:s,cwd:e,workspace:e}},{model:s?.agent?.[o]?.model||"auto",workspace:e,config:s,timeout:12e4}),a=(typeof r=="string"?r:r?.raw||JSON.stringify(r?.structured||r)).match(/\{[\s\S]*\}/);if(!a)throw new Error("Agent did not return valid JSON");return JSON.parse(a[0])}catch(t){return console.warn(`Agent code generation failed (${t.message}), using templates`),I(n)}}function I(n){const e={};for(const s of n.nodes){const o=y(s.name),t=`${s.name.split("_").map(a=>a.charAt(0).toUpperCase()+a.slice(1)).join("")}OutputSchema`,i=s.outputFields?.length?s.outputFields.map(a=>` ${a}: z.string().describe('${a}'),`).join(`
|
|
190
|
+
IMPORTANT: Return ONLY valid JSON. No markdown fences, no explanation outside the JSON.`}async function D(r,e){let n=await G(e),i=K(n);try{let{invokeAgent:o}=await import("@zibby/core"),s=U(r),t=await o(s,{state:{agentType:i,config:n,cwd:e,workspace:e}},{model:n?.agent?.[i]?.model||"auto",workspace:e,config:n,timeout:12e4}),a=(typeof t=="string"?t:t?.raw||JSON.stringify(t?.structured||t)).match(/\{[\s\S]*\}/);if(!a)throw new Error("Agent did not return valid JSON");return JSON.parse(a[0])}catch(o){return console.warn(`Agent code generation failed (${o.message}), using templates`),q(r)}}function q(r){let e={};for(let n of r.nodes){let i=h(n.name),o=`${n.name.split("_").map(a=>a.charAt(0).toUpperCase()+a.slice(1)).join("")}OutputSchema`,s=n.outputFields?.length?n.outputFields.map(a=>` ${a}: z.string().describe('${a}'),`).join(`
|
|
127
191
|
`):` summary: z.string().describe('Summary of the result'),
|
|
128
|
-
status: z.enum(['ok', 'warn', 'error']).describe('Overall status'),`,r
|
|
129
|
-
`),
|
|
192
|
+
status: z.enum(['ok', 'warn', 'error']).describe('Overall status'),`,t=r.edges.filter(a=>a.to===n.name&&a.from!=="START").map(a=>`Previous step (${a.from}): \${JSON.stringify(state.${a.from} || {}, null, 2)}`).join(`
|
|
193
|
+
`),d=t?`${n.description}
|
|
130
194
|
|
|
131
195
|
Input:
|
|
132
196
|
\${JSON.stringify(state.input || {}, null, 2)}
|
|
133
197
|
|
|
134
|
-
${
|
|
198
|
+
${t}`:`${n.description}
|
|
135
199
|
|
|
136
200
|
Input:
|
|
137
|
-
\${JSON.stringify(state.input || {}, null, 2)}`;e[
|
|
201
|
+
\${JSON.stringify(state.input || {}, null, 2)}`;e[n.name]={code:`import { z } from '@zibby/core';
|
|
138
202
|
|
|
139
|
-
const ${
|
|
140
|
-
${
|
|
203
|
+
const ${o} = z.object({
|
|
204
|
+
${s}
|
|
141
205
|
});
|
|
142
206
|
|
|
143
|
-
export const ${
|
|
144
|
-
name: '${
|
|
145
|
-
prompt: (state) => \`${
|
|
146
|
-
outputSchema: ${
|
|
207
|
+
export const ${i} = {
|
|
208
|
+
name: '${n.name}',
|
|
209
|
+
prompt: (state) => \`${d}\`,
|
|
210
|
+
outputSchema: ${o},
|
|
147
211
|
};
|
|
148
|
-
`}}return{nodes:e}}function
|
|
212
|
+
`}}return{nodes:e}}function B(r,e,n,i){let o=e.toLowerCase(),s=W(o),t=l(r,".zibby","workflows",o),d=l(t,"nodes");J(d,{recursive:!0});let a=n.nodes.map(c=>c.name);for(let c of n.nodes){let f=i.nodes?.[c.name]?.code;f&&m(l(d,`${c.name.replace(/_/g,"-")}.mjs`),f,"utf-8")}let p=a.map(c=>{let f=h(c),E=c.replace(/_/g,"-");return`export { ${f} } from './${E}.mjs';`});m(l(d,"index.mjs"),`${p.join(`
|
|
149
213
|
`)}
|
|
150
|
-
`,"utf-8");
|
|
151
|
-
`),
|
|
152
|
-
${
|
|
153
|
-
});`:` graph.addEdge('${
|
|
154
|
-
`),
|
|
155
|
-
import { ${
|
|
156
|
-
|
|
157
|
-
export class ${
|
|
214
|
+
`,"utf-8");let $=a[0],L=a.map(c=>h(c)).join(", "),k=a.map(c=>` graph.addNode('${c}', ${h(c)});`).join(`
|
|
215
|
+
`),b=n.edges.map(c=>c.condition?` graph.addConditionalEdges('${c.from}', (state) => {
|
|
216
|
+
${c.condition}
|
|
217
|
+
});`:` graph.addEdge('${c.from}', '${c.to}');`).join(`
|
|
218
|
+
`),S=`import { WorkflowAgent, WorkflowGraph } from '@zibby/core';
|
|
219
|
+
import { ${L} } from './nodes/index.mjs';
|
|
220
|
+
|
|
221
|
+
export class ${s} extends WorkflowAgent {
|
|
158
222
|
buildGraph() {
|
|
159
223
|
const graph = new WorkflowGraph();
|
|
160
224
|
|
|
161
|
-
${
|
|
225
|
+
${k}
|
|
162
226
|
|
|
163
227
|
graph.setEntryPoint('${$}');
|
|
164
|
-
${
|
|
228
|
+
${b}
|
|
165
229
|
|
|
166
230
|
return graph;
|
|
167
231
|
}
|
|
168
232
|
|
|
169
233
|
async onComplete(result) {
|
|
170
|
-
console.log(\`[${
|
|
234
|
+
console.log(\`[${o}] workflow complete \u2014 success: \${result.success !== false}\`);
|
|
171
235
|
}
|
|
172
236
|
}
|
|
173
|
-
`;m(
|
|
174
|
-
`,"utf-8");
|
|
175
|
-
`,u
|
|
237
|
+
`;m(l(t,"graph.mjs"),S,"utf-8");let g={name:o,description:n.description||`${s} workflow`,entryClass:s,triggers:{api:!0}};m(l(t,"workflow.json"),`${JSON.stringify(g,null,2)}
|
|
238
|
+
`,"utf-8");let w=["graph.mjs","workflow.json","nodes/index.mjs",...a.map(c=>`nodes/${c.replace(/_/g,"-")}.mjs`)];return{workflowDir:C(r,t),files:w,className:s,slug:o}}async function Z(r){let{name:e,description:n,nodes:i,edges:o}=r;if(!e||!O.test(e.toLowerCase()))return JSON.stringify({error:`Invalid workflow name "${e}". Must be kebab-case, 2-64 chars, lowercase letters/numbers/hyphens.`});if(!i||i.length===0)return JSON.stringify({error:"At least one node is required."});let s={name:e.toLowerCase(),description:n||`${W(e.toLowerCase())} workflow`,nodes:i.map(t=>({name:t.name.replace(/-/g,"_"),description:t.description||`Process ${t.name}`,inputFields:t.inputFields||[],outputFields:t.outputFields||[]})),edges:o||[]};if(s.edges.length===0&&s.nodes.length>0){for(let t=0;t<s.nodes.length-1;t++)s.edges.push({from:s.nodes[t].name,to:s.nodes[t+1].name});s.edges.push({from:s.nodes[s.nodes.length-1].name,to:"END"})}return JSON.stringify({ok:!0,spec:s,message:`Workflow "${s.name}" designed with ${s.nodes.length} node(s). Call build_workflow to generate the code.`,preview:{nodes:s.nodes.map(t=>t.name),flow:s.edges.map(t=>t.condition?`${t.from} \u2192(if ${t.condition})\u2192 ${t.to}`:`${t.from} \u2192 ${t.to}`)}})}async function H(r,e){let{name:n,spec:i}=r,o=(n||i?.name||"").toLowerCase();if(!o||!O.test(o))return JSON.stringify({error:`Invalid workflow name "${o}".`});if(!i||!i.nodes||i.nodes.length===0)return JSON.stringify({error:"spec with nodes is required. Call design_workflow first."});let s=l(e,".zibby","workflows",o);if(u(s))return JSON.stringify({error:`Workflow "${o}" already exists at .zibby/workflows/${o}/. Delete it first or choose a different name.`});let t=await D(i,e),d=B(e,o,i,t);return JSON.stringify({ok:!0,...d,message:`Workflow "${o}" created at ${d.workflowDir}/`,nextSteps:[`Test locally: zibby start ${o}`,`Deploy to cloud: zibby deploy ${o} --project <project-id>`,`Tail logs: zibby logs --workflow ${o} --project <project-id>`]})}async function Y(r,e){let{workflowName:n,nodeName:i,description:o,inputFields:s,outputFields:t}=r,d=(n||"").toLowerCase(),a=(i||"").replace(/-/g,"_"),p=l(e,".zibby","workflows",d);if(!u(p))return JSON.stringify({error:`Workflow "${d}" not found. Create it first with build_workflow.`});let $={name:d,description:"",nodes:[{name:a,description:o||`Process ${a}`,inputFields:s||[],outputFields:t||[]}],edges:[]},k=(await D($,e)).nodes?.[a]?.code;if(!k)return JSON.stringify({error:"Failed to generate node code."});let b=l(p,"nodes"),S=`${a.replace(/_/g,"-")}.mjs`;m(l(b,S),k,"utf-8");let g=l(b,"index.mjs"),w=h(a),c=`export { ${w} } from './${a.replace(/_/g,"-")}.mjs';
|
|
239
|
+
`,f=u(g)?y(g,"utf-8"):"";return f.includes(w)||m(g,f+c,"utf-8"),JSON.stringify({ok:!0,file:`nodes/${S}`,exportName:w,message:`Node "${a}" added. Update graph.mjs to wire it into the graph.`})}async function Q(r,e){let{name:n,projectId:i}=r,o=(n||"").toLowerCase();if(!o)return JSON.stringify({error:"Workflow name is required."});if(!i)return JSON.stringify({error:"projectId is required."});let s=l(e,".zibby","workflows",o);if(!u(s))return JSON.stringify({error:`Workflow "${o}" not found at .zibby/workflows/${o}/`});try{let{execSync:t}=await import("child_process"),d=t(`node "${l(e,"packages/cli/bin/zibby.js")}" deploy ${o} --project ${i}`,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]});return JSON.stringify({ok:!0,output:d.trim()})}catch{try{let{execSync:d}=await import("child_process"),a=d(`npx zibby deploy ${o} --project ${i}`,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]});return JSON.stringify({ok:!0,output:a.trim()})}catch(d){return JSON.stringify({error:`Deploy failed: ${d.message}`})}}}function V(r){let e=l(r,".zibby","workflows");if(!u(e))return JSON.stringify({workflows:[],message:"No workflows found. Use build_workflow to create one."});let i=N(e).filter(o=>{try{return _(l(e,o)).isDirectory()}catch{return!1}}).map(o=>{let s=l(e,o,"workflow.json"),t={};try{t=JSON.parse(y(s,"utf-8"))}catch{}let d=l(e,o,"nodes"),a=0;try{a=N(d).filter(p=>p.endsWith(".mjs")&&p!=="index.mjs").length}catch{}return{name:o,description:t.description||"",nodeCount:a,path:C(r,l(e,o))}});return JSON.stringify({workflows:i})}var re={id:"workflow-builder",description:"Build, scaffold, and deploy custom AI workflows via conversation",envKeys:[],promptFragment:T,tools:[{name:"design_workflow",description:"Design a workflow spec (nodes, edges, descriptions) for the user to review before building. Call this after understanding requirements.",input_schema:{type:"object",properties:{name:{type:"string",description:"Workflow name in kebab-case (e.g., ticket-triage)"},description:{type:"string",description:"What the workflow does"},nodes:{type:"array",items:{type:"object",properties:{name:{type:"string",description:"Node name in snake_case (e.g., classify_ticket)"},description:{type:"string",description:"What this node does \u2014 be specific about input/output"},inputFields:{type:"array",items:{type:"string"},description:"Key fields this node reads from state"},outputFields:{type:"array",items:{type:"string"},description:"Key fields this node produces"}},required:["name","description"]},description:"Workflow nodes (processing steps)"},edges:{type:"array",items:{type:"object",properties:{from:{type:"string",description:"Source node name"},to:{type:"string",description:'Target node name (or "END")'},condition:{type:"string",description:"JS expression for conditional routing (optional)"}},required:["from","to"]},description:"Edges connecting nodes. If omitted, nodes are wired linearly."}},required:["name","description","nodes"]}},{name:"build_workflow",description:"Generate real workflow code on disk from a design spec. Uses the configured AI agent for high-quality code generation.",input_schema:{type:"object",properties:{name:{type:"string",description:"Workflow name (from design_workflow)"},spec:{type:"object",description:"The full spec object returned by design_workflow",properties:{name:{type:"string"},description:{type:"string"},nodes:{type:"array",items:{type:"object"}},edges:{type:"array",items:{type:"object"}}}}},required:["name","spec"]}},{name:"add_node",description:"Add a new node to an existing workflow. Generates the node file and updates the barrel export.",input_schema:{type:"object",properties:{workflowName:{type:"string",description:"Existing workflow name (kebab-case)"},nodeName:{type:"string",description:"New node name (snake_case)"},description:{type:"string",description:"What this node does"},inputFields:{type:"array",items:{type:"string"},description:"Fields read from state"},outputFields:{type:"array",items:{type:"string"},description:"Fields produced"}},required:["workflowName","nodeName","description"]}},{name:"deploy_workflow",description:"Deploy a workflow to Zibby Cloud. Returns the trigger URL.",input_schema:{type:"object",properties:{name:{type:"string",description:"Workflow name to deploy"},projectId:{type:"string",description:"Target project ID"}},required:["name","projectId"]}},{name:"list_workflows",description:"List all local workflows in .zibby/workflows/.",input_schema:{type:"object",properties:{}}},{name:"explore_framework_docs",description:"Read Zibby framework documentation on demand. Call this before building complex workflows or when you need details on advanced patterns (middleware, conditional routing, skills, deployment, CLI commands).",input_schema:{type:"object",properties:{topic:{type:"string",description:'Doc topic to read (e.g., "workflow", "custom-workflows", "cli-reference", "packages/core", "packages/skills", "integrations/jira"). Call with no topic to list all available docs.'}}}}],async handleToolCall(r,e,n){let i=n?.options?.workspace||process.cwd();try{switch(r){case"design_workflow":return await Z(e);case"build_workflow":return await H(e,i);case"add_node":return await Y(e,i);case"deploy_workflow":return await Q(e,i);case"list_workflows":return V(i);case"explore_framework_docs":{let o=(e.topic||"").trim();if(!o){let t=I();return JSON.stringify({available:t,hint:"Call again with a topic to read its content."})}let s=A(o);if(!s){let t=I();return JSON.stringify({error:`Doc "${o}" not found.`,available:t})}return JSON.stringify({topic:o,content:s})}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(o){return JSON.stringify({error:o.message})}},resolve(){return null}};export{re as workflowBuilderSkill};
|
package/docs/analysis.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
title: Running Analysis
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Running Analysis
|
|
7
|
+
|
|
8
|
+
Analysis is where Zibby's AI reads your Jira ticket, studies your codebase, and produces code changes and test cases.
|
|
9
|
+
|
|
10
|
+
## Starting an Analysis
|
|
11
|
+
|
|
12
|
+
1. Go to your project's **Tickets** page
|
|
13
|
+
2. Click on a ticket to open its details
|
|
14
|
+
3. Click **Analyze**
|
|
15
|
+
4. Optionally add **additional context** or select an AI model
|
|
16
|
+
5. The analysis runs in the cloud (AWS Fargate)
|
|
17
|
+
|
|
18
|
+
## Analysis Pipeline
|
|
19
|
+
|
|
20
|
+
The AI runs through these steps automatically:
|
|
21
|
+
|
|
22
|
+
### 1. Setup
|
|
23
|
+
|
|
24
|
+
- Clones your GitHub repository into a secure container
|
|
25
|
+
- Creates a git baseline for tracking changes
|
|
26
|
+
|
|
27
|
+
### 2. Analyze Ticket
|
|
28
|
+
|
|
29
|
+
The AI reads:
|
|
30
|
+
- The Jira ticket summary and description
|
|
31
|
+
- Acceptance criteria and requirements
|
|
32
|
+
- Your codebase structure and existing code
|
|
33
|
+
|
|
34
|
+
It produces a **structured analysis** with:
|
|
35
|
+
- Understanding of the requirement
|
|
36
|
+
- Affected files and components
|
|
37
|
+
- Implementation approach
|
|
38
|
+
- Edge cases and considerations
|
|
39
|
+
|
|
40
|
+
If the ticket lacks sufficient detail, the analysis may stop here with a **"needs clarification"** status and explain what information is missing.
|
|
41
|
+
|
|
42
|
+
### 3. Generate Code
|
|
43
|
+
|
|
44
|
+
Based on the analysis, the AI:
|
|
45
|
+
- Writes or modifies code to implement the ticket
|
|
46
|
+
- Captures all changes as a git diff
|
|
47
|
+
- Lists affected files
|
|
48
|
+
|
|
49
|
+
You can review the diff side-by-side in the dashboard and create a **Pull Request** directly.
|
|
50
|
+
|
|
51
|
+
### 4. Generate Test Cases
|
|
52
|
+
|
|
53
|
+
The AI produces structured test cases including:
|
|
54
|
+
- Test case title and description
|
|
55
|
+
- Step-by-step instructions
|
|
56
|
+
- Test data and credentials
|
|
57
|
+
- Expected outcomes
|
|
58
|
+
- Preconditions and postconditions
|
|
59
|
+
|
|
60
|
+
### 5. Finalize
|
|
61
|
+
|
|
62
|
+
- Compiles the final report
|
|
63
|
+
- Uploads all artifacts to the dashboard
|
|
64
|
+
- Updates the execution status
|
|
65
|
+
|
|
66
|
+
## Custom Instructions
|
|
67
|
+
|
|
68
|
+
You can add custom prompt instructions for each AI node in **Project Settings > Node Configuration**:
|
|
69
|
+
|
|
70
|
+
- **analyze_ticket** — additional context about your architecture
|
|
71
|
+
- **generate_code** — coding standards, framework preferences
|
|
72
|
+
- **generate_test_cases** — test credentials, login flows, specific data to use
|
|
73
|
+
|
|
74
|
+
For example, to ensure tests use specific credentials:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Use test account for login:
|
|
78
|
+
Email: test@example.com
|
|
79
|
+
Password: TestPass123
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Analysis Statuses
|
|
83
|
+
|
|
84
|
+
| Status | Meaning |
|
|
85
|
+
|---|---|
|
|
86
|
+
| **running** | Analysis is in progress |
|
|
87
|
+
| **completed** | All steps finished successfully |
|
|
88
|
+
| **failed** | A step encountered an error |
|
|
89
|
+
| **blocked** | Ticket lacks information to proceed |
|
|
90
|
+
|
|
91
|
+
## Reviewing Analysis Results
|
|
92
|
+
|
|
93
|
+
After completion, the analysis page shows:
|
|
94
|
+
|
|
95
|
+
- **Pipeline progress** — status of each step with logs
|
|
96
|
+
- **Code Changes** — side-by-side diff with file tree
|
|
97
|
+
- **Test Cases** — editable test cases you can refine
|
|
98
|
+
- **Create PR** — one-click pull request creation
|
|
99
|
+
- **Suggested Changes** — AI suggestions for the ticket itself
|
|
100
|
+
|
|
101
|
+
## Running Tests from Analysis
|
|
102
|
+
|
|
103
|
+
Once test cases are generated, you can run them locally using the CLI:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
zibby test --sources TC001,TC002 --execution <execution-id> --sync
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or copy the full command from the **Code** button in the dashboard.
|