@zibby/agent-workflow 0.1.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zibby
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,229 @@
1
+ # @zibby/agent-workflow
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@zibby/agent-workflow.svg)](https://www.npmjs.com/package/@zibby/agent-workflow)
4
+ [![CI](https://github.com/ZibbyHQ/agent-workflow/actions/workflows/ci.yml/badge.svg)](https://github.com/ZibbyHQ/agent-workflow/actions/workflows/ci.yml)
5
+ [![Types](https://img.shields.io/npm/types/@zibby/agent-workflow.svg)](https://www.npmjs.com/package/@zibby/agent-workflow)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
7
+
8
+ > **Run agents inside a workflow.** Graph-based JavaScript engine for orchestrating real coding agents — Claude Code, Cursor, Codex, Gemini, OpenAI Assistants — with structured I/O between nodes.
9
+
10
+ ```
11
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
12
+ trigger → │ plan │ → │ implement│ → │ verify │ → result
13
+ │ (claude) │ │ (cursor) │ │ (codex) │
14
+ └──────────┘ └──────────┘ └──────────┘
15
+ │ │ │
16
+ Zod out Zod out Zod out
17
+ ```
18
+
19
+ Each node hands off to a complete agent. The agent does its own tool calls, file edits, and multi-turn reasoning. Your graph defines *what* agent runs *when*, *what schema* it has to return, and *what state* flows between them.
20
+
21
+ Mix and match agents per node — Claude for planning, Cursor for implementation, Codex for verification. Or stick with one. Your call:
22
+
23
+ ```js
24
+ graph
25
+ .addNode('plan', { prompt, outputSchema: Plan, agent: 'claude' })
26
+ .addNode('implement', { prompt, outputSchema: Diff, agent: 'cursor' })
27
+ .addNode('verify', { prompt, outputSchema: Result, agent: 'codex' });
28
+ ```
29
+
30
+ ---
31
+
32
+ ## ⚡ Try it in 60 seconds
33
+
34
+ A complete loop — generate, run locally, deploy to cloud, trigger remotely, watch logs. No global install needed:
35
+
36
+ ```bash
37
+ # 1. Project scaffold (.zibby/, config, graph.mjs)
38
+ npx @zibby/cli init
39
+
40
+ # 2. Generate a new workflow under .zibby/workflows/my-pipeline/
41
+ npx @zibby/cli g workflow my-pipeline
42
+
43
+ # 3. Run it locally — names are folder names, not cloud identifiers
44
+ npx @zibby/cli start my-pipeline
45
+
46
+ # 4. Ship it to Zibby Cloud (returns a UUID + caches it in .zibby-deploy.json)
47
+ npx @zibby/cli login
48
+ npx @zibby/cli deploy my-pipeline
49
+
50
+ # 5. Trigger a remote run by UUID. Tail the logs Heroku-style.
51
+ npx @zibby/cli trigger <uuid> # uuid printed by `deploy` or `workflow list`
52
+ npx @zibby/cli logs -t
53
+
54
+ # 6. Manage the fleet
55
+ npx @zibby/cli workflow list # local + deployed (shows UUIDs)
56
+ npx @zibby/cli workflow delete <uuid> # tear one down
57
+ ```
58
+
59
+ Prefer to install once instead of `npx` every time:
60
+
61
+ ```bash
62
+ npm install -g @zibby/cli
63
+ zibby --help
64
+ ```
65
+
66
+ ---
67
+
68
+ ## The CLI: full workflow lifecycle
69
+
70
+ | Command | What it does |
71
+ |---|---|
72
+ | `zibby init` | Scaffold a workflow project — `.zibby/graph.mjs`, `.zibby.config.js`, sane defaults. |
73
+ | `zibby g workflow <name>` | **Generate** a new custom workflow under `.zibby/workflows/<name>/`. |
74
+ | `zibby start <name>` | Run a workflow **locally** with hot-reload (defaults to port 3848). Name = folder under `.zibby/workflows/`. |
75
+ | `zibby login` / `logout` / `status` | Cloud auth. |
76
+ | `zibby deploy [name]` | **Deploy** a workflow to Zibby Cloud (interactive picker if name omitted). |
77
+ | `zibby trigger <uuid>` | **Run** a deployed workflow in the cloud. UUID is canonical (names are local-only). Get UUIDs from `workflow list` or the `deploy` output. |
78
+ | `zibby logs [jobId] -t` | Tail **logs** from a run, Heroku-style. `-t` to follow live. |
79
+ | `zibby workflow list` | **List** local + deployed workflows. |
80
+ | `zibby workflow delete <uuid>` | **Delete** a deployed workflow. |
81
+
82
+ **Local** runs land in `.zibby/output/sessions/<id>/` with raw outputs, parsed JSON, and a JSONL execution log — replay-friendly. **Cloud** runs use the same on-disk format, fronted by the trigger/logs commands.
83
+
84
+ **Local vs cloud identity**: workflow folder names (`my-pipeline`) are *local* — used by `start`, `g workflow`, `deploy`. Cloud workflows are identified by **UUID** — used by `trigger`, `logs`, `workflow delete`. After your first `deploy`, the UUID is cached in `.zibby/workflows/<name>/.zibby-deploy.json` (commit it to git so collaborators share the same canonical reference).
85
+
86
+ The CLI also integrates with [Zibby Studio](https://zibby.app) — a desktop UI for visualising live runs, pinning sessions, and stopping a workflow from a button.
87
+
88
+ ---
89
+
90
+ ## Use as a library
91
+
92
+ If you don't want the CLI, drop into JavaScript directly:
93
+
94
+ ```bash
95
+ npm install @zibby/agent-workflow
96
+ ```
97
+
98
+ ```js
99
+ import { WorkflowGraph, AgentStrategy, registerStrategy } from '@zibby/agent-workflow';
100
+ import { z } from 'zod';
101
+
102
+ class MyAgent extends AgentStrategy {
103
+ constructor() { super('mine', 'demo'); }
104
+ canHandle() { return true; }
105
+ async invoke(prompt, { schema }) {
106
+ return { raw: '...', structured: { summary: 'hello' } };
107
+ }
108
+ }
109
+ registerStrategy(new MyAgent());
110
+
111
+ const Plan = z.object({ tasks: z.array(z.string()) });
112
+ const Done = z.object({ summary: z.string() });
113
+
114
+ const graph = new WorkflowGraph()
115
+ .addNode('plan', { prompt: 'List 3 tasks for: {{goal}}', outputSchema: Plan })
116
+ .addNode('finish', { prompt: 'Summarise the work', outputSchema: Done })
117
+ .addEdge('plan', 'finish')
118
+ .setEntryPoint('plan');
119
+
120
+ const { state } = await graph.run(null, {
121
+ goal: 'add a dark-mode toggle',
122
+ agentType: 'mine',
123
+ });
124
+
125
+ console.log(state.finish.summary);
126
+ ```
127
+
128
+ See [`examples/`](./examples/) for runnable demos of each pattern.
129
+
130
+ ---
131
+
132
+ ## What this is *not*
133
+
134
+ | | What it does | Why this is different |
135
+ |---|---|---|
136
+ | **LangGraph** | Orchestrates LLM messages — ReAct loops, tool-call dispatch, prompt-level state machines. | We work one level *above*. A node hands off to a full agent (Claude Code, Cursor) that already owns its message loop and tools. You compose agent calls, not LLM messages. |
137
+ | **n8n / Zapier** | Visual no-code SaaS automation — wire APIs together. | Code-first, AI-agent-native, no UI. n8n connects Slack to Notion. We compose agents that read code, run tests, file PRs. |
138
+ | **CrewAI / AutoGen** | Multi-agent role-play — agents converse to solve a task. | No agent debate. Each node is a discrete, schema-validated invocation. Deterministic edges, retry-friendly. |
139
+
140
+ If you've used LangGraph and wished the nodes could be *agents that already know how to use tools* instead of LLM call sites you have to wire up — this is that.
141
+
142
+ ---
143
+
144
+ ## Concepts
145
+
146
+ | Primitive | What it does |
147
+ |---|---|
148
+ | `WorkflowGraph` | The DAG. `addNode`, `addEdge`, `addConditionalEdges`, `setEntryPoint`. |
149
+ | `Node` | One agent invocation. Config: `prompt`, `outputSchema` (Zod), optional `agent`, `retries`, `skills`. |
150
+ | `AgentStrategy` | Abstract base. Implement `canHandle(ctx)` and `invoke(prompt, opts)`. |
151
+ | `registerStrategy()` | Tells the engine what agents are available. Selected by node `agent` field → `config.agents[name]` → `state.agentType`. |
152
+ | `WorkflowState` | History-tracked state passed between nodes. `set` / `update` / `append` / `rollback`. |
153
+ | Skills | Named MCP tool bundles a node can request. `registerSkill({ id, serverName, tools, ... })`. |
154
+ | `ContextLoader` | Walks the spec dir for `CONTEXT.md` / `AGENTS.md` and merges them into state. |
155
+ | `compileGraph()` | Build a graph from a JSON config (the format Studio writes). |
156
+ | `timeline` | CLI progress UX + structured `__WORKFLOW_GRAPH_LOG__` markers consumed by Studio. |
157
+
158
+ State flows automatically: when node `plan` completes with output `{ tasks: [...] }`, that lands at `state.plan.tasks` and downstream nodes see it.
159
+
160
+ ---
161
+
162
+ ## Examples
163
+
164
+ | | Shows |
165
+ |---|---|
166
+ | [01-hello-world](./examples/01-hello-world/) | Smallest possible graph — one node, one fake agent. |
167
+ | [02-pipeline](./examples/02-pipeline/) | Three nodes with **typed handoff** — `state.plan.tasks` flows into the next node. |
168
+ | [03-conditional-routing](./examples/03-conditional-routing/) | Branch on state with `addConditionalEdges`. |
169
+ | [04-custom-agent](./examples/04-custom-agent/) | Bring your own `AgentStrategy` — calls OpenAI directly. |
170
+ | [05-with-skills](./examples/05-with-skills/) | Register an MCP-style skill, scope it to a node. |
171
+
172
+ Run any of them:
173
+
174
+ ```bash
175
+ cd examples/01-hello-world
176
+ npm install
177
+ node index.js
178
+ ```
179
+
180
+ Examples 01–03 and 05 use a fake agent — no API key required.
181
+
182
+ ---
183
+
184
+ ## Why graph-of-agents
185
+
186
+ Real coding agents (Claude Code, cursor-agent, OpenAI Codex CLI) are themselves capable runtimes — they edit files, run shells, call MCP tools, handle multi-turn. But on their own they have no memory across runs and no way to verify their own output.
187
+
188
+ A graph gives you:
189
+
190
+ - **Structured handoff** — node A returns a typed object, node B reads `state.A`. No prompt-stuffing, no parser bugs.
191
+ - **Retries scoped to a node** — bad output? rerun just that step.
192
+ - **Conditional routing** — `addConditionalEdges` for branch-on-state.
193
+ - **Skill scoping** — node A gets browser tools; node B gets git tools; they don't interfere.
194
+ - **Replay / inspect** — every run lands in a session folder with raw outputs, parsed JSON, and a JSONL execution log.
195
+ - **Studio integration** — pin a session, watch live state, stop a run from the UI.
196
+
197
+ You're not replacing the agent. You're giving it a job description, a contract, and a place in a pipeline.
198
+
199
+ ---
200
+
201
+ ## Companion packages
202
+
203
+ | Package | What it adds |
204
+ |---|---|
205
+ | [`@zibby/cli`](https://www.npmjs.com/package/@zibby/cli) | `zibby` command — scaffold, dev server, deploy, trigger, logs. |
206
+ | [`@zibby/core`](https://www.npmjs.com/package/@zibby/core) | Built-in agent strategies (Claude / Cursor / Codex / Gemini / OpenAI Assistant), MCP client, runtime. |
207
+ | [`@zibby/skills`](https://www.npmjs.com/package/@zibby/skills) | Pre-built skills (browser via Playwright MCP, GitHub, Jira, Slack, memory). |
208
+
209
+ Workflow itself ships **zero agent strategies and zero skills** — bring your own, or `npm install @zibby/core @zibby/skills` for the batteries-included experience.
210
+
211
+ ---
212
+
213
+ ## Status
214
+
215
+ `0.1.x`. The public protocol surface is stable and consumed by Zibby Studio + tooling:
216
+
217
+ - `WORKFLOW_GRAPH_LOG_MARKER_PREFIX` (`__WORKFLOW_GRAPH_LOG__`)
218
+ - `STUDIO_STOP_REQUEST_FILE` (`.zibby-studio-stop`)
219
+ - `ZIBBY_RUN_SOURCE=studio` env trigger
220
+ - `stoppedByStudio: true` return key
221
+ - Marker payload `{ phase: 'node_begin' | 'node_end', node: string }`
222
+
223
+ The JS API is still pre-1.0 — minor versions may add or rename surface area, breaking changes will be called out in release notes.
224
+
225
+ ---
226
+
227
+ ## License
228
+
229
+ MIT
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Abstract base class for AI agent strategies.
3
+ * All provider implementations must extend this class.
4
+ *
5
+ * @abstract
6
+ */
7
+ export class AgentStrategy {
8
+ /**
9
+ * @param {string} name - Provider identifier (e.g. 'claude', 'openai')
10
+ * @param {string} description - Human-readable description
11
+ * @param {number} [priority] - Selection priority (higher = preferred)
12
+ */
13
+ constructor(name: string, description: string, priority?: number);
14
+ name: string;
15
+ description: string;
16
+ priority: number;
17
+ /**
18
+ * Execute a prompt against this agent.
19
+ *
20
+ * @abstract
21
+ * @param {string} prompt
22
+ * @param {AgentInvokeOptions} options
23
+ * @returns {Promise<string | AgentStructuredResult>}
24
+ * - Without schema: returns raw string
25
+ * - With schema: returns { raw: string, structured: object }
26
+ * - On failure: throws Error
27
+ *
28
+ * @typedef {Object} AgentInvokeOptions
29
+ * @property {string} [model] - Model name or alias
30
+ * @property {string} [workspace] - Working directory
31
+ * @property {object} [schema] - Zod schema for structured output
32
+ * @property {Array} [skills] - Skill IDs available to the agent
33
+ * @property {Array} [images] - Image attachments (provider-specific)
34
+ * @property {string} [sessionPath] - Session artifact directory
35
+ * @property {number} [timeout] - Execution timeout in ms
36
+ * @property {object} [config] - Full workflow config
37
+ *
38
+ * @typedef {Object} AgentStructuredResult
39
+ * @property {string} raw - Raw agent output
40
+ * @property {object} structured - Parsed and validated output
41
+ */
42
+ invoke(_prompt: any, _options?: {}): Promise<string | {
43
+ /**
44
+ * - Raw agent output
45
+ */
46
+ raw: string;
47
+ /**
48
+ * - Parsed and validated output
49
+ */
50
+ structured: object;
51
+ }>;
52
+ /**
53
+ * Return true if this strategy can run in the current environment.
54
+ * @abstract
55
+ * @param {object} [context]
56
+ * @returns {boolean}
57
+ */
58
+ canHandle(_context: any): boolean;
59
+ getName(): string;
60
+ getDescription(): string;
61
+ getPriority(): number;
62
+ }
63
+ export default AgentStrategy;
@@ -0,0 +1 @@
1
+ var r=class{constructor(t,e,i=0){this.name=t,this.description=e,this.priority=i}async invoke(t,e={}){throw new Error(`${this.constructor.name}.invoke() must be implemented`)}canHandle(t){throw new Error(`${this.constructor.name}.canHandle() must be implemented`)}getName(){return this.name}getDescription(){return this.description}getPriority(){return this.priority}},o=r;export{r as AgentStrategy,o as default};
@@ -0,0 +1,2 @@
1
+ export function generateWorkflowCode(config: any, meta?: {}): string;
2
+ export function generateNodeConfigsJson(nodeConfigs: any): {};
@@ -0,0 +1,29 @@
1
+ var R=Object.defineProperty;var N=(e,o)=>()=>(e&&(o=e(e=0)),o);var D=(e,o)=>{for(var t in o)R(e,t,{get:o[t],enumerable:!0})};function v(e){return L.get(e)||null}var L,x=N(()=>{L=new Map});var _,M,T,k,S=N(()=>{_=()=>{},M={debug:_,info:_,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},T={impl:M},k={debug:(...e)=>T.impl.debug?.(...e),info:(...e)=>T.impl.info?.(...e),warn:(...e)=>T.impl.warn?.(...e),error:(...e)=>T.impl.error?.(...e)}});var $,A=N(()=>{$=class{constructor(o,t,r=0){this.name=o,this.description=t,this.priority=r}async invoke(o,t={}){throw new Error(`${this.constructor.name}.invoke() must be implemented`)}canHandle(o){throw new Error(`${this.constructor.name}.canHandle() must be implemented`)}getName(){return this.name}getDescription(){return this.description}getPriority(){return this.priority}}});var j={};D(j,{getAgentStrategy:()=>C,invokeAgent:()=>G,listStrategies:()=>B,registerStrategy:()=>F});function F(e){if(!(e instanceof $))throw new Error("strategy must be an instance of AgentStrategy");let o=m.findIndex(t=>t.getName()===e.getName());o>=0?m[o]=e:m.push(e)}function B(){return m.map(e=>e.getName())}function C(e={}){let{state:o={},preferredAgent:t=null}=e,r=t||o.agentType||process.env.AGENT_TYPE;if(!r){let s=m.map(n=>n.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${s}`)}k.debug(`[workflow] agent selection: requested=${r}`);let i=m.find(s=>s.getName()===r);if(!i){let s=m.map(n=>n.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${r}'. Available: ${s}`)}if(!i.canHandle(e))throw new Error(`Agent '${r}' is not available in this environment. Check credentials/environment.`);return k.debug(`[workflow] using agent: ${i.getName()}`),i}async function G(e,o={},t={}){let r=C(o),i=o.state?.config||t.config||{},s=i.models||{},n=t.nodeName&&s[t.nodeName]||null,a=s.default||null,c=i.agent?.[r.name]?.model||null,l=n||a||c||t.model||null,p={...t,model:l,workspace:o.state?.workspace||t.workspace,schema:t.schema||o.schema,images:t.images||o.images||[],skills:t.skills||o.skills||[],config:i},f=e,g=p.skills||[];if(g.length>0&&!t.skipPromptFragments){let d=g.map(y=>{let u=v(y)?.promptFragment;return typeof u=="function"?u():u}).filter(Boolean);d.length>0&&(f+=`
2
+
3
+ ${d.join(`
4
+
5
+ `)}`)}let h=o.state?._currentNodeConfig?.extraPromptInstructions?.trim();return h&&(f+=`
6
+
7
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
8
+ PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PREVIOUS CONTENT
9
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
10
+
11
+ ${h}
12
+ `),k.debug(`[workflow] prompt length: ${f.length} chars`),r.invoke(f,p)}var m,b=N(()=>{A();S();x();m=[]});x();S();var E={};var I=new Map;function U(e,o){I.set(e,o)}function O(e){let o=I.get(e);return o?o.factory&&typeof o.create=="function"?o.create.toString():typeof o.execute=="function"?o.execute.toString():typeof o=="function"?o.toString():null:null}U("ai_agent",{name:"ai_agent",factory:!0,create:(e,o={})=>({name:e,_isCustomCode:!0,execute:async t=>{let r=t?._coreInvokeAgent;r||(r=(await Promise.resolve().then(()=>(b(),j))).invokeAgent);let i=o.extraPromptInstructions||"Execute the task based on the current state.",s=V(i,t),n=await r(s,{cwd:t.workspace||process.cwd(),model:t.model,tools:o.resolvedTools||null});return{success:!0,output:{raw:n,nodeId:e},raw:typeof n=="string"?n:n.raw}}})});function V(e,o){let t=/@([\w.]+)/g,r=new Set,i;for(;(i=t.exec(e))!==null;)r.add(i[1]);if(r.size===0)return e;let s=[],n=new Set;for(let a of r){let c=a.split(".")[0];if(n.has(c))continue;let l=a.split(".").reduce((g,h)=>g?.[h],o);if(l===void 0)continue;let p=typeof l=="string"?l:l?.raw??JSON.stringify(l,null,2),f=a.replace(/_/g," ").replace(/\b\w/g,g=>g.toUpperCase());s.push(`## ${f}
13
+ ${p}`),a.includes(".")||n.add(c)}return s.length===0?e:`${e}
14
+
15
+ ---
16
+ # Referenced Context
17
+
18
+ ${s.join(`
19
+
20
+ `)}`}function de(e,o={}){let{nodes:t,edges:r,nodeConfigs:i={}}=e,s=new Set,n=[],a=new Map;for(let u of t){let w=u.data?.nodeType||u.type;a.set(u.id,w),w==="decision"?s.add(u.id):n.push({id:u.id,nodeType:w,label:u.data?.label||u.id})}let c=n.some(u=>{let w=i[u.id]||{};return!w.customCode&&!w.executeCode}),{toolsPerNode:l,toolIdsByVar:p}=Z(n,i),{simpleEdges:f,conditionalEdges:g}=q(r,s),h=Q(n,r,s),d=[],y=o.workflowType||"workflow";return d.push(z(o)),d.push(H(y,{usesRegisteredNodes:c})),d.push(W(p)),d.push(J(y)),d.push(Y(n,i)),d.push(K(n,h,f,g,l,y)),d.filter(Boolean).join(`
21
+ `)}function pe(e){let o={};for(let[t,r]of Object.entries(e)){let{tools:i,...s}=r;Object.keys(s).length>0&&(o[t]=s)}return o}function z(e){let o=e.workflowType||"workflow";return["// Generated workflow",`// ${e.projectId?`Project: ${e.projectId} | `:""}Type: ${o} | Version: ${e.version??0}`,`// Downloaded: ${new Date().toISOString()}`,""].join(`
22
+ `)}function H(e,{usesRegisteredNodes:o=!0}={}){let t=["import { WorkflowGraph, invokeAgent, getResolvedToolDefinitions } from '@zibby/agent-workflow';"];return o&&t.push("// import './register-nodes.js'; // register custom node types here"),t.push("import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';","import { join, dirname } from 'node:path';","import { fileURLToPath } from 'node:url';",""),t.join(`
23
+ `)}function W(e){if(e.size===0)return"";let o=["// \u2500\u2500 Tool Bindings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"];for(let[t,r]of e)o.push(`const ${t} = getResolvedToolDefinitions(${JSON.stringify(r)}); // ${r.join(", ")}`);return o.push(""),o.join(`
24
+ `)}function J(e){return["// \u2500\u2500 Node Configs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500","const __filename = fileURLToPath(import.meta.url);","const __dirname = dirname(__filename);",`const configPath = join(__dirname, 'workflow-${e}.config.json');`,"const nodeConfigs = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};",""].join(`
25
+ `)}function Y(e,o){let t=["// \u2500\u2500 Node Implementations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",""];for(let r of e){let i=P(r.id),s=o[r.id]?.customCode;if(s)t.push(`// @custom \u2014 modified from default "${r.nodeType}" template`),t.push(`const ${i}_execute = ${s};`);else{let n=O(r.nodeType);n?(t.push(`// Default "${r.nodeType}" implementation`),t.push(`const ${i}_execute = ${n};`)):(t.push(`// No template for "${r.nodeType}" \u2014 passthrough`),t.push(`const ${i}_execute = async (state) => ({ success: true, output: {}, raw: null });`))}t.push("")}return t.join(`
26
+ `)}function K(e,o,t,r,i,s){let n=["// \u2500\u2500 Graph Builder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"];n.push("export function buildGraph(options = {}) {"),n.push(" const graph = new WorkflowGraph(options);",""),n.push(" // Nodes");for(let c of e){let l=P(c.id);n.push(` graph.addNode('${c.id}', { name: '${c.id}', execute: ${l}_execute });`),n.push(` graph.setNodeType('${c.id}', '${c.nodeType}');`)}n.push("",` graph.setEntryPoint('${o}');`,""),(t.length>0||r.length>0)&&n.push(" // Edges");for(let c of t)n.push(` graph.addEdge('${c.source}', '${c.target}');`);for(let c of r){let l=c.code.split(`
27
+ `).map((p,f)=>f===0?p:` ${p}`).join(`
28
+ `);n.push(` graph.addConditionalEdges('${c.source}', ${l});`)}let a=[];for(let c of e){let l=i.get(c.id);l&&a.push(` '${c.id}': ${l},`)}return a.length>0&&n.push(""," graph.resolvedToolsMap = {",...a," };"),n.push(""," return graph;","}",""),n.push("export { nodeConfigs };",""),n.join(`
29
+ `)}function Z(e,o){let t=new Map,r=new Map;for(let i of e){let s=o[i.id]?.tools,n;if(Array.isArray(s)&&s.length>0)n=[...s].sort();else{let a=E[i.nodeType];a?.length>0&&(n=[...a].sort())}if(n){let a=`${n.map(c=>c.replace(/[^a-zA-Z0-9]/g,"")).join("And")}Tools`;t.set(i.id,a),r.has(a)||r.set(a,n)}}return{toolsPerNode:t,toolIdsByVar:r}}function q(e,o){let t=[],r=[],i=new Map,s=new Set;for(let n of e)i.has(n.source)||i.set(n.source,[]),i.get(n.source).push(n);for(let n of e)if(!o.has(n.source))if(o.has(n.target)){if(s.has(n.target))continue;s.add(n.target);let c=(i.get(n.target)||[]).find(l=>l.data?.conditionalCode||l.conditionalCode);c&&r.push({source:n.source,code:c.data?.conditionalCode||c.conditionalCode})}else t.push({source:n.source,target:n.target});return{simpleEdges:t,conditionalEdges:r}}function Q(e,o,t){let r=new Set;for(let s of o)t.has(s.target)||r.add(s.target);let i=e.find(s=>!r.has(s.id));return i?i.id:e[0]?.id}function P(e){return e.replace(/[^a-zA-Z0-9]/g,"_")}export{pe as generateNodeConfigsJson,de as generateWorkflowCode};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Framework constants — paths, filenames, and well-known skill IDs.
3
+ */
4
+ export const DEFAULT_OUTPUT_BASE: ".zibby/output";
5
+ export const SESSIONS_DIR: "sessions";
6
+ export const SESSION_INFO_FILE: ".session-info.json";
7
+ /** Written by Zibby Studio / CLI bridge when user stops a run; WorkflowGraph polls and exits. */
8
+ export const STUDIO_STOP_REQUEST_FILE: ".zibby-studio-stop";
9
+ export const RESULT_FILE: "result.json";
10
+ export const RAW_OUTPUT_FILE: "raw_stream_output.txt";
11
+ export const EVENTS_FILE: "events.json";
12
+ export namespace SKILLS {
13
+ let BROWSER: string;
14
+ let JIRA: string;
15
+ let GITHUB: string;
16
+ let SLACK: string;
17
+ let MEMORY: string;
18
+ let CHAT_MEMORY: string;
19
+ let RUNNER: string;
20
+ let SKILL_INSTALLER: string;
21
+ let CORE_TOOLS: string;
22
+ let WORKFLOW_BUILDER: string;
23
+ }
24
+ /** CI env vars checked when generating session IDs. */
25
+ export const CI_ENV_VARS: string[];
@@ -0,0 +1 @@
1
+ var o=".zibby/output",t="sessions",s=".session-info.json",_=".zibby-studio-stop",I="result.json",r="raw_stream_output.txt",E="events.json",e={BROWSER:"browser",JIRA:"jira",GITHUB:"github",SLACK:"slack",MEMORY:"memory",CHAT_MEMORY:"chat-memory",RUNNER:"runner",SKILL_INSTALLER:"skill-installer",CORE_TOOLS:"core-tools",WORKFLOW_BUILDER:"workflow-builder"},S=["CI_JOB_ID","GITHUB_RUN_ID","CIRCLE_WORKFLOW_ID","BUILD_ID"];export{S as CI_ENV_VARS,o as DEFAULT_OUTPUT_BASE,E as EVENTS_FILE,r as RAW_OUTPUT_FILE,I as RESULT_FILE,t as SESSIONS_DIR,s as SESSION_INFO_FILE,e as SKILLS,_ as STUDIO_STOP_REQUEST_FILE};
@@ -0,0 +1,5 @@
1
+ export class ContextLoader {
2
+ static loadContext(specPath: any, cwd: any, config?: {}): Promise<{}>;
3
+ static findAndMergeContextFiles(filename: any, startDir: any, rootDir: any): Promise<any>;
4
+ static loadFile(filePath: any): Promise<any>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import{existsSync as f,readFileSync as y}from"node:fs";import{join as l,dirname as d}from"node:path";var m=class{static async loadContext(e,o,a={}){let t={},r=a.filenames||["CONTEXT.md","AGENTS.md"];if(e){let s=d(l(o,e));for(let i of r){let c=await this.findAndMergeContextFiles(i,s,o);if(c){let u=i.replace(/\.[^.]+$/,"").toLowerCase();t[u]=c}}}let n=a.discovery||{};for(let[s,i]of Object.entries(n))try{let c=l(o,i);f(c)&&(t[s]=await this.loadFile(c))}catch(c){console.warn(`[workflow] could not load context '${s}' from '${i}': ${c.message}`)}return t}static async findAndMergeContextFiles(e,o,a){let t=[],r=o;for(;r.startsWith(a);){let n=l(r,e);if(f(n))try{t.unshift(await this.loadFile(n))}catch(i){console.warn(`[workflow] could not load ${e} from ${n}: ${i.message}`)}let s=d(r);if(s===r)break;r=s}return t.length===0?null:t.every(n=>typeof n=="string")?t.join(`
2
+
3
+ ---
4
+
5
+ `):t.every(n=>typeof n=="object")?Object.assign({},...t):t[t.length-1]}static async loadFile(e){let o=y(e,"utf-8");if(e.endsWith(".json"))return JSON.parse(o);if(e.endsWith(".js")||e.endsWith(".mjs")){let{pathToFileURL:a}=await import("url"),t=await import(a(e).href);return t.default||t}return o}};export{m as ContextLoader};
@@ -0,0 +1,10 @@
1
+ export function compileGraph(config: any, options?: {}): WorkflowGraph;
2
+ export function validateGraphConfig(config: any): {
3
+ valid: boolean;
4
+ errors: string[];
5
+ };
6
+ export function extractSteps(config: any): any;
7
+ export class CompilationError extends Error {
8
+ constructor(message: any);
9
+ }
10
+ import { WorkflowGraph } from './graph.js';
@@ -0,0 +1,45 @@
1
+ var Qe=Object.defineProperty;var se=(o=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(o,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):o)(function(o){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+o+'" is not supported')});var J=(o,e)=>()=>(o&&(e=o(o=0)),e);var $e=(o,e)=>{for(var t in e)Qe(o,t,{get:e[t],enumerable:!0})};var Ee,tt,V,w,D=J(()=>{Ee=()=>{},tt={debug:Ee,info:Ee,warn:(...o)=>console.warn("[workflow]",...o),error:(...o)=>console.error("[workflow]",...o)},V={impl:tt},w={debug:(...o)=>V.impl.debug?.(...o),info:(...o)=>V.impl.info?.(...o),warn:(...o)=>V.impl.warn?.(...o),error:(...o)=>V.impl.error?.(...o)}});var q,Pe=J(()=>{q=class{constructor(e,t,s=0){this.name=e,this.description=t,this.priority=s}async invoke(e,t={}){throw new Error(`${this.constructor.name}.invoke() must be implemented`)}canHandle(e){throw new Error(`${this.constructor.name}.canHandle() must be implemented`)}getName(){return this.name}getDescription(){return this.description}getPriority(){return this.priority}}});var Re={};$e(Re,{clearSkills:()=>at,getAllSkills:()=>it,getSkill:()=>F,hasSkill:()=>nt,listSkillIds:()=>ct,registerSkill:()=>rt});function rt(o){if(!o||typeof o.id!="string")throw new Error("Skill definition must include a string id");B.set(o.id,Object.freeze({...o}))}function F(o){return B.get(o)||null}function nt(o){return B.has(o)}function it(){return new Map(B)}function ct(){return Array.from(B.keys())}function at(){B.clear()}var B,X=J(()=>{B=new Map});var j={};$e(j,{getAgentStrategy:()=>Be,invokeAgent:()=>dt,listStrategies:()=>ut,registerStrategy:()=>lt});function lt(o){if(!(o instanceof q))throw new Error("strategy must be an instance of AgentStrategy");let e=C.findIndex(t=>t.getName()===o.getName());e>=0?C[e]=o:C.push(o)}function ut(){return C.map(o=>o.getName())}function Be(o={}){let{state:e={},preferredAgent:t=null}=o,s=t||e.agentType||process.env.AGENT_TYPE;if(!s){let r=C.map(i=>i.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${r}`)}w.debug(`[workflow] agent selection: requested=${s}`);let n=C.find(r=>r.getName()===s);if(!n){let r=C.map(i=>i.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${s}'. Available: ${r}`)}if(!n.canHandle(o))throw new Error(`Agent '${s}' is not available in this environment. Check credentials/environment.`);return w.debug(`[workflow] using agent: ${n.getName()}`),n}async function dt(o,e={},t={}){let s=Be(e),n=e.state?.config||t.config||{},r=n.models||{},i=t.nodeName&&r[t.nodeName]||null,c=r.default||null,a=n.agent?.[s.name]?.model||null,l=i||c||a||t.model||null,m={...t,model:l,workspace:e.state?.workspace||t.workspace,schema:t.schema||e.schema,images:t.images||e.images||[],skills:t.skills||e.skills||[],config:n},d=o,u=m.skills||[];if(u.length>0&&!t.skipPromptFragments){let p=u.map(_=>{let N=F(_)?.promptFragment;return typeof N=="function"?N():N}).filter(Boolean);p.length>0&&(d+=`
2
+
3
+ ${p.join(`
4
+
5
+ `)}`)}let g=e.state?._currentNodeConfig?.extraPromptInstructions?.trim();return g&&(d+=`
6
+
7
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
8
+ PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PREVIOUS CONTENT
9
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
10
+
11
+ ${g}
12
+ `),w.debug(`[workflow] prompt length: ${d.length} chars`),s.invoke(d,m)}var C,U=J(()=>{Pe();D();X();C=[]});var et=new Set(["__proto__","constructor","prototype"]);function re(o){if(et.has(o))throw new Error(`Invalid state key: "${o}"`)}var H=class{constructor(e={}){this._state=Object.create(null),Object.assign(this._state,{messages:[],errors:[],artifacts:{},metadata:{},...e}),this._history=[]}get(e){return this._state[e]}set(e,t){re(e),this._history.push({...this._state}),this._state[e]=t}update(e){let t=Object.getOwnPropertyNames(e);for(let s of t)re(s);this._history.push({...this._state});for(let s of t)this._state[s]=e[s]}append(e,t){re(e),this._history.push({...this._state}),Array.isArray(this._state[e])||(this._state[e]=[]),this._state[e].push(t)}getAll(){return{...this._state}}rollback(){this._history.length>0&&(this._state=this._history.pop())}};var K=class{constructor(e){this.schema=e}parse(e){let t=e.match(/```json\s*([\s\S]*?)\s*```/);if(t)return this.validate(JSON.parse(t[1]));let s=e.match(/\{[\s\S]*\}/);return s?this.validate(JSON.parse(s[0])):this.validate({result:e.trim()})}validate(e){let t=[];for(let[s,n]of Object.entries(this.schema)){if(n.required&&!(s in e)&&t.push(`Missing required field: ${s}`),s in e&&n.type){let r=typeof e[s];r!==n.type&&t.push(`Field '${s}' expected ${n.type}, got ${r}`)}if(n.validate&&s in e){let r=n.validate(e[s]);r&&t.push(`Field '${s}': ${r}`)}}if(t.length>0)throw new Error(`Output validation failed:
13
+ ${t.join(`
14
+ `)}`);return e}};D();import{writeFileSync as ae,readFileSync as We,existsSync as Me,mkdirSync as pt}from"node:fs";import{join as le,dirname as ft}from"node:path";import y from"chalk";var ot="__WORKFLOW_GRAPH_LOG__",L=y.gray("\u2502"),st=y.gray("\u250C"),Ie=y.gray("\u2514"),ne=y.green("\u25C6"),ve=y.hex("#c084fc")("\u25C6"),Ne=y.hex("#2dd4bf")("\u25C6"),ie=y.red("\u25C6"),ke=`${L} `,Oe=2;function xe(o){return o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`}function Te(o,e){return(t,s,n)=>{if(typeof t!="string")return o(t,s,n);let r=process.stdout.columns||120,i="";for(let c=0;c<t.length;c++){let a=t[c];e.lineStart&&(i+=ke,e.col=Oe,e.lineStart=!1),a===`
15
+ `?(i+=a,e.lineStart=!0,e.col=0,e.inEsc=!1):a==="\x1B"?(e.inEsc=!0,i+=a):e.inEsc?(i+=a,(a>="A"&&a<="Z"||a>="a"&&a<="z")&&(e.inEsc=!1)):(e.col++,i+=a,e.col>=r&&(i+=`
16
+ ${ke}`,e.col=Oe))}return o(i,s,n)}}var ce=class{constructor(){this._currentNode=null,this._origStdoutWrite=null,this._origStderrWrite=null;let e=String(process.env.ZIBBY_RUN_SOURCE||"").trim().toLowerCase(),t=String(process.env.ZIBBY_WORKFLOW_GRAPH_LOG_MARKERS||"").trim()==="1";this._emitWorkflowGraphMarkers=t||e==="studio"}get isInsideNode(){return this._currentNode!==null}_startIntercepting(){this._origStdoutWrite=process.stdout.write.bind(process.stdout),this._origStderrWrite=process.stderr.write.bind(process.stderr);let e={lineStart:!0,col:0,inEsc:!1},t={lineStart:!0,col:0,inEsc:!1};this._outState=e,this._errState=t,process.stdout.write=Te(this._origStdoutWrite,e),process.stderr.write=Te(this._origStderrWrite,t)}_stopIntercepting(){this._origStdoutWrite&&(this._outState&&!this._outState.lineStart&&this._origStdoutWrite(`
17
+ `),process.stdout.write=this._origStdoutWrite),this._origStderrWrite&&(this._errState&&!this._errState.lineStart&&this._origStderrWrite(`
18
+ `),process.stderr.write=this._origStderrWrite),this._origStdoutWrite=null,this._origStderrWrite=null}_rawWrite(e){(this._origStdoutWrite||process.stdout.write.bind(process.stdout))(`${e}
19
+ `)}_emitGraphLogMarker(e){if(!this._emitWorkflowGraphMarkers)return;let t=`${ot}${JSON.stringify(e)}
20
+ `;this._origStdoutWrite?this._origStdoutWrite(t):process.stdout.write(t)}_writeDot(e,t){this._origStdoutWrite?(this._outState&&!this._outState.lineStart&&(this._origStdoutWrite(`
21
+ `),this._outState.lineStart=!0,this._outState.col=0),this._origStdoutWrite(`${e} ${t}
22
+ `)):process.stdout.write.bind(process.stdout)(`${e} ${t}
23
+ `)}step(e){this._origStdoutWrite?this._writeDot(ne,e):process.stdout.write.bind(process.stdout)(`${L} ${ne} ${e}
24
+ `)}stepInfo(e){this.step(e)}stepTool(e){this._origStdoutWrite?this._writeDot(ve,e):process.stdout.write.bind(process.stdout)(`${L} ${ve} ${e}
25
+ `)}stepMemory(e){let t=y.hex("#2dd4bf")(e);this._origStdoutWrite?this._writeDot(Ne,t):process.stdout.write.bind(process.stdout)(`${L} ${Ne} ${t}
26
+ `)}stepFail(e){this._origStdoutWrite?this._writeDot(ie,y.red(e)):process.stdout.write.bind(process.stdout)(`${L} ${ie} ${y.red(e)}
27
+ `)}nodeStart(e){this._currentNode=e,this._emitGraphLogMarker({phase:"node_begin",node:e}),this._rawWrite(`${st} ${e}`),this._startIntercepting()}nodeComplete(e,t={}){this._stopIntercepting();let{duration:s,details:n}=t;if(n)for(let i of n)this._rawWrite(`${ne} ${i}`);let r=s?y.dim(` ${xe(s)}`):"";this._rawWrite(`${Ie} ${y.green("done")}${r}`),this._emitGraphLogMarker({phase:"node_end",node:e}),this._rawWrite("")}nodeFailed(e,t,s={}){this._stopIntercepting();let{duration:n}=s,r=n?y.dim(` ${xe(n)}`):"";this._rawWrite(`${ie} ${y.red(t)}`),this._rawWrite(`${Ie} ${y.red("failed")}${r}`),this._emitGraphLogMarker({phase:"node_end",node:e}),this._rawWrite("")}route(e,t){this._rawWrite(y.dim(` ${e} \u2192 ${t}`)),this._rawWrite("")}graphComplete(){this._rawWrite(y.green.bold("\u2713 Workflow completed"))}},E=new ce;var z=".zibby/output",Ae="sessions",R=".session-info.json",be=".zibby-studio-stop";var Ce=["CI_JOB_ID","GITHUB_RUN_ID","CIRCLE_WORKFLOW_ID","BUILD_ID"];var W=class{constructor(e){if(this.config=e,this.name=e.name,this.prompt=e.prompt,this.outputSchema=e.outputSchema,!this.outputSchema&&!e._isCustomCode)throw new Error(`Node '${this.name}' must define outputSchema (Zod schema). This defines the contract for what the node returns to state.`);this.isZodSchema=this.outputSchema&&typeof this.outputSchema._def<"u",this.parser=e.outputSchema&&!this.isZodSchema?new K(e.outputSchema):null,this.retries=e.retries||0,this.onComplete=e.onComplete,this.customExecute=e.execute}async execute(e,t){let s=()=>t&&typeof t.getAll=="function"?t.getAll():e,n=d=>t&&typeof t.get=="function"?t.get(d):e?.[d];if(typeof this.customExecute=="function"){w.debug(`[workflow] node '${this.name}': custom execute (skipping LLM)`);try{let d=await this.customExecute(e);return typeof d=="object"&&d!==null&&d.success===!1?{success:!1,error:d.error||"Node execution failed",raw:d.raw||null}:this.isZodSchema?(w.debug(`[workflow] node '${this.name}': validating output schema`),{success:!0,output:this.outputSchema.parse(d),raw:null}):{success:!0,output:d,raw:null}}catch(d){return w.error(`[workflow] node '${this.name}' failed: ${d.message}`),d.name==="ZodError"&&w.error(`Schema errors: ${JSON.stringify(d.errors,null,2)}`),{success:!1,error:d.message,raw:null}}}let r=typeof this.prompt=="function"?this.prompt(s()):this.prompt,i=n("_skillHints");i&&(r=`${i}
28
+
29
+ ${r}`);let c=s(),a=c.cwd||process.cwd(),l=c.sessionPath;try{if(l){let d=le(l,R);if(Me(d)){let g=JSON.parse(We(d,"utf-8"));g.currentNode=this.name,ae(d,JSON.stringify(g,null,2),"utf-8")}let u=le(l,"..",R);if(Me(u))try{let g=JSON.parse(We(u,"utf-8"));g.currentNode=this.name,ae(u,JSON.stringify(g,null,2),"utf-8")}catch{}}}catch(d){w.debug(`[workflow] could not update session info: ${d.message}`)}let m=null;for(let d=0;d<=this.retries;d++)try{w.debug(`[workflow] node '${this.name}' attempt ${d}`);let u=s().config||{},g=u.agents||{},p=this.config.agent??g[this.name]??null,_={state:s()};p&&(_.preferredAgent=p);let N={workspace:a,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],sessionPath:l,config:u,nodeName:this.name,timeout:this.config?.timeout||3e5},v=e?._coreInvokeAgent;v||(v=(await Promise.resolve().then(()=>(U(),j))).invokeAgent);let f=await v(r,_,N),S,k;if(typeof f=="string"?(S=f,k=null):f.structured?(S=f.raw||JSON.stringify(f.structured,null,2),k=f.structured):(S=f.raw||JSON.stringify(f,null,2),k=f.extracted||null),l)try{let h=le(l,this.name,"raw_stream_output.txt");pt(ft(h),{recursive:!0}),ae(h,typeof S=="string"?S:JSON.stringify(S),"utf-8")}catch(h){w.debug(`[workflow] could not save raw output: ${h.message}`)}if(this.isZodSchema&&k){w.info(`[workflow] node '${this.name}': output validated: ${JSON.stringify(k,null,2)}`);let h=k;if(typeof this.onComplete=="function")try{h=await this.onComplete(s(),k)}catch($){w.warn(`[workflow] onComplete hook failed: ${$.message}`)}return{success:!0,output:h,raw:S}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(s(),{raw:S}),raw:S}}catch(h){throw new Error(`onComplete failed: ${h.message}`,{cause:h})}if(this.parser){let h=this.parser.parse(S);return w.info(`[workflow] node '${this.name}': parsed output: ${JSON.stringify(h,null,2)}`),E.step("Output parsed"),{success:!0,output:h,raw:S}}return{success:!0,output:S,raw:S}}catch(u){m=u,d<this.retries&&w.info(`[workflow] node '${this.name}' failed, retrying (${d+1}/${this.retries})\u2026`)}return{success:!1,error:m.message,raw:null}}},Q=class extends W{constructor(e){super({...e,_isCustomCode:!0}),this.condition=e.condition}async execute(e,t){let s=t&&typeof t.getAll=="function"?t.getAll():e;return{success:!0,output:{nextNode:this.condition(s)},raw:null}}};import{existsSync as De,readFileSync as ht}from"node:fs";import{join as ue,dirname as Le}from"node:path";var ee=class{static async loadContext(e,t,s={}){let n={},r=s.filenames||["CONTEXT.md","AGENTS.md"];if(e){let c=Le(ue(t,e));for(let a of r){let l=await this.findAndMergeContextFiles(a,c,t);if(l){let m=a.replace(/\.[^.]+$/,"").toLowerCase();n[m]=l}}}let i=s.discovery||{};for(let[c,a]of Object.entries(i))try{let l=ue(t,a);De(l)&&(n[c]=await this.loadFile(l))}catch(l){console.warn(`[workflow] could not load context '${c}' from '${a}': ${l.message}`)}return n}static async findAndMergeContextFiles(e,t,s){let n=[],r=t;for(;r.startsWith(s);){let i=ue(r,e);if(De(i))try{n.unshift(await this.loadFile(i))}catch(a){console.warn(`[workflow] could not load ${e} from ${i}: ${a.message}`)}let c=Le(r);if(c===r)break;r=c}return n.length===0?null:n.every(i=>typeof i=="string")?n.join(`
30
+
31
+ ---
32
+
33
+ `):n.every(i=>typeof i=="object")?Object.assign({},...n):n[n.length-1]}static async loadFile(e){let t=ht(e,"utf-8");if(e.endsWith(".json"))return JSON.parse(t);if(e.endsWith(".js")||e.endsWith(".mjs")){let{pathToFileURL:s}=await import("url"),n=await import(s(e).href);return n.default||n}return t}};import{mkdirSync as Ue,existsSync as de,writeFileSync as Fe,unlinkSync as mt}from"node:fs";import{join as P,resolve as Ze}from"node:path";import{config as gt}from"dotenv";import{zodToJsonSchema as je}from"zod-to-json-schema";import St from"handlebars";function wt({traceFrom:o,sessionId:e,sessionPath:t,idSource:s,mkdirFresh:n}){if(process.env.ZIBBY_SESSION_LOG==="0"||process.env.ZIBBY_SESSION_LOG==="false")return;let r=typeof process.ppid=="number"?process.ppid:"n/a",i=`[zibby:session] from=${o} pid=${process.pid} ppid=${r} sessionId=${e} source=${s} mkdir=${n?"yes":"no"} path=${t}`;if(console.log(i),(process.env.ZIBBY_TRACE_SESSION==="1"||process.env.ZIBBY_TRACE_SESSION==="true")&&process.env.ZIBBY_SESSION_LOG!=="0"&&process.env.ZIBBY_SESSION_LOG!=="false"){let l=(new Error("session trace").stack||"").split(`
34
+ `).slice(2,14).join(`
35
+ `);console.log(`[zibby:session] stack (${o}):
36
+ ${l}`)}}function _t(){return process.env.ZIBBY_RUN_SOURCE==="studio"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function yt(){if(process.env.ZIBBY_RUN_SOURCE!=="studio")return;let o=process.env.ZIBBY_SESSION_PATH;if(!(o==null||String(o).trim()===""))try{return Ze(String(o).trim())}catch{return String(o).trim()}}function $t(){_t()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function Et({sessionPath:o,sessionId:e}){o&&typeof o=="string"&&(process.env.ZIBBY_SESSION_PATH=o),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function It(o={}){let e=Ce.map(r=>process.env[r]).find(Boolean),t=Math.random().toString(36).slice(2,6),s=e||`${Date.now()}_${t}`,n=o.paths?.sessionPrefix;return n?`${n}_${s}`:s}function vt({cwd:o=process.cwd(),config:e={},initialState:t={},traceFrom:s="resolveWorkflowSession"}={}){let n=t.sessionPath,r=t.sessionTimestamp,i="initialState.sessionPath";if(!n&&process.env.ZIBBY_SESSION_PATH)try{let l=Ze(String(process.env.ZIBBY_SESSION_PATH));l&&(n=l,i="ZIBBY_SESSION_PATH")}catch{}let c;if(n)c=String(n).split(/[/\\]/).filter(Boolean).pop(),r==null&&(r=Date.now());else{let l=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(l)c=l,i="ZIBBY_SESSION_ID";else{let d=e.sessionId!=null?String(e.sessionId).trim():"";d&&d!=="last"?(c=d,i="config.sessionId"):(c=It(e),i="generated")}r=r??Date.now();let m=e.paths?.output||z;n=P(o,m,Ae,c)}let a=!de(n);return a&&Ue(n,{recursive:!0}),(a||i!=="initialState.sessionPath")&&wt({traceFrom:s,sessionId:c,sessionPath:n,idSource:i,mkdirFresh:a}),Et({sessionPath:n,sessionId:c}),{sessionPath:n,sessionId:c,sessionTimestamp:r}}var te=class{constructor(e={}){this.nodes=new Map,this.edges=new Map,this.entryPoint=null,this.middleware=Array.isArray(e.middleware)?[...e.middleware]:[],e.nodeMiddleware&&this.middleware.push(e.nodeMiddleware),this.nodeTypeMap=new Map,this.conditionalCodeMap=new Map,this.stateSchema=e.stateSchema||null,this.nodePrompts=new Map,this.nodeOptions=new Map,this._invokeAgent=e.invokeAgent||null}setStateSchema(e){return this.stateSchema=e,this}getStateSchema(){return this.stateSchema}addNode(e,t,s={}){let n=t instanceof W?t:new W(t);return n.name=e,this.nodes.set(e,n),s.prompt&&this.nodePrompts.set(e,s.prompt),Object.keys(s).length>0&&this.nodeOptions.set(e,s),this}addConditionalNode(e,t){return this.nodes.set(e,new Q({...t,name:e})),this}addEdge(e,t){return this.edges.set(e,t),this}setNodeType(e,t){return this.nodeTypeMap.set(e,t),this}addConditionalEdges(e,t,{labels:s}={}){return this.edges.set(e,{conditional:!0,routes:t,labels:s}),typeof t=="function"&&this.conditionalCodeMap.set(e,t.toString()),this}setEntryPoint(e){return this.entryPoint=e,this}use(e){return typeof e=="function"&&this.middleware.push(e),this}_composeMiddleware(e,t,s,n,r){let i=s;for(let c=e.length-1;c>=0;c--){let a=e[c],l=i;i=()=>a(t,l,n,r)}return i()}serialize(){let e=[],t={};for(let[r,i]of this.nodes){let c=this.nodeTypeMap.get(r)||r;e.push({id:r,type:c,data:{nodeType:c,label:r}});let a={};i._isCustomCode&&typeof i.execute=="function"&&(a.customCode=i.execute.toString());let l=this.nodePrompts.get(r);if(l&&(a.prompt=l),typeof i.customExecute=="function"&&(a.executeCode=i.customExecute.toString()),i.outputSchema)try{if(typeof i.outputSchema._def<"u"){let d=je(i.outputSchema,{target:"openApi3"});a.outputSchema={jsonSchema:d,variables:this._flattenJsonSchemaToVariables(d)}}else a.outputSchema={schema:i.outputSchema}}catch(d){console.warn(`[workflow] failed to convert schema for ${r}:`,d.message)}let m=(this.resolvedToolsMap||{})[r];m?.toolIds&&(a.tools=m.toolIds),Object.keys(a).length>0&&(t[r]=a)}let s=[];for(let[r,i]of this.edges)if(typeof i=="string")s.push({source:r,target:i});else if(i.conditional){let c=this.conditionalCodeMap.get(r)||i.routes.toString(),a=this._inferConditionalTargets(i.routes),l=i.labels||{};for(let m of a){let d={source:r,target:m,data:{conditionalCode:c}};l[m]&&(d.label=l[m]),s.push(d)}}let n=null;if(this.stateSchema)try{n=je(this.stateSchema,{target:"openApi3"})}catch{n=this.stateSchema}return{nodes:e,edges:s,nodeConfigs:t,stateSchema:n}}_inferConditionalTargets(e){let t=e.toString(),s=new Set,n=/return\s+['"]([^'"]+)['"]/g,r;for(;(r=n.exec(t))!==null;)s.add(r[1]);return[...s]}_flattenJsonSchemaToVariables(e,t=""){let s=e;if(e.$ref&&e.definitions){let n=e.$ref.replace("#/definitions/","");s=e.definitions[n]||e}return this._flattenSchema(s,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];let s=[],n=e.properties||{},r=e.required||[];for(let[i,c]of Object.entries(n)){let a=t?`${t}.${i}`:i;s.push({path:a,type:c.type||"unknown",label:c.description||this._formatLabel(i),optional:!r.includes(i)}),c.type==="object"&&c.properties&&s.push(...this._flattenSchema(c,a)),c.type==="array"&&c.items?.type==="object"&&c.items.properties&&s.push(...this._flattenSchema(c.items,`${a}[]`))}return s}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];let s=[];t.success!==void 0&&s.push(`Result: ${t.success?"passed":"failed"}`);for(let[n,r]of Object.entries(t))if(!(n==="success"||n==="raw"||n==="nextNode")){if(typeof r=="string"&&r.length<=80)s.push(`${n}: ${r}`);else if(Array.isArray(r)){let i=r.length,c=r.filter(l=>l?.passed===!0).length,a=r.some(l=>l?.passed!==void 0);s.push(a?`${n}: ${c}/${i} passed${i-c?`, ${i-c} failed`:""}`:`${n}: ${i} items`)}if(s.length>=4)break}return s}async run(e,t={}){if(!this.entryPoint)throw new Error("No entry point set for graph");let s=t.cwd||process.cwd();gt({path:P(s,".env")});let n=t.config||{};if(!n||Object.keys(n).length===0)try{let h=P(s,".zibby.config.js");de(h)&&(n=(await import(h)).default||{})}catch{}process.env.EXECUTION_ID&&!n.agent?.strictMode&&(n.agent={...n.agent,strictMode:!0});let r=t.agentType;if(!r){let h=n?.agent;h?.provider?r=h.provider:h?.gemini?r="gemini":h?.claude?r="claude":h?.cursor?r="cursor":h?.codex?r="codex":r=process.env.AGENT_TYPE||"cursor"}let i=t.contextConfig||e?.config?.contextConfig||e?.config?.context||n?.context||{};if(this.stateSchema){let h=this.stateSchema.safeParse(t);if(!h.success){let $=h.error.issues.map(O=>`${O.path.join(".")}: ${O.message}`);throw console.error("\u274C Initial state validation failed:"),$.forEach(O=>console.error(` - ${O}`)),new Error(`State validation failed: ${$.join(", ")}`)}E.step("State validated against schema")}let c=yt(),a=t.sessionPath||c;a||$t();let{sessionPath:l,sessionTimestamp:m,sessionId:d}=vt({cwd:s,config:n,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:a,sessionTimestamp:t.sessionTimestamp}});E.step(`Session ${d}`);let u=await ee.loadContext(t.specPath||"",s,i);Object.keys(u).length>0&&E.step(`Context loaded: ${Object.keys(u).join(", ")}`);let g=t.outputPath;!g&&t.specPath&&(e?.calculateOutputPath?g=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));let p=new H({...t,config:n,agentType:r,outputPath:g,sessionPath:l,sessionTimestamp:m,context:u,resolvedTools:this.resolvedToolsMap||{}}),_=new Map;try{await import("@zibby/skills")}catch{}let{getSkill:N}=await Promise.resolve().then(()=>(X(),Re)),v=new Set;for(let[,h]of this.nodes)for(let $ of h.config?.skills||[])v.add($);for(let h of v){let $=N(h);if(typeof $?.middleware=="function")try{let O=await $.middleware();typeof O=="function"&&_.set(h,O)}catch{}}let f=this.entryPoint,S=[];for(;f&&f!=="END";){let h=P(l,be);if(de(h)){console.warn(`
37
+ \u{1F6D1} Studio stop requested \u2014 ending workflow.`);try{mt(h)}catch{}if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return E.step("Workflow stopped by Studio"),{success:!0,state:p.getAll(),executionLog:S,stoppedByStudio:!0}}let $=this.nodes.get(f);if(!$)throw new Error(`Node '${f}' not found in graph`);let O=JSON.stringify({sessionPath:l,sessionTimestamp:m,currentNode:f,createdAt:new Date().toISOString(),config:p.get("config")}),Ke=P(l,R);Fe(Ke,O,"utf-8");let he=p.get("config")?.paths?.output||z,Ve=P(s,he,R);Ue(P(s,he),{recursive:!0});try{Fe(Ve,O,"utf-8")}catch{}let me=t.onPipelineProgress;if(typeof me=="function")try{me({cwd:s,sessionPath:l,sessionId:d,outputBase:p.get("config")?.paths?.output||z,currentNode:f})}catch{}let ze=(this.resolvedToolsMap||{})[f]||null;p.set("_currentNodeTools",ze);let qe=p.get("nodeConfigs")||{};p.set("_currentNodeConfig",qe[f]||{}),E.nodeStart(f);let ge=Date.now(),Z=this.nodePrompts.get(f);if(!this._invokeAgent){let T=await Promise.resolve().then(()=>(U(),j));this._invokeAgent=T.invokeAgent}let Se=this._invokeAgent,we={state:p,invokeAgent:async(T={},A={})=>{let I=A.prompt||"";if(Z)try{I=St.compile(Z,{noEscape:!0})(T)}catch(b){throw console.error(`\u274C Template rendering failed for node '${f}':`,b.message),new Error(`Template rendering failed: ${b.message}`,{cause:b})}else if(!I)throw new Error(`No prompt template configured for node '${f}' and no prompt provided in options`);return Se(I,{state:p.getAll(),images:A.images||[]},{model:A.model||p.get("model"),workspace:p.get("workspace"),schema:A.schema,...A})},_coreInvokeAgent:Se,agent:e,nodeId:f,promptTemplate:Z,getPromptTemplate:()=>Z,...p.getAll()};try{let T=($.config?.skills||[]).map(M=>_.get(M)).filter(Boolean),A=[...this.middleware,...T],I;A.length>0?I=await this._composeMiddleware(A,f,async()=>$.execute(we,p),p.getAll(),p):I=await $.execute(we,p);let b=Date.now()-ge;if(S.push({node:f,success:I.success,duration:b,timestamp:new Date().toISOString()}),!I.success){if(String(I.error||"").includes("Stopped from Zibby Studio")){if(E.step("Workflow stopped by Studio"),p.set("stoppedByStudio",!0),e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return{success:!0,state:p.getAll(),executionLog:S,stoppedByStudio:!0}}p.append("errors",{node:f,error:I.error});let _e=$.config?.retries||0,ye=`${f}_retries`,G=p.getAll()[ye]||0;if(G<_e){E.stepInfo(`Retrying (attempt ${G+1}/${_e})`),p.update({[ye]:G+1,[`${f}_raw`]:I.raw});continue}throw E.nodeFailed(f,I.error,{duration:b}),new Error(`Node '${f}' failed after ${G} attempts: ${I.error}`)}p.update({[f]:I.output});let Xe=this._summarizeNodeOutput(f,I.output);E.nodeComplete(f,{duration:b,details:Xe});let Y=this.edges.get(f);if(!Y)f="END";else if(Y.conditional){let M=Y.routes(p.getAll());E.route(f,M),f=M}else f=Y}catch(T){throw E.isInsideNode&&E.nodeFailed(f,T.message,{duration:Date.now()-ge}),p.set("failed",!0),p.set("failedAt",f),T}}E.graphComplete();let k={success:!0,state:p.getAll(),executionLog:S};return e&&typeof e.onComplete=="function"&&await e.onComplete(k),k}};var pe=new Map;function Nt(o,e){pe.set(o,e)}function Ye(o){return pe.get(o)}function fe(o){return pe.has(o)}Nt("ai_agent",{name:"ai_agent",factory:!0,create:(o,e={})=>({name:o,_isCustomCode:!0,execute:async t=>{let s=t?._coreInvokeAgent;s||(s=(await Promise.resolve().then(()=>(U(),j))).invokeAgent);let n=e.extraPromptInstructions||"Execute the task based on the current state.",r=kt(n,t),i=await s(r,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:i,nodeId:o},raw:typeof i=="string"?i:i.raw}}})});function kt(o,e){let t=/@([\w.]+)/g,s=new Set,n;for(;(n=t.exec(o))!==null;)s.add(n[1]);if(s.size===0)return o;let r=[],i=new Set;for(let c of s){let a=c.split(".")[0];if(i.has(a))continue;let l=c.split(".").reduce((u,g)=>u?.[g],e);if(l===void 0)continue;let m=typeof l=="string"?l:l?.raw??JSON.stringify(l,null,2),d=c.replace(/_/g," ").replace(/\b\w/g,u=>u.toUpperCase());r.push(`## ${d}
38
+ ${m}`),c.includes(".")||i.add(a)}return r.length===0?o:`${o}
39
+
40
+ ---
41
+ # Referenced Context
42
+
43
+ ${r.join(`
44
+
45
+ `)}`}X();D();var Ot={};function Je(o,e){if(Array.isArray(e))return Ge(e);let t=Ot[o];return!t||t.length===0?null:Ge(t)}function Ge(o){if(!Array.isArray(o)||o.length===0)return null;let e=[],t={},s=[];for(let n of o){let r=F(n);if(!r){w.warn(`[workflow] unknown skill "${n}" \u2014 skipping`);continue}s.push(n);for(let i of r.tools||[])e.push({name:i.name,description:i.description,input_schema:i.input_schema||{type:"object",properties:{}}});if(!t[r.serverName])if(typeof r.resolve=="function"){let i=r.resolve();i&&(t[r.serverName]={...i,toolPrefix:n})}else{let i={};for(let c of r.envKeys||[]){let a=process.env[c];a&&(i[c]=a)}t[r.serverName]={command:r.command,args:[...r.args||[]],env:i,toolPrefix:n}}}return s.length===0?null:{toolIds:s,claudeTools:e,mcpServers:t}}D();function wo(o,e={}){let{nodes:t,edges:s,nodeConfigs:n={}}=o;if(!Array.isArray(t)||t.length===0)throw new x("Graph must have at least one node");if(!Array.isArray(s))throw new x("Graph edges must be an array");let r=new te(e);e.stateSchema&&r.setStateSchema(e.stateSchema);let i=new Set,c=new Map,a={};for(let u of t){let g=oe(u);c.set(u.id,{...u,resolvedType:g}),g==="decision"&&i.add(u.id)}for(let[u,g]of c){if(i.has(u))continue;let p=g.resolvedType,_=n[u]||{},N=Je(p,_.tools);N&&(a[u]=N);let v={};_.prompt&&(v.prompt=_.prompt);let f=fe(p);if(w.debug(`[workflow] compiler: node "${u}" type="${p}" registered=${f}`),_.customCode&&!f)r.addNode(u,He(u,_.customCode,_),v),r.setNodeType(u,p);else if(f){let S=Ye(p);S.factory?r.addNode(u,S.create(u,{..._,resolvedTools:N}),v):r.addNode(u,S,v),r.setNodeType(u,p)}else if(_.executeCode)r.addNode(u,He(u,_.executeCode,_),v),r.setNodeType(u,p);else throw new x(`Unknown node type "${p}" for node "${u}". Did you forget to register it?`)}r.resolvedToolsMap=a;let l=new Set;for(let u of s)i.has(u.target)||l.add(u.target);let m=t.find(u=>!i.has(u.id)&&!l.has(u.id));if(!m)throw new x("Could not determine entry point: no node without incoming edges found");r.setEntryPoint(m.id);let d=xt(s,"source");for(let u of s)if(!i.has(u.source))if(i.has(u.target)){let g=u.target,p=d.get(g)||[];if(p.length===0)throw new x(`Decision node "${g}" has no outgoing edges`);let _=Tt(g,p,i);r.addConditionalEdges(u.source,_)}else r.addEdge(u.source,u.target);return r}function _o(o){let e=[];if(!o||typeof o!="object")return{valid:!1,errors:["Config must be a non-null object"]};if((!Array.isArray(o.nodes)||o.nodes.length===0)&&e.push("Graph must have at least one node"),Array.isArray(o.edges)||e.push("Graph edges must be an array"),e.length>0)return{valid:!1,errors:e};let t=o.nodeConfigs||{};for(let c of o.nodes){let a=oe(c);if(a==="decision"||fe(a))continue;let l=t[c.id]||{};l.customCode||l.executeCode||e.push(`Unknown node type "${a}" for node "${c.id}". Register it or provide customCode/executeCode.`)}let s=new Set(o.nodes.map(c=>c.id));for(let c of o.edges)s.has(c.source)||e.push(`Edge references unknown source node "${c.source}"`),s.has(c.target)||e.push(`Edge references unknown target node "${c.target}"`);let n=new Set(o.nodes.filter(c=>oe(c)==="decision").map(c=>c.id)),r=new Set;for(let c of o.edges)n.has(c.target)||r.add(c.target);let i=o.nodes.filter(c=>!n.has(c.id)&&!r.has(c.id));i.length===0?e.push("No entry point found (every node has incoming edges)"):i.length>1&&e.push(`Multiple entry points found: ${i.map(c=>c.id).join(", ")}`);for(let c of n){let a=o.edges.filter(m=>m.source===c);a.length===0&&e.push(`Decision node "${c}" has no outgoing edges`),a.some(m=>m.data?.conditionalCode||m.conditionalCode)||e.push(`Decision node "${c}" outgoing edges have no conditionalCode`)}return{valid:e.length===0,errors:e}}function yo(o){return!o||!Array.isArray(o.nodes)?[]:o.nodes.filter(e=>oe(e)!=="decision").map(e=>e.id)}function oe(o){let e=o.data?.nodeType||o.data?.type||o.type;return e==="workflowNode"||e==="custom"||e==="default"?o.id:e}function xt(o,e){let t=new Map;for(let s of o){let n=s[e];t.has(n)||t.set(n,[]),t.get(n).push(s)}return t}function Tt(o,e,t){let s=e.find(c=>c.data?.conditionalCode||c.conditionalCode);if(!s)throw new x(`Decision node "${o}" has no conditionalCode on its outgoing edges`);let n=s.data?.conditionalCode||s.conditionalCode,r=new Set(e.map(c=>c.target).filter(c=>!t.has(c))),i;try{let a=new Function(`return (${n})`)();i=l=>{let m=a(l);return r.has(m)||w.warn(`[workflow] conditional route from "${o}" returned "${m}" which is not in valid targets: ${[...r].join(", ")}`),m}}catch(c){throw new x(`Failed to compile conditionalCode for "${o}": ${c.message}`)}return i}function He(o,e,t={}){let s;try{s=new Function("invokeAgent","require","console",`return (${e})`)}catch(i){throw new x(`Failed to compile customCode for node "${o}": ${i.message}`)}let n=s(async(...i)=>{let{invokeAgent:c}=await Promise.resolve().then(()=>(U(),j));return c(...i)},typeof se<"u"?se:void 0,console),r=null;return t.outputSchema&&(r=t.outputSchema.jsonSchema||t.outputSchema),{name:o,_isCustomCode:!0,outputSchema:r,execute:async i=>{try{let c=await n(i);return typeof c=="object"&&"success"in c?c:{success:!0,output:c,raw:null}}catch(c){return{success:!1,error:c.message,raw:null}}}}}var x=class extends Error{constructor(e){super(e),this.name="CompilationError"}};export{x as CompilationError,wo as compileGraph,yo as extractSteps,_o as validateGraphConfig};
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Studio spawns `zibby run` with ZIBBY_SESSION_* already set — do not strip.
3
+ * Set ZIBBY_KEEP_SESSION_ENV=1 to allow inherited session env for advanced CLI use.
4
+ */
5
+ export function shouldTrustInheritedSessionEnv(): boolean;
6
+ /**
7
+ * Studio sets `ZIBBY_RUN_SOURCE=studio` and `ZIBBY_SESSION_PATH` before spawning `zibby run`.
8
+ * Snapshot this path *before* `clearInheritedSessionEnvForFreshRun()` so we still pin the folder when:
9
+ * - an older global `@zibby/core` clears session env unconditionally, or
10
+ * - `--session-path` is dropped by shell/argv quirks but env was set.
11
+ */
12
+ export function readStudioPinnedSessionPathFromEnv(): any;
13
+ /** Drop stale shell exports so graph + children do not write to an old session folder. */
14
+ export function clearInheritedSessionEnvForFreshRun(): void;
15
+ /**
16
+ * Cursor agent and MCP subprocesses inherit `process.env`. Keep it aligned with the
17
+ * resolved workflow session so Playwright does not mkdir under a ghost path.
18
+ */
19
+ export function syncProcessEnvToSession({ sessionPath, sessionId }: {
20
+ sessionPath: any;
21
+ sessionId: any;
22
+ }): void;
23
+ /**
24
+ * New session folder id (timestamp + random suffix). Shared by WorkflowGraph and runTest pre-allocation.
25
+ * @param {object} [config]
26
+ */
27
+ export function generateWorkflowSessionId(config?: object): any;
28
+ /**
29
+ * Resolve session directory (Studio/CLI env, explicit path, or new id). Ensures the directory exists.
30
+ * runTest calls this once before agent.run so a single process reuses one session even if graph.run is entered multiple times.
31
+ */
32
+ export function resolveWorkflowSession({ cwd, config, initialState, traceFrom, }?: {
33
+ cwd?: any;
34
+ config?: {};
35
+ initialState?: {};
36
+ traceFrom?: string;
37
+ }): {
38
+ sessionPath: any;
39
+ sessionId: any;
40
+ sessionTimestamp: any;
41
+ };
42
+ export class WorkflowGraph {
43
+ constructor(options?: {});
44
+ nodes: Map<any, any>;
45
+ edges: Map<any, any>;
46
+ entryPoint: any;
47
+ middleware: any[];
48
+ nodeTypeMap: Map<any, any>;
49
+ conditionalCodeMap: Map<any, any>;
50
+ stateSchema: any;
51
+ nodePrompts: Map<any, any>;
52
+ nodeOptions: Map<any, any>;
53
+ _invokeAgent: any;
54
+ setStateSchema(schema: any): this;
55
+ getStateSchema(): any;
56
+ addNode(name: any, nodeOrConfig: any, options?: {}): this;
57
+ addConditionalNode(name: any, config: any): this;
58
+ addEdge(from: any, to: any): this;
59
+ setNodeType(name: any, nodeType: any): this;
60
+ addConditionalEdges(from: any, routes: any, { labels }?: {}): this;
61
+ setEntryPoint(nodeName: any): this;
62
+ use(middlewareFn: any): this;
63
+ _composeMiddleware(middlewareList: any, nodeName: any, coreFn: any, stateValues: any, state: any): any;
64
+ serialize(): {
65
+ nodes: {
66
+ id: any;
67
+ type: any;
68
+ data: {
69
+ nodeType: any;
70
+ label: any;
71
+ };
72
+ }[];
73
+ edges: ({
74
+ source: any;
75
+ target: any;
76
+ data: {
77
+ conditionalCode: any;
78
+ };
79
+ } | {
80
+ source: any;
81
+ target: string;
82
+ })[];
83
+ nodeConfigs: {};
84
+ stateSchema: any;
85
+ };
86
+ _inferConditionalTargets(routeFn: any): any[];
87
+ _flattenJsonSchemaToVariables(jsonSchema: any, prefix?: string): any;
88
+ _flattenSchema(schema: any, prefix?: string): any;
89
+ _formatLabel(str: any): any;
90
+ _summarizeNodeOutput(nodeName: any, output: any): string[];
91
+ run(agent: any, initialState?: {}): Promise<{
92
+ success: boolean;
93
+ state: any;
94
+ executionLog: {
95
+ node: any;
96
+ success: any;
97
+ duration: number;
98
+ timestamp: string;
99
+ }[];
100
+ }>;
101
+ }