@zibby/core 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/base.js +17 -0
- package/dist/backend-client.js +1 -0
- package/dist/constants/tool-names.js +1 -0
- package/dist/constants/zibby-scratch.js +1 -0
- package/dist/constants.js +1 -0
- package/dist/enrichment/base.js +1 -0
- package/dist/enrichment/enrichers/accessibility-enricher.js +1 -0
- package/dist/enrichment/enrichers/dom-enricher.js +1 -0
- package/dist/enrichment/enrichers/page-state-enricher.js +1 -0
- package/dist/enrichment/enrichers/position-enricher.js +1 -0
- package/dist/enrichment/index.js +1 -0
- package/dist/enrichment/mcp-integration.js +1 -0
- package/dist/enrichment/mcp-ref-enricher.js +1 -0
- package/dist/enrichment/pipeline.js +3 -0
- package/dist/enrichment/trace-text-enricher.js +1 -0
- package/dist/framework/agents/assistant-strategy.js +5 -0
- package/dist/framework/agents/base.js +1 -0
- package/dist/framework/agents/claude-strategy.js +4 -0
- package/dist/framework/agents/codex-strategy.js +4 -0
- package/dist/framework/agents/cursor-strategy.js +32 -0
- package/dist/framework/agents/gemini-strategy.js +11 -0
- package/dist/framework/agents/index.js +13 -0
- package/dist/framework/agents/middleware/assistant-round-pipeline.js +3 -0
- package/dist/framework/agents/providers/base.js +1 -0
- package/dist/framework/agents/providers/index.js +1 -0
- package/dist/framework/agents/providers/openai-transport.js +2 -0
- package/dist/framework/agents/providers/openai.js +1 -0
- package/dist/framework/agents/providers/transport-base.js +1 -0
- package/dist/framework/agents/utils/auth-resolver.js +1 -0
- package/dist/framework/agents/utils/cursor-output-formatter.js +1 -0
- package/dist/framework/agents/utils/openai-proxy-formatter.js +9 -0
- package/dist/framework/agents/utils/payload-budget.js +3 -0
- package/dist/framework/agents/utils/structured-output-formatter.js +21 -0
- package/dist/framework/code-generator.js +10 -0
- package/dist/framework/constants.js +1 -0
- package/dist/framework/context-loader.js +5 -0
- package/dist/framework/function-bridge.js +2 -0
- package/dist/framework/function-skill-registry.js +1 -0
- package/dist/framework/graph-compiler.js +1 -0
- package/dist/framework/graph.js +5 -0
- package/dist/framework/index.js +1 -0
- package/dist/framework/mcp-client.js +2 -0
- package/dist/framework/node-registry.js +9 -0
- package/dist/framework/node.js +5 -0
- package/dist/framework/output-parser.js +3 -0
- package/dist/framework/skill-registry.js +1 -0
- package/dist/framework/state-utils.js +1 -0
- package/dist/framework/state.js +1 -0
- package/dist/framework/tool-resolver.js +1 -0
- package/dist/index.js +8 -0
- package/dist/runtime/generation/base.js +1 -0
- package/dist/runtime/generation/index.js +3 -0
- package/dist/runtime/generation/mcp-ref-strategy.js +41 -0
- package/dist/runtime/generation/stable-id-strategy.js +16 -0
- package/dist/runtime/stable-id-runtime.js +1 -0
- package/dist/runtime/verification/base.js +1 -0
- package/dist/runtime/verification/index.js +3 -0
- package/dist/runtime/verification/playwright-json-strategy.js +1 -0
- package/dist/runtime/zibby-runtime.js +1 -0
- package/dist/sync/index.js +1 -0
- package/dist/sync/uploader.js +1 -0
- package/dist/tools/run-playwright-test.js +5 -0
- package/dist/utils/adf-converter.js +7 -0
- package/dist/utils/ast-utils.js +1 -0
- package/dist/utils/ci-setup.js +5 -0
- package/dist/utils/cursor-mcp-isolated-home.js +1 -0
- package/dist/utils/cursor-utils.js +18 -0
- package/dist/utils/live-frame-discovery.js +1 -0
- package/dist/utils/logger.js +1 -0
- package/dist/utils/mcp-config-writer.js +10 -0
- package/dist/utils/mission-control-from-run-states.js +1 -0
- package/dist/utils/node-schema-parser.js +1 -0
- package/dist/utils/parallel-config.js +1 -0
- package/dist/utils/post-process-events.js +1 -0
- package/dist/utils/result-handler.js +1 -0
- package/{src → dist}/utils/ripple-effect.js +3 -12
- package/dist/utils/run-capacity-coordinator.js +1 -0
- package/dist/utils/run-capacity-queue.js +2 -0
- package/dist/utils/run-index-merge.js +1 -0
- package/dist/utils/run-index-post-cli.js +1 -0
- package/dist/utils/run-registry.js +3 -0
- package/dist/utils/run-state-session.js +2 -0
- package/dist/utils/selector-generator.js +4 -0
- package/dist/utils/session-state-constants.js +1 -0
- package/dist/utils/session-state-live-runs.js +1 -0
- package/dist/utils/streaming-parser.js +4 -0
- package/dist/utils/test-post-processor.js +18 -0
- package/dist/utils/timeline.js +14 -0
- package/dist/utils/trace-parser.js +2 -0
- package/dist/utils/video-organizer.js +3 -0
- package/package.json +49 -35
- package/templates/browser-test-automation/README.md +29 -7
- package/templates/browser-test-automation/chat.mjs +36 -0
- package/templates/browser-test-automation/graph.mjs +5 -9
- package/templates/browser-test-automation/nodes/execute-live.mjs +30 -58
- package/templates/browser-test-automation/nodes/generate-script.mjs +32 -12
- package/templates/browser-test-automation/nodes/utils.mjs +153 -10
- package/templates/browser-test-automation/pipeline-ids.js +12 -0
- package/templates/browser-test-automation/result-handler.mjs +78 -2
- package/templates/browser-test-automation/run-index.mjs +418 -0
- package/scripts/export-default-workflows.js +0 -51
- package/scripts/patch-cursor-mcp.js +0 -174
- package/scripts/setup-ci.sh +0 -115
- package/scripts/setup-official-playwright-mcp.sh +0 -226
- package/scripts/test-with-video.sh +0 -49
- package/src/agents/base.js +0 -361
- package/src/constants.js +0 -47
- package/src/enrichment/base.js +0 -49
- package/src/enrichment/enrichers/accessibility-enricher.js +0 -197
- package/src/enrichment/enrichers/dom-enricher.js +0 -171
- package/src/enrichment/enrichers/page-state-enricher.js +0 -129
- package/src/enrichment/enrichers/position-enricher.js +0 -67
- package/src/enrichment/index.js +0 -96
- package/src/enrichment/mcp-integration.js +0 -149
- package/src/enrichment/mcp-ref-enricher.js +0 -78
- package/src/enrichment/pipeline.js +0 -192
- package/src/enrichment/trace-text-enricher.js +0 -115
- package/src/framework/AGENTS.md +0 -98
- package/src/framework/agents/base.js +0 -72
- package/src/framework/agents/claude-strategy.js +0 -278
- package/src/framework/agents/cursor-strategy.js +0 -544
- package/src/framework/agents/index.js +0 -105
- package/src/framework/agents/utils/cursor-output-formatter.js +0 -67
- package/src/framework/agents/utils/openai-proxy-formatter.js +0 -249
- package/src/framework/code-generator.js +0 -301
- package/src/framework/constants.js +0 -33
- package/src/framework/context-loader.js +0 -101
- package/src/framework/function-bridge.js +0 -78
- package/src/framework/function-skill-registry.js +0 -20
- package/src/framework/graph-compiler.js +0 -342
- package/src/framework/graph.js +0 -610
- package/src/framework/index.js +0 -28
- package/src/framework/node-registry.js +0 -163
- package/src/framework/node.js +0 -259
- package/src/framework/output-parser.js +0 -71
- package/src/framework/skill-registry.js +0 -55
- package/src/framework/state-utils.js +0 -52
- package/src/framework/state.js +0 -67
- package/src/framework/tool-resolver.js +0 -65
- package/src/index.js +0 -345
- package/src/runtime/generation/base.js +0 -46
- package/src/runtime/generation/index.js +0 -70
- package/src/runtime/generation/mcp-ref-strategy.js +0 -197
- package/src/runtime/generation/stable-id-strategy.js +0 -170
- package/src/runtime/stable-id-runtime.js +0 -248
- package/src/runtime/verification/base.js +0 -44
- package/src/runtime/verification/index.js +0 -67
- package/src/runtime/verification/playwright-json-strategy.js +0 -119
- package/src/runtime/zibby-runtime.js +0 -299
- package/src/sync/index.js +0 -2
- package/src/sync/uploader.js +0 -29
- package/src/tools/run-playwright-test.js +0 -158
- package/src/utils/adf-converter.js +0 -68
- package/src/utils/ast-utils.js +0 -37
- package/src/utils/ci-setup.js +0 -124
- package/src/utils/cursor-utils.js +0 -71
- package/src/utils/logger.js +0 -144
- package/src/utils/mcp-config-writer.js +0 -115
- package/src/utils/node-schema-parser.js +0 -522
- package/src/utils/post-process-events.js +0 -55
- package/src/utils/result-handler.js +0 -102
- package/src/utils/selector-generator.js +0 -239
- package/src/utils/streaming-parser.js +0 -387
- package/src/utils/test-post-processor.js +0 -211
- package/src/utils/timeline.js +0 -217
- package/src/utils/trace-parser.js +0 -325
- package/src/utils/video-organizer.js +0 -91
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getSkill as u}from"./skill-registry.js";const f={};function v(r,t){if(Array.isArray(t))return a(t);const n=f[r];return!n||n.length===0?null:a(n)}function a(r){if(!Array.isArray(r)||r.length===0)return null;const t=[],n={},i=[];for(const s of r){const e=u(s);if(!e){console.warn(`[ToolResolver] Unknown skill "${s}" \u2014 skipping`);continue}i.push(s);for(const o of e.tools||[])t.push({name:o.name,description:o.description,input_schema:o.input_schema||{type:"object",properties:{}}});if(!n[e.serverName])if(typeof e.resolve=="function"){const o=e.resolve();o&&(n[e.serverName]={...o,toolPrefix:s})}else{const o={};for(const l of e.envKeys||[]){const c=process.env[l];c&&(o[l]=c)}n[e.serverName]={command:e.command,args:[...e.args||[]],env:o,toolPrefix:s}}}return i.length===0?null:{toolIds:i,claudeTools:t,mcpServers:n}}export{f as NODE_DEFAULT_TOOLS,a as getResolvedToolDefinitions,v as resolveNodeTools};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{readFileSync as O,existsSync as M}from"fs";import{join as S,resolve as j,isAbsolute as K}from"path";import{DEFAULT_OUTPUT_BASE as Q,SESSIONS_DIR as G,RESULT_FILE as Z}from"./framework/constants.js";import{postCliRunIndex as C,postCliInterruptedRunIndex as W,createCliRunIndexPipelineProgressAppender as q}from"./utils/run-index-post-cli.js";import{WorkflowAgent as R,workflow as Y}from"./agents/base.js";import{resolveWorkflowSession as ee,clearInheritedSessionEnvForFreshRun as te,readStudioPinnedSessionPathFromEnv as oe}from"./framework/graph.js";import{WorkflowGraph as he,resolveWorkflowSession as we,generateWorkflowSessionId as ye,clearInheritedSessionEnvForFreshRun as Ee,shouldTrustInheritedSessionEnv as xe,readStudioPinnedSessionPathFromEnv as Ae,syncProcessEnvToSession as Pe}from"./framework/graph.js";import{ResultHandler as Ie}from"./utils/result-handler.js";import{z as Re}from"zod/v3";import{invokeAgent as _e,getAgentStrategy as ke,AssistantStrategy as ve,CursorAgentStrategy as Le,ClaudeAgentStrategy as Fe,CodexAgentStrategy as Ne,GeminiAgentStrategy as Ue,AgentStrategy as Oe}from"./framework/agents/index.js";import{ToolCallProvider as je,OpenAIToolProvider as Ge}from"./framework/agents/providers/index.js";import{McpClientManager as De}from"./framework/mcp-client.js";import{SKILLS as ze}from"./framework/constants.js";import{registerSkill as Be,getSkill as Je,hasSkill as Xe,getAllSkills as He,listSkillIds as Ke}from"./framework/skill-registry.js";export*from"./constants/tool-names.js";import{resolveIntegrationToken as qe,clearTokenCache as Ye}from"./backend-client.js";import{organizeVideos as tt}from"./utils/video-organizer.js";import{ZibbyUploader as rt,createUploader as nt}from"./sync/index.js";import{patchCursorAgentForCI as it,checkCursorAgentPatched as at,getApprovalKeys as lt,saveApprovalKeys as ct}from"./utils/ci-setup.js";import{DEFAULT_MODELS as pt,AGENT_TYPES as ft,LOG_LEVELS as dt}from"./constants.js";import{DEFAULT_OUTPUT_BASE as gt,SESSIONS_DIR as St,SESSION_INFO_FILE as ht,RESULT_FILE as wt,RAW_OUTPUT_FILE as yt,EVENTS_FILE as Et,CI_ENV_VARS as xt}from"./framework/constants.js";import{RIPPLE_EFFECT_SCRIPT as Pt,injectRippleEffect as Tt,generateRippleHelperCode as It}from"./utils/ripple-effect.js";import{checkCursorAgentInstalled as Rt,getCursorAgentInstallInstructions as bt}from"./utils/cursor-utils.js";import{SelectorGenerator as kt}from"./utils/selector-generator.js";import{TestPostProcessor as Lt}from"./utils/test-post-processor.js";import{TraceParser as Nt}from"./utils/trace-parser.js";import{StreamingParser as Ot}from"./utils/streaming-parser.js";import{ZibbyRuntime as jt}from"./runtime/zibby-runtime.js";import{StableIdRuntime as Wt}from"./runtime/stable-id-runtime.js";import{logger as $t,Logger as zt,LOG_LEVELS as Vt}from"./utils/logger.js";import{timeline as Jt}from"./utils/timeline.js";import{resolveMaxParallelRuns as Ht,DEFAULT_MAX_CONCURRENT_RUNS as Kt,MIN_MAX_CONCURRENT_RUNS as Qt,MAX_MAX_CONCURRENT_RUNS as Zt}from"./utils/parallel-config.js";import{postProcessEvents as Yt}from"./utils/post-process-events.js";import{runPlaywrightTestTool as to,resetExecutionCount as oo}from"./tools/run-playwright-test.js";import{testGenerationManager as no,TestGenerationStrategy as so,MCPRefStrategy as io,StableIdStrategy as ao}from"./runtime/generation/index.js";import{testVerificationManager as co,TestVerificationStrategy as uo,PlaywrightJsonVerificationStrategy as po}from"./runtime/verification/index.js";import{EventEnricher as mo,EnrichmentPipeline as go,PositionEnricher as So,AccessibilityEnricher as ho,PageStateEnricher as wo,DOMEnricher as yo,createDefaultPipeline as Eo,createMinimalPipeline as xo,createCustomPipeline as Ao}from"./enrichment/index.js";import{enrichRecordedEvents as To,LiveEnrichmentRecorder as Io}from"./enrichment/mcp-integration.js";const D=t=>{t?.message?.includes("Connection closed")||t?.message?.includes("MCP error -32000")||t?.code===-32e3||console.error("Unhandled rejection:",t)};process.listeners("unhandledRejection").includes(D)||process.on("unhandledRejection",D);async function re(t,e={}){const{agent:l,mcp:f,headless:h,cwd:r=process.cwd(),specPath:o,sessionPath:c,sessionTimestamp:n,...p}=e,a=O(t,"utf-8"),E=null,{agent:$,error:b}=await ie(r,p);let s=$;if(!s&&e.fallbackAgentModule){const u=e.fallbackAgentModule,m=u.BrowserTestAutomationAgent||u.default;m&&(s=new m(p))}if(!s&&b&&console.warn(`\u26A0\uFE0F Failed to load local agent: ${b}`),!s)throw new Error(`No agent found. Please run:
|
|
2
|
+
zibby init
|
|
3
|
+
|
|
4
|
+
This will create .zibby/graph.mjs with your workflow definition.`);await s.initialize(E);let A=!1;const x=()=>{if(!A)try{W({cwd:r||process.cwd(),config:e}),A=!0}catch(u){console.warn("[zibby] run-index interrupt row:",u?.message||u)}};process.on("SIGINT",x),process.on("SIGTERM",x);try{if(e.singleNode){console.log(`
|
|
5
|
+
\u{1F3AF} Running Single Node: ${e.singleNode} (Framework Mode)
|
|
6
|
+
`);const i=s.calculateOutputPath(o||t),k=s.buildGraph(),v={};for(const[d,w]of k.nodes.entries())v[d]=w.config||w;let L={};if(e.sessionId){let d=e.sessionId;const w=e.paths?.output||Q;if(d==="last"){const y=S(r,w,G);if(M(y)){const{readdirSync:X,statSync:N}=await import("fs"),U=X(y).filter(g=>N(S(y,g)).isDirectory()).map(g=>({name:g,time:N(S(y,g)).mtimeMs})).sort((g,H)=>H.time-g.time);U.length>0?(d=U[0].name,console.log(`\u{1F4C2} Using latest session: ${d}`)):console.log(`\u26A0\uFE0F No sessions found in ${y}`)}}const I=S(r,w,G,d),J=S(I,"execute_live"),F=S(J,Z);M(F)?(console.log(`\u{1F4C2} Loading session: ${d}`),L={sessionPath:I,execute_live_output:JSON.parse(O(F,"utf-8"))}):console.log(`\u26A0\uFE0F Session not found: ${I}`)}const T=await s.runSingleNode(e.singleNode,v,{testSpec:a,outputPath:i,cwd:r||process.cwd(),contextConfig:e.contextConfig,specPath:o||t,config:e,...L});return typeof s.onComplete=="function"&&await s.onComplete(T),C({cwd:r,config:e,result:T,success:!0,specPath:o||t}),T}let u;typeof e.onPipelineProgress=="function"?u=e.onPipelineProgress:e.runIndex?.pipelineProgress!==!1&&(u=q({cwd:r||process.cwd(),config:e}));const m=r||process.cwd(),z=c!=null&&String(c).trim()!==""?(()=>{const i=String(c).trim();try{return K(i)?j(i):j(m,i)}catch{return i}})():void 0,V=oe(),B=z??V;te();const _=ee({cwd:m,config:e,traceFrom:"runTest",initialState:{sessionPath:B,sessionTimestamp:n}});let P;try{P=await s.run(a,{testSpec:a,specPath:o||t,cwd:m,config:e,sessionPath:_.sessionPath,sessionTimestamp:_.sessionTimestamp,...u?{onPipelineProgress:u}:{}})}catch(i){throw typeof i?.message=="string"&&i.message.includes("Interrupted by user")&&W({cwd:r||process.cwd(),config:e}),A||C({cwd:r,config:e,result:i?.partialResult||{},success:!1,specPath:o||t,errorMessage:i?.message}),i}return C({cwd:r,config:e,result:P,success:!0,specPath:o||t}),P}finally{process.off("SIGINT",x),process.off("SIGTERM",x),await s.cleanup()}}function ne(t){return t.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join("")}function se(t,e){if(t[e])return t[e];const l=ne(e);if(t[l])return t[l];const f=`${l}Workflow`;return t[f]?t[f]:null}async function de(t=process.cwd()){try{const{join:e}=await import("path"),{existsSync:l}=await import("fs"),{pathToFileURL:f}=await import("url"),h=e(t,".zibby/graph.mjs");if(!l(h))return{available:[],default:null,error:"No .zibby/graph.mjs found"};const r=await import(f(h).href),o=Object.keys(r).filter(n=>n!=="default"&&typeof r[n]=="function"&&r[n].prototype instanceof R),c=r.BrowserTestAutomationAgent?"BrowserTestAutomationAgent":r.CursorAgent?"CursorAgent":r.default?"default":o[0]||null;return{available:o,default:c,error:null}}catch(e){return{available:[],default:null,error:e.message}}}async function ie(t,e){try{const{join:l}=await import("path"),{existsSync:f}=await import("fs"),{pathToFileURL:h}=await import("url"),r=l(t,".zibby/graph.mjs");if(!f(r))return{agent:null,error:null};const o=await import(h(r).href),c=e.workflow;let n;if(c){if(n=se(o,c),!n){const a=Object.keys(o).filter(E=>E!=="default"&&typeof o[E]=="function");throw new Error(`Workflow "${c}" not found.
|
|
7
|
+
Available workflows: ${a.join(", ")}
|
|
8
|
+
Supported formats: QuickSmokeWorkflow, QuickSmoke, quick-smoke`)}const p=Object.keys(o).find(a=>o[a]===n);console.log(`\u2713 Using workflow: ${p} (from --workflow ${c})`)}else{if(n=o.BrowserTestAutomationAgent||o.CursorAgent||o.default,!n){const p=Object.keys(o).filter(a=>a!=="default"&&typeof o[a]=="function"&&o[a].prototype instanceof R);p.length>0&&(n=o[p[0]],console.log(`\u2713 Using workflow: ${p[0]} (auto-detected)`))}if(!n)return{agent:null,error:"Could not find any WorkflowAgent export in local graph.js"};n.name?.includes("auto-detected")||console.log("\u2713 Using local agent from .zibby/graph.mjs")}return{agent:new n(e),error:null}}catch(l){return{agent:null,error:l.message}}}class me{constructor(e={}){this.config=e}async run(e){return re(e.spec||e.specPath,{...this.config,...e})}}export{ft as AGENT_TYPES,ho as AccessibilityEnricher,Oe as AgentStrategy,ve as AssistantStrategy,xt as CI_ENV_VARS,dt as CORE_LOG_LEVELS,Fe as ClaudeAgentStrategy,Ne as CodexAgentStrategy,Le as CursorAgentStrategy,Kt as DEFAULT_MAX_CONCURRENT_RUNS,pt as DEFAULT_MODELS,gt as DEFAULT_OUTPUT_BASE,yo as DOMEnricher,Et as EVENTS_FILE,go as EnrichmentPipeline,mo as EventEnricher,Ue as GeminiAgentStrategy,Vt as LOG_LEVELS,Io as LiveEnrichmentRecorder,zt as Logger,Zt as MAX_MAX_CONCURRENT_RUNS,io as MCPRefStrategy,Qt as MIN_MAX_CONCURRENT_RUNS,De as McpClientManager,Ge as OpenAIToolProvider,wo as PageStateEnricher,po as PlaywrightJsonVerificationStrategy,So as PositionEnricher,yt as RAW_OUTPUT_FILE,wt as RESULT_FILE,Pt as RIPPLE_EFFECT_SCRIPT,Ie as ResultHandler,St as SESSIONS_DIR,ht as SESSION_INFO_FILE,ze as SKILLS,kt as SelectorGenerator,Wt as StableIdRuntime,ao as StableIdStrategy,Ot as StreamingParser,me as TestAutomation,so as TestGenerationStrategy,Lt as TestPostProcessor,uo as TestVerificationStrategy,je as ToolCallProvider,Nt as TraceParser,R as WorkflowAgent,he as WorkflowGraph,jt as ZibbyRuntime,rt as ZibbyUploader,Rt as checkCursorAgentInstalled,at as checkCursorAgentPatched,Ee as clearInheritedSessionEnvForFreshRun,Ye as clearTokenCache,Ao as createCustomPipeline,Eo as createDefaultPipeline,xo as createMinimalPipeline,nt as createUploader,To as enrichRecordedEvents,It as generateRippleHelperCode,ye as generateWorkflowSessionId,ke as getAgentStrategy,He as getAllSkills,lt as getApprovalKeys,bt as getCursorAgentInstallInstructions,Je as getSkill,Xe as hasSkill,Tt as injectRippleEffect,_e as invokeAgent,Ke as listSkillIds,de as listWorkflows,$t as logger,tt as organizeVideos,it as patchCursorAgentForCI,Yt as postProcessEvents,Ae as readStudioPinnedSessionPathFromEnv,Be as registerSkill,oo as resetExecutionCount,qe as resolveIntegrationToken,Ht as resolveMaxParallelRuns,we as resolveWorkflowSession,to as runPlaywrightTestTool,re as runTest,ct as saveApprovalKeys,xe as shouldTrustInheritedSessionEnv,Pe as syncProcessEnvToSession,no as testGenerationManager,co as testVerificationManager,Jt as timeline,Y as workflow,Re as z};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class t{async generate(e){throw new Error("TestGenerationStrategy.generate() must be implemented")}canGenerate(e){throw new Error("TestGenerationStrategy.canGenerate() must be implemented")}getName(){throw new Error("TestGenerationStrategy.getName() must be implemented")}getPriority(){return 0}}var n=t;export{t as TestGenerationStrategy,n as default};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{MCPRefStrategy as a}from"./mcp-ref-strategy.js";import{StableIdStrategy as o}from"./stable-id-strategy.js";class s{constructor(){this.strategies=[new o,new a],this.strategies.sort((e,t)=>t.getPriority()-e.getPriority())}registerStrategy(e){this.strategies.push(e),this.strategies.sort((t,r)=>r.getPriority()-t.getPriority())}async generate(e){console.log(`
|
|
2
|
+
\u{1F4CB} Available generation strategies (${this.strategies.length}):`),this.strategies.forEach(t=>{const r=t.canGenerate(e);console.log(` ${r?"\u2713":"\u2717"} ${t.getName()} (priority: ${t.getPriority()})`)});for(const t of this.strategies)if(t.canGenerate(e))return console.log(`
|
|
3
|
+
\u{1F3AF} Selected: ${t.getName()}`),t.generate(e);throw new Error("No generation strategy available for this context")}getStrategy(e){return this.strategies.find(t=>t.getName().includes(e))||null}}import{MCPRefStrategy as h}from"./mcp-ref-strategy.js";import{StableIdStrategy as m}from"./stable-id-strategy.js";import{TestGenerationStrategy as u}from"./base.js";const i=new s;var y=i;export{h as MCPRefStrategy,m as StableIdStrategy,u as TestGenerationStrategy,s as TestGenerationStrategyManager,y as default,i as testGenerationManager};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import{TestGenerationStrategy as v}from"./base.js";import{readFileSync as d,writeFileSync as R}from"fs";class T extends v{constructor(){super("mcp-ref","MCP Reference Replay (Exact 1:1)",200)}canGenerate(a){const n=a.eventsPath||`${a.sessionPath}/execute_live/events.json`;try{return JSON.parse(d(n,"utf-8")).some(l=>l.data?.params?.element)?(console.log("[MCPRefStrategy] \u2705 MCP element descriptions available"),!0):(console.log("[MCPRefStrategy] \u274C No MCP element descriptions found in events"),!1)}catch(i){return console.log("[MCPRefStrategy] \u274C Failed to read events:",i.message),!1}}getName(){return"MCP Reference Replay (Exact 1:1)"}getPriority(){return 200}async generate(a){const{testFilePath:n,sessionPath:i,state:g}=a,l=`${i}/execute_live/events.json`,h=g?.title||"Generated Test";console.log("[MCPRefStrategy] \u{1F3AF} Generating test using MCP element descriptions (1:1 replay)"),console.log(`[MCPRefStrategy] events: ${l}`),console.log(`[MCPRefStrategy] output: ${n}`);const p=JSON.parse(d(l,"utf-8")).filter(t=>["navigate","type","fill","click","select_option"].includes(t.type));let e=`import { test, expect } from '@playwright/test';
|
|
2
|
+
`;e+=`import { ZibbyRuntime } from '@zibby/core';
|
|
3
|
+
|
|
4
|
+
`,e+=`test('${h}', async ({ page }) => {
|
|
5
|
+
`,e+=` const timestamp = Date.now();
|
|
6
|
+
|
|
7
|
+
`;for(const t of p){const s=t.data?.params?.element||"element",_=t.data?.params?.ref,m=t.enrichedData?.traceActualText,$=t.enrichedData?.traceActualRole,C=t.enrichedData?.traceActualAriaLabel,f=t.enrichedData?.actualText,r=m||f,b=$||t.enrichedData?.actualRole,M=r||s,c=r||this._extractName(s),y=b||this._extractRole(s),u=m?" [accessibility-tree]":f?" [live]":" [AI]";if(t.type==="navigate")e+=` await page.goto('${t.data.params.url}');
|
|
8
|
+
|
|
9
|
+
`;else if(t.type==="click")e+=` // ${s}${r?` (actual: "${r}")${u}`:""}
|
|
10
|
+
`,e+=` await ZibbyRuntime.step(page, {
|
|
11
|
+
`,e+=` name: '${this._escapeString(s)}',
|
|
12
|
+
`,e+=` action: 'click',
|
|
13
|
+
`,e+=` strategies: [
|
|
14
|
+
`,e+=` { type: 'role', role: '${y}', name: '${this._escapeString(c)}' },
|
|
15
|
+
`,e+=` { type: 'text', text: '${this._escapeString(c)}' }
|
|
16
|
+
`,e+=` ]
|
|
17
|
+
`,e+=` });
|
|
18
|
+
|
|
19
|
+
`;else if(t.type==="fill"||t.type==="type"){const o=t.data.params.text;e+=` // ${s}${r?` (actual: "${r}")${u}`:""}
|
|
20
|
+
`,e+=` await ZibbyRuntime.step(page, {
|
|
21
|
+
`,e+=` name: '${this._escapeString(s)}',
|
|
22
|
+
`,e+=` action: 'fill',
|
|
23
|
+
`,e+=` value: '${this._escapeString(o)}',
|
|
24
|
+
`,e+=` strategies: [
|
|
25
|
+
`,e+=` { type: 'role', role: '${y}', name: '${this._escapeString(c)}' },
|
|
26
|
+
`,e+=` { type: 'attributes', placeholder: '${this._escapeString(c)}' }
|
|
27
|
+
`,e+=` ]
|
|
28
|
+
`,e+=` });
|
|
29
|
+
|
|
30
|
+
`}else if(t.type==="select_option"){const o=t.data.params.values,x=Array.isArray(o)?o[0]:o;e+=` // ${s}${r?` (actual: "${r}")${u}`:""}
|
|
31
|
+
`,e+=` await ZibbyRuntime.step(page, {
|
|
32
|
+
`,e+=` name: '${this._escapeString(s)}',
|
|
33
|
+
`,e+=` action: 'select',
|
|
34
|
+
`,e+=` value: '${this._escapeString(x)}',
|
|
35
|
+
`,e+=` strategies: [
|
|
36
|
+
`,e+=` { type: 'role', role: 'combobox', name: '${this._escapeString(c)}' }
|
|
37
|
+
`,e+=` ]
|
|
38
|
+
`,e+=` });
|
|
39
|
+
|
|
40
|
+
`}}return e+=`});
|
|
41
|
+
`,R(n,e),console.log(`[MCPRefStrategy] \u2705 Generated test with ${p.length} actions using MCP descriptions`),{success:!0,testPath:n,method:"MCP Reference Replay (1:1)",actionsGenerated:p.length}}_extractRole(a){const n=a.toLowerCase();return n.includes("button")?"button":n.includes("textbox")?"textbox":n.includes("link")?"link":n.includes("checkbox")?"checkbox":n.includes("radio")?"radio":n.includes("combobox")?"combobox":n.includes("heading")?"heading":"button"}_extractName(a){return a.replace(/\s+(button|textbox|link|checkbox|radio|combobox)$/i,"").trim()}_escapeRegex(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}_escapeString(a){return a.replace(/'/g,"\\'").replace(/\n/g,"\\n")}}export{T as MCPRefStrategy};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import{TestGenerationStrategy as f}from"./base.js";import{readFileSync as S,writeFileSync as m}from"fs";class $ extends f{constructor(){super("stable-id","Stable ID Injection (Experimental)",300)}canGenerate(t){const a=t.eventsPath||`${t.sessionPath}/execute_live/events.json`;try{return JSON.parse(S(a,"utf-8")).some(r=>r.stableId||r.data?.stableId)?(console.log("[StableIdStrategy] \u2705 Stable IDs available"),!0):(console.log("[StableIdStrategy] \u274C No stable IDs found in events"),!1)}catch(l){return console.log("[StableIdStrategy] \u274C Failed to read events:",l.message),!1}}getName(){return"Stable ID Injection (Experimental)"}getPriority(){return 300}async generate(t){const{testFilePath:a,sessionPath:l,state:i}=t,r=`${l}/execute_live/events.json`,y=i?.title||"Generated Test";console.log("[StableIdStrategy] \u{1F3AF} Generating test using stable IDs"),console.log(`[StableIdStrategy] events: ${r}`),console.log(`[StableIdStrategy] output: ${a}`);const g=JSON.parse(S(r,"utf-8")).filter(c=>["navigate","type","fill","click","select_option","select"].includes(c.type));let s=`import { test, expect } from '@playwright/test';
|
|
2
|
+
`;s+=`import { StableIdRuntime } from '@zibby/core';
|
|
3
|
+
|
|
4
|
+
`,s+=`test('${y}', async ({ page }) => {
|
|
5
|
+
`;let p=!1,d=null;for(let c=0;c<g.length;c++){const e=g[c],o=e.stableId||e.data?.stableId,u=e.data?.element||e.data?.params?.element||"element";if(e.type==="click"&&o&&o===d){console.log(`[StableIdStrategy] Skipping duplicate click on ${o}`);continue}if(e.type==="navigate"){const n=e.data?.url||e.data?.params?.url;n&&!p&&(s+=` await page.goto('${n}');
|
|
6
|
+
`,s+=` await StableIdRuntime.injectStableIds(page);
|
|
7
|
+
|
|
8
|
+
`)}else if(e.type==="click")if(p=!0,d=o,o)s+=` await StableIdRuntime.clickWithRetry(page, '${o}');
|
|
9
|
+
`;else{const n=this._generateSemanticSelector(u);s+=` await ${n}.click();
|
|
10
|
+
`,s+=` await StableIdRuntime.afterNavigation(page);
|
|
11
|
+
`}else if(e.type==="fill"||e.type==="type"){p=!1;const n=e.data?.text||e.data?.params?.text||"";o?s+=` await StableIdRuntime.fillWithRetry(page, '${o}', '${this._escapeString(n)}');
|
|
12
|
+
`:s+=` await page.getByPlaceholder('${this._escapeString(u)}').fill('${this._escapeString(n)}');
|
|
13
|
+
`}else if(e.type==="select_option"||e.type==="select"){p=!1;const n=e.data?.values||e.data?.params?.values,b=Array.isArray(n)?n[0]:n||"";o?s+=` await StableIdRuntime.selectWithRetry(page, '${o}', '${this._escapeString(b)}');
|
|
14
|
+
`:s+=` await page.locator('select').selectOption('${this._escapeString(b)}');
|
|
15
|
+
`}}return s+=`});
|
|
16
|
+
`,m(a,s),console.log(`[StableIdStrategy] \u2705 Generated test with ${g.length} actions using stable IDs`),{success:!0,testPath:a,method:"Stable ID Injection (Experimental)",actionsGenerated:g.length}}_escapeString(t){return t.replace(/'/g,"\\'").replace(/\n/g,"\\n")}_generateSemanticSelector(t){const a=t.toLowerCase();let l="locator",i=t;return a.includes("button")?(l="button",i=t.replace(/\s*button\s*/gi,"").trim()):a.includes("link")?(l="link",i=t.replace(/\s*link\s*/gi,"").trim()):a.includes("textbox")?(l="textbox",i=t.replace(/\s*textbox\s*/gi,"").trim()):a.includes("checkbox")?(l="checkbox",i=t.replace(/\s*checkbox\s*/gi,"").trim()):(a.includes("combobox")||a.includes("dropdown")||a.includes("select"))&&(l="combobox",i=t.replace(/\s*(combobox|dropdown|select)\s*/gi,"").trim()),l!=="locator"&&i?`page.getByRole('${l}', { name: '${this._escapeString(i)}' })`:`page.getByText('${this._escapeString(t)}')`}}export{$ as StableIdStrategy};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class ${static async beforeEach(e){await this.injectStableIds(e),e.on("load",async()=>{await this.injectStableIds(e)})}static async afterNavigation(e){await e.waitForLoadState("domcontentloaded").catch(()=>{}),await this.injectStableIds(e)}static async clickWithRetry(e,u,h={}){const s=h.timeout||1e4,l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);const c=e.locator(l);if(await c.count()>0)try{await c.click({timeout:2e3});return}catch(t){if(t.message.includes("intercepts pointer")){await c.click({force:!0});return}}await e.waitForTimeout(200)}throw new Error(`Element ${l} not found after ${s}ms`)}static async fillWithRetry(e,u,h,s=1e4){const l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);const c=e.locator(l);if(await c.count()>0){await c.fill(h);return}await e.waitForTimeout(200)}throw new Error(`Element ${l} not found after ${s}ms`)}static async selectWithRetry(e,u,h,s=1e4){const l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);const c=e.locator(l);if(await c.count()>0){await c.selectOption(h);return}await e.waitForTimeout(200)}throw new Error(`Element ${l} not found after ${s}ms`)}static async injectStableIds(e){try{await e.evaluate(()=>{function u(t){if(t.getAttribute("aria-label"))return t.getAttribute("aria-label").trim();const o=t.getAttribute("aria-labelledby");if(o){const n=document.getElementById(o);if(n)return n.textContent.trim()}if(t.id){const n=document.querySelector(`label[for="${t.id}"]`);if(n)return n.textContent.trim()}const i=t.closest("label");if(i){const n=i.cloneNode(!0);n.querySelectorAll("input, select, textarea").forEach(f=>f.remove());const m=n.textContent.trim();if(m)return m}if(t.placeholder)return t.placeholder;const r=t.tagName.toLowerCase();return r==="button"||r==="a"||t.getAttribute("role")==="button"?(t.textContent||"").trim().slice(0,50):t.title?t.title:r==="input"&&(t.type==="submit"||t.type==="button")&&t.value||""}function h(t){const o=[],i=t.closest("form");if(i)if(i.id)o.push(`form#${i.id}`);else if(i.name)o.push(`form[name=${i.name}]`);else if(i.action)try{const a=new URL(i.action,window.location.origin).pathname;o.push(`form[action=${a}]`)}catch{o.push(`form[action=${i.getAttribute("action")}]`)}else{const a=document.querySelectorAll("form"),b=Array.from(a).indexOf(i);o.push(`form:nth(${b})`)}const r=t.closest('header, nav, main, footer, aside, [role="banner"], [role="navigation"], [role="main"], [role="contentinfo"]');if(r){const a=r.tagName.toLowerCase(),b=r.getAttribute("role");o.push(b||a)}const n=t.closest('section, article, [role="region"]');if(n){const a=n.querySelector("h1, h2, h3, h4, h5, h6");a&&o.push(`section:${a.textContent.trim().slice(0,30)}`)}const m=t.closest("fieldset");if(m){const a=m.querySelector("legend");a&&o.push(`fieldset:${a.textContent.trim()}`)}const f=t.closest('dialog, [role="dialog"], [role="alertdialog"]');if(f){const a=f.querySelector('[role="heading"], h1, h2, h3');a?o.push(`dialog:${a.textContent.trim().slice(0,30)}`):o.push("dialog")}return o.join("/")}function s(t){const o=t.tagName.toLowerCase(),i=t.id||"",r=t.name||"",n=t.type||"",m=t.getAttribute("role")||"";let f="";if(t.href)try{f=new URL(t.href,window.location.origin).pathname.slice(0,50)}catch{f=t.getAttribute("href")?.slice(0,50)||""}const a=u(t).slice(0,50).replace(/\s+/g," "),b=h(t),g=[o,i,r,n,m,f,a,b].join("|");let w=5381;for(let y=0;y<g.length;y++)w=(w<<5)+w^g.charCodeAt(y);return`zibby-${(w>>>0).toString(36)}`}const l=["button","a","input","select","textarea","label[for]",'[role="button"]','[role="link"]','[role="textbox"]','[role="checkbox"]','[role="radio"]','[role="combobox"]','[role="menuitem"]','[role="tab"]','[role="option"]','[role="switch"]','[role="slider"]',"[onclick]","[data-action]"].join(", "),d=new Map;let c=0;document.querySelectorAll(l).forEach(t=>{const o=window.getComputedStyle(t);if(o.display==="none"||o.visibility==="hidden")return;let i=s(t);const r=i,n=d.get(r)||0;n>0&&(i=`${r}-${n}`),d.set(r,n+1),t.setAttribute("data-zibby-id",i),c++}),console.log(`[Zibby] Injected ${c} stable IDs`)})}catch{}}}export{$ as StableIdRuntime};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class t{async verify(e){throw new Error("TestVerificationStrategy.verify() must be implemented")}canVerify(e){throw new Error("TestVerificationStrategy.canVerify() must be implemented")}getName(){throw new Error("TestVerificationStrategy.getName() must be implemented")}getPriority(){return 0}}var i=t;export{t as TestVerificationStrategy,i as default};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{PlaywrightJsonVerificationStrategy as i}from"./playwright-json-strategy.js";class s{constructor(){this.strategies=[new i],this.strategies.sort((e,t)=>t.getPriority()-e.getPriority())}registerStrategy(e){this.strategies.push(e),this.strategies.sort((t,r)=>r.getPriority()-t.getPriority())}async verify(e){console.log(`
|
|
2
|
+
\u{1F4CB} Available verification strategies (${this.strategies.length}):`),this.strategies.forEach(t=>{const r=t.canVerify(e);console.log(` ${r?"\u2713":"\u2717"} ${t.getName()} (priority: ${t.getPriority()})`)});for(const t of this.strategies)if(t.canVerify(e))return console.log(`
|
|
3
|
+
\u{1F3AF} Selected: ${t.getName()}`),t.verify(e);throw new Error("No verification strategy available for this context")}getStrategy(e){return this.strategies.find(t=>t.getName().includes(e))||null}}import{PlaywrightJsonVerificationStrategy as y}from"./playwright-json-strategy.js";import{TestVerificationStrategy as h}from"./base.js";const o=new s;var n=o;export{y as PlaywrightJsonVerificationStrategy,h as TestVerificationStrategy,s as TestVerificationStrategyManager,n as default,o as testVerificationManager};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{TestVerificationStrategy as g}from"./base.js";import{execSync as f}from"child_process";import{existsSync as h}from"fs";class m extends g{getName(){return"Playwright JSON Reporter"}getPriority(){return 100}canVerify(i){const{testFilePath:o}=i;return h(o)}async verify(i){const{testFilePath:o,cwd:x,timeout:p=3e4}=i;try{console.log(`\u{1F9EA} Running test: ${o}`);const n=`npx playwright test ${o} --reporter=json --timeout=${p}`,s=f(n,{cwd:x,encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:p+1e4}),t=JSON.parse(s).stats||{};return{success:t.unexpected===0,passed:t.expected||0,failed:t.unexpected||0,error:null,errorDetails:null}}catch(n){const s=n.stdout||n.stderr||n.message;try{const r=JSON.parse(s),t=r.stats||{};let e="Test execution failed";if(r.suites&&r.suites.length>0){const l=r.suites[0];if(l.specs&&l.specs.length>0){const a=l.specs[0];if(a.tests&&a.tests.length>0){const u=a.tests[0];if(u.results&&u.results.length>0){const d=u.results[0];d.error&&(e=d.error.message||e)}}}}const c=e.includes("Executable doesn't exist")||e.includes("browserType.launch")||e.includes("Please run the following command")||e.includes("npx playwright install")||s.includes("Executable doesn't exist")||s.includes("npx playwright install");return{success:!1,passed:t.expected||0,failed:t.unexpected||0,error:e,errorDetails:e,isEnvironmentError:c}}catch{const t=s.match(/Error: (.+)/),e=t?t[1]:"Test execution failed",c=e.includes("Executable doesn't exist")||e.includes("browserType.launch")||e.includes("Please run the following command")||e.includes("npx playwright install")||s.includes("Executable doesn't exist")||s.includes("npx playwright install");return{success:!1,passed:0,failed:1,error:e,errorDetails:e,isEnvironmentError:c}}}}}var S=m;export{m as PlaywrightJsonVerificationStrategy,S as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class p{static async step(i,t){const{name:e,action:a,value:n,strategies:o,options:r={timeout:1e4},enrichedData:s}=t;console.log(`[Zibby] \u26A1 Executing step: ${e}`),await this.waitForPageStability(i,r.timeout);const c=await this.findBestMatch(i,o,e);if(!c)throw new Error(`[Zibby] \u274C Failed to find "${e}" using ${o.length} strategies`);s?.position&&await this.verifyPosition(c,s.position),await this.performActionWithRetry(i,c,a,n,3),console.log(`[Zibby] \u2728 Step "${e}" completed.`)}static async waitForPageStability(i,t=1e4){try{await i.waitForLoadState("networkidle",{timeout:3e3}).catch(()=>{}),await i.evaluate(()=>new Promise(e=>{let a;const n=new MutationObserver(()=>{clearTimeout(a),a=setTimeout(()=>{n.disconnect(),e()},500)});n.observe(document.body,{childList:!0,subtree:!0,attributes:!0}),a=setTimeout(()=>{n.disconnect(),e()},500)})).catch(()=>{})}catch{}}static async verifyPosition(i,t){try{const e=await i.boundingBox();if(!e)return;const a=Math.abs(e.x-t.x),n=Math.abs(e.y-t.y);(a>50||n>50)&&(console.log(`[Zibby] \u26A0\uFE0F Element moved: expected (${t.x}, ${t.y}), got (${e.x}, ${e.y})`),await new Promise(o=>setTimeout(o,500)))}catch{}}static async performActionWithRetry(i,t,e,a,n=3){for(let o=1;o<=n;o++)try{e==="click"?await t.click():e==="fill"?await t.fill(a||""):e==="type"?await t.pressSequentially(a||""):e==="selectOption"&&await t.selectOption(a||"");return}catch(r){if(o===n)throw r;console.log(`[Zibby] \u26A0\uFE0F Action failed (attempt ${o}/${n}), retrying...`),await new Promise(s=>setTimeout(s,1e3*o))}}static async findBestMatch(i,t,e){const n=Date.now(),o=t.map(async(c,u)=>{try{const b=await this.getLocator(i,c).all();return b.length===0?[]:(await Promise.all(b.map(async(l,h)=>{try{if(!await l.isVisible({timeout:100}))return null;const m=await this.scoreCandidate(l,c,i);return{element:l,strategy:c,score:m,strategyIdx:u,elIdx:h}}catch{return null}}))).filter(l=>l!==null)}catch{return[]}}),r=(await Promise.all(o)).flat();if(r.length===0)return console.log(`[Zibby] \u274C No visible candidates found for "${e}"`),null;r.sort((c,u)=>u.score-c.score);const s=r[0];return console.log(`[Zibby] \u2705 Found element using ${s.strategy.type} (score: ${s.score.toFixed(2)}, ${r.length} candidates)`),s.element}static async scoreCandidate(i,t,e){let a=0;if(a+={testid:120,id:110,role:100,label:90,class:85,placeholder:85,text:80,css:50}[t.type]||50,t.priority==="high"&&(a+=20),t.priority==="medium"&&(a+=10),t.fuzzy&&(a-=15),t.parent)try{await i.locator("xpath=ancestor::*").first().evaluate((s,c)=>s.matches(c),t.parent)&&(a+=30)}catch{}if(t.sibling)try{await i.evaluate((r,s)=>r.parentElement?.querySelector(s)!==null,t.sibling)&&(a+=20)}catch{}try{const o=await i.boundingBox();o&&o.y<1e3&&(a+=10)}catch{}try{const o=await i.evaluate(r=>{let s=0,c=r;for(;c;)c.tagName==="IFRAME"&&s++,c=c.parentElement;return s});a-=o*5}catch{}return a}static getLocator(i,t){let e;switch(t.type){case"testid":e=i.getByTestId(t.value);break;case"id":e=i.locator(`#${t.value}`);break;case"class":e=i.locator(`.${t.value.replace(/\./g,".")}`);break;case"text":t.fuzzy?e=i.getByText(new RegExp(t.text,"i")):e=i.getByText(t.text,{exact:!1});break;case"role":e=i.getByRole(t.role,{name:t.name,exact:!1});break;case"label":e=i.getByLabel(t.label,{exact:!1});break;case"placeholder":e=i.getByPlaceholder(t.placeholder);break;default:{const a=t.value?.replace(/aria-ref=e\d+ >> /g,"")||t.css;e=i.locator(a);break}}return t.parent&&(e=e.filter({has:i.locator(t.parent)})),e}}export{p as ZibbyRuntime};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ZibbyUploader as o,createUploader as a}from"./uploader.js";export{o as ZibbyUploader,a as createUploader};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class t{constructor(r,s={}){this.apiKey=r,this.baseUrl=s.baseUrl||process.env.ZIBBY_API_URL||"https://api-prod.zibby.app",this.enabled=!!r}isEnabled(){return this.enabled}}function a(){const e=process.env.ZIBBY_API_KEY;return new t(e)}export{t as ZibbyUploader,a as createUploader};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{spawn as T}from"child_process";import{existsSync as S}from"fs";import{dirname as k,resolve as $,relative as I}from"path";const m=new Map,l=8,M={name:"run_playwright_test",description:`Run a Playwright test file and return results. Use this after writing a test to verify it works. If it fails, fix the issues and run again. Maximum ${l} attempts per session.`,inputSchema:{type:"object",properties:{scriptPath:{type:"string",description:"Path to the Playwright test file (e.g., tests/login.spec.js)"}},required:["scriptPath"]},async execute({scriptPath:o},i){const x=`${i?.sessionId||"default"}:${o}`,t=(m.get(x)||0)+1;if(m.set(x,t),t>l)return{success:!1,executionCount:t,maxReached:!0,error:`Maximum ${l} executions reached. Stop retrying and return your best result.`};const h=i?.projectRoot||process.cwd(),e=$(h,o),y=I(h,e);return y.startsWith("..")||$(e)!==e&&y.includes("..")?{success:!1,executionCount:t,error:"Path traversal detected: scriptPath must be within the project root."}:S(e)?new Promise(d=>{const j=k(e),u=T("npx",["playwright","test",e,"--reporter=line"],{cwd:h,env:{...process.env,FORCE_COLOR:"0"}});let c="",f="";u.stdout.on("data",s=>{c+=s.toString()}),u.stderr.on("data",s=>{f+=s.toString()});const w=setTimeout(()=>{u.kill("SIGTERM"),d({success:!1,executionCount:t,error:"Test timed out after 60 seconds",stdout:c.slice(-2e3),stderr:f.slice(-1e3)})},6e4);u.on("close",s=>{clearTimeout(w);const p=`${c}
|
|
2
|
+
${f}`.split(`
|
|
3
|
+
`);let g="",C=null;for(let a=0;a<p.length;a++){const r=p[a];if(r.includes("Error:")||r.includes("error:")||r.includes("\u2718")){g+=`${r}
|
|
4
|
+
`;for(let n=a+1;n<Math.min(a+5,p.length);n++)g+=`${p[n]}
|
|
5
|
+
`}if(r.includes("at ")&&r.includes(".spec.")){const n=r.match(/:(\d+):\d+/);n&&(C=parseInt(n[1]))}}d(s===0?{success:!0,executionCount:t,message:"All tests passed!",output:c.slice(-500)}:{success:!1,executionCount:t,remainingAttempts:l-t,error:g.slice(0,1500)||"Test failed (see output)",failedAtLine:C,stdout:c.slice(-1500),stderr:f.slice(-500),hint:t<l?"Fix the error and run again.":"Last attempt - make your best fix."})}),u.on("error",s=>{clearTimeout(w),d({success:!1,executionCount:t,error:`Failed to run test: ${s.message}`})})}):{success:!1,executionCount:t,error:`Test file not found: ${e}. Make sure you wrote the file first using the write tool.`}},resetCount(o){for(const i of m.keys())i.startsWith(`${o}:`)&&m.delete(i)}};function b(o){M.resetCount(o)}export{b as resetExecutionCount,M as runPlaywrightTestTool};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
function e(t){return!t||typeof t!="object"?String(t||""):t.type==="doc"&&Array.isArray(t.content)?t.content.map(n=>r(n)).join(`
|
|
2
|
+
|
|
3
|
+
`):JSON.stringify(t,null,2)}function r(t){if(!t)return"";if(t.type==="text")return t.text||"";if(t.type==="paragraph"&&Array.isArray(t.content)||t.type==="heading"&&Array.isArray(t.content))return t.content.map(r).join("");if(t.type==="bulletList"&&Array.isArray(t.content))return t.content.map(n=>`\u2022 ${r(n)}`).join(`
|
|
4
|
+
`);if(t.type==="orderedList"&&Array.isArray(t.content))return t.content.map((n,i)=>`${i+1}. ${r(n)}`).join(`
|
|
5
|
+
`);if(t.type==="listItem"&&Array.isArray(t.content))return t.content.map(r).join("");if(t.type==="codeBlock"&&Array.isArray(t.content)){const n=t.content.map(r).join("");return`\`\`\`${t.attrs?.language||""}
|
|
6
|
+
${n}
|
|
7
|
+
\`\`\``}return Array.isArray(t.content)?t.content.map(r).join(""):""}export{e as adfToText};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as i from"acorn";import*as o from"acorn-walk";function l(e){if(!e||typeof e!="string")return!1;try{const n=e.trimStart().startsWith("async")?`const __fn = ${e}`:e,s=i.parse(n,{ecmaVersion:"latest",sourceType:"module",allowAwaitOutsideModules:!0});let r=!1;return o.simple(s,{CallExpression(a){if(r)return;const t=a.callee;t.type==="Identifier"&&t.name==="invokeAgent"&&(r=!0),t.type==="MemberExpression"&&t.property.type==="Identifier"&&t.property.name==="invokeAgent"&&(r=!0)}}),r}catch{return!0}}export{l as hasAgentCall};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{spawn as i}from"child_process";import{readFileSync as u,writeFileSync as d,existsSync as a}from"fs";import{homedir as l}from"os";import{join as c}from"path";async function v(){const s=c(l(),".local/share/cursor-agent/versions");if(!a(s))throw new Error(`cursor-agent not found at ${s}. Please install cursor-agent first.`);return console.log(`\u{1F527} Patching cursor-agent for CI/CD...
|
|
2
|
+
`),new Promise((t,o)=>{const e=c(__dirname,"../../scripts/patch-cursor-mcp.py");if(!a(e)){o(new Error("Patch script not found"));return}const n=i("python3",[e],{stdio:"inherit"});n.on("close",r=>{r===0?t({success:!0}):o(new Error(`Patch failed with code ${r}`))}),n.on("error",r=>{o(r)})})}function w(){const s=c(l(),".local/share/cursor-agent/versions");if(!a(s))return{patched:!1,installed:!1};try{const t=require("fs").readdirSync(s);if(t.length===0)return{patched:!1,installed:!1};const o=t.sort().reverse()[0],e=c(s,o,"index.js");return a(e)?{patched:u(e,"utf-8").includes("AUTO-APPROVE MCP TOOLS FOR CI/CD"),installed:!0,path:e}:{patched:!1,installed:!1}}catch(t){return{patched:!1,installed:!1,error:t.message}}}async function P(s){return console.log(`\u{1F511} Getting MCP approval keys...
|
|
3
|
+
`),new Promise((t,o)=>{const e=i("cursor-agent",["mcp","list"],{cwd:s,stdio:"pipe"});let n="";e.stdout.on("data",r=>{n+=r.toString(),process.stdout.write(r)}),e.stderr.on("data",r=>{process.stderr.write(r)}),e.on("close",r=>{if(r===0){const p=f(n);t({success:!0,keys:p,output:n})}else o(new Error(`Failed to get approval keys (exit code ${r})`))}),e.on("error",r=>{o(r)})})}function f(s){const t={},o=/🔑 APPROVAL KEY:\s+(\S+)\s+=>\s+(\S+)/g;let e;for(;(e=o.exec(s))!==null;)t[e[1]]=e[2];return t}function S(s,t){const o=c(s,".cursor/projects"),e=c(o,"mcp-approvals.json");d(e,JSON.stringify(t,null,2)),console.log(`
|
|
4
|
+
\u2705 Saved approval keys to: ${e}
|
|
5
|
+
`)}export{w as checkCursorAgentPatched,P as getApprovalKeys,v as patchCursorAgentForCI,S as saveApprovalKeys};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{copyFileSync as m,existsSync as c,lstatSync as p,mkdirSync as a,rmSync as l,symlinkSync as S,unlinkSync as L}from"fs";import{join as o}from"path";import{homedir as _}from"os";import{randomBytes as C}from"crypto";const b=["cli-config.json","config.json","auth.json","argv.json"];function B(r){return!(!r||typeof r!="string"||process.env.ZIBBY_CURSOR_USE_GLOBAL_MCP==="1"||process.env.ZIBBY_CURSOR_USE_GLOBAL_MCP==="true")}function O(r){const t=o(r||process.cwd(),".zibby","tmp");a(t,{recursive:!0});const y=`${process.pid}-${Date.now()}-${C(4).toString("hex")}`,n=o(t,`cursor-agent-home-${y}`),s=o(n,".cursor");a(s,{recursive:!0});const i=_(),u=o(i,".cursor");if(c(u))for(const e of b){const f=o(u,e);if(c(f))try{m(f,o(s,e))}catch{}}if(process.platform==="darwin"){const e=o(i,"Library");if(c(e))try{S(e,o(n,"Library"))}catch{}}return n}function k(r){if(!(!r||typeof r!="string"))try{const t=o(r,"Library");try{p(t).isSymbolicLink()&&L(t)}catch{}l(r,{recursive:!0,force:!0})}catch{}}export{b as CURSOR_HOME_DOT_FILES,O as createIsolatedCursorAgentHome,k as removeIsolatedCursorAgentHome,B as shouldUseIsolatedCursorMcpHome};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{exec as e}from"child_process";import{promisify as a}from"util";import{existsSync as i}from"fs";import{join as t}from"path";import{homedir as o}from"os";const n=a(e);async function u(){try{return await n("cursor-agent --version"),"cursor-agent"}catch{const c=[t(o(),".local","bin","cursor-agent"),t(o(),".cursor","bin","cursor-agent"),t(o(),".cursor-agent","bin","cursor-agent")];for(const r of c)if(i(r))try{return await n(`"${r}" --version`),r}catch{}return null}}async function b(){return await u()!==null}function y(){return`
|
|
2
|
+
\u274C cursor-agent CLI not found!
|
|
3
|
+
|
|
4
|
+
To use the Cursor agent, install it from:
|
|
5
|
+
\u{1F4E6} https://github.com/getcursor/cursor-agent
|
|
6
|
+
|
|
7
|
+
Installation:
|
|
8
|
+
curl https://cursor.com/install -fsS | bash
|
|
9
|
+
|
|
10
|
+
After installation:
|
|
11
|
+
1. Add ~/.local/bin to your PATH:
|
|
12
|
+
For zsh: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
|
|
13
|
+
For bash: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
|
|
14
|
+
|
|
15
|
+
2. Or restart your terminal/shell
|
|
16
|
+
|
|
17
|
+
Then retry your command.
|
|
18
|
+
`}export{b as checkCursorAgentInstalled,u as findCursorAgentPath,y as getCursorAgentInstallInstructions};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as a,readdirSync as f,statSync as s,readFileSync as p}from"fs";import{join as r}from"path";const u=/^live-frame.*\.(png|jpe?g)$/i,l=["live-frame.png","live-frame.jpg"];function g(t){return[r(t,"execute_live","frames"),r(t,"frames"),r(t,"execute_live"),t]}function y(t){const e=[];for(const n of g(t)){if(!a(n))continue;for(const m of l){const i=r(n,m);if(a(i))try{e.push({p:i,mtime:s(i).mtimeMs})}catch{}}let c;try{c=f(n)}catch{continue}for(const m of c){if(!u.test(m))continue;const i=r(n,m);try{const o=s(i);o.isFile()&&e.push({p:i,mtime:o.mtimeMs})}catch{}}}return e.length===0?null:(e.sort((n,c)=>c.mtime-n.mtime),e[0])}function v(t){const e=y(t);if(!e)return null;try{return{base64:p(e.p).toString("base64"),mime:e.p.toLowerCase().endsWith(".png")?"image/png":"image/jpeg",mtime:e.mtime,path:e.p}}catch{return null}}export{y as findLatestLiveFrameFileSync,g as liveFrameScanDirs,v as readLatestLiveFramePayloadSync};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import o from"chalk";const r={debug:0,info:1,warn:2,error:3,silent:4};class i{constructor(){this._level=this._getLogLevel()}_getLogLevel(){if(process.env.ZIBBY_DEBUG==="true")return r.debug;if(process.env.ZIBBY_VERBOSE==="true")return r.info;const e=process.env.LOG_LEVEL?.toLowerCase();return e&&e in r?r[e]:r.info}_shouldLog(e){return r[e]>=this._level}_formatMessage(e,t,s={}){const f=new Date().toISOString();let n=`${this._getPrefix(e)} ${t}`;return Object.keys(s).length>0&&(n+=o.dim(` ${JSON.stringify(s)}`)),n}_getPrefix(e){return{debug:o.gray("[DEBUG]"),info:o.cyan("[INFO]"),warn:o.yellow("[WARN]"),error:o.red("\u274C [ERROR]")}[e]||""}debug(e,t){this._shouldLog("debug")&&console.log(this._formatMessage("debug",e,t))}info(e,t){this._shouldLog("info")&&console.log(this._formatMessage("info",e,t))}warn(e,t){this._shouldLog("warn")&&console.warn(this._formatMessage("warn",e,t))}error(e,t){this._shouldLog("error")&&console.error(this._formatMessage("error",e,t))}setLevel(e){e in r&&(this._level=r[e])}getLevel(){return Object.keys(r).find(e=>r[e]===this._level)}}const _=new i;export{r as LOG_LEVELS,i as Logger,_ as logger};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{readFileSync as C,writeFileSync as y,existsSync as a,mkdirSync as S}from"fs";import{join as m}from"path";import{homedir as d}from"os";import{getSkill as v}from"../framework/skill-registry.js";const f=m(d(),".cursor","mcp.json");function k(o){const r=new Set;if(!o||typeof o!="object")return r;for(const e of Object.keys(o)){const s=o[e];if(Array.isArray(s.tools))for(const t of s.tools)r.add(t)}return r}function w(o){const r=k(o);if(r.size===0)return console.log("[MCP Config] No tools requested \u2014 skipping MCP config write"),!1;let e={mcpServers:{}};try{a(f)&&(e=JSON.parse(C(f,"utf-8")),e.mcpServers||(e.mcpServers={}))}catch(i){console.warn(`[MCP Config] Could not read existing config, starting fresh: ${i.message}`),e={mcpServers:{}}}let s=0;for(const i of r){const n=v(i);if(!n){console.log(`[MCP Config] Unknown skill "${i}" \u2014 skipping`);continue}if(e.mcpServers[n.serverName]){console.log(`[MCP Config] Server "${n.serverName}" already configured \u2014 skipping`);continue}const g={};let p=!1;for(const c of n.envKeys||[]){const u=process.env[c];if(!u){console.warn(`[MCP Config] Missing env var ${c} for skill "${i}" \u2014 skipping server`),p=!0;break}g[c]=u}if(p)continue;const l=(n.args||[]).map(c=>c);if(n.command==="node"&&l.length>0&&!a(l[0])){console.warn(`[MCP Config] Binary not found at ${l[0]} for "${i}" \u2014 skipping server`);continue}e.mcpServers[n.serverName]={command:n.command,args:l,env:g,description:n.description},s++,console.log(`[MCP Config] Added "${n.serverName}" server`)}if(s===0)return console.log("[MCP Config] No new MCP servers to add"),!1;const t=m(d(),".cursor");return a(t)||S(t,{recursive:!0}),y(f,JSON.stringify(e,null,2),"utf-8"),console.log(`[MCP Config] Wrote ${f} with ${Object.keys(e.mcpServers).length} server(s)`),!0}function A(o){if(!Array.isArray(o)||o.length===0)return"";const r=[];for(const e of o){const s=v(e);if(!s)continue;const t=(s.tools||[]).map(i=>`- ${i.name}: ${i.description}`).join(`
|
|
2
|
+
`);r.push(`### ${s.description}
|
|
3
|
+
${t}`)}return r.length===0?"":`
|
|
4
|
+
|
|
5
|
+
AVAILABLE MCP TOOLS:
|
|
6
|
+
You have access to the following MCP tools. Use them when your task requires interacting with these services.
|
|
7
|
+
|
|
8
|
+
${r.join(`
|
|
9
|
+
|
|
10
|
+
`)}`}export{k as collectRequiredTools,A as getToolDescriptions,w as writeMcpConfig};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{liveRunsFromSessionStateRows as n}from"./session-state-live-runs.js";export{n as missionControlFromRunningSessionStates};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as x from"acorn";import*as m from"acorn-walk";function S(e){if(!e||typeof e.execute!="function")return a("No execute function found");const t=e.execute.toString();return j(t)}function j(e){if(!e||typeof e!="string")return a("Invalid code");try{let t;const r=e.trimStart();r.startsWith("async execute(")?t=`const __fn = async ${r.substring(13).replace(/^\(/,"(").replace(/\)\s*\{/,") => {")}`:r.startsWith("execute(")?t=`const __fn = ${r.substring(7).replace(/\)\s*\{/,") => {")}`:t=`const __fn = ${r}`;const n=x.parse(t,{ecmaVersion:"latest",sourceType:"module",allowAwaitOutsideModules:!0}),i=[],s=new Map;return m.simple(n,{VariableDeclarator(o){o.id.type==="Identifier"&&o.init&&s.set(o.id.name,o.init)}}),m.simple(n,{ReturnStatement(o){if(o.argument){const u=p(o.argument,s);i.push(u)}}}),i.length===0?a("No return statements found"):c(i)}catch(t){return a(`Parse error: ${t.message}`)}}function p(e,t){switch(e.type){case"ObjectExpression":return k(e,t);case"ArrayExpression":return E(e,t);case"Literal":return O(e);case"Identifier":return g(e.name,t);case"MemberExpression":return h(e);case"ConditionalExpression":{const r=p(e.consequent,t),n=p(e.alternate,t);return c([r,n])}case"LogicalExpression":return e.operator==="||"?p(e.left,t):p(e.right,t);case"CallExpression":return I(e);case"AwaitExpression":return p(e.argument,t);case"TemplateLiteral":return{type:"string"};case"UnaryExpression":return e.operator==="!"?{type:"boolean"}:{type:"unknown"};case"BinaryExpression":return["===","!==","==","!=","<",">","<=",">="].includes(e.operator)?{type:"boolean"}:["+","-","*","/","%"].includes(e.operator)?{type:"number"}:{type:"unknown"};default:return{type:"unknown",astType:e.type}}}function k(e,t){const r={};for(const n of e.properties)if(n.type==="SpreadElement"){const i=w(n.argument,t);if(i.properties)for(const[s,o]of Object.entries(i.properties))r[s]={...o,optional:!0}}else if(n.type==="Property"){const i=T(n);if(i){const s=p(n.value,t);r[i]=s}}return{type:"object",properties:r}}function w(e,t){return e.type==="LogicalExpression"&&e.operator==="&&"?p(e.right,t):e.type==="Identifier"?g(e.name,t):e.type==="MemberExpression"?h(e):p(e,t)}function E(e,t){if(e.elements.length===0)return{type:"array",items:{type:"unknown"}};const r=e.elements[0];return r?{type:"array",items:p(r,t)}:{type:"array",items:{type:"unknown"}}}function O(e){const t=e.value;return t===null?{type:"null"}:typeof t=="boolean"?{type:"boolean",value:t}:typeof t=="number"?{type:"number"}:typeof t=="string"?{type:"string"}:{type:"unknown"}}function g(e,t){const r=t.get(e);if(r)return p(r,t);const n={true:{type:"boolean",value:!0},false:{type:"boolean",value:!1},null:{type:"null"},undefined:{type:"undefined"}};return n[e]?n[e]:{type:"reference",name:e,label:y(e)}}function h(e){const t=d(e),r=t[t.length-1];return{length:{type:"number"},trim:{type:"string"},toString:{type:"string"},toISOString:{type:"string"},success:{type:"boolean"},error:{type:"string"},message:{type:"string"},url:{type:"string"},path:{type:"string"},name:{type:"string"},id:{type:"string"},count:{type:"number"},total:{type:"number"},timestamp:{type:"string"}}[r]||{type:"reference",path:t.join("."),label:y(r)}}function d(e){const t=[];function r(n){n.type==="MemberExpression"?(r(n.object),n.property.type==="Identifier"?t.push(n.property.name):n.property.type==="Literal"&&t.push(String(n.property.value))):n.type==="Identifier"&&t.push(n.name)}return r(e),t}function I(e){const t=e.callee;if(t.type==="MemberExpression"){const r=t.property?.name,n={trim:{type:"string"},toString:{type:"string"},toISOString:{type:"string"},toJSON:{type:"object"},join:{type:"string"},map:{type:"array"},filter:{type:"array"},slice:{type:"array"},concat:{type:"array"},split:{type:"array"},stringify:{type:"string"},parse:{type:"object"}};if(n[r])return n[r]}if(t.type==="Identifier"){const r={Date:{type:"object",label:"Date"},Array:{type:"array"},Object:{type:"object"},String:{type:"string"},Number:{type:"number"},Boolean:{type:"boolean"}};if(r[t.name])return r[t.name]}return{type:"unknown",call:!0}}function T(e){return e.key.type==="Identifier"?e.key.name:e.key.type==="Literal"?String(e.key.value):null}function c(e){if(e.length===0)return a("Empty schemas");if(e.length===1)return e[0];const t=e.filter(r=>r.type==="object");if(t.length===e.length){const r={};for(const n of t)if(n.properties)for(const[i,s]of Object.entries(n.properties))r[i]?r[i]={...c([r[i],s]),optional:!0}:r[i]=s;return{type:"object",properties:r}}return{type:"union",schemas:e}}function a(e){return{type:"unknown",reason:e}}function y(e){return e?e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim():""}function M(e){const t={};for(const[r,n]of Object.entries(e))t[r]={name:n.name||r,hasOutputSchema:!!n.outputSchema,stateSchema:S(n)};return t}function f(e,t=""){const r=[];if(e.type==="union"&&e.schemas){const n={};for(const i of e.schemas)if(i.type==="object"&&i.properties)for(const[s,o]of Object.entries(i.properties))n[s]||(n[s]={...o,optional:!0});return f({type:"object",properties:n},t)}if(e.type==="object"&&e.properties)for(const[n,i]of Object.entries(e.properties)){const s=t?`${t}.${n}`:n,o=i.label||y(n);if(r.push({path:s,type:i.type,label:o,optional:i.optional||!1}),i.type==="object"&&i.properties&&r.push(...f(i,s)),i.type==="union"&&i.schemas){const u=f(i,s);for(const l of u)r.find(b=>b.path===l.path)||r.push(l)}}return r}export{M as parseAllNodeSchemas,j as parseExecuteSchema,S as parseNodeSchema,f as schemaToVariables};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n=8,o=1,_=64;function U(e){if(!e||typeof e!="object")return 8;const t=e.parallel;if(!t||typeof t!="object")return 8;const R=t.maxConcurrentRuns??t.maxConcurrent,r=Number(R);if(!Number.isFinite(r))return 8;const N=Math.floor(r);return N<1?8:Math.min(64,N)}function a(e){if(!e||typeof e!="object")return!1;const t=e.parallel;return!(!t||typeof t!="object"||t.waitWhenAtCapacity===!1)}export{n as DEFAULT_MAX_CONCURRENT_RUNS,_ as MAX_MAX_CONCURRENT_RUNS,o as MIN_MAX_CONCURRENT_RUNS,U as resolveMaxParallelRuns,a as resolveWaitWhenAtCapacity};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as f,writeFileSync as i,existsSync as h}from"fs";import{join as a}from"path";import{TraceTextEnricher as v}from"../enrichment/trace-text-enricher.js";async function p(r){const s=a(r,"events.json"),l=a(r,"events-enriched.json");if(!h(s))return console.log("[PostProcess] No events.json found"),{enriched:0,failed:0};try{const e=JSON.parse(f(s,"utf-8")),d=new v;let n=0,c=0;for(const t of e)try{const o=await d.enrich(t,{sessionPath:r});o&&(t.enrichedData={...t.enrichedData||{},...o},n++)}catch(o){console.log(`[PostProcess] Failed to enrich event ${t.id}: ${o.message}`),c++}return n>0&&(i(l,JSON.stringify(e,null,2)),i(s,JSON.stringify(e,null,2)),console.log(`[PostProcess] \u2705 Enriched ${n} events (${c} failed)`)),{enriched:n,failed:c}}catch(e){return console.log(`[PostProcess] \u274C Failed to post-process events: ${e.message}`),{enriched:0,failed:0}}}export{p as postProcessEvents};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{writeFileSync as l,existsSync as d,mkdirSync as h}from"fs";import{join as r}from"path";import{logger as c}from"./logger.js";class f{static saveTitle(s,n){const t=s.state.sessionPath;if(!t)return;const e=f._findInState(s.state,"title")||f._findInState(s.state,"result");if(!(!e||typeof e!="string"))try{const a=r(t,"title.txt");l(a,e,"utf-8"),c.info(`Saved title to session: "${e}"`)}catch(a){console.warn("\u26A0\uFE0F Could not save title file:",a.message)}}static _findInState(s,n){for(const[,t]of Object.entries(s))if(t&&typeof t=="object"&&t[n]!==void 0)return t[n]}static async saveExecutionData(s){const n=s.state.sessionPath;if(n)for(const[t,e]of Object.entries(s.state)){if(!e||typeof e!="object")continue;const a=Array.isArray(e.actions)&&e.actions.length>0,o=typeof e.scriptPath=="string"&&e.scriptPath.trim().length>0;if(!(!a&&!o))try{const i=r(n,t);d(i)||h(i,{recursive:!0});const u=r(i,"result.json");l(u,JSON.stringify(e,null,2),"utf-8"),c.info(`Saved execution data to ${t} folder`),await this.onNodeSaved(i,e)}catch(i){console.warn(`\u26A0\uFE0F Could not save execution data for ${t}:`,i.message)}}}static async onNodeSaved(s,n){}static logResult(s,n){const t=Object.entries(s.state).filter(([,o])=>o&&typeof o=="object"&&o.success!==void 0),e=t.length>0&&t.every(([,o])=>o.success),a=t.some(([,o])=>o.success===!1);if(e)c.info("Workflow completed successfully."),n&&c.info(`Output: ${n}`);else if(a){const o=t.filter(([,i])=>!i.success).map(([i])=>i);c.info(`Workflow completed with failures in: ${o.join(", ")}`),n&&c.info(`Output: ${n}`)}return e}static handle(s,n,t){return this.saveTitle(s,n),this.saveExecutionData(s),this.logResult(s,t)}}export{f as ResultHandler};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const t=`
|
|
2
2
|
const style = document.createElement('style');
|
|
3
3
|
style.textContent = \`
|
|
4
4
|
@keyframes zibby-ripple {
|
|
@@ -59,14 +59,7 @@ export const RIPPLE_EFFECT_SCRIPT = `
|
|
|
59
59
|
setTimeout(() => ripple.remove(), 600);
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
|
-
`;
|
|
63
|
-
|
|
64
|
-
export function injectRippleEffect(page) {
|
|
65
|
-
return page.addInitScript(RIPPLE_EFFECT_SCRIPT);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function generateRippleHelperCode() {
|
|
69
|
-
return `
|
|
62
|
+
`;function i(e){return e.addInitScript(t)}function o(){return`
|
|
70
63
|
async function showRipple(page, locator) {
|
|
71
64
|
const box = await locator.boundingBox().catch(() => null);
|
|
72
65
|
if (box) {
|
|
@@ -79,6 +72,4 @@ async function showRipple(page, locator) {
|
|
|
79
72
|
}, { x, y }).catch(() => {});
|
|
80
73
|
}
|
|
81
74
|
}
|
|
82
|
-
`.trim();
|
|
83
|
-
}
|
|
84
|
-
|
|
75
|
+
`.trim()}export{t as RIPPLE_EFFECT_SCRIPT,o as generateRippleHelperCode,i as injectRippleEffect};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as R,mkdirSync as a,readFileSync as T,rmSync as _,statSync as g,writeFileSync as v}from"fs";import{join as s}from"path";import{randomUUID as b}from"crypto";import{DEFAULT_OUTPUT_BASE as h,SESSIONS_DIR as E}from"../framework/constants.js";import{resolveMaxParallelRuns as L,resolveWaitWhenAtCapacity as O}from"./parallel-config.js";import{listRunningSessionStatesFromSessionsRoot as P,processPidLooksAlive as U}from"./run-state-session.js";import{removeRunCapacityQueueEntry as S,upsertRunCapacityQueueEntry as F}from"./run-capacity-queue.js";const B=".zibby-run-capacity-guard",j=12e4;function x(e,r){const t=r?.paths?.output||h,n=s(e,t),i=s(n,E);return{outputAbs:n,sessionsRootAbs:i}}function u(e){try{_(e,{recursive:!0,force:!0})}catch{}}function D(e){try{const r=T(s(e,"owner.pid"),"utf8"),t=Number(String(r).trim());return Number.isFinite(t)&&t>0?t:null}catch{return null}}function M(e){if(!R(e))return!0;const r=D(e);if(r!=null){const t=U(r);if(t===!0)return!1;if(t===!1)return u(e),!0}try{const t=g(e);if(Date.now()-t.mtimeMs>j)return u(e),!0}catch{return u(e),!0}return!1}async function N(e,r){a(e,{recursive:!0});const t=s(e,B);for(;;)try{a(t,{recursive:!1}),v(s(t,"owner.pid"),String(process.pid),"utf8");try{return await r()}finally{u(t)}}catch(n){if((n&&typeof n=="object"?n.code:"")!=="EEXIST")throw n;if(M(t))continue;await new Promise(l=>setTimeout(l,35+Math.random()*45))}}async function Z(e){const{cwd:r,config:t,meta:n={},log:i,pollMs:l=1500}=e;if(process.env.ZIBBY_WAIT_FOR_RUN_CAPACITY==="0"||process.env.ZIBBY_WAIT_FOR_RUN_CAPACITY==="false")return{waited:!1,jobId:""};if(!O(t))return{waited:!1,jobId:""};const p=L(t),{outputAbs:o,sessionsRootAbs:w}=x(r,t);a(o,{recursive:!0});const c=b(),C=n.studioTestCaseId!=null&&String(n.studioTestCaseId).trim()!==""?String(n.studioTestCaseId).trim():null,I={id:c,pid:process.pid,cwd:String(r),enqueuedAt:Date.now(),updatedAt:Date.now(),source:n.source!=null?String(n.source):"cli",specHint:n.specHint!=null&&String(n.specHint).trim()!==""?String(n.specHint).trim().slice(0,240):"",studioTestCaseId:C};let f=!1,d=0;const A=()=>{try{S(o,c)}catch{}};try{for(;;){let m=!1;if(await N(o,async()=>{if(a(o,{recursive:!0}),d=P(w,{reconcile:{}}).length,d<p){S(o,c),m=!0;return}F(o,{...I,updatedAt:Date.now()})}),m)return{waited:f,jobId:c};f||(typeof i=="function"&&i(`Waiting for run capacity (${d}/${p} active)\u2026`),f=!0),await new Promise(y=>setTimeout(y,l))}}finally{A()}}export{x as resolveRunCapacityPaths,Z as waitUntilRunCapacity};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{existsSync as a,mkdirSync as N,readFileSync as h,renameSync as A,unlinkSync as C,writeFileSync as g}from"fs";import{join as p}from"path";import{processPidLooksAlive as v}from"./run-state-session.js";const m="run-capacity-wait.json",o=1,x=10800*1e3;function S(e){return p(e,m)}function R(e){return!e||typeof e!="string"?null:p(p(e,".."),m)}function s(){return{v:o,entries:[]}}function f(e){if(!e||!a(e))return s();const t=S(e);if(!a(t))return s();try{const n=h(t,"utf8"),i=JSON.parse(n);if(!i||typeof i!="object")return s();const r=Array.isArray(i.entries)?i.entries:[];return{v:o,entries:r}}catch{return s()}}function y(e,t=Date.now()){const n=e&&Array.isArray(e.entries)?e.entries:[],i=[];for(const r of n){if(!r||typeof r!="object")continue;const c=Number(r.pid),u=Number(r.updatedAt)||Number(r.enqueuedAt)||0,l=Number.isFinite(c)&&c>0?v(c):null;l!==!1&&(l===null&&u>0&&t-u>x||i.push(r))}return{v:o,entries:i}}function d(e,t){const n=S(e);N(e,{recursive:!0});const i={v:o,entries:Array.isArray(t.entries)?t.entries:[]},r=`${n}.${process.pid}.${Date.now()}.tmp`;g(r,`${JSON.stringify(i)}
|
|
2
|
+
`,"utf8");try{a(n)&&C(n)}catch{}A(r,n)}function F(e,t){const n=y(f(e)),i=t?.id!=null?String(t.id):"";if(!i)return;const r=n.entries.filter(u=>u&&String(u.id)!==i),c=Date.now();r.push({...t,id:i,pid:Number.isFinite(Number(t.pid))?Number(t.pid):process.pid,enqueuedAt:Number(t.enqueuedAt)||c,updatedAt:c}),d(e,{v:o,entries:r})}function _(e,t){const n=t!=null?String(t):"";if(!n||!e)return;const i=y(f(e)),r=i.entries.filter(c=>c&&String(c.id)!==n);r.length!==i.entries.length&&d(e,{v:o,entries:r})}function O(e){const t=f(e),n=y(t);return n.entries.length!==t.entries.length&&d(e,n),n.entries}export{m as RUN_CAPACITY_QUEUE_FILENAME,f as readRunCapacityQueueDoc,O as readRunCapacityWaitSnapshot,y as reconcileRunCapacityQueueDoc,_ as removeRunCapacityQueueEntry,S as runCapacityQueuePathFromOutputDir,R as runCapacityQueuePathFromSessionsRoot,F as upsertRunCapacityQueueEntry,d as writeRunCapacityQueueDocAtomic};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function a(n){return n?.recordKind==="progress"}function u(n){const t=Number(n)||0;return t<=0?0:t<1e12?t*1e3:t}function d(n,t={}){const s=t.maxProgressAgeMs!=null&&Number.isFinite(t.maxProgressAgeMs)?Math.max(0,t.maxProgressAgeMs):21e5,e=typeof t.now=="number"?t.now:Date.now(),{summary:r,progress:i}=n||{};if(!i)return!1;const o=u(i.ts);if(s>0&&o>0&&e-o>s)return!1;if(!r)return o>0;const c=u(r.ts);return o>c}function l(n){const t=p(n),s=new Set;for(const[e,r]of t){if(!d(r))continue;const i=r.progress,o=String((i?.studioTestCaseId!=null&&String(i.studioTestCaseId).trim()!==""?i.studioTestCaseId:null)||e).trim();o&&s.add(o)}return[...s]}function p(n){const t=new Map;for(const s of n||[]){if(!s?.sessionId)continue;let e=t.get(s.sessionId);e||(e={summary:null,progress:null});const r=Number(s.ts)||0;a(s)?(!e.progress||r>=(Number(e.progress.ts)||0))&&(e.progress=s):(!e.summary||r>=(Number(e.summary.ts)||0))&&(e.summary=s),t.set(s.sessionId,e)}return t}function m(n){const{summary:t,progress:s}=n||{},e=t?{...t}:{},r=s&&Number(s.ts)||0,i=t&&Number(t.ts)||0;return s&&(!t||r>=i)&&(e.pipelineActiveNode=s.activeNode,e.pipelineStageIndex=s.activeStageIndex,e.runIndexProgressTs=s.ts,s.specRel!=null&&String(s.specRel).trim()!==""&&(e.specRel=s.specRel),s.taskDescription!=null&&String(s.taskDescription).trim()!==""&&(e.taskDescription=s.taskDescription),s.studioTestCaseId!=null&&s.studioTestCaseId!==""&&(e.studioTestCaseId=s.studioTestCaseId)),!t&&s&&(e.sessionId=s.sessionId,e.cwd=s.cwd,e.outputBase=s.outputBase,e.sessionPathAbs=s.sessionPathAbs,e.source=s.source,s.specRel!=null&&String(s.specRel).trim()!==""&&(e.specRel=s.specRel),s.taskDescription!=null&&String(s.taskDescription).trim()!==""&&(e.taskDescription=s.taskDescription)),t&&(e.runIndexSummaryTs=t.ts),e}export{l as listLiveRunIndexCorrelationIds,m as mergedRunIndexEntryForSession,p as partitionRunIndexBySession,d as runIndexSessionEntryIsLive};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{tryAppendBrowserTestRunIndex as r,createBrowserTestPipelineProgressAppender as n,tryAppendBrowserTestInterruptedRunIndex as t}from"../../templates/browser-test-automation/run-index.mjs";function o(e){r(e)}function s(e){t(e)}function d(e){return n(e)}export{d as createCliRunIndexPipelineProgressAppender,s as postCliInterruptedRunIndex,o as postCliRunIndex};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{appendFileSync as f,readFileSync as d,existsSync as i,mkdirSync as a}from"fs";import{join as r}from"path";import{DEFAULT_OUTPUT_BASE as c}from"../framework/constants.js";const u="run-index.jsonl";function I(n,o=c){const t=r(n,o);return r(t,u)}function y(n){if(!n||!n.sessionId)return;const o=n.cwd||process.cwd(),t=n.outputBase||c,e=r(o,t);i(e)||a(e,{recursive:!0});const s=r(e,u),p=`${JSON.stringify(n)}
|
|
2
|
+
`;f(s,p,"utf8")}function R(n){if(!n||!i(n))return[];let o;try{o=d(n,"utf8")}catch{return[]}const t=[];for(const e of o.split(`
|
|
3
|
+
`)){const s=e.trim();if(s)try{t.push(JSON.parse(s))}catch{}}return t}function S(n){const o=new Map;for(const t of n){if(!t?.sessionId)continue;const e=o.get(t.sessionId),s=Number(t.ts)||0;(!e||s>=(Number(e.ts)||0))&&o.set(t.sessionId,t)}return o}export{u as RUN_INDEX_FILENAME,y as appendRunIndexRecord,S as latestRunRecordsBySession,R as readRunIndexRecordsFromFile,I as resolveRunIndexPath};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{existsSync as S,mkdirSync as g,readFileSync as h,readdirSync as x,statSync as N,writeFileSync as w}from"fs";import{join as m}from"path";function v(t){const e=Number(t);if(!Number.isFinite(e)||e<=0)return null;try{return process.kill(e,0),!0}catch(n){const r=n&&typeof n=="object"?n.code:"";return r==="ESRCH"?!1:r==="EPERM"?!0:null}}function F(t,e={}){if(!t||!S(t))return{patched:0};const n=e.studioNoPidMaxAgeMs!=null&&Number.isFinite(e.studioNoPidMaxAgeMs)?Math.max(0,e.studioNoPidMaxAgeMs):120*1e3,r=Date.now();let u=0,o;try{o=x(t)}catch{return{patched:0}}for(const s of o){const c=m(t,s);let a;try{a=N(c)}catch{continue}if(!a.isDirectory())continue;const i=p(c);if(!i||i.status!=="running")continue;const l=Number(i.updatedAt)||0,y=v(i.pid);let f=!1,d="";y===!1?(f=!0,d="process-exited"):y===null&&i.runSource==="studio"&&n>0&&l>0&&r-l>n&&(f=!0,d="studio-stale-no-pid"),f&&(D(c,{status:"interrupted",activeNode:null,activeStageIndex:null,exitReason:d}),u+=1)}return{patched:u}}const E="zibby-run-state.json";function M(t){return m(t,E)}function p(t){if(!t||typeof t!="string")return null;const e=M(t);if(!S(e))return null;try{const n=h(e,"utf8"),r=JSON.parse(n);return r&&typeof r=="object"?r:null}catch{return null}}function D(t,e){if(!t||typeof t!="string")return;try{g(t,{recursive:!0})}catch{return}const r={...p(t)||{v:1},...e,v:1,updatedAt:Date.now()};try{w(M(t),`${JSON.stringify(r)}
|
|
2
|
+
`,"utf8")}catch(u){console.warn(`[zibby run-state] ${u.message}`)}}function P(t,e={}){if(!t||!S(t))return[];e.reconcile!==!1&&F(t,e.reconcile||{});const n=e.maxStaleMs!=null&&Number.isFinite(e.maxStaleMs)&&e.maxStaleMs>0?e.maxStaleMs:1800*1e3,r=typeof e.now=="number"?e.now:Date.now();let u;try{u=x(t)}catch{return[]}const o=[];for(const s of u){const c=m(t,s);let a;try{a=N(c)}catch{continue}if(!a.isDirectory())continue;const i=p(c);if(!i||i.status!=="running")continue;const l=Number(i.updatedAt)||0;n>0&&l>0&&r-l>n||o.push({sessionId:s,sessionPathAbs:c,...i})}return o}export{E as SESSION_RUN_STATE_FILENAME,P as listRunningSessionStatesFromSessionsRoot,D as mergeSessionRunState,v as processPidLooksAlive,p as readSessionRunState,F as reconcileStaleRunningSessionStates,M as sessionRunStateFilePath};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
class l{static generate(e,n="element"){const{selectors:t}=e;if(!t||typeof t!="object")return this.generateFallbackSelector(e,n);const r=[];return t.role&&r.push(this.generateRoleSelector(t.role)),t.attributes&&r.push(this.generateAttributeSelector(t.attributes)),t.partialMatch&&r.push(this.generatePartialMatchSelector(t.partialMatch)),t.structure&&r.push(this.generateStructuralSelector(t.structure)),r.length===0?this.generateFallbackSelector(e,n):r.length===1?`const ${n} = ${r[0]};`:`const ${n} = ${r[0]}
|
|
2
|
+
${r.slice(1).map(a=>` .or(${a})`).join(`
|
|
3
|
+
`)};`}static generateRoleSelector(e){const{role:n,name:t}=e;if(!n)return null;if(t){const r=this.escapeRegex(t);return`page.getByRole('${n}', { name: /${r}/i })`}return`page.getByRole('${n}')`}static generateAttributeSelector(e){if(!e||typeof e!="object")return null;const n=Object.entries(e).filter(([r,c])=>c!=null).map(([r,c])=>r==="placeholder"||r==="aria-label"?r==="placeholder"?`page.getByPlaceholder('${this.escapeString(c)}')`:`page.locator('[${r}="${this.escapeString(c)}"]')`:`[${r}="${this.escapeString(c)}"]`);if(e.placeholder)return`page.getByPlaceholder('${this.escapeString(e.placeholder)}')`;const t=n.filter(r=>!r.startsWith("page.")).join("");return t?`page.locator('${t}')`:null}static generatePartialMatchSelector(e){if(!e||typeof e!="object")return null;const n=Object.entries(e).filter(([t,r])=>r!==void 0).map(([t,r])=>{const c=r.replace(/^\^/,"");return`[${t}^="${this.escapeString(c)}"]`});return n.length>0?`page.locator('${n.join("")}')`:null}static generateStructuralSelector(e){return!e||typeof e!="string"?null:`page.locator('${this.escapeString(e)}')`}static generateFallbackSelector(e,n){const{description:t,type:r}=e;if(r==="fill"||r==="type")return`const ${n} = page.locator('input').first();`;if(r==="click"){if(t.toLowerCase().includes("button"))return`const ${n} = page.locator('button').first();`;if(t.toLowerCase().includes("link"))return`const ${n} = page.locator('a').first();`}return`const ${n} = page.locator('body');`}static escapeString(e){return typeof e!="string"?String(e):e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/"/g,'\\"')}static escapeRegex(e){return typeof e!="string"?String(e):e.replace(/[.*+?^${}()[\]\\]/g,"\\$&")}static generateActionCode(e,n){const{type:t,value:r,description:c,selectors:a}=e,o=`element${n}`,i=this.generate(e,o),s=this.generateActionMethod(t,o,r);return`${i}
|
|
4
|
+
${s}`}static generateActionMethod(e,n,t){switch(e){case"fill":case"type":return`await ${n}.fill('${this.escapeString(t||"")}');`;case"click":return`await ${n}.click();`;case"navigate":return`await page.goto('${this.escapeString(t||"")}');`;case"wait":return`await page.waitForTimeout(${parseInt(t)||2e3});`;default:return`// Unknown action type: ${e}`}}static generateAssertionCode(e,n){const{description:t,expected:r,actual:c,passed:a}=e;return t.toLowerCase().includes("url")?`await expect(page).toHaveURL(/${this.escapeRegex(c)}/);`:t.toLowerCase().includes("visible")?"await expect(page.locator('body')).toBeVisible();":`// ${t}`}}var g=l;export{l as SelectorGenerator,g as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _=12e4,S=72e4,T=72e4,E=72e4;export{E as SESSION_STATE_DEFAULT_LIST_MAX_STALE_MS,S as SESSION_STATE_DEFAULT_STALE_NO_UPDATED_AT_MS,T as SESSION_STATE_DEFAULT_STALE_RUNNING_NO_PID_MS,_ as SESSION_STATE_DEFAULT_STUDIO_NO_PID_MAX_AGE_MS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function d(n){const i=[],s={};for(const e of n||[]){const t=String(e.studioTestCaseId!=null&&String(e.studioTestCaseId).trim()!==""?e.studioTestCaseId:e.sessionId||"").trim();if(!t)continue;i.push(t);const o=Number(e.updatedAt)||0;s[t]={ts:o,activeStageIndex:typeof e.activeStageIndex=="number"&&Number.isFinite(e.activeStageIndex)?e.activeStageIndex:null,activeNode:e.activeNode!=null?String(e.activeNode):null}}return{liveIdList:i,progressByKey:s}}export{d as liveRunsFromSessionStateRows};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
class p{constructor(){this.buffer="",this.extractedResult=null,this.rawText="",this.zodSchema=null,this.lastOutputLength=0,this.onToolCall=null,this._lastToolEmit=null}processChunk(t){if(!t)return null;this.buffer+=t;const s=this.buffer.split(`
|
|
2
|
+
`);this.buffer=s.pop()||"";let r="";for(const l of s)if(l.trim())try{const n=JSON.parse(l);this._emitToolCalls(n);const e=this.extractText(n);if(e){if(this.rawText&&e.startsWith(this.rawText)){const i=e.substring(this.rawText.length);this.rawText=e,r+=i}else(!this.rawText.includes(e)||e.length<20)&&(this.rawText+=e,r+=e);this.tryExtractResult(this.rawText)}else this.isValidResult(n)&&(this.rawText+=`${l}
|
|
3
|
+
`,r+=`${l}
|
|
4
|
+
`,this.extractedResult=n)}catch{if(l.includes('"text"')||l.includes('"content"')){const e=l.match(/"text"\s*:\s*"([^"]*)/),i=l.match(/"content"\s*:\s*"([^"]*)/),a=e?e[1]:i?i[1]:null;a&&!this.rawText.includes(a)&&(r+=a,this.rawText+=a)}}return r||null}flush(){if(!this.buffer.trim())return null;let t="";try{const s=JSON.parse(this.buffer);this._emitToolCalls(s);const r=this.extractText(s);r&&(this.rawText+=r,t+=r,this.tryExtractResult(r))}catch{this.rawText+=this.buffer,t+=this.buffer,this.tryExtractResult(this.buffer)}return this.buffer="",t||null}_emitToolCalls(t){if(!this.onToolCall)return;const s=(e,i)=>{if(!e)return;const a=`${e}:${JSON.stringify(i??{})}`;this._lastToolEmit!==a&&(this._lastToolEmit=a,this.onToolCall(e,i??void 0))},r=e=>{if(e!=null){if(typeof e=="object"&&!Array.isArray(e))return e;if(typeof e=="string")try{return JSON.parse(e)}catch{return}}};if(t.type==="tool_use"||t.type==="tool_call"){if(t.name){s(t.name,r(t.input??t.arguments));return}const e=t.tool_call;if(e&&typeof e=="object"&&!Array.isArray(e)){const i=Object.keys(e);if(i.length===1){const a=i[0],o=e[a],h=o&&typeof o=="object"?o.args??o.input??o:void 0;s(a,r(h))}return}return}if(Array.isArray(t.tool_calls)){for(const e of t.tool_calls)s(e.name,r(e.input??e.arguments));return}const l=t.message??t;if(Array.isArray(l?.tool_calls)){for(const e of l.tool_calls)s(e.name,r(e.input??e.arguments));return}const n=l?.content??t.content;if(Array.isArray(n))for(const e of n)(e.type==="tool_use"||e.type==="tool_call")&&e.name&&s(e.name,r(e.input??e.arguments))}extractText(t){if(t.type==="assistant"&&t.message?.content){const s=t.message.content;if(Array.isArray(s))return s.filter(r=>r.type==="text"&&r.text).map(r=>r.text).join("")}return t.type==="thinking"&&t.text||t.text?t.text:t.content&&typeof t.content=="string"?t.content:t.delta?t.delta:null}tryExtractResult(t){if(!t||typeof t!="string")return;const s=[],r=/```json\s*\n?([\s\S]*?)\n?```/g;let l;for(;(l=r.exec(t))!==null;){const c=l[1].trim();try{JSON.parse(c),s.push({text:c,source:"markdown"})}catch{}}let n=0,e=0;for(;n<t.length&&(n=t.indexOf("{",n),n!==-1);){let c=0,f=n;for(let u=n;u<t.length;u++)if(t[u]==="{")c++;else if(t[u]==="}"&&(c--,c===0)){f=u,s.push({text:t.substring(n,f+1),source:"brace"}),e++;break}n=f+1}let i=this.extractedResult,a=i?JSON.stringify(i).length:0,o=0,h=-1;for(let c=0;c<s.length;c++){const f=s[c];try{const u=f.text.replace(/,(\s*[}\]])/g,"$1"),y=JSON.parse(u);this.isValidResult(y)&&(o++,a=JSON.stringify(y).length,i=y,h=c)}catch{}}i&&(this.extractedResult=i)}isValidResult(t){if(!t||typeof t!="object"||Array.isArray(t)||t.session_id||t.timestamp_ms||t.type||t.call_id||t.tool_call||t.result&&typeof t.result=="object"&&(t.result.success&&typeof t.result.success=="object"||t.result.error&&typeof t.result.error=="object")||t.args&&typeof t.args=="object")return!1;if(this.zodSchema)try{return this.zodSchema.parse(t),!0}catch{return!1}return!0}getResult(){return this.extractedResult}getRawText(){return this.rawText}static extractResult(t,s=null){const r=new p;r.zodSchema=s,r.processChunk(t),r.flush();const l=r.getResult();return!l&&process.env.LOG_LEVEL==="debug"&&console.error("[StreamingParser] No result extracted from",t?.length||0,"chars"),l}}export{p as StreamingParser};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import g from"fs/promises";import{SelectorGenerator as w}from"./selector-generator.js";class h{static async generateFromEvents(n,a,t,e){try{console.log("[TestPostProcessor] \u{1F3AF} Generating test from events.json (100% accurate)");const{readFileSync:r}=await import("fs"),i=JSON.parse(r(a,"utf-8")),c=i.filter(o=>["navigate","type","fill","click","select_option"].includes(o.type)),p=c.filter(o=>o.type!=="navigate");console.log(`[TestPostProcessor] Found ${c.length} action events, ${t.length} trace actions`);let s=`import { ZibbyRuntime } from '@zibby/core';
|
|
2
|
+
import { test, expect } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
`;s+=`test('${e}', async ({ page }) => {
|
|
5
|
+
`,s+=` const timestamp = Date.now();
|
|
6
|
+
|
|
7
|
+
`;let l=0;for(const o of c)if(o.type==="navigate")s+=` await page.goto('${o.data.params.url}');
|
|
8
|
+
|
|
9
|
+
`;else if(o.type==="type"||o.type==="fill"){const{element:u,text:f}=o.data.params,d=t[l]?.strategies||[];s+=` await ZibbyRuntime.step(page, ${JSON.stringify({name:u,action:"fill",value:f,strategies:d},null,2)});
|
|
10
|
+
|
|
11
|
+
`,l++}else if(o.type==="click"){const{element:u}=o.data.params,f=t[l]?.strategies||[];s+=` await ZibbyRuntime.step(page, ${JSON.stringify({name:u,action:"click",value:"",strategies:f},null,2)});
|
|
12
|
+
|
|
13
|
+
`,l++}else if(o.type==="select_option"){const{element:u,values:f}=o.data.params,d=t[l]?.strategies||[],b={name:u,action:"selectOption",value:Array.isArray(f)?f[0]:f,strategies:d};s+=` await ZibbyRuntime.step(page, ${JSON.stringify(b,null,2)});
|
|
14
|
+
|
|
15
|
+
`,l++}s+=`});
|
|
16
|
+
`;const{dirname:m}=await import("path"),{mkdirSync:y}=await import("fs");return y(m(n),{recursive:!0}),await g.writeFile(n,s,"utf-8"),console.log(`[TestPostProcessor] \u2705 Generated test with ${i.filter(o=>["type","fill","click","select_option"].includes(o.type)).length} actions`),!0}catch(r){return console.warn("[TestPostProcessor] Failed to generate from events:",r.message),!1}}static async enhanceSelectorsWithTrace(n,a,t){try{console.log("[TestPostProcessor] \u{1F6E1}\uFE0F Applying Zibby Safe Action Wrappers...");let e=await g.readFile(n,"utf-8");e.includes("ZibbyRuntime")||(e=`import { ZibbyRuntime } from '@zibby/core';
|
|
17
|
+
${e}`);for(let r=0;r<a.length;r++){const i=a[r],c=`element${r}`,p=new RegExp(`const ${c}\\b\\s*=\\s*page\\.[^;]+;(\\s*await ${c}\\.waitFor\\([^)]*\\);)?\\s*await ${c}\\.(click|fill|type|selectOption|pressSequentially)\\(([^)]*)\\);`,"s"),s=e.match(p);if(!s)continue;const l={name:i.name||`Action ${r}`,action:i.method==="type"?"fill":i.method,value:s[3].trim().replace(/^['"]|['"]$/g,""),strategies:i.strategies||[]},m=`await ZibbyRuntime.step(page, ${JSON.stringify(l,null,2)});`;e=e.replace(s[0],m)}return await g.writeFile(n,e,"utf-8"),console.log("[TestPostProcessor] \u2705 Successfully converted test to Resilient Zibby format"),!0}catch(e){return console.warn("[TestPostProcessor] Failed to apply safe wrappers:",e.message),!1}}static async enhanceSelectors(n,a){try{const{actions:t=[]}=a;if(!t.length)return!1;let e=await g.readFile(n,"utf-8");const r=this.buildSelectorMap(t);return e=this.replaceSimpleSelectors(e,r),await g.writeFile(n,e,"utf-8"),!0}catch(t){return console.warn("Failed to enhance selectors:",t),!1}}static buildSelectorMap(n){const a=new Map;for(let t=0;t<n.length;t++){const e=n[t];if(!e.selectors||e.type==="navigate")continue;const r=`element${t}`,c=w.generate(e,r).match(/= (.+);/s);if(c){const p=c[1].trim(),s=`${e.type}:${this.normalizeDescription(e.description)}`;a.set(s,p),e.selectors.role&&a.set(`role:${e.selectors.role.name}`,p),e.selectors.attributes?.placeholder&&a.set(`placeholder:${e.selectors.attributes.placeholder}`,p)}}return a}static replaceSimpleSelectors(n,a){let t=n;const e=[/await page\.(getByRole|getByPlaceholder|getByText|getByLabel|locator)\([^)]+\)\.(fill|click|type)\([^)]*\)/g];for(const r of e)t=t.replace(r,i=>{for(const[c,p]of a.entries())if(i.includes(c.split(":")[1])){const s=i.match(/\.(fill|click|type)\(([^)]*)\)/);if(s){const[,l,m]=s,y="element";return`const ${y} = ${p};
|
|
18
|
+
await ${y}.${l}(${m})`}}return i});return t}static normalizeDescription(n){return n?n.toLowerCase().replace(/[^a-z0-9]+/g," ").trim():""}}var P=h;export{h as TestPostProcessor,P as default};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import e from"chalk";const $="__WORKFLOW_GRAPH_LOG__",c=e.gray("\u2502"),E=e.gray("\u250C"),a=e.gray("\u2514"),h=e.green("\u25C6"),S=e.hex("#c084fc")("\u25C6"),p=e.hex("#2dd4bf")("\u25C6"),l=e.red("\u25C6"),W=`${c} `,w=2;function f(d){return d<1e3?`${d}ms`:`${(d/1e3).toFixed(1)}s`}function g(d,t){return(r,o,n)=>{if(typeof r!="string")return d(r,o,n);const _=process.stdout.columns||120;let s="";for(let u=0;u<r.length;u++){const i=r[u];t.lineStart&&(s+=W,t.col=w,t.lineStart=!1),i===`
|
|
2
|
+
`?(s+=i,t.lineStart=!0,t.col=0,t.inEsc=!1):i==="\x1B"?(t.inEsc=!0,s+=i):t.inEsc?(s+=i,(i>="A"&&i<="Z"||i>="a"&&i<="z")&&(t.inEsc=!1)):(t.col++,s+=i,t.col>=_&&(s+=`
|
|
3
|
+
${W}`,t.col=w))}return d(s,o,n)}}class I{constructor(){this._currentNode=null,this._origStdoutWrite=null,this._origStderrWrite=null;const t=String(process.env.ZIBBY_RUN_SOURCE||"").trim().toLowerCase(),r=String(process.env.ZIBBY_WORKFLOW_GRAPH_LOG_MARKERS||"").trim()==="1";this._emitWorkflowGraphMarkers=r||t==="studio"}get isInsideNode(){return this._currentNode!==null}_startIntercepting(){this._origStdoutWrite=process.stdout.write.bind(process.stdout),this._origStderrWrite=process.stderr.write.bind(process.stderr);const t={lineStart:!0,col:0,inEsc:!1},r={lineStart:!0,col:0,inEsc:!1};this._outState=t,this._errState=r,process.stdout.write=g(this._origStdoutWrite,t),process.stderr.write=g(this._origStderrWrite,r)}_stopIntercepting(){this._origStdoutWrite&&(this._outState&&!this._outState.lineStart&&this._origStdoutWrite(`
|
|
4
|
+
`),process.stdout.write=this._origStdoutWrite),this._origStderrWrite&&(this._errState&&!this._errState.lineStart&&this._origStderrWrite(`
|
|
5
|
+
`),process.stderr.write=this._origStderrWrite),this._origStdoutWrite=null,this._origStderrWrite=null}_rawWrite(t){(this._origStdoutWrite||process.stdout.write.bind(process.stdout))(`${t}
|
|
6
|
+
`)}_emitGraphLogMarker(t){if(!this._emitWorkflowGraphMarkers)return;const r=`${$}${JSON.stringify(t)}
|
|
7
|
+
`;this._origStdoutWrite?this._origStdoutWrite(r):process.stdout.write(r)}_writeDot(t,r){this._origStdoutWrite?(this._outState&&!this._outState.lineStart&&(this._origStdoutWrite(`
|
|
8
|
+
`),this._outState.lineStart=!0,this._outState.col=0),this._origStdoutWrite(`${t} ${r}
|
|
9
|
+
`)):process.stdout.write.bind(process.stdout)(`${t} ${r}
|
|
10
|
+
`)}step(t){this._origStdoutWrite?this._writeDot(h,t):process.stdout.write.bind(process.stdout)(`${c} ${h} ${t}
|
|
11
|
+
`)}stepTool(t){this._origStdoutWrite?this._writeDot(S,t):process.stdout.write.bind(process.stdout)(`${c} ${S} ${t}
|
|
12
|
+
`)}stepMemory(t){const r=e.hex("#2dd4bf")(t);this._origStdoutWrite?this._writeDot(p,r):process.stdout.write.bind(process.stdout)(`${c} ${p} ${r}
|
|
13
|
+
`)}stepFail(t){this._origStdoutWrite?this._writeDot(l,e.red(t)):process.stdout.write.bind(process.stdout)(`${c} ${l} ${e.red(t)}
|
|
14
|
+
`)}nodeStart(t){this._currentNode=t,this._emitGraphLogMarker({phase:"node_begin",node:t}),this._rawWrite(`${E} ${t}`),this._startIntercepting()}nodeComplete(t,r={}){this._stopIntercepting();const{duration:o,details:n}=r;if(n)for(const s of n)this._rawWrite(`${h} ${s}`);const _=o?e.dim(` ${f(o)}`):"";this._rawWrite(`${a} ${e.green("done")}${_}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}nodeFailed(t,r,o={}){this._stopIntercepting();const{duration:n}=o,_=n?e.dim(` ${f(n)}`):"";this._rawWrite(`${l} ${e.red(r)}`),this._rawWrite(`${a} ${e.red("failed")}${_}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}route(t,r){this._rawWrite(e.dim(` ${t} \u2192 ${r}`)),this._rawWrite("")}graphComplete(){this._rawWrite(e.green.bold("\u2713 Workflow completed"))}}const O=new I;var m=O;export{$ as WORKFLOW_GRAPH_LOG_MARKER_PREFIX,m as default,O as timeline};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{readFileSync as j,existsSync as k,readdirSync as F}from"fs";import{join as N}from"path";import{execSync as W}from"child_process";import{tmpdir as L}from"os";class P{static async parseTraceZip(h){let o;if(h.endsWith(".zip")&&k(h)){const n=N(L(),`trace-${Date.now()}`);W(`unzip -q "${h}" -d "${n}"`,{stdio:"pipe"});const a=F(n).find(c=>c.endsWith(".trace"));if(!a)throw new Error("No .trace file found in zip");o=N(n,a)}else if(k(h)){const u=F(h).find(a=>a.endsWith(".trace"));if(!u)throw new Error("No .trace file found");o=N(h,u)}else throw new Error(`Trace not found at ${h}`);try{const u=j(o,"utf-8").trim().split(`
|
|
2
|
+
`),a=[],c=new Map,l=new Map;for(const w of u)try{const t=JSON.parse(w);if(t.type==="snapshot"&&t.snapshot&&t.snapshot.accessibility){const r=new Map;for(const i of t.snapshot.accessibility)i.ref&&r.set(i.ref,i);c.set(t.snapshotName,r)}if(t.type==="frame-snapshot"&&t.snapshot){const r=Buffer.from(t.snapshot.html||"","base64").toString("utf-8");r&&r.length>100&&l.set(t.pageId||"default",r)}}catch{}for(const w of u)try{const t=JSON.parse(w);if(t.type==="before"&&t.params&&t.params.selector){const r=t.method;if(["click","fill","type","selectOption"].includes(r)){const i=t.params.selector,z=t.params.text||t.params.value||"",e=[];let p=null,f=null,m=null;const v=i.match(/aria-ref=([a-z0-9]+)/i);if(v&&t.snapshotName){const s=v[1],x=c.get(t.snapshotName);if(x&&x.has(s)){const y=x.get(s);p=y.name||null,f=y.role||null,m=y.label||null,console.log(`[TraceParser] \u2705 Found ACTUAL element data: text="${p}", role="${f}"`)}}const d=i.match(/internal:text="([^"]+)"/i),R=i.match(/internal:label="([^"]+)"/i),T=i.match(/internal:placeholder="([^"]+)"/i),E=i.match(/internal:role=([^ ]+)/i),M=i.match(/internal:describe="([^"]+)"/i),C=i.match(/name="([^"]+)"/i);if(d){e.push({type:"text",text:d[1]});const s=d[1].split(" ");s.length>1&&(e.push({type:"text",text:s[0],fuzzy:!0}),e.push({type:"text",text:s[s.length-1],fuzzy:!0}))}if(R&&e.push({type:"label",label:R[1]}),T&&e.push({type:"placeholder",placeholder:T[1]}),p){e.unshift({type:"text",text:p,source:"accessibility-tree"});const s=p.split(" ");s.length>1&&e.push({type:"text",text:s[0],fuzzy:!0,source:"accessibility-tree"})}if(f||E){const s=f||E[1],x=p||(C?C[1]:d?d[1]:null);e.unshift({type:"role",role:s,name:x,source:p?"accessibility-tree":"selector"})}if(m&&e.unshift({type:"label",label:m,source:"accessibility-tree"}),M){const s=M[1],x=["link","button","textbox","menuitem","submenu","combobox","checkbox","radio","tab","treeitem","menu item"];let y=null,$=s;for(const g of x)if(s.toLowerCase().endsWith(` ${g}`)){y=g.replace(" ",""),$=s.substring(0,s.length-g.length-1);break}if(y){e.push({type:"role",role:y,name:$});const g=$.replace(/\s*\([^)]+\)\s*$/,"");e.push({type:"text",text:g}),e.push({type:"text",text:$});const S=$.split(" ");S.length>1&&(e.push({type:"text",text:S[0],fuzzy:!0}),e.push({type:"text",text:S.slice(0,2).join(" "),fuzzy:!0}))}else{const g=s.replace(/\s*\([^)]+\)\s*$/,"");e.push({type:"text",text:g}),e.push({type:"text",text:s})}}const O=this.extractDOMStrategies(i,l,d?.[1]||M?.[1],t.pageId);e.push(...O);const b=this.extractStructuralContext(i);(b.parent||b.sibling)&&e.forEach(s=>{["role","text","label","testid"].includes(s.type)&&(b.parent&&(s.parent=b.parent),b.sibling&&(s.sibling=b.sibling))}),e.push({type:"css",value:i});const A=p||d?d[1]:M?M[1].replace(/\s*\([^)]+\)\s*$/,""):`Action ${a.length}`;a.push({method:r,name:A,action:r==="type"?"fill":r,value:z,strategies:e,timestamp:t.startTime,actualText:p,actualRole:f,actualAriaLabel:m})}}}catch{}return a}catch(n){throw new Error(`Failed to parse trace: ${n.message}`,{cause:n})}}static extractDOMStrategies(h,o,n,u){const a=[];if(!o||o.size===0||!n)return a;try{const c=o.get(u);if(!c)return a;const l=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),w=new RegExp(`data-testid=["']([^"']+)["'][^>]*>[^<]*${l}`,"i"),t=c.match(w);t&&a.push({type:"testid",value:t[1],priority:"high"});const r=new RegExp(`class=["']([^"']+)["'][^>]*>[^<]*${l}`,"gi"),i=c.matchAll(r);for(const p of i){const f=p[1].split(/\s+/).filter(m=>m&&!m.match(/^(css|jss|makeStyles|MuiBox|MuiStack)-\w+/)&&m.length>2);f.length>0&&(a.push({type:"class",value:f.join("."),priority:"medium"}),f.length===1&&a.push({type:"class",value:f[0],priority:"medium"}))}const z=new RegExp(`id=["']([^"']+)["'][^>]*>[^<]*${l}`,"i"),e=c.match(z);e&&!e[1].match(/^(root|app|\d+|[a-f0-9-]{20,})$/i)&&a.push({type:"id",value:e[1],priority:"high"})}catch(c){console.warn(`[TraceParser] DOM extraction failed: ${c.message}`)}return a}static extractStructuralContext(h){const o={parent:null,sibling:null},n=h.split(">>").map(c=>c.trim());if(n.length>1){const l=n[n.length-2].replace(/internal:text="[^"]+"\s*/gi,"").replace(/internal:role=\S+\s*/gi,"").replace(/internal:label="[^"]+"\s*/gi,"").trim();l&&(l.match(/^(form|section|nav|header|aside|main|article)\b/)||l.includes("[")||l.match(/[#.]\w/))&&(o.parent=l)}const a=n[n.length-1].match(/([^+~]+)\s*[+~]\s*(.+)/);return a&&(o.sibling=a[1].trim()),o}}var U=P;export{P as TraceParser,U as default};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{readdir as v,access as h,copyFile as w,constants as g}from"fs/promises";import{join as i,relative as $}from"path";async function F(c={}){const{testResultsDir:a="test-results",testsDir:o="tests",projectRoot:t=process.cwd(),verbose:s=!0}=c;s&&console.log(`\u{1F3A5} Organizing test videos...
|
|
2
|
+
`);const r=i(t,a),l=i(t,o);try{const e=await v(r);let f=0;for(const n of e){if(n.startsWith("."))continue;const u=i(r,n,"video.webm");try{await h(u,g.F_OK)}catch{continue}const m=n.replace(/-chromium$/,"").replace(/-firefox$/,"").replace(/-webkit$/,""),d=await P(l,m);if(d){const p=d.replace(/\.spec\.(js|ts)$/,".spec.webm");await w(u,p),s&&console.log(`\u2705 ${$(t,p)}`),f++}else s&&console.log(`\u26A0\uFE0F Could not find test file for: ${n}`)}return s&&(console.log(`
|
|
3
|
+
\u{1F3AC} Organized ${f} video(s)`),console.log(`\u{1F4C2} Videos are now next to their test files in ${o}/`)),{movedCount:f,success:!0}}catch(e){return s&&console.error("\u274C Error organizing videos:",e.message),{movedCount:0,success:!1,error:e.message}}}async function P(c,a){const o=a.split("-");for(let t=o.length;t>0;t--){const r=o.slice(0,t).join("/");for(const l of["js","ts"]){const e=i(c,`${r}.spec.${l}`);try{return await h(e,g.F_OK),e}catch{}}}return null}export{F as organizeVideos};
|