@zibby/core 0.1.33 → 0.1.36

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.
Files changed (94) hide show
  1. package/dist/agents/base.js +286 -14
  2. package/dist/backend-client.js +1 -1
  3. package/dist/constants/tool-names.js +1 -1
  4. package/dist/constants/zibby-scratch.js +1 -1
  5. package/dist/constants.js +1 -1
  6. package/dist/enrichment/base.js +1 -1
  7. package/dist/enrichment/enrichers/accessibility-enricher.js +1 -1
  8. package/dist/enrichment/enrichers/dom-enricher.js +1 -1
  9. package/dist/enrichment/enrichers/page-state-enricher.js +1 -1
  10. package/dist/enrichment/enrichers/position-enricher.js +1 -1
  11. package/dist/enrichment/index.js +4 -1
  12. package/dist/enrichment/mcp-integration.js +4 -1
  13. package/dist/enrichment/mcp-ref-enricher.js +1 -1
  14. package/dist/enrichment/pipeline.js +2 -2
  15. package/dist/enrichment/trace-text-enricher.js +2 -1
  16. package/dist/framework/agents/assistant-strategy.js +69 -5
  17. package/dist/framework/agents/base.js +1 -1
  18. package/dist/framework/agents/claude-strategy.js +106 -4
  19. package/dist/framework/agents/codex-strategy.js +23 -4
  20. package/dist/framework/agents/cursor-strategy.js +106 -20
  21. package/dist/framework/agents/gemini-strategy.js +34 -7
  22. package/dist/framework/agents/index.js +252 -6
  23. package/dist/framework/agents/middleware/assistant-round-pipeline.js +2 -2
  24. package/dist/framework/agents/providers/base.js +1 -1
  25. package/dist/framework/agents/providers/index.js +4 -1
  26. package/dist/framework/agents/providers/openai-transport.js +4 -2
  27. package/dist/framework/agents/providers/openai.js +1 -1
  28. package/dist/framework/agents/providers/transport-base.js +1 -1
  29. package/dist/framework/agents/utils/auth-resolver.js +1 -1
  30. package/dist/framework/agents/utils/cursor-output-formatter.js +25 -1
  31. package/dist/framework/agents/utils/openai-proxy-formatter.js +43 -5
  32. package/dist/framework/agents/utils/payload-budget.js +2 -2
  33. package/dist/framework/agents/utils/structured-output-formatter.js +8 -4
  34. package/dist/framework/code-generator.js +276 -10
  35. package/dist/framework/constants.js +1 -1
  36. package/dist/framework/context-loader.js +2 -2
  37. package/dist/framework/function-bridge.js +60 -1
  38. package/dist/framework/function-skill-registry.js +1 -1
  39. package/dist/framework/graph-compiler.js +281 -1
  40. package/dist/framework/graph.js +272 -4
  41. package/dist/framework/index.js +298 -1
  42. package/dist/framework/mcp-client.js +56 -2
  43. package/dist/framework/node-registry.js +262 -4
  44. package/dist/framework/node.js +264 -4
  45. package/dist/framework/output-parser.js +2 -2
  46. package/dist/framework/skill-registry.js +1 -1
  47. package/dist/framework/state-utils.js +5 -1
  48. package/dist/framework/state.js +1 -1
  49. package/dist/framework/tool-resolver.js +1 -1
  50. package/dist/index.js +479 -5
  51. package/dist/package.json +1 -1
  52. package/dist/runtime/generation/base.js +1 -1
  53. package/dist/runtime/generation/index.js +58 -3
  54. package/dist/runtime/generation/mcp-ref-strategy.js +17 -17
  55. package/dist/runtime/generation/stable-id-strategy.js +14 -14
  56. package/dist/runtime/stable-id-runtime.js +1 -1
  57. package/dist/runtime/verification/base.js +1 -1
  58. package/dist/runtime/verification/index.js +3 -3
  59. package/dist/runtime/verification/playwright-json-strategy.js +1 -1
  60. package/dist/runtime/zibby-runtime.js +1 -1
  61. package/dist/sync/index.js +1 -1
  62. package/dist/sync/uploader.js +1 -1
  63. package/dist/tools/run-playwright-test.js +3 -3
  64. package/dist/utils/adf-converter.js +1 -1
  65. package/dist/utils/ast-utils.js +9 -1
  66. package/dist/utils/ci-setup.js +4 -4
  67. package/dist/utils/cursor-mcp-isolated-home.js +1 -1
  68. package/dist/utils/cursor-utils.js +1 -1
  69. package/dist/utils/live-frame-discovery.js +1 -1
  70. package/dist/utils/logger.js +1 -1
  71. package/dist/utils/mcp-config-writer.js +4 -4
  72. package/dist/utils/mission-control-from-run-states.js +1 -1
  73. package/dist/utils/node-schema-parser.js +9 -1
  74. package/dist/utils/parallel-config.js +1 -1
  75. package/dist/utils/post-process-events.js +2 -1
  76. package/dist/utils/repo-clone.js +1 -0
  77. package/dist/utils/result-handler.js +1 -1
  78. package/dist/utils/ripple-effect.js +1 -1
  79. package/dist/utils/run-capacity-coordinator.js +3 -1
  80. package/dist/utils/run-capacity-queue.js +2 -2
  81. package/dist/utils/run-index-merge.js +1 -1
  82. package/dist/utils/run-index-post-cli.js +4 -1
  83. package/dist/utils/run-registry.js +3 -3
  84. package/dist/utils/run-state-session.js +2 -2
  85. package/dist/utils/selector-generator.js +4 -4
  86. package/dist/utils/session-state-constants.js +1 -1
  87. package/dist/utils/session-state-live-runs.js +1 -1
  88. package/dist/utils/streaming-parser.js +3 -3
  89. package/dist/utils/test-post-processor.js +14 -11
  90. package/dist/utils/timeline.js +6 -6
  91. package/dist/utils/trace-parser.js +2 -2
  92. package/dist/utils/video-organizer.js +3 -3
  93. package/package.json +1 -1
  94. package/templates/browser-test-automation/result-handler.mjs +4 -39
@@ -1,4 +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};
1
+ var a=class{static generate(e,n="element"){let{selectors:t}=e;if(!t||typeof t!="object")return this.generateFallbackSelector(e,n);let 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(i=>` .or(${i})`).join(`
3
+ `)};`}static generateRoleSelector(e){let{role:n,name:t}=e;if(!n)return null;if(t){let 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;let 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)}')`;let t=n.filter(r=>!r.startsWith("page.")).join("");return t?`page.locator('${t}')`:null}static generatePartialMatchSelector(e){if(!e||typeof e!="object")return null;let n=Object.entries(e).filter(([t,r])=>r!==void 0).map(([t,r])=>{let 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){let{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){let{type:t,value:r,description:c,selectors:i}=e,o=`element${n}`,s=this.generate(e,o),l=this.generateActionMethod(t,o,r);return`${s}
4
+ ${l}`}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){let{description:t,expected:r,actual:c,passed:i}=e;return t.toLowerCase().includes("url")?`await expect(page).toHaveURL(/${this.escapeRegex(c)}/);`:t.toLowerCase().includes("visible")?"await expect(page.locator('body')).toBeVisible();":`// ${t}`}},g=a;export{a as SelectorGenerator,g as default};
@@ -1 +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};
1
+ var _=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};
@@ -1 +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};
1
+ function d(n){let i=[],s={};for(let e of n||[]){let t=String(e.studioTestCaseId!=null&&String(e.studioTestCaseId).trim()!==""?e.studioTestCaseId:e.sessionId||"").trim();if(!t)continue;i.push(t);let 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};
@@ -1,4 +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}
1
+ var p=class d{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;let s=this.buffer.split(`
2
+ `);this.buffer=s.pop()||"";let r="";for(let l of s)if(l.trim())try{let n=JSON.parse(l);this._emitToolCalls(n);let e=this.extractText(n);if(e){if(this.rawText&&e.startsWith(this.rawText)){let 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
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};
4
+ `,this.extractedResult=n)}catch{if(l.includes('"text"')||l.includes('"content"')){let 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{let s=JSON.parse(this.buffer);this._emitToolCalls(s);let 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;let s=(e,i)=>{if(!e)return;let 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}let e=t.tool_call;if(e&&typeof e=="object"&&!Array.isArray(e)){let i=Object.keys(e);if(i.length===1){let 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(let e of t.tool_calls)s(e.name,r(e.input??e.arguments));return}let l=t.message??t;if(Array.isArray(l?.tool_calls)){for(let e of l.tool_calls)s(e.name,r(e.input??e.arguments));return}let n=l?.content??t.content;if(Array.isArray(n))for(let 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){let 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;let s=[],r=/```json\s*\n?([\s\S]*?)\n?```/g,l;for(;(l=r.exec(t))!==null;){let 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++){let f=s[c];try{let 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){let r=new d;r.zodSchema=s,r.processChunk(t),r.flush();let 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};
@@ -1,18 +1,21 @@
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';
1
+ import d from"fs/promises";var h=class{static generate(t,n="element"){let{selectors:r}=t;if(!r||typeof r!="object")return this.generateFallbackSelector(t,n);let e=[];return r.role&&e.push(this.generateRoleSelector(r.role)),r.attributes&&e.push(this.generateAttributeSelector(r.attributes)),r.partialMatch&&e.push(this.generatePartialMatchSelector(r.partialMatch)),r.structure&&e.push(this.generateStructuralSelector(r.structure)),e.length===0?this.generateFallbackSelector(t,n):e.length===1?`const ${n} = ${e[0]};`:`const ${n} = ${e[0]}
2
+ ${e.slice(1).map(o=>` .or(${o})`).join(`
3
+ `)};`}static generateRoleSelector(t){let{role:n,name:r}=t;if(!n)return null;if(r){let e=this.escapeRegex(r);return`page.getByRole('${n}', { name: /${e}/i })`}return`page.getByRole('${n}')`}static generateAttributeSelector(t){if(!t||typeof t!="object")return null;let n=Object.entries(t).filter(([e,s])=>s!=null).map(([e,s])=>e==="placeholder"||e==="aria-label"?e==="placeholder"?`page.getByPlaceholder('${this.escapeString(s)}')`:`page.locator('[${e}="${this.escapeString(s)}"]')`:`[${e}="${this.escapeString(s)}"]`);if(t.placeholder)return`page.getByPlaceholder('${this.escapeString(t.placeholder)}')`;let r=n.filter(e=>!e.startsWith("page.")).join("");return r?`page.locator('${r}')`:null}static generatePartialMatchSelector(t){if(!t||typeof t!="object")return null;let n=Object.entries(t).filter(([r,e])=>e!==void 0).map(([r,e])=>{let s=e.replace(/^\^/,"");return`[${r}^="${this.escapeString(s)}"]`});return n.length>0?`page.locator('${n.join("")}')`:null}static generateStructuralSelector(t){return!t||typeof t!="string"?null:`page.locator('${this.escapeString(t)}')`}static generateFallbackSelector(t,n){let{description:r,type:e}=t;if(e==="fill"||e==="type")return`const ${n} = page.locator('input').first();`;if(e==="click"){if(r.toLowerCase().includes("button"))return`const ${n} = page.locator('button').first();`;if(r.toLowerCase().includes("link"))return`const ${n} = page.locator('a').first();`}return`const ${n} = page.locator('body');`}static escapeString(t){return typeof t!="string"?String(t):t.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/"/g,'\\"')}static escapeRegex(t){return typeof t!="string"?String(t):t.replace(/[.*+?^${}()[\]\\]/g,"\\$&")}static generateActionCode(t,n){let{type:r,value:e,description:s,selectors:o}=t,i=`element${n}`,l=this.generate(t,i),a=this.generateActionMethod(r,i,e);return`${l}
4
+ ${a}`}static generateActionMethod(t,n,r){switch(t){case"fill":case"type":return`await ${n}.fill('${this.escapeString(r||"")}');`;case"click":return`await ${n}.click();`;case"navigate":return`await page.goto('${this.escapeString(r||"")}');`;case"wait":return`await page.waitForTimeout(${parseInt(r)||2e3});`;default:return`// Unknown action type: ${t}`}}static generateAssertionCode(t,n){let{description:r,expected:e,actual:s,passed:o}=t;return r.toLowerCase().includes("url")?`await expect(page).toHaveURL(/${this.escapeRegex(s)}/);`:r.toLowerCase().includes("visible")?"await expect(page.locator('body')).toBeVisible();":`// ${r}`}};var $=class{static async generateFromEvents(t,n,r,e){try{console.log("[TestPostProcessor] \u{1F3AF} Generating test from events.json (100% accurate)");let{readFileSync:s}=await import("fs"),o=JSON.parse(s(n,"utf-8")),i=o.filter(c=>["navigate","type","fill","click","select_option"].includes(c.type)),l=i.filter(c=>c.type!=="navigate");console.log(`[TestPostProcessor] Found ${i.length} action events, ${r.length} trace actions`);let a=`import { ZibbyRuntime } from '@zibby/core';
2
5
  import { test, expect } from '@playwright/test';
3
6
 
4
- `;s+=`test('${e}', async ({ page }) => {
5
- `,s+=` const timestamp = Date.now();
7
+ `;a+=`test('${e}', async ({ page }) => {
8
+ `,a+=` const timestamp = Date.now();
6
9
 
7
- `;let l=0;for(const o of c)if(o.type==="navigate")s+=` await page.goto('${o.data.params.url}');
10
+ `;let p=0;for(let c of i)if(c.type==="navigate")a+=` await page.goto('${c.data.params.url}');
8
11
 
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)});
12
+ `;else if(c.type==="type"||c.type==="fill"){let{element:f,text:g}=c.data.params,m=r[p]?.strategies||[];a+=` await ZibbyRuntime.step(page, ${JSON.stringify({name:f,action:"fill",value:g,strategies:m},null,2)});
10
13
 
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)});
14
+ `,p++}else if(c.type==="click"){let{element:f}=c.data.params,g=r[p]?.strategies||[];a+=` await ZibbyRuntime.step(page, ${JSON.stringify({name:f,action:"click",value:"",strategies:g},null,2)});
12
15
 
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)});
16
+ `,p++}else if(c.type==="select_option"){let{element:f,values:g}=c.data.params,m=r[p]?.strategies||[],w={name:f,action:"selectOption",value:Array.isArray(g)?g[0]:g,strategies:m};a+=` await ZibbyRuntime.step(page, ${JSON.stringify(w,null,2)});
14
17
 
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};
18
+ `,p++}a+=`});
19
+ `;let{dirname:u}=await import("path"),{mkdirSync:y}=await import("fs");return y(u(t),{recursive:!0}),await d.writeFile(t,a,"utf-8"),console.log(`[TestPostProcessor] \u2705 Generated test with ${o.filter(c=>["type","fill","click","select_option"].includes(c.type)).length} actions`),!0}catch(s){return console.warn("[TestPostProcessor] Failed to generate from events:",s.message),!1}}static async enhanceSelectorsWithTrace(t,n,r){try{console.log("[TestPostProcessor] \u{1F6E1}\uFE0F Applying Zibby Safe Action Wrappers...");let e=await d.readFile(t,"utf-8");e.includes("ZibbyRuntime")||(e=`import { ZibbyRuntime } from '@zibby/core';
20
+ ${e}`);for(let s=0;s<n.length;s++){let o=n[s],i=`element${s}`,l=new RegExp(`const ${i}\\b\\s*=\\s*page\\.[^;]+;(\\s*await ${i}\\.waitFor\\([^)]*\\);)?\\s*await ${i}\\.(click|fill|type|selectOption|pressSequentially)\\(([^)]*)\\);`,"s"),a=e.match(l);if(!a)continue;let p={name:o.name||`Action ${s}`,action:o.method==="type"?"fill":o.method,value:a[3].trim().replace(/^['"]|['"]$/g,""),strategies:o.strategies||[]},u=`await ZibbyRuntime.step(page, ${JSON.stringify(p,null,2)});`;e=e.replace(a[0],u)}return await d.writeFile(t,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(t,n){try{let{actions:r=[]}=n;if(!r.length)return!1;let e=await d.readFile(t,"utf-8"),s=this.buildSelectorMap(r);return e=this.replaceSimpleSelectors(e,s),await d.writeFile(t,e,"utf-8"),!0}catch(r){return console.warn("Failed to enhance selectors:",r),!1}}static buildSelectorMap(t){let n=new Map;for(let r=0;r<t.length;r++){let e=t[r];if(!e.selectors||e.type==="navigate")continue;let s=`element${r}`,i=h.generate(e,s).match(/= (.+);/s);if(i){let l=i[1].trim(),a=`${e.type}:${this.normalizeDescription(e.description)}`;n.set(a,l),e.selectors.role&&n.set(`role:${e.selectors.role.name}`,l),e.selectors.attributes?.placeholder&&n.set(`placeholder:${e.selectors.attributes.placeholder}`,l)}}return n}static replaceSimpleSelectors(t,n){let r=t,e=[/await page\.(getByRole|getByPlaceholder|getByText|getByLabel|locator)\([^)]+\)\.(fill|click|type)\([^)]*\)/g];for(let s of e)r=r.replace(s,o=>{for(let[i,l]of n.entries())if(o.includes(i.split(":")[1])){let a=o.match(/\.(fill|click|type)\(([^)]*)\)/);if(a){let[,p,u]=a,y="element";return`const ${y} = ${l};
21
+ await ${y}.${p}(${u})`}}return o});return r}static normalizeDescription(t){return t?t.toLowerCase().replace(/[^a-z0-9]+/g," ").trim():""}},R=$;export{$ as TestPostProcessor,R as default};
@@ -1,14 +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===`
1
+ import e from"chalk";var E="__WORKFLOW_GRAPH_LOG__",c=e.gray("\u2502"),I=e.gray("\u250C"),S=e.gray("\u2514"),h=e.green("\u25C6"),p=e.hex("#c084fc")("\u25C6"),W=e.hex("#2dd4bf")("\u25C6"),l=e.red("\u25C6"),w=`${c} `,f=2;function g(d){return d<1e3?`${d}ms`:`${(d/1e3).toFixed(1)}s`}function $(d,t){return(r,o,n)=>{if(typeof r!="string")return d(r,o,n);let _=process.stdout.columns||120,s="";for(let u=0;u<r.length;u++){let i=r[u];t.lineStart&&(s+=w,t.col=f,t.lineStart=!1),i===`
2
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(`
3
+ ${w}`,t.col=f))}return d(s,o,n)}}var a=class{constructor(){this._currentNode=null,this._origStdoutWrite=null,this._origStderrWrite=null;let 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);let t={lineStart:!0,col:0,inEsc:!1},r={lineStart:!0,col:0,inEsc:!1};this._outState=t,this._errState=r,process.stdout.write=$(this._origStdoutWrite,t),process.stderr.write=$(this._origStderrWrite,r)}_stopIntercepting(){this._origStdoutWrite&&(this._outState&&!this._outState.lineStart&&this._origStdoutWrite(`
4
4
  `),process.stdout.write=this._origStdoutWrite),this._origStderrWrite&&(this._errState&&!this._errState.lineStart&&this._origStderrWrite(`
5
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)}
6
+ `)}_emitGraphLogMarker(t){if(!this._emitWorkflowGraphMarkers)return;let r=`${E}${JSON.stringify(t)}
7
7
  `;this._origStdoutWrite?this._origStdoutWrite(r):process.stdout.write(r)}_writeDot(t,r){this._origStdoutWrite?(this._outState&&!this._outState.lineStart&&(this._origStdoutWrite(`
8
8
  `),this._outState.lineStart=!0,this._outState.col=0),this._origStdoutWrite(`${t} ${r}
9
9
  `)):process.stdout.write.bind(process.stdout)(`${t} ${r}
10
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}
11
+ `)}stepTool(t){this._origStdoutWrite?this._writeDot(p,t):process.stdout.write.bind(process.stdout)(`${c} ${p} ${t}
12
+ `)}stepMemory(t){let r=e.hex("#2dd4bf")(t);this._origStdoutWrite?this._writeDot(W,r):process.stdout.write.bind(process.stdout)(`${c} ${W} ${r}
13
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};
14
+ `)}nodeStart(t){this._currentNode=t,this._emitGraphLogMarker({phase:"node_begin",node:t}),this._rawWrite(`${I} ${t}`),this._startIntercepting()}nodeComplete(t,r={}){this._stopIntercepting();let{duration:o,details:n}=r;if(n)for(let s of n)this._rawWrite(`${h} ${s}`);let _=o?e.dim(` ${g(o)}`):"";this._rawWrite(`${S} ${e.green("done")}${_}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}nodeFailed(t,r,o={}){this._stopIntercepting();let{duration:n}=o,_=n?e.dim(` ${g(n)}`):"";this._rawWrite(`${l} ${e.red(r)}`),this._rawWrite(`${S} ${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"))}},O=new a,P=O;export{E as WORKFLOW_GRAPH_LOG_MARKER_PREFIX,P as default,O as timeline};
@@ -1,2 +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};
1
+ import{readFileSync as W,existsSync as F,readdirSync as O}from"node:fs";import{join as N}from"node:path";import{execSync as L}from"node:child_process";import{tmpdir as B}from"node:os";var v=class{static async parseTraceZip(h){let o;if(h.endsWith(".zip")&&F(h)){let n=N(B(),`trace-${Date.now()}`);L(`unzip -q "${h}" -d "${n}"`,{stdio:"pipe"});let a=O(n).find(c=>c.endsWith(".trace"));if(!a)throw new Error("No .trace file found in zip");o=N(n,a)}else if(F(h)){let u=O(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{let u=W(o,"utf-8").trim().split(`
2
+ `),a=[],c=new Map,r=new Map;for(let w of u)try{let t=JSON.parse(w);if(t.type==="snapshot"&&t.snapshot&&t.snapshot.accessibility){let l=new Map;for(let i of t.snapshot.accessibility)i.ref&&l.set(i.ref,i);c.set(t.snapshotName,l)}if(t.type==="frame-snapshot"&&t.snapshot){let l=Buffer.from(t.snapshot.html||"","base64").toString("utf-8");l&&l.length>100&&r.set(t.pageId||"default",l)}}catch{}for(let w of u)try{let t=JSON.parse(w);if(t.type==="before"&&t.params&&t.params.selector){let l=t.method;if(["click","fill","type","selectOption"].includes(l)){let i=t.params.selector,z=t.params.text||t.params.value||"",e=[],p=null,f=null,m=null,R=i.match(/aria-ref=([a-z0-9]+)/i);if(R&&t.snapshotName){let s=R[1],x=c.get(t.snapshotName);if(x&&x.has(s)){let 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}"`)}}let d=i.match(/internal:text="([^"]+)"/i),E=i.match(/internal:label="([^"]+)"/i),C=i.match(/internal:placeholder="([^"]+)"/i),T=i.match(/internal:role=([^ ]+)/i),M=i.match(/internal:describe="([^"]+)"/i),k=i.match(/name="([^"]+)"/i);if(d){e.push({type:"text",text:d[1]});let 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(E&&e.push({type:"label",label:E[1]}),C&&e.push({type:"placeholder",placeholder:C[1]}),p){e.unshift({type:"text",text:p,source:"accessibility-tree"});let s=p.split(" ");s.length>1&&e.push({type:"text",text:s[0],fuzzy:!0,source:"accessibility-tree"})}if(f||T){let s=f||T[1],x=p||(k?k[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){let s=M[1],x=["link","button","textbox","menuitem","submenu","combobox","checkbox","radio","tab","treeitem","menu item"],y=null,$=s;for(let 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:$});let g=$.replace(/\s*\([^)]+\)\s*$/,"");e.push({type:"text",text:g}),e.push({type:"text",text:$});let 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{let g=s.replace(/\s*\([^)]+\)\s*$/,"");e.push({type:"text",text:g}),e.push({type:"text",text:s})}}let A=this.extractDOMStrategies(i,r,d?.[1]||M?.[1],t.pageId);e.push(...A);let 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});let j=p||d?d[1]:M?M[1].replace(/\s*\([^)]+\)\s*$/,""):`Action ${a.length}`;a.push({method:l,name:j,action:l==="type"?"fill":l,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){let a=[];if(!o||o.size===0||!n)return a;try{let c=o.get(u);if(!c)return a;let r=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),w=new RegExp(`data-testid=["']([^"']+)["'][^>]*>[^<]*${r}`,"i"),t=c.match(w);t&&a.push({type:"testid",value:t[1],priority:"high"});let l=new RegExp(`class=["']([^"']+)["'][^>]*>[^<]*${r}`,"gi"),i=c.matchAll(l);for(let p of i){let 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"}))}let z=new RegExp(`id=["']([^"']+)["'][^>]*>[^<]*${r}`,"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){let o={parent:null,sibling:null},n=h.split(">>").map(c=>c.trim());if(n.length>1){let r=n[n.length-2].replace(/internal:text="[^"]+"\s*/gi,"").replace(/internal:role=\S+\s*/gi,"").replace(/internal:label="[^"]+"\s*/gi,"").trim();r&&(r.match(/^(form|section|nav|header|aside|main|article)\b/)||r.includes("[")||r.match(/[#.]\w/))&&(o.parent=r)}let a=n[n.length-1].match(/([^+~]+)\s*[+~]\s*(.+)/);return a&&(o.sibling=a[1].trim()),o}},U=v;export{v as TraceParser,U as default};
@@ -1,3 +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};
1
+ import{readdir as v,access as h,copyFile as w,constants as g}from"fs/promises";import{join as i,relative as $}from"node:path";async function F(c={}){let{testResultsDir:a="test-results",testsDir:o="tests",projectRoot:t=process.cwd(),verbose:s=!0}=c;s&&console.log(`\u{1F3A5} Organizing test videos...
2
+ `);let r=i(t,a),l=i(t,o);try{let e=await v(r),f=0;for(let n of e){if(n.startsWith("."))continue;let u=i(r,n,"video.webm");try{await h(u,g.F_OK)}catch{continue}let m=n.replace(/-chromium$/,"").replace(/-firefox$/,"").replace(/-webkit$/,""),d=await P(l,m);if(d){let 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){let o=a.split("-");for(let t=o.length;t>0;t--){let r=o.slice(0,t).join("/");for(let l of["js","ts"]){let e=i(c,`${r}.spec.${l}`);try{return await h(e,g.F_OK),e}catch{}}}return null}export{F as organizeVideos};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.33",
3
+ "version": "0.1.36",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,8 +8,6 @@ import {
8
8
  writeFileSync,
9
9
  existsSync,
10
10
  readFileSync,
11
- readdirSync,
12
- renameSync,
13
11
  statSync,
14
12
  copyFileSync,
15
13
  mkdirSync,
@@ -22,7 +20,10 @@ export class BrowserTestResultHandler extends ResultHandler {
22
20
 
23
21
  static async onNodeSaved(nodeFolder, executionData) {
24
22
  this.enrichEvents(nodeFolder, executionData);
25
- await this.renameVideoFile(nodeFolder);
23
+ const videoPath = join(nodeFolder, 'recording.webm');
24
+ if (existsSync(videoPath)) {
25
+ this.recalculateEventTimestamps(nodeFolder, videoPath);
26
+ }
26
27
  }
27
28
 
28
29
  // ── Video ──────────────────────────────────────────────────
@@ -124,42 +125,6 @@ export class BrowserTestResultHandler extends ResultHandler {
124
125
  return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(3, '0')}`;
125
126
  }
126
127
 
127
- static async renameVideoFile(folder) {
128
- logger.debug(`renameVideoFile called for: ${folder}`);
129
- await new Promise(resolve => setTimeout(resolve, 1000));
130
-
131
- try {
132
- const files = readdirSync(folder);
133
- logger.debug(`Files in directory: ${files.join(', ')}`);
134
- let videoFile = files.find(f => f.endsWith('.webm') && f !== 'recording.webm');
135
-
136
- if (!videoFile) {
137
- const parentDir = join(folder, '..');
138
- const parentFiles = readdirSync(parentDir);
139
- const parentVideo = parentFiles.find(f => f.endsWith('.webm') && f !== 'recording.webm');
140
- if (parentVideo) {
141
- const srcPath = join(parentDir, parentVideo);
142
- const destPath = join(folder, parentVideo);
143
- renameSync(srcPath, destPath);
144
- logger.debug(`Moved video from session root: ${parentVideo}`);
145
- videoFile = parentVideo;
146
- }
147
- }
148
-
149
- if (videoFile) {
150
- const oldPath = join(folder, videoFile);
151
- const newPath = join(folder, 'recording.webm');
152
- renameSync(oldPath, newPath);
153
- logger.debug(`Renamed video: ${videoFile} → recording.webm`);
154
- this.recalculateEventTimestamps(folder, newPath);
155
- } else {
156
- logger.debug(`No video file to rename (files: ${files.length})`);
157
- }
158
- } catch (err) {
159
- console.warn(`⚠️ Error in renameVideoFile: ${err.message}`);
160
- }
161
- }
162
-
163
128
  // ── Event enrichment + assertion resolution ────────────────
164
129
 
165
130
  static enrichEvents(executeLiveFolder, executionData) {