@zibby/core 0.1.23 → 0.1.25

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.
@@ -1,5 +1,5 @@
1
- import{WorkflowState as X}from"./state.js";import{Node as U,ConditionalNode as ee}from"./node.js";import{ContextLoader as te}from"./context-loader.js";import{mkdirSync as L,existsSync as C,writeFileSync as W,unlinkSync as oe}from"fs";import{join as I,resolve as z}from"path";import{config as se}from"dotenv";import{zodToJsonSchema as G}from"zod-to-json-schema";import ne from"handlebars";import{invokeAgent as re}from"./agents/index.js";import{DEFAULT_OUTPUT_BASE as x,SESSIONS_DIR as ie,SESSION_INFO_FILE as H,CI_ENV_VARS as ce,STUDIO_STOP_REQUEST_FILE as ae}from"./constants.js";import{timeline as S}from"../utils/timeline.js";function de({traceFrom:f,sessionId:e,sessionPath:t,idSource:s,mkdirFresh:o}){if(process.env.ZIBBY_SESSION_LOG==="0"||process.env.ZIBBY_SESSION_LOG==="false")return;const n=typeof process.ppid=="number"?process.ppid:"n/a",r=`[zibby:session] from=${f} pid=${process.pid} ppid=${n} sessionId=${e} source=${s} mkdir=${o?"yes":"no"} path=${t}`;if(console.log(r),(process.env.ZIBBY_TRACE_SESSION==="1"||process.env.ZIBBY_TRACE_SESSION==="true")&&process.env.ZIBBY_SESSION_LOG!=="0"&&process.env.ZIBBY_SESSION_LOG!=="false"){const i=(new Error("session trace").stack||"").split(`
1
+ import{WorkflowState as ee}from"./state.js";import{Node as L,ConditionalNode as te}from"./node.js";import{ContextLoader as oe}from"./context-loader.js";import{mkdirSync as W,existsSync as b,writeFileSync as z,unlinkSync as se}from"fs";import{join as E,resolve as G}from"path";import{config as ne}from"dotenv";import{zodToJsonSchema as H}from"zod-to-json-schema";import re from"handlebars";import{DEFAULT_OUTPUT_BASE as C,SESSIONS_DIR as ie,SESSION_INFO_FILE as V,CI_ENV_VARS as ce,STUDIO_STOP_REQUEST_FILE as ae}from"./constants.js";import{timeline as S}from"../utils/timeline.js";function de({traceFrom:f,sessionId:e,sessionPath:t,idSource:s,mkdirFresh:o}){if(process.env.ZIBBY_SESSION_LOG==="0"||process.env.ZIBBY_SESSION_LOG==="false")return;const n=typeof process.ppid=="number"?process.ppid:"n/a",r=`[zibby:session] from=${f} pid=${process.pid} ppid=${n} sessionId=${e} source=${s} mkdir=${o?"yes":"no"} path=${t}`;if(console.log(r),(process.env.ZIBBY_TRACE_SESSION==="1"||process.env.ZIBBY_TRACE_SESSION==="true")&&process.env.ZIBBY_SESSION_LOG!=="0"&&process.env.ZIBBY_SESSION_LOG!=="false"){const i=(new Error("session trace").stack||"").split(`
2
2
  `).slice(2,14).join(`
3
3
  `);console.log(`[zibby:session] stack (${f}):
4
- ${i}`)}}function pe(){return process.env.ZIBBY_RUN_SOURCE==="studio"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function le(){if(process.env.ZIBBY_RUN_SOURCE!=="studio")return;const f=process.env.ZIBBY_SESSION_PATH;if(!(f==null||String(f).trim()===""))try{return z(String(f).trim())}catch{return String(f).trim()}}function fe(){pe()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function ue({sessionPath:f,sessionId:e}){f&&typeof f=="string"&&(process.env.ZIBBY_SESSION_PATH=f),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function he(f={}){const e=ce.map(n=>process.env[n]).find(Boolean),t=Math.random().toString(36).slice(2,6),s=e||`${Date.now()}_${t}`,o=f.paths?.sessionPrefix;return o?`${o}_${s}`:s}function me({cwd:f=process.cwd(),config:e={},initialState:t={},traceFrom:s="resolveWorkflowSession"}={}){let o=t.sessionPath,n=t.sessionTimestamp,r="initialState.sessionPath";if(!o&&process.env.ZIBBY_SESSION_PATH)try{const i=z(String(process.env.ZIBBY_SESSION_PATH));i&&(o=i,r="ZIBBY_SESSION_PATH")}catch{}let c;if(o)c=String(o).split(/[/\\]/).filter(Boolean).pop(),n==null&&(n=Date.now());else{const i=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(i)c=i,r="ZIBBY_SESSION_ID";else{const g=e.sessionId!=null?String(e.sessionId).trim():"";g&&g!=="last"?(c=g,r="config.sessionId"):(c=he(e),r="generated")}n=n??Date.now();const u=e.paths?.output||x;o=I(f,u,ie,c)}const l=!C(o);return l&&L(o,{recursive:!0}),de({traceFrom:s,sessionId:c,sessionPath:o,idSource:r,mkdirFresh:l}),ue({sessionPath:o,sessionId:c}),{sessionPath:o,sessionId:c,sessionTimestamp:n}}class Te{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}setStateSchema(e){return this.stateSchema=e,this}getStateSchema(){return this.stateSchema}addNode(e,t,s={}){const o=t instanceof U?t:new U(t);return o.name=e,this.nodes.set(e,o),s.prompt&&this.nodePrompts.set(e,s.prompt),Object.keys(s).length>0&&this.nodeOptions.set(e,s),this}addConditionalNode(e,t){const s=new ee({...t,name:e});return this.nodes.set(e,s),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,o,n){let r=s;for(let c=e.length-1;c>=0;c--){const l=e[c],i=r;r=()=>l(t,i,o,n)}return r()}serialize(){const e=[],t={};for(const[n,r]of this.nodes){const c=this.nodeTypeMap.get(n)||n;e.push({id:n,type:c,data:{nodeType:c,label:n}});const l=r._isCustomCode||!1,i={};l&&typeof r.execute=="function"&&(i.customCode=r.execute.toString());const u=this.nodePrompts.get(n);if(u&&(i.prompt=u),typeof r.customExecute=="function"&&(i.executeCode=r.customExecute.toString()),r.outputSchema)try{if(typeof r.outputSchema._def<"u"){const v=G(r.outputSchema,{target:"openApi3"}),d=this._flattenJsonSchemaToVariables(v);i.outputSchema={jsonSchema:v,variables:d}}else i.outputSchema={schema:r.outputSchema}}catch(E){console.warn(`Failed to convert schema for ${n}:`,E.message)}const g=(this.resolvedToolsMap||{})[n];g?.toolIds&&(i.tools=g.toolIds),Object.keys(i).length>0&&(t[n]=i)}const s=[];for(const[n,r]of this.edges)if(typeof r=="string")s.push({source:n,target:r});else if(r.conditional){const c=this.conditionalCodeMap.get(n)||r.routes.toString(),l=this._inferConditionalTargets(r.routes),i=r.labels||{};for(const u of l){const g={source:n,target:u,data:{conditionalCode:c}};i[u]&&(g.label=i[u]),s.push(g)}}let o=null;if(this.stateSchema)try{o=G(this.stateSchema,{target:"openApi3"})}catch{o=this.stateSchema}return{nodes:e,edges:s,nodeConfigs:t,stateSchema:o}}_inferConditionalTargets(e){const t=e.toString(),s=new Set,o=/return\s+['"]([^'"]+)['"]/g;let n;for(;(n=o.exec(t))!==null;)s.add(n[1]);return[...s]}_flattenJsonSchemaToVariables(e,t=""){let s=e;if(e.$ref&&e.definitions){const o=e.$ref.replace("#/definitions/","");s=e.definitions[o]||e}return this._flattenSchema(s,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];const s=[],o=e.properties||{},n=e.required||[];for(const[r,c]of Object.entries(o)){const l=t?`${t}.${r}`:r,i=!n.includes(r);if(s.push({path:l,type:c.type||"unknown",label:c.description||this._formatLabel(r),optional:i}),c.type==="object"&&c.properties){const u=this._flattenSchema(c,l);s.push(...u)}if(c.type==="array"&&c.items?.type==="object"&&c.items.properties){const u=this._flattenSchema(c.items,`${l}[]`);s.push(...u)}}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[];const s=[];t.success!==void 0&&s.push(`Result: ${t.success?"passed":"failed"}`);for(const[o,n]of Object.entries(t))if(!(o==="success"||o==="raw"||o==="nextNode")){if(typeof n=="string"&&n.length<=80)s.push(`${o}: ${n}`);else if(Array.isArray(n)){const r=n.length,c=n.filter(i=>i?.passed===!0).length;if(n.some(i=>i?.passed!==void 0)){const i=r-c;s.push(`${o}: ${c}/${r} passed${i?`, ${i} failed`:""}`)}else s.push(`${o}: ${r} items`)}if(s.length>=4)break}return s}async run(e,t={}){if(!this.entryPoint)throw new Error("No entry point set for graph");const s=t.cwd||process.cwd();se({path:I(s,".env")});let o=t.config||{};if(!o||Object.keys(o).length===0)try{const p=I(s,".zibby.config.js");C(p)&&(o=(await import(p)).default||{})}catch{}process.env.EXECUTION_ID&&!o.agent?.strictMode&&(o.agent={...o.agent,strictMode:!0});let n=t.agentType;if(!n){const p=o?.agent;p?.provider?n=p.provider:p?.claude?n="claude":p?.cursor?n="cursor":n=process.env.AGENT_TYPE||"cursor"}const r=t.contextConfig||e?.config?.contextConfig||e?.config?.context||o?.context||{};if(this.stateSchema){const p=this.stateSchema.safeParse(t);if(!p.success){const m=p.error.issues.map(w=>`${w.path.join(".")}: ${w.message}`);throw console.error("\u274C Initial state validation failed:"),m.forEach(w=>console.error(` - ${w}`)),new Error(`State validation failed: ${m.join(", ")}`)}S.step("State validated against schema")}const c=le(),l=t.sessionPath||c;l||fe();const{sessionPath:i,sessionTimestamp:u,sessionId:g}=me({cwd:s,config:o,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:l,sessionTimestamp:t.sessionTimestamp}});S.step(`Session ${g}`);const E=await te.loadContext(t.specPath||"",s,r);Object.keys(E).length>0&&S.step(`Context loaded: ${Object.keys(E).join(", ")}`);let v=t.outputPath;!v&&t.specPath&&(e?.calculateOutputPath?v=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));const d=new X({...t,config:o,agentType:n,outputPath:v,sessionPath:i,sessionTimestamp:u,context:E,resolvedTools:this.resolvedToolsMap||{}}),A=new Map;try{await import("@zibby/skills")}catch{}const{getSkill:V}=await import("./skill-registry.js"),M=new Set;for(const[,p]of this.nodes)for(const m of p.config?.skills||[])M.add(m);for(const p of M){const m=V(p);if(typeof m?.middleware=="function")try{const w=await m.middleware();typeof w=="function"&&A.set(p,w)}catch{}}let a=this.entryPoint;const O=[];for(;a&&a!=="END";){const p=I(i,ae);if(C(p)){console.warn(`
5
- \u{1F6D1} Studio stop requested \u2014 ending workflow.`);try{oe(p)}catch{}if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return S.step("Workflow stopped by Studio"),{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}const m=this.nodes.get(a);if(!m)throw new Error(`Node '${a}' not found in graph`);const w=JSON.stringify({sessionPath:i,sessionTimestamp:u,currentNode:a,createdAt:new Date().toISOString(),config:d.get("config")}),J=I(i,H);W(J,w,"utf-8");const D=d.get("config")?.paths?.output||x,q=I(s,D,H);L(I(s,D),{recursive:!0});try{W(q,w,"utf-8")}catch{}const Y=t.onPipelineProgress;if(typeof Y=="function")try{Y({cwd:s,sessionPath:i,sessionId:g,outputBase:d.get("config")?.paths?.output||x,currentNode:a})}catch{}const K=(this.resolvedToolsMap||{})[a]||null;d.set("_currentNodeTools",K);const Q=d.get("nodeConfigs")||{};d.set("_currentNodeConfig",Q[a]||{}),S.nodeStart(a);const R=Date.now(),T=this.nodePrompts.get(a),j={state:d,invokeAgent:async(P={},_={})=>{let h=_.prompt||"";if(T)try{h=ne.compile(T,{noEscape:!0})(P)}catch(y){throw console.error(`\u274C Template rendering failed for node '${a}':`,y.message),new Error(`Template rendering failed: ${y.message}`,{cause:y})}else if(!h)throw new Error(`No prompt template configured for node '${a}' and no prompt provided in options`);const B={state:d.getAll(),images:_.images||[]},b={model:_.model||d.get("model"),workspace:d.get("workspace"),schema:_.schema,..._};return re(h,B,b)},agent:e,nodeId:a,promptTemplate:T,getPromptTemplate:()=>T,...d.getAll()};try{const P=(m.config?.skills||[]).map($=>A.get($)).filter(Boolean),_=[...this.middleware,...P];let h;_.length>0?h=await this._composeMiddleware(_,a,async()=>m.execute(j,d),d.getAll(),d):h=await m.execute(j,d);const B=Date.now()-R;if(O.push({node:a,success:h.success,duration:B,timestamp:new Date().toISOString()}),!h.success){if(String(h.error||"").includes("Stopped from Zibby Studio")){if(S.step("Workflow stopped by Studio"),d.set("stoppedByStudio",!0),e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}d.append("errors",{node:a,error:h.error});const N=m.config?.retries||0,F=`${a}_retries`,k=d.getAll()[F]||0;if(k<N){S.stepInfo(`Retrying (attempt ${k+1}/${N})`),d.update({[F]:k+1,[`${a}_raw`]:h.raw});continue}throw S.nodeFailed(a,h.error,{duration:B}),new Error(`Node '${a}' failed after ${k} attempts: ${h.error}`)}d.update({[a]:h.output});const b=this._summarizeNodeOutput(a,h.output);S.nodeComplete(a,{duration:B,details:b});const y=this.edges.get(a);if(!y)a="END";else if(y.conditional){const $=d.getAll(),N=y.routes($);S.route(a,N),a=N}else a=y}catch(P){throw S.isInsideNode&&S.nodeFailed(a,P.message,{duration:Date.now()-R}),d.set("failed",!0),d.set("failedAt",a),P}}S.graphComplete();const Z={success:!0,state:d.getAll(),executionLog:O};return e&&typeof e.onComplete=="function"&&await e.onComplete(Z),Z}}export{Te as WorkflowGraph,fe as clearInheritedSessionEnvForFreshRun,he as generateWorkflowSessionId,le as readStudioPinnedSessionPathFromEnv,me as resolveWorkflowSession,pe as shouldTrustInheritedSessionEnv,ue as syncProcessEnvToSession};
4
+ ${i}`)}}function le(){return process.env.ZIBBY_RUN_SOURCE==="studio"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function pe(){if(process.env.ZIBBY_RUN_SOURCE!=="studio")return;const f=process.env.ZIBBY_SESSION_PATH;if(!(f==null||String(f).trim()===""))try{return G(String(f).trim())}catch{return String(f).trim()}}function fe(){le()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function ue({sessionPath:f,sessionId:e}){f&&typeof f=="string"&&(process.env.ZIBBY_SESSION_PATH=f),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function he(f={}){const e=ce.map(n=>process.env[n]).find(Boolean),t=Math.random().toString(36).slice(2,6),s=e||`${Date.now()}_${t}`,o=f.paths?.sessionPrefix;return o?`${o}_${s}`:s}function me({cwd:f=process.cwd(),config:e={},initialState:t={},traceFrom:s="resolveWorkflowSession"}={}){let o=t.sessionPath,n=t.sessionTimestamp,r="initialState.sessionPath";if(!o&&process.env.ZIBBY_SESSION_PATH)try{const i=G(String(process.env.ZIBBY_SESSION_PATH));i&&(o=i,r="ZIBBY_SESSION_PATH")}catch{}let c;if(o)c=String(o).split(/[/\\]/).filter(Boolean).pop(),n==null&&(n=Date.now());else{const i=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(i)c=i,r="ZIBBY_SESSION_ID";else{const g=e.sessionId!=null?String(e.sessionId).trim():"";g&&g!=="last"?(c=g,r="config.sessionId"):(c=he(e),r="generated")}n=n??Date.now();const u=e.paths?.output||C;o=E(f,u,ie,c)}const p=!b(o);return p&&W(o,{recursive:!0}),de({traceFrom:s,sessionId:c,sessionPath:o,idSource:r,mkdirFresh:p}),ue({sessionPath:o,sessionId:c}),{sessionPath:o,sessionId:c,sessionTimestamp:n}}class Oe{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={}){const o=t instanceof L?t:new L(t);return o.name=e,this.nodes.set(e,o),s.prompt&&this.nodePrompts.set(e,s.prompt),Object.keys(s).length>0&&this.nodeOptions.set(e,s),this}addConditionalNode(e,t){const s=new te({...t,name:e});return this.nodes.set(e,s),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,o,n){let r=s;for(let c=e.length-1;c>=0;c--){const p=e[c],i=r;r=()=>p(t,i,o,n)}return r()}serialize(){const e=[],t={};for(const[n,r]of this.nodes){const c=this.nodeTypeMap.get(n)||n;e.push({id:n,type:c,data:{nodeType:c,label:n}});const p=r._isCustomCode||!1,i={};p&&typeof r.execute=="function"&&(i.customCode=r.execute.toString());const u=this.nodePrompts.get(n);if(u&&(i.prompt=u),typeof r.customExecute=="function"&&(i.executeCode=r.customExecute.toString()),r.outputSchema)try{if(typeof r.outputSchema._def<"u"){const P=H(r.outputSchema,{target:"openApi3"}),d=this._flattenJsonSchemaToVariables(P);i.outputSchema={jsonSchema:P,variables:d}}else i.outputSchema={schema:r.outputSchema}}catch(v){console.warn(`Failed to convert schema for ${n}:`,v.message)}const g=(this.resolvedToolsMap||{})[n];g?.toolIds&&(i.tools=g.toolIds),Object.keys(i).length>0&&(t[n]=i)}const s=[];for(const[n,r]of this.edges)if(typeof r=="string")s.push({source:n,target:r});else if(r.conditional){const c=this.conditionalCodeMap.get(n)||r.routes.toString(),p=this._inferConditionalTargets(r.routes),i=r.labels||{};for(const u of p){const g={source:n,target:u,data:{conditionalCode:c}};i[u]&&(g.label=i[u]),s.push(g)}}let o=null;if(this.stateSchema)try{o=H(this.stateSchema,{target:"openApi3"})}catch{o=this.stateSchema}return{nodes:e,edges:s,nodeConfigs:t,stateSchema:o}}_inferConditionalTargets(e){const t=e.toString(),s=new Set,o=/return\s+['"]([^'"]+)['"]/g;let n;for(;(n=o.exec(t))!==null;)s.add(n[1]);return[...s]}_flattenJsonSchemaToVariables(e,t=""){let s=e;if(e.$ref&&e.definitions){const o=e.$ref.replace("#/definitions/","");s=e.definitions[o]||e}return this._flattenSchema(s,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];const s=[],o=e.properties||{},n=e.required||[];for(const[r,c]of Object.entries(o)){const p=t?`${t}.${r}`:r,i=!n.includes(r);if(s.push({path:p,type:c.type||"unknown",label:c.description||this._formatLabel(r),optional:i}),c.type==="object"&&c.properties){const u=this._flattenSchema(c,p);s.push(...u)}if(c.type==="array"&&c.items?.type==="object"&&c.items.properties){const u=this._flattenSchema(c.items,`${p}[]`);s.push(...u)}}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[];const s=[];t.success!==void 0&&s.push(`Result: ${t.success?"passed":"failed"}`);for(const[o,n]of Object.entries(t))if(!(o==="success"||o==="raw"||o==="nextNode")){if(typeof n=="string"&&n.length<=80)s.push(`${o}: ${n}`);else if(Array.isArray(n)){const r=n.length,c=n.filter(i=>i?.passed===!0).length;if(n.some(i=>i?.passed!==void 0)){const i=r-c;s.push(`${o}: ${c}/${r} passed${i?`, ${i} failed`:""}`)}else s.push(`${o}: ${r} items`)}if(s.length>=4)break}return s}async run(e,t={}){if(!this.entryPoint)throw new Error("No entry point set for graph");const s=t.cwd||process.cwd();ne({path:E(s,".env")});let o=t.config||{};if(!o||Object.keys(o).length===0)try{const l=E(s,".zibby.config.js");b(l)&&(o=(await import(l)).default||{})}catch{}process.env.EXECUTION_ID&&!o.agent?.strictMode&&(o.agent={...o.agent,strictMode:!0});let n=t.agentType;if(!n){const l=o?.agent;l?.provider?n=l.provider:l?.claude?n="claude":l?.cursor?n="cursor":n=process.env.AGENT_TYPE||"cursor"}const r=t.contextConfig||e?.config?.contextConfig||e?.config?.context||o?.context||{};if(this.stateSchema){const l=this.stateSchema.safeParse(t);if(!l.success){const m=l.error.issues.map(w=>`${w.path.join(".")}: ${w.message}`);throw console.error("\u274C Initial state validation failed:"),m.forEach(w=>console.error(` - ${w}`)),new Error(`State validation failed: ${m.join(", ")}`)}S.step("State validated against schema")}const c=pe(),p=t.sessionPath||c;p||fe();const{sessionPath:i,sessionTimestamp:u,sessionId:g}=me({cwd:s,config:o,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:p,sessionTimestamp:t.sessionTimestamp}});S.step(`Session ${g}`);const v=await oe.loadContext(t.specPath||"",s,r);Object.keys(v).length>0&&S.step(`Context loaded: ${Object.keys(v).join(", ")}`);let P=t.outputPath;!P&&t.specPath&&(e?.calculateOutputPath?P=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));const d=new ee({...t,config:o,agentType:n,outputPath:P,sessionPath:i,sessionTimestamp:u,context:v,resolvedTools:this.resolvedToolsMap||{}}),x=new Map;try{await import("@zibby/skills")}catch{}const{getSkill:J}=await import("./skill-registry.js"),M=new Set;for(const[,l]of this.nodes)for(const m of l.config?.skills||[])M.add(m);for(const l of M){const m=J(l);if(typeof m?.middleware=="function")try{const w=await m.middleware();typeof w=="function"&&x.set(l,w)}catch{}}let a=this.entryPoint;const O=[];for(;a&&a!=="END";){const l=E(i,ae);if(b(l)){console.warn(`
5
+ \u{1F6D1} Studio stop requested \u2014 ending workflow.`);try{se(l)}catch{}if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return S.step("Workflow stopped by Studio"),{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}const m=this.nodes.get(a);if(!m)throw new Error(`Node '${a}' not found in graph`);const w=JSON.stringify({sessionPath:i,sessionTimestamp:u,currentNode:a,createdAt:new Date().toISOString(),config:d.get("config")}),q=E(i,V);z(q,w,"utf-8");const D=d.get("config")?.paths?.output||C,K=E(s,D,V);W(E(s,D),{recursive:!0});try{z(K,w,"utf-8")}catch{}const Y=t.onPipelineProgress;if(typeof Y=="function")try{Y({cwd:s,sessionPath:i,sessionId:g,outputBase:d.get("config")?.paths?.output||C,currentNode:a})}catch{}const Q=(this.resolvedToolsMap||{})[a]||null;d.set("_currentNodeTools",Q);const X=d.get("nodeConfigs")||{};d.set("_currentNodeConfig",X[a]||{}),S.nodeStart(a);const R=Date.now(),T=this.nodePrompts.get(a);if(!this._invokeAgent){const _=await import("./agents/index.js");this._invokeAgent=_.invokeAgent}const j=this._invokeAgent,F={state:d,invokeAgent:async(_={},I={})=>{let h=I.prompt||"";if(T)try{h=re.compile(T,{noEscape:!0})(_)}catch(y){throw console.error(`\u274C Template rendering failed for node '${a}':`,y.message),new Error(`Template rendering failed: ${y.message}`,{cause:y})}else if(!h)throw new Error(`No prompt template configured for node '${a}' and no prompt provided in options`);const B={state:d.getAll(),images:I.images||[]},A={model:I.model||d.get("model"),workspace:d.get("workspace"),schema:I.schema,...I};return j(h,B,A)},_coreInvokeAgent:j,agent:e,nodeId:a,promptTemplate:T,getPromptTemplate:()=>T,...d.getAll()};try{const _=(m.config?.skills||[]).map($=>x.get($)).filter(Boolean),I=[...this.middleware,..._];let h;I.length>0?h=await this._composeMiddleware(I,a,async()=>m.execute(F,d),d.getAll(),d):h=await m.execute(F,d);const B=Date.now()-R;if(O.push({node:a,success:h.success,duration:B,timestamp:new Date().toISOString()}),!h.success){if(String(h.error||"").includes("Stopped from Zibby Studio")){if(S.step("Workflow stopped by Studio"),d.set("stoppedByStudio",!0),e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}d.append("errors",{node:a,error:h.error});const N=m.config?.retries||0,U=`${a}_retries`,k=d.getAll()[U]||0;if(k<N){S.stepInfo(`Retrying (attempt ${k+1}/${N})`),d.update({[U]:k+1,[`${a}_raw`]:h.raw});continue}throw S.nodeFailed(a,h.error,{duration:B}),new Error(`Node '${a}' failed after ${k} attempts: ${h.error}`)}d.update({[a]:h.output});const A=this._summarizeNodeOutput(a,h.output);S.nodeComplete(a,{duration:B,details:A});const y=this.edges.get(a);if(!y)a="END";else if(y.conditional){const $=d.getAll(),N=y.routes($);S.route(a,N),a=N}else a=y}catch(_){throw S.isInsideNode&&S.nodeFailed(a,_.message,{duration:Date.now()-R}),d.set("failed",!0),d.set("failedAt",a),_}}S.graphComplete();const Z={success:!0,state:d.getAll(),executionLog:O};return e&&typeof e.onComplete=="function"&&await e.onComplete(Z),Z}}export{Oe as WorkflowGraph,fe as clearInheritedSessionEnvForFreshRun,he as generateWorkflowSessionId,pe as readStudioPinnedSessionPathFromEnv,me as resolveWorkflowSession,le as shouldTrustInheritedSessionEnv,ue as syncProcessEnvToSession};
@@ -1 +1 @@
1
- import{WorkflowGraph as t}from"./graph.js";import{Node as l,ConditionalNode as a}from"./node.js";import{WorkflowState as p}from"./state.js";import{OutputParser as s,SchemaTypes as f}from"./output-parser.js";import{compileGraph as m,validateGraphConfig as d,extractSteps as S,CompilationError as x}from"./graph-compiler.js";import{registerNode as k,getNodeImpl as A,hasNode as C,listNodeTypes as h,getNodeTemplate as T}from"./node-registry.js";import{resolveNodeTools as u,getResolvedToolDefinitions as v,NODE_DEFAULT_TOOLS as O}from"./tool-resolver.js";import{registerSkill as w,getSkill as D,hasSkill as E,getAllSkills as G,listSkillIds as W}from"./skill-registry.js";import{generateWorkflowCode as L,generateNodeConfigsJson as _}from"./code-generator.js";import{hasAgentCall as J}from"../utils/ast-utils.js";import{invokeAgent as R,getAgentStrategy as U,CursorAgentStrategy as b,ClaudeAgentStrategy as j,AgentStrategy as q}from"./agents/index.js";export{q as AgentStrategy,j as ClaudeAgentStrategy,x as CompilationError,a as ConditionalNode,b as CursorAgentStrategy,O as NODE_DEFAULT_TOOLS,l as Node,s as OutputParser,f as SchemaTypes,t as WorkflowGraph,p as WorkflowState,m as compileGraph,S as extractSteps,_ as generateNodeConfigsJson,L as generateWorkflowCode,U as getAgentStrategy,G as getAllSkills,A as getNodeImpl,T as getNodeTemplate,v as getResolvedToolDefinitions,D as getSkill,J as hasAgentCall,C as hasNode,E as hasSkill,R as invokeAgent,h as listNodeTypes,W as listSkillIds,k as registerNode,w as registerSkill,u as resolveNodeTools,d as validateGraphConfig};
1
+ import{WorkflowGraph as r}from"./graph.js";import{Node as l,ConditionalNode as p}from"./node.js";import{WorkflowState as a}from"./state.js";import{OutputParser as f,SchemaTypes as g}from"./output-parser.js";import{compileGraph as n,validateGraphConfig as d,extractSteps as x,CompilationError as S}from"./graph-compiler.js";import{registerNode as k,getNodeImpl as h,hasNode as T,listNodeTypes as A,getNodeTemplate as C}from"./node-registry.js";import{resolveNodeTools as y,getResolvedToolDefinitions as O,NODE_DEFAULT_TOOLS as c}from"./tool-resolver.js";import{registerSkill as D,getSkill as E,hasSkill as G,getAllSkills as W,listSkillIds as u}from"./skill-registry.js";import{generateWorkflowCode as L,generateNodeConfigsJson as _}from"./code-generator.js";import{hasAgentCall as J}from"../utils/ast-utils.js";import{AgentStrategy as R}from"./agents/base.js";import{invokeAgent as b,getAgentStrategy as j}from"./agents/index.js";export{R as AgentStrategy,S as CompilationError,p as ConditionalNode,c as NODE_DEFAULT_TOOLS,l as Node,f as OutputParser,g as SchemaTypes,r as WorkflowGraph,a as WorkflowState,n as compileGraph,x as extractSteps,_ as generateNodeConfigsJson,L as generateWorkflowCode,j as getAgentStrategy,W as getAllSkills,h as getNodeImpl,C as getNodeTemplate,O as getResolvedToolDefinitions,E as getSkill,J as hasAgentCall,T as hasNode,G as hasSkill,b as invokeAgent,A as listNodeTypes,u as listSkillIds,k as registerNode,D as registerSkill,y as resolveNodeTools,d as validateGraphConfig};
@@ -1,4 +1,4 @@
1
- const s=new Map;function p(t,e){s.set(t,e)}function m(t){return s.get(t)}function x(t){return s.has(t)}function h(){return Array.from(s.keys())}function S(t){const e=s.get(t);return e?e.factory&&typeof e.create=="function"?e.create.toString():typeof e.execute=="function"?e.execute.toString():typeof e=="function"?e.toString():null:null}p("ai_agent",{name:"ai_agent",factory:!0,create:(t,e={})=>({name:t,execute:async r=>{const{invokeAgent:n}=await import("./agents/index.js"),c=e.extraPromptInstructions||"Execute the task based on the current state.",i=y(c,r),o=await n(i,{cwd:r.workspace||process.cwd(),model:r.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:o,nodeId:t},raw:typeof o=="string"?o:o.raw}}})});function g(t){const e=/@([\w.]+)/g,r=new Set;let n;for(;(n=e.exec(t))!==null;)r.add(n[1]);return Array.from(r)}function d(t,e){const r=e.split(".");let n=t;for(const c of r){if(n==null)return;n=n[c]}return n}function w(t){return t==null?"[not available]":typeof t=="string"?t:typeof t=="object"?t.raw&&typeof t.raw=="string"?t.raw:JSON.stringify(t,null,2):String(t)}function y(t,e){const r=g(t);if(r.length===0)return t;const n=[],c=new Set;for(const i of r){const o=i.split(".")[0];if(c.has(o))continue;const f=d(e,i);if(f!==void 0){const u=w(f),a=i.replace(/_/g," ").replace(/\b\w/g,l=>l.toUpperCase());n.push(`## ${a}
1
+ const f=new Map;function p(t,e){f.set(t,e)}function y(t){return f.get(t)}function x(t){return f.has(t)}function h(){return Array.from(f.keys())}function S(t){const e=f.get(t);return e?e.factory&&typeof e.create=="function"?e.create.toString():typeof e.execute=="function"?e.execute.toString():typeof e=="function"?e.toString():null:null}p("ai_agent",{name:"ai_agent",factory:!0,create:(t,e={})=>({name:t,execute:async r=>{let n=r?._coreInvokeAgent;n||(n=(await import("./agents/index.js")).invokeAgent);const c=e.extraPromptInstructions||"Execute the task based on the current state.",i=w(c,r),o=await n(i,{cwd:r.workspace||process.cwd(),model:r.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:o,nodeId:t},raw:typeof o=="string"?o:o.raw}}})});function g(t){const e=/@([\w.]+)/g,r=new Set;let n;for(;(n=e.exec(t))!==null;)r.add(n[1]);return Array.from(r)}function d(t,e){const r=e.split(".");let n=t;for(const c of r){if(n==null)return;n=n[c]}return n}function m(t){return t==null?"[not available]":typeof t=="string"?t:typeof t=="object"?t.raw&&typeof t.raw=="string"?t.raw:JSON.stringify(t,null,2):String(t)}function w(t,e){const r=g(t);if(r.length===0)return t;const n=[],c=new Set;for(const i of r){const o=i.split(".")[0];if(c.has(o))continue;const s=d(e,i);if(s!==void 0){const u=m(s),a=i.replace(/_/g," ").replace(/\b\w/g,l=>l.toUpperCase());n.push(`## ${a}
2
2
  ${u}`),i.includes(".")||c.add(o)}}return n.length===0?t:`${t}
3
3
 
4
4
  ---
@@ -6,4 +6,4 @@ ${u}`),i.includes(".")||c.add(o)}}return n.length===0?t:`${t}
6
6
 
7
7
  ${n.join(`
8
8
 
9
- `)}`}export{m as getNodeImpl,S as getNodeTemplate,x as hasNode,h as listNodeTypes,p as registerNode};
9
+ `)}`}export{y as getNodeImpl,S as getNodeTemplate,x as hasNode,h as listNodeTypes,p as registerNode};
@@ -1,5 +1,5 @@
1
- import{OutputParser as _}from"./output-parser.js";import{writeFileSync as f,readFileSync as N,existsSync as C,mkdirSync as b}from"fs";import{join as d,dirname as v}from"path";import h from"chalk";import{invokeAgent as A}from"./agents/index.js";import{logger as u}from"../utils/logger.js";import{timeline as I}from"../utils/timeline.js";import{SESSION_INFO_FILE as $}from"./constants.js";class P{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 _(e.outputSchema):null,this.retries=e.retries||0,this.onComplete=e.onComplete,this.customExecute=e.execute}async execute(e,o){const a=()=>o&&typeof o.getAll=="function"?o.getAll():e,S=t=>o&&typeof o.get=="function"?o.get(t):e?.[t];if(typeof this.customExecute=="function"){u.info("\u26A1 Using custom execute method (skipping LLM)");try{const t=await this.customExecute(e);return typeof t=="object"&&t!==null&&t.success===!1?{success:!1,error:t.error||"Node execution failed",raw:t.raw||null}:this.isZodSchema?(u.debug("Validating return value against outputSchema..."),{success:!0,output:this.outputSchema.parse(t),raw:null}):{success:!0,output:t,raw:null}}catch(t){return u.error(`\u274C Node '${this.name}' execution failed: ${t.message}`),t.name==="ZodError"&&u.error(`Schema validation errors: ${JSON.stringify(t.errors,null,2)}`),{success:!1,error:t.message,raw:null}}}let m=typeof this.prompt=="function"?this.prompt(a()):this.prompt;const g=S("_skillHints");g&&(m=`${g}
1
+ import{OutputParser as A}from"./output-parser.js";import{writeFileSync as d,readFileSync as C,existsSync as $,mkdirSync as E}from"fs";import{join as g,dirname as b}from"path";import h from"chalk";import{logger as u}from"../utils/logger.js";import{timeline as I}from"../utils/timeline.js";import{SESSION_INFO_FILE as x}from"./constants.js";class P{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 A(e.outputSchema):null,this.retries=e.retries||0,this.onComplete=e.onComplete,this.customExecute=e.execute}async execute(e,o){const a=()=>o&&typeof o.getAll=="function"?o.getAll():e,S=t=>o&&typeof o.get=="function"?o.get(t):e?.[t];if(typeof this.customExecute=="function"){u.info("\u26A1 Using custom execute method (skipping LLM)");try{const t=await this.customExecute(e);return typeof t=="object"&&t!==null&&t.success===!1?{success:!1,error:t.error||"Node execution failed",raw:t.raw||null}:this.isZodSchema?(u.debug("Validating return value against outputSchema..."),{success:!0,output:this.outputSchema.parse(t),raw:null}):{success:!0,output:t,raw:null}}catch(t){return u.error(`\u274C Node '${this.name}' execution failed: ${t.message}`),t.name==="ZodError"&&u.error(`Schema validation errors: ${JSON.stringify(t.errors,null,2)}`),{success:!1,error:t.message,raw:null}}}let m=typeof this.prompt=="function"?this.prompt(a()):this.prompt;const w=S("_skillHints");w&&(m=`${w}
2
2
 
3
- ${m}`);const w=a(),O=w.cwd||process.cwd(),p=w.sessionPath;try{if(p){const t=d(p,$);if(C(t)){const c=JSON.parse(N(t,"utf-8"));c.currentNode=this.name,f(t,JSON.stringify(c,null,2),"utf-8")}const i=d(p,"..",$);if(C(i))try{const c=JSON.parse(N(i,"utf-8"));c.currentNode=this.name,f(i,JSON.stringify(c,null,2),"utf-8")}catch{}}}catch(t){u.debug(`Could not update session info: ${t.message}`)}let y=null;for(let t=0;t<=this.retries;t++)try{u.debug(`Node.execute attempt ${t} for '${this.name}'`);const i=a(),c=i.config||{},J={state:i},k={workspace:O,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],sessionPath:p,config:c,nodeName:this.name,timeout:this.config?.timeout||3e5},n=await A(m,J,k);let r,l;if(typeof n=="string"?(r=n,l=null):n.structured?(r=n.raw||JSON.stringify(n.structured,null,2),l=n.structured):(r=n.raw||JSON.stringify(n,null,2),l=n.extracted||null),p)try{const s=d(p,this.name,"raw_stream_output.txt");b(v(s),{recursive:!0}),f(s,typeof r=="string"?r:JSON.stringify(r),"utf-8")}catch(s){u.debug(`Could not save raw output: ${s.message}`)}if(this.isZodSchema&&l){console.log(`
4
- \u{1F50D} ${h.cyan("Validated output:")} ${h.white(JSON.stringify(l,null,2))}`);let s=l;if(typeof this.onComplete=="function")try{s=await this.onComplete(a(),l)}catch(E){u.warn(`onComplete hook failed: ${E.message}`)}return{success:!0,output:s,raw:r}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(a(),{raw:r}),raw:r}}catch(s){throw new Error(`onComplete failed: ${s.message}`,{cause:s})}if(this.parser){const s=this.parser.parse(r);return console.log(`
5
- \u{1F50D} ${h.cyan("Parsed output:")} ${h.white(JSON.stringify(s,null,2))}`),I.step("Output parsed"),{success:!0,output:s,raw:r}}return{success:!0,output:r,raw:r}}catch(i){y=i,t<this.retries&&u.info(`Node '${this.name}' failed, retrying (${t+1}/${this.retries})...`)}return{success:!1,error:y.message,raw:null}}}class M extends P{constructor(e){super({...e,_isCustomCode:!0}),this.condition=e.condition}async execute(e,o){const a=o&&typeof o.getAll=="function"?o.getAll():e;return{success:!0,output:{nextNode:this.condition(a)},raw:null}}}export{M as ConditionalNode,P as Node};
3
+ ${m}`);const y=a(),k=y.cwd||process.cwd(),p=y.sessionPath;try{if(p){const t=g(p,x);if($(t)){const c=JSON.parse(C(t,"utf-8"));c.currentNode=this.name,d(t,JSON.stringify(c,null,2),"utf-8")}const n=g(p,"..",x);if($(n))try{const c=JSON.parse(C(n,"utf-8"));c.currentNode=this.name,d(n,JSON.stringify(c,null,2),"utf-8")}catch{}}}catch(t){u.debug(`Could not update session info: ${t.message}`)}let N=null;for(let t=0;t<=this.retries;t++)try{u.debug(`Node.execute attempt ${t} for '${this.name}'`);const n=a(),c=n.config||{},J={state:n},_={workspace:k,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],sessionPath:p,config:c,nodeName:this.name,timeout:this.config?.timeout||3e5};let f=e?._coreInvokeAgent;f||(f=(await import("./agents/index.js")).invokeAgent);const i=await f(m,J,_);let r,l;if(typeof i=="string"?(r=i,l=null):i.structured?(r=i.raw||JSON.stringify(i.structured,null,2),l=i.structured):(r=i.raw||JSON.stringify(i,null,2),l=i.extracted||null),p)try{const s=g(p,this.name,"raw_stream_output.txt");E(b(s),{recursive:!0}),d(s,typeof r=="string"?r:JSON.stringify(r),"utf-8")}catch(s){u.debug(`Could not save raw output: ${s.message}`)}if(this.isZodSchema&&l){console.log(`
4
+ \u{1F50D} ${h.cyan("Validated output:")} ${h.white(JSON.stringify(l,null,2))}`);let s=l;if(typeof this.onComplete=="function")try{s=await this.onComplete(a(),l)}catch(v){u.warn(`onComplete hook failed: ${v.message}`)}return{success:!0,output:s,raw:r}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(a(),{raw:r}),raw:r}}catch(s){throw new Error(`onComplete failed: ${s.message}`,{cause:s})}if(this.parser){const s=this.parser.parse(r);return console.log(`
5
+ \u{1F50D} ${h.cyan("Parsed output:")} ${h.white(JSON.stringify(s,null,2))}`),I.step("Output parsed"),{success:!0,output:s,raw:r}}return{success:!0,output:r,raw:r}}catch(n){N=n,t<this.retries&&u.info(`Node '${this.name}' failed, retrying (${t+1}/${this.retries})...`)}return{success:!1,error:N.message,raw:null}}}class z extends P{constructor(e){super({...e,_isCustomCode:!0}),this.condition=e.condition}async execute(e,o){const a=o&&typeof o.getAll=="function"?o.getAll():e;return{success:!0,output:{nextNode:this.condition(a)},raw:null}}}export{z as ConditionalNode,P as Node};
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "@zibby/core",
3
+ "version": "0.1.25",
4
+ "description": "Core test automation engine with multi-agent and multi-MCP support",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./backend-client.js": "./src/backend-client.js",
10
+ "./sync": "./src/sync/index.js",
11
+ "./framework/graph.js": "./src/framework/graph.js",
12
+ "./framework/state.js": "./src/framework/state.js",
13
+ "./framework/node.js": "./src/framework/node.js",
14
+ "./framework/graph-compiler.js": "./src/framework/graph-compiler.js",
15
+ "./framework/node-registry.js": "./src/framework/node-registry.js",
16
+ "./framework/skill-registry.js": "./src/framework/skill-registry.js",
17
+ "./framework/tool-resolver.js": "./src/framework/tool-resolver.js",
18
+ "./framework/function-bridge.js": "./src/framework/function-bridge.js",
19
+ "./framework/function-skill-registry.js": "./src/framework/function-skill-registry.js",
20
+ "./framework/code-generator.js": "./src/framework/code-generator.js",
21
+ "./utils/ast-utils.js": "./src/utils/ast-utils.js",
22
+ "./utils/mcp-config-writer.js": "./src/utils/mcp-config-writer.js",
23
+ "./utils/node-schema-parser.js": "./src/utils/node-schema-parser.js",
24
+ "./utils/parallel-config.js": "./src/utils/parallel-config.js",
25
+ "./utils/run-registry.js": "./src/utils/run-registry.js",
26
+ "./utils/run-index-merge.js": "./src/utils/run-index-merge.js",
27
+ "./utils/run-index-post-cli.js": "./src/utils/run-index-post-cli.js",
28
+ "./utils/run-state-session.js": "./src/utils/run-state-session.js",
29
+ "./utils/session-state-live-runs.js": "./src/utils/session-state-live-runs.js",
30
+ "./utils/mission-control-from-run-states.js": "./src/utils/mission-control-from-run-states.js",
31
+ "./utils/live-frame-discovery.js": "./src/utils/live-frame-discovery.js",
32
+ "./utils/run-capacity-coordinator.js": "./src/utils/run-capacity-coordinator.js",
33
+ "./utils/run-capacity-queue.js": "./src/utils/run-capacity-queue.js",
34
+ "./utils/cursor-mcp-isolated-home.js": "./src/utils/cursor-mcp-isolated-home.js",
35
+ "./constants/zibby-scratch.js": "./src/constants/zibby-scratch.js",
36
+ "./templates/browser-test-automation/pipeline-ids.js": "./templates/browser-test-automation/pipeline-ids.js",
37
+ "./templates/browser-test-automation/run-index.mjs": "./templates/browser-test-automation/run-index.mjs",
38
+ "./templates/register-nodes.js": "./templates/register-nodes.js",
39
+ "./templates": "./templates/index.js",
40
+ "./templates/*": "./templates/*",
41
+ "./package.json": "./package.json"
42
+ },
43
+ "scripts": {
44
+ "build": "node ../scripts/build.mjs",
45
+ "test": "vitest run --exclude '**/memory/**'",
46
+ "test:watch": "vitest",
47
+ "test:state-schema": "vitest run src/framework/__tests__/state-schema.test.js",
48
+ "test:state-schema:e2e": "node src/framework/__tests__/state-schema.e2e.test.js",
49
+ "export:workflows": "node scripts/export-default-workflows.js",
50
+ "lint": "eslint .",
51
+ "lint:fix": "eslint --fix ."
52
+ },
53
+ "keywords": [
54
+ "testing",
55
+ "automation",
56
+ "playwright",
57
+ "ai",
58
+ "mcp"
59
+ ],
60
+ "author": "Zibby",
61
+ "license": "MIT",
62
+ "homepage": "https://zibby.app",
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "https://github.com/ZibbyHQ/zibby-agent"
66
+ },
67
+ "bugs": {
68
+ "url": "https://github.com/ZibbyHQ/zibby-agent/issues"
69
+ },
70
+ "files": [
71
+ "src/",
72
+ "templates/",
73
+ "!templates/**/__tests__/",
74
+ "!templates/**/*.test.js",
75
+ "!templates/**/*.spec.js",
76
+ "README.md",
77
+ "LICENSE"
78
+ ],
79
+ "engines": {
80
+ "node": ">=18.0.0"
81
+ },
82
+ "dependencies": {
83
+ "@anthropic-ai/claude-agent-sdk": "^0.2.104",
84
+ "@anthropic-ai/sdk": "^0.88.0",
85
+ "@modelcontextprotocol/sdk": "^1.29.0",
86
+ "@openai/codex-sdk": "^0.120.0",
87
+ "@playwright/mcp": "^0.0.70",
88
+ "@zibby/mcp-browser": "^0.1.6",
89
+ "acorn": "^8.15.0",
90
+ "acorn-walk": "^8.3.5",
91
+ "axios": "^1.15.0",
92
+ "chalk": "^5.3.0",
93
+ "dotenv": "^17.4.1",
94
+ "handlebars": "^4.7.9",
95
+ "zod": "^4.3.6",
96
+ "zod-to-json-schema": "^3.25.2"
97
+ },
98
+ "peerDependencies": {
99
+ "@playwright/test": ">=1.49.0",
100
+ "playwright": ">=1.49.0"
101
+ },
102
+ "devDependencies": {
103
+ "@playwright/test": "^1.59.1",
104
+ "esbuild": "^0.28.0",
105
+ "vitest": "^4.1.4"
106
+ }
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,10 +9,10 @@ import {
9
9
  appendRunIndexRecord,
10
10
  readRunIndexRecordsFromFile,
11
11
  resolveRunIndexPath,
12
- } from '../../src/utils/run-registry.js';
13
- import { mergeSessionRunState, readSessionRunState } from '../../src/utils/run-state-session.js';
14
- import { partitionRunIndexBySession, runIndexSessionEntryIsLive } from '../../src/utils/run-index-merge.js';
15
- import { DEFAULT_OUTPUT_BASE, SESSIONS_DIR } from '../../src/framework/constants.js';
12
+ } from '../../dist/utils/run-registry.js';
13
+ import { mergeSessionRunState, readSessionRunState } from '../../dist/utils/run-state-session.js';
14
+ import { partitionRunIndexBySession, runIndexSessionEntryIsLive } from '../../dist/utils/run-index-merge.js';
15
+ import { DEFAULT_OUTPUT_BASE, SESSIONS_DIR } from '../../dist/framework/constants.js';
16
16
  import { BROWSER_TEST_PIPELINE_NODE_IDS } from './pipeline-ids.js';
17
17
 
18
18
  export { BROWSER_TEST_PIPELINE_NODE_IDS };
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { randomBytes } from 'crypto';
4
4
  import { z } from 'zod';
5
- import { adfToText } from '../../../src/utils/adf-converter.js';
5
+ import { adfToText } from '../../../dist/utils/adf-converter.js';
6
6
 
7
7
  const generateId = () => randomBytes(16).toString('hex');
8
8
 
@@ -49,7 +49,7 @@ const AnalysisOutputSchema = z.object({
49
49
 
50
50
  affectedFiles: z.array(z.string())
51
51
  .nullable()
52
- .describe('Files that will likely need changes (null if unknown). Each path MUST start with a top-level repo directory name (e.g. "my-api/src/...")'),
52
+ .describe('Files that will likely need changes (null if unknown). Each path MUST start with a top-level repo directory name (e.g. "my-api/dist/...")'),
53
53
 
54
54
  complexity: z.enum(['simple', 'medium', 'complex', 'unknown'])
55
55
  .describe('Estimated complexity of the implementation'),
@@ -63,7 +63,7 @@ const AnalysisOutputSchema = z.object({
63
63
  .describe('Brief summary of the analysis findings'),
64
64
 
65
65
  implementationPlan: z.string()
66
- .describe('Markdown implementation plan for the code generation agent. Include: 1) A brief summary of what to build, 2) Which top-level repositories need changes — MUST be the exact directory names from Repository Information, NEVER internal sub-modules or Maven modules, 3) An ordered TODO checklist where every file path starts with a top-level repo name (e.g. "In my-api/src/.../Foo.java" NOT "src/.../Foo.java"), 4) Key technical details like function signatures, patterns to follow, and gotchas. This will be passed directly to the coding agent as its instructions.')
66
+ .describe('Markdown implementation plan for the code generation agent. Include: 1) A brief summary of what to build, 2) Which top-level repositories need changes — MUST be the exact directory names from Repository Information, NEVER internal sub-modules or Maven modules, 3) An ordered TODO checklist where every file path starts with a top-level repo name (e.g. "In my-api/dist/.../Foo.java" NOT "src/.../Foo.java"), 4) Key technical details like function signatures, patterns to follow, and gotchas. This will be passed directly to the coding agent as its instructions.')
67
67
  });
68
68
 
69
69
  // Node output schema (what this node returns to state)
@@ -1,5 +1,5 @@
1
1
  import axios from 'axios';
2
- import { adfToText } from '../../../src/utils/adf-converter.js';
2
+ import { adfToText } from '../../../dist/utils/adf-converter.js';
3
3
  import { z } from 'zod';
4
4
 
5
5
  const CreatePROutputSchema = z.object({
@@ -10,7 +10,7 @@ import { existsSync, readFileSync } from 'fs';
10
10
  import Handlebars from 'handlebars';
11
11
  import { invokeAgent } from '@zibby/core';
12
12
  import { generatePRMeta } from './services/prMetaService.js';
13
- import { adfToText } from '../../../src/utils/adf-converter.js';
13
+ import { adfToText } from '../../../dist/utils/adf-converter.js';
14
14
  import { z } from 'zod';
15
15
 
16
16
  const CodeImplementationOutputSchema = z.object({
@@ -11,7 +11,7 @@
11
11
  import { invokeAgent } from '@zibby/core';
12
12
  import { z } from 'zod';
13
13
  import { randomBytes } from 'crypto';
14
- import { adfToText } from '../../../src/utils/adf-converter.js';
14
+ import { adfToText } from '../../../dist/utils/adf-converter.js';
15
15
 
16
16
  // Generate a simple unique ID
17
17
  const generateId = () => randomBytes(8).toString('hex');
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { z } from 'zod';
6
6
  import { invokeAgent } from '@zibby/core';
7
- import { adfToText } from '../../../../src/utils/adf-converter.js';
7
+ import { adfToText } from '../../../../dist/utils/adf-converter.js';
8
8
 
9
9
  const PRMetaSchema = z.object({
10
10
  prTitle: z.string().describe('Short PR title that includes the ticket key'),
@@ -7,7 +7,7 @@
7
7
  * Usage: import '@zibby/core/templates/register-nodes.js';
8
8
  */
9
9
 
10
- import { registerNode } from '../src/framework/node-registry.js';
10
+ import { registerNode } from '../dist/framework/node-registry.js';
11
11
  import { setupNode } from './code-analysis/nodes/setup-node.js';
12
12
  import { analyzeTicketNode } from './code-analysis/nodes/analyze-ticket-node.js';
13
13
  import { generateCodeNode, implementCodeNode } from './code-analysis/nodes/generate-code-node.js';