@zibby/core 0.1.31 → 0.1.34

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 +319 -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 +107 -4
  19. package/dist/framework/agents/codex-strategy.js +23 -4
  20. package/dist/framework/agents/cursor-strategy.js +138 -20
  21. package/dist/framework/agents/gemini-strategy.js +34 -7
  22. package/dist/framework/agents/index.js +285 -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 +75 -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 +309 -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 +314 -1
  40. package/dist/framework/graph.js +305 -4
  41. package/dist/framework/index.js +331 -1
  42. package/dist/framework/mcp-client.js +56 -2
  43. package/dist/framework/node-registry.js +294 -3
  44. package/dist/framework/node.js +297 -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 +512 -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
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.31",
3
+ "version": "0.1.34",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1 +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};
1
+ var e=class{async generate(t){throw new Error("TestGenerationStrategy.generate() must be implemented")}canGenerate(t){throw new Error("TestGenerationStrategy.canGenerate() must be implemented")}getName(){throw new Error("TestGenerationStrategy.getName() must be implemented")}getPriority(){return 0}},n=e;export{e as TestGenerationStrategy,n as default};
@@ -1,3 +1,58 @@
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};
1
+ var d=class{async generate(a){throw new Error("TestGenerationStrategy.generate() must be implemented")}canGenerate(a){throw new Error("TestGenerationStrategy.canGenerate() must be implemented")}getName(){throw new Error("TestGenerationStrategy.getName() must be implemented")}getPriority(){return 0}};import{readFileSync as w,writeFileSync as G}from"fs";var b=class extends d{constructor(){super("mcp-ref","MCP Reference Replay (Exact 1:1)",200)}canGenerate(a){let t=a.eventsPath||`${a.sessionPath}/execute_live/events.json`;try{return JSON.parse(w(t,"utf-8")).some(p=>p.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(s){return console.log("[MCPRefStrategy] \u274C Failed to read events:",s.message),!1}}getName(){return"MCP Reference Replay (Exact 1:1)"}getPriority(){return 200}async generate(a){let{testFilePath:t,sessionPath:s,state:o}=a,p=`${s}/execute_live/events.json`,x=o?.title||"Generated Test";console.log("[MCPRefStrategy] \u{1F3AF} Generating test using MCP element descriptions (1:1 replay)"),console.log(`[MCPRefStrategy] events: ${p}`),console.log(`[MCPRefStrategy] output: ${t}`);let u=JSON.parse(w(p,"utf-8")).filter(n=>["navigate","type","fill","click","select_option"].includes(n.type)),e=`import { test, expect } from '@playwright/test';
2
+ `;e+=`import { ZibbyRuntime } from '@zibby/core';
3
+
4
+ `,e+=`test('${x}', async ({ page }) => {
5
+ `,e+=` const timestamp = Date.now();
6
+
7
+ `;for(let n of u){let l=n.data?.params?.element||"element",m=n.data?.params?.ref,r=n.enrichedData?.traceActualText,c=n.enrichedData?.traceActualRole,$=n.enrichedData?.traceActualAriaLabel,i=n.enrichedData?.actualText,g=r||i,k=c||n.enrichedData?.actualRole,M=g||l,y=g||this._extractName(l),_=k||this._extractRole(l),v=r?" [accessibility-tree]":i?" [live]":" [AI]";if(n.type==="navigate")e+=` await page.goto('${n.data.params.url}');
8
+
9
+ `;else if(n.type==="click")e+=` // ${l}${g?` (actual: "${g}")${v}`:""}
10
+ `,e+=` await ZibbyRuntime.step(page, {
11
+ `,e+=` name: '${this._escapeString(l)}',
12
+ `,e+=` action: 'click',
13
+ `,e+=` strategies: [
14
+ `,e+=` { type: 'role', role: '${_}', name: '${this._escapeString(y)}' },
15
+ `,e+=` { type: 'text', text: '${this._escapeString(y)}' }
16
+ `,e+=` ]
17
+ `,e+=` });
18
+
19
+ `;else if(n.type==="fill"||n.type==="type"){let f=n.data.params.text;e+=` // ${l}${g?` (actual: "${g}")${v}`:""}
20
+ `,e+=` await ZibbyRuntime.step(page, {
21
+ `,e+=` name: '${this._escapeString(l)}',
22
+ `,e+=` action: 'fill',
23
+ `,e+=` value: '${this._escapeString(f)}',
24
+ `,e+=` strategies: [
25
+ `,e+=` { type: 'role', role: '${_}', name: '${this._escapeString(y)}' },
26
+ `,e+=` { type: 'attributes', placeholder: '${this._escapeString(y)}' }
27
+ `,e+=` ]
28
+ `,e+=` });
29
+
30
+ `}else if(n.type==="select_option"){let f=n.data.params.values,C=Array.isArray(f)?f[0]:f;e+=` // ${l}${g?` (actual: "${g}")${v}`:""}
31
+ `,e+=` await ZibbyRuntime.step(page, {
32
+ `,e+=` name: '${this._escapeString(l)}',
33
+ `,e+=` action: 'select',
34
+ `,e+=` value: '${this._escapeString(C)}',
35
+ `,e+=` strategies: [
36
+ `,e+=` { type: 'role', role: 'combobox', name: '${this._escapeString(y)}' }
37
+ `,e+=` ]
38
+ `,e+=` });
39
+
40
+ `}}return e+=`});
41
+ `,G(t,e),console.log(`[MCPRefStrategy] \u2705 Generated test with ${u.length} actions using MCP descriptions`),{success:!0,testPath:t,method:"MCP Reference Replay (1:1)",actionsGenerated:u.length}}_extractRole(a){let t=a.toLowerCase();return t.includes("button")?"button":t.includes("textbox")?"textbox":t.includes("link")?"link":t.includes("checkbox")?"checkbox":t.includes("radio")?"radio":t.includes("combobox")?"combobox":t.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")}};import{readFileSync as R,writeFileSync as N}from"fs";var h=class extends d{constructor(){super("stable-id","Stable ID Injection (Experimental)",300)}canGenerate(a){let t=a.eventsPath||`${a.sessionPath}/execute_live/events.json`;try{return JSON.parse(R(t,"utf-8")).some(p=>p.stableId||p.data?.stableId)?(console.log("[StableIdStrategy] \u2705 Stable IDs available"),!0):(console.log("[StableIdStrategy] \u274C No stable IDs found in events"),!1)}catch(s){return console.log("[StableIdStrategy] \u274C Failed to read events:",s.message),!1}}getName(){return"Stable ID Injection (Experimental)"}getPriority(){return 300}async generate(a){let{testFilePath:t,sessionPath:s,state:o}=a,p=`${s}/execute_live/events.json`,x=o?.title||"Generated Test";console.log("[StableIdStrategy] \u{1F3AF} Generating test using stable IDs"),console.log(`[StableIdStrategy] events: ${p}`),console.log(`[StableIdStrategy] output: ${t}`);let u=JSON.parse(R(p,"utf-8")).filter(m=>["navigate","type","fill","click","select_option","select"].includes(m.type)),e=`import { test, expect } from '@playwright/test';
42
+ `;e+=`import { StableIdRuntime } from '@zibby/core';
43
+
44
+ `,e+=`test('${x}', async ({ page }) => {
45
+ `;let n=!1,l=null;for(let m=0;m<u.length;m++){let r=u[m],c=r.stableId||r.data?.stableId,$=r.data?.element||r.data?.params?.element||"element";if(r.type==="click"&&c&&c===l){console.log(`[StableIdStrategy] Skipping duplicate click on ${c}`);continue}if(r.type==="navigate"){let i=r.data?.url||r.data?.params?.url;i&&!n&&(e+=` await page.goto('${i}');
46
+ `,e+=` await StableIdRuntime.injectStableIds(page);
47
+
48
+ `)}else if(r.type==="click")if(n=!0,l=c,c)e+=` await StableIdRuntime.clickWithRetry(page, '${c}');
49
+ `;else{let i=this._generateSemanticSelector($);e+=` await ${i}.click();
50
+ `,e+=` await StableIdRuntime.afterNavigation(page);
51
+ `}else if(r.type==="fill"||r.type==="type"){n=!1;let i=r.data?.text||r.data?.params?.text||"";c?e+=` await StableIdRuntime.fillWithRetry(page, '${c}', '${this._escapeString(i)}');
52
+ `:e+=` await page.getByPlaceholder('${this._escapeString($)}').fill('${this._escapeString(i)}');
53
+ `}else if(r.type==="select_option"||r.type==="select"){n=!1;let i=r.data?.values||r.data?.params?.values,g=Array.isArray(i)?i[0]:i||"";c?e+=` await StableIdRuntime.selectWithRetry(page, '${c}', '${this._escapeString(g)}');
54
+ `:e+=` await page.locator('select').selectOption('${this._escapeString(g)}');
55
+ `}}return e+=`});
56
+ `,N(t,e),console.log(`[StableIdStrategy] \u2705 Generated test with ${u.length} actions using stable IDs`),{success:!0,testPath:t,method:"Stable ID Injection (Experimental)",actionsGenerated:u.length}}_escapeString(a){return a.replace(/'/g,"\\'").replace(/\n/g,"\\n")}_generateSemanticSelector(a){let t=a.toLowerCase(),s="locator",o=a;return t.includes("button")?(s="button",o=a.replace(/\s*button\s*/gi,"").trim()):t.includes("link")?(s="link",o=a.replace(/\s*link\s*/gi,"").trim()):t.includes("textbox")?(s="textbox",o=a.replace(/\s*textbox\s*/gi,"").trim()):t.includes("checkbox")?(s="checkbox",o=a.replace(/\s*checkbox\s*/gi,"").trim()):(t.includes("combobox")||t.includes("dropdown")||t.includes("select"))&&(s="combobox",o=a.replace(/\s*(combobox|dropdown|select)\s*/gi,"").trim()),s!=="locator"&&o?`page.getByRole('${s}', { name: '${this._escapeString(o)}' })`:`page.getByText('${this._escapeString(a)}')`}};var P=class{constructor(){this.strategies=[new h,new b],this.strategies.sort((a,t)=>t.getPriority()-a.getPriority())}registerStrategy(a){this.strategies.push(a),this.strategies.sort((t,s)=>s.getPriority()-t.getPriority())}async generate(a){console.log(`
57
+ \u{1F4CB} Available generation strategies (${this.strategies.length}):`),this.strategies.forEach(t=>{let s=t.canGenerate(a);console.log(` ${s?"\u2713":"\u2717"} ${t.getName()} (priority: ${t.getPriority()})`)});for(let t of this.strategies)if(t.canGenerate(a))return console.log(`
58
+ \u{1F3AF} Selected: ${t.getName()}`),t.generate(a);throw new Error("No generation strategy available for this context")}getStrategy(a){return this.strategies.find(t=>t.getName().includes(a))||null}},E=new P,B=E;export{b as MCPRefStrategy,h as StableIdStrategy,d as TestGenerationStrategy,P as TestGenerationStrategyManager,B as default,E as testGenerationManager};
@@ -1,41 +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';
1
+ var p=class{async generate(n){throw new Error("TestGenerationStrategy.generate() must be implemented")}canGenerate(n){throw new Error("TestGenerationStrategy.canGenerate() must be implemented")}getName(){throw new Error("TestGenerationStrategy.getName() must be implemented")}getPriority(){return 0}};import{readFileSync as h,writeFileSync as R}from"fs";var x=class extends p{constructor(){super("mcp-ref","MCP Reference Replay (Exact 1:1)",200)}canGenerate(n){let a=n.eventsPath||`${n.sessionPath}/execute_live/events.json`;try{return JSON.parse(h(a,"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(n){let{testFilePath:a,sessionPath:i,state:g}=n,l=`${i}/execute_live/events.json`,$=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: ${a}`);let u=JSON.parse(h(l,"utf-8")).filter(t=>["navigate","type","fill","click","select_option"].includes(t.type)),e=`import { test, expect } from '@playwright/test';
2
2
  `;e+=`import { ZibbyRuntime } from '@zibby/core';
3
3
 
4
- `,e+=`test('${h}', async ({ page }) => {
4
+ `,e+=`test('${$}', async ({ page }) => {
5
5
  `,e+=` const timestamp = Date.now();
6
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}');
7
+ `;for(let t of u){let r=t.data?.params?.element||"element",C=t.data?.params?.ref,y=t.enrichedData?.traceActualText,v=t.enrichedData?.traceActualRole,w=t.enrichedData?.traceActualAriaLabel,d=t.enrichedData?.actualText,s=y||d,_=v||t.enrichedData?.actualRole,M=s||r,o=s||this._extractName(r),f=_||this._extractRole(r),m=y?" [accessibility-tree]":d?" [live]":" [AI]";if(t.type==="navigate")e+=` await page.goto('${t.data.params.url}');
8
8
 
9
- `;else if(t.type==="click")e+=` // ${s}${r?` (actual: "${r}")${u}`:""}
9
+ `;else if(t.type==="click")e+=` // ${r}${s?` (actual: "${s}")${m}`:""}
10
10
  `,e+=` await ZibbyRuntime.step(page, {
11
- `,e+=` name: '${this._escapeString(s)}',
11
+ `,e+=` name: '${this._escapeString(r)}',
12
12
  `,e+=` action: 'click',
13
13
  `,e+=` strategies: [
14
- `,e+=` { type: 'role', role: '${y}', name: '${this._escapeString(c)}' },
15
- `,e+=` { type: 'text', text: '${this._escapeString(c)}' }
14
+ `,e+=` { type: 'role', role: '${f}', name: '${this._escapeString(o)}' },
15
+ `,e+=` { type: 'text', text: '${this._escapeString(o)}' }
16
16
  `,e+=` ]
17
17
  `,e+=` });
18
18
 
19
- `;else if(t.type==="fill"||t.type==="type"){const o=t.data.params.text;e+=` // ${s}${r?` (actual: "${r}")${u}`:""}
19
+ `;else if(t.type==="fill"||t.type==="type"){let c=t.data.params.text;e+=` // ${r}${s?` (actual: "${s}")${m}`:""}
20
20
  `,e+=` await ZibbyRuntime.step(page, {
21
- `,e+=` name: '${this._escapeString(s)}',
21
+ `,e+=` name: '${this._escapeString(r)}',
22
22
  `,e+=` action: 'fill',
23
- `,e+=` value: '${this._escapeString(o)}',
23
+ `,e+=` value: '${this._escapeString(c)}',
24
24
  `,e+=` strategies: [
25
- `,e+=` { type: 'role', role: '${y}', name: '${this._escapeString(c)}' },
26
- `,e+=` { type: 'attributes', placeholder: '${this._escapeString(c)}' }
25
+ `,e+=` { type: 'role', role: '${f}', name: '${this._escapeString(o)}' },
26
+ `,e+=` { type: 'attributes', placeholder: '${this._escapeString(o)}' }
27
27
  `,e+=` ]
28
28
  `,e+=` });
29
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}`:""}
30
+ `}else if(t.type==="select_option"){let c=t.data.params.values,P=Array.isArray(c)?c[0]:c;e+=` // ${r}${s?` (actual: "${s}")${m}`:""}
31
31
  `,e+=` await ZibbyRuntime.step(page, {
32
- `,e+=` name: '${this._escapeString(s)}',
32
+ `,e+=` name: '${this._escapeString(r)}',
33
33
  `,e+=` action: 'select',
34
- `,e+=` value: '${this._escapeString(x)}',
34
+ `,e+=` value: '${this._escapeString(P)}',
35
35
  `,e+=` strategies: [
36
- `,e+=` { type: 'role', role: 'combobox', name: '${this._escapeString(c)}' }
36
+ `,e+=` { type: 'role', role: 'combobox', name: '${this._escapeString(o)}' }
37
37
  `,e+=` ]
38
38
  `,e+=` });
39
39
 
40
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};
41
+ `,R(a,e),console.log(`[MCPRefStrategy] \u2705 Generated test with ${u.length} actions using MCP descriptions`),{success:!0,testPath:a,method:"MCP Reference Replay (1:1)",actionsGenerated:u.length}}_extractRole(n){let a=n.toLowerCase();return a.includes("button")?"button":a.includes("textbox")?"textbox":a.includes("link")?"link":a.includes("checkbox")?"checkbox":a.includes("radio")?"radio":a.includes("combobox")?"combobox":a.includes("heading")?"heading":"button"}_extractName(n){return n.replace(/\s+(button|textbox|link|checkbox|radio|combobox)$/i,"").trim()}_escapeRegex(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}_escapeString(n){return n.replace(/'/g,"\\'").replace(/\n/g,"\\n")}};export{x as MCPRefStrategy};
@@ -1,16 +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';
1
+ var d=class{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}};import{readFileSync as m,writeFileSync as I}from"fs";var y=class extends d{constructor(){super("stable-id","Stable ID Injection (Experimental)",300)}canGenerate(e){let a=e.eventsPath||`${e.sessionPath}/execute_live/events.json`;try{return JSON.parse(m(a,"utf-8")).some(o=>o.stableId||o.data?.stableId)?(console.log("[StableIdStrategy] \u2705 Stable IDs available"),!0):(console.log("[StableIdStrategy] \u274C No stable IDs found in events"),!1)}catch(s){return console.log("[StableIdStrategy] \u274C Failed to read events:",s.message),!1}}getName(){return"Stable ID Injection (Experimental)"}getPriority(){return 300}async generate(e){let{testFilePath:a,sessionPath:s,state:i}=e,o=`${s}/execute_live/events.json`,h=i?.title||"Generated Test";console.log("[StableIdStrategy] \u{1F3AF} Generating test using stable IDs"),console.log(`[StableIdStrategy] events: ${o}`),console.log(`[StableIdStrategy] output: ${a}`);let g=JSON.parse(m(o,"utf-8")).filter(c=>["navigate","type","fill","click","select_option","select"].includes(c.type)),n=`import { test, expect } from '@playwright/test';
2
+ `;n+=`import { StableIdRuntime } from '@zibby/core';
3
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);
4
+ `,n+=`test('${h}', async ({ page }) => {
5
+ `;let p=!1,u=null;for(let c=0;c<g.length;c++){let t=g[c],r=t.stableId||t.data?.stableId,b=t.data?.element||t.data?.params?.element||"element";if(t.type==="click"&&r&&r===u){console.log(`[StableIdStrategy] Skipping duplicate click on ${r}`);continue}if(t.type==="navigate"){let l=t.data?.url||t.data?.params?.url;l&&!p&&(n+=` await page.goto('${l}');
6
+ `,n+=` await StableIdRuntime.injectStableIds(page);
7
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};
8
+ `)}else if(t.type==="click")if(p=!0,u=r,r)n+=` await StableIdRuntime.clickWithRetry(page, '${r}');
9
+ `;else{let l=this._generateSemanticSelector(b);n+=` await ${l}.click();
10
+ `,n+=` await StableIdRuntime.afterNavigation(page);
11
+ `}else if(t.type==="fill"||t.type==="type"){p=!1;let l=t.data?.text||t.data?.params?.text||"";r?n+=` await StableIdRuntime.fillWithRetry(page, '${r}', '${this._escapeString(l)}');
12
+ `:n+=` await page.getByPlaceholder('${this._escapeString(b)}').fill('${this._escapeString(l)}');
13
+ `}else if(t.type==="select_option"||t.type==="select"){p=!1;let l=t.data?.values||t.data?.params?.values,S=Array.isArray(l)?l[0]:l||"";r?n+=` await StableIdRuntime.selectWithRetry(page, '${r}', '${this._escapeString(S)}');
14
+ `:n+=` await page.locator('select').selectOption('${this._escapeString(S)}');
15
+ `}}return n+=`});
16
+ `,I(a,n),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(e){return e.replace(/'/g,"\\'").replace(/\n/g,"\\n")}_generateSemanticSelector(e){let a=e.toLowerCase(),s="locator",i=e;return a.includes("button")?(s="button",i=e.replace(/\s*button\s*/gi,"").trim()):a.includes("link")?(s="link",i=e.replace(/\s*link\s*/gi,"").trim()):a.includes("textbox")?(s="textbox",i=e.replace(/\s*textbox\s*/gi,"").trim()):a.includes("checkbox")?(s="checkbox",i=e.replace(/\s*checkbox\s*/gi,"").trim()):(a.includes("combobox")||a.includes("dropdown")||a.includes("select"))&&(s="combobox",i=e.replace(/\s*(combobox|dropdown|select)\s*/gi,"").trim()),s!=="locator"&&i?`page.getByRole('${s}', { name: '${this._escapeString(i)}' })`:`page.getByText('${this._escapeString(e)}')`}};export{y as StableIdStrategy};
@@ -1 +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};
1
+ var p=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={}){let s=h.timeout||1e4,l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);let 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){let l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);let 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){let l=`[data-zibby-id="${u}"]`,d=Date.now();for(;Date.now()-d<s;){await this.injectStableIds(e);let 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();let o=t.getAttribute("aria-labelledby");if(o){let n=document.getElementById(o);if(n)return n.textContent.trim()}if(t.id){let n=document.querySelector(`label[for="${t.id}"]`);if(n)return n.textContent.trim()}let i=t.closest("label");if(i){let n=i.cloneNode(!0);n.querySelectorAll("input, select, textarea").forEach(f=>f.remove());let m=n.textContent.trim();if(m)return m}if(t.placeholder)return t.placeholder;let 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){let 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{let a=new URL(i.action,window.location.origin).pathname;o.push(`form[action=${a}]`)}catch{o.push(`form[action=${i.getAttribute("action")}]`)}else{let a=document.querySelectorAll("form"),b=Array.from(a).indexOf(i);o.push(`form:nth(${b})`)}let r=t.closest('header, nav, main, footer, aside, [role="banner"], [role="navigation"], [role="main"], [role="contentinfo"]');if(r){let a=r.tagName.toLowerCase(),b=r.getAttribute("role");o.push(b||a)}let n=t.closest('section, article, [role="region"]');if(n){let a=n.querySelector("h1, h2, h3, h4, h5, h6");a&&o.push(`section:${a.textContent.trim().slice(0,30)}`)}let m=t.closest("fieldset");if(m){let a=m.querySelector("legend");a&&o.push(`fieldset:${a.textContent.trim()}`)}let f=t.closest('dialog, [role="dialog"], [role="alertdialog"]');if(f){let 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){let o=t.tagName.toLowerCase(),i=t.id||"",r=t.name||"",n=t.type||"",m=t.getAttribute("role")||"",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)||""}let a=u(t).slice(0,50).replace(/\s+/g," "),b=h(t),g=[o,i,r,n,m,f,a,b].join("|"),w=5381;for(let y=0;y<g.length;y++)w=(w<<5)+w^g.charCodeAt(y);return`zibby-${(w>>>0).toString(36)}`}let 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,c=0;document.querySelectorAll(l).forEach(t=>{let o=window.getComputedStyle(t);if(o.display==="none"||o.visibility==="hidden")return;let i=s(t),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{p as StableIdRuntime};
@@ -1 +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};
1
+ var e=class{async verify(t){throw new Error("TestVerificationStrategy.verify() must be implemented")}canVerify(t){throw new Error("TestVerificationStrategy.canVerify() must be implemented")}getName(){throw new Error("TestVerificationStrategy.getName() must be implemented")}getPriority(){return 0}},i=e;export{e as TestVerificationStrategy,i as default};
@@ -1,3 +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};
1
+ var c=class{async verify(t){throw new Error("TestVerificationStrategy.verify() must be implemented")}canVerify(t){throw new Error("TestVerificationStrategy.canVerify() must be implemented")}getName(){throw new Error("TestVerificationStrategy.getName() must be implemented")}getPriority(){return 0}};import{execSync as x}from"child_process";import{existsSync as w}from"fs";var l=class extends c{getName(){return"Playwright JSON Reporter"}getPriority(){return 100}canVerify(t){let{testFilePath:e}=t;return w(e)}async verify(t){let{testFilePath:e,cwd:n,timeout:m=3e4}=t;try{console.log(`\u{1F9EA} Running test: ${e}`);let a=`npx playwright test ${e} --reporter=json --timeout=${m}`,i=x(a,{cwd:n,encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:m+1e4}),s=JSON.parse(i).stats||{};return{success:s.unexpected===0,passed:s.expected||0,failed:s.unexpected||0,error:null,errorDetails:null}}catch(a){let i=a.stdout||a.stderr||a.message;try{let o=JSON.parse(i),s=o.stats||{},r="Test execution failed";if(o.suites&&o.suites.length>0){let g=o.suites[0];if(g.specs&&g.specs.length>0){let p=g.specs[0];if(p.tests&&p.tests.length>0){let d=p.tests[0];if(d.results&&d.results.length>0){let h=d.results[0];h.error&&(r=h.error.message||r)}}}}let u=r.includes("Executable doesn't exist")||r.includes("browserType.launch")||r.includes("Please run the following command")||r.includes("npx playwright install")||i.includes("Executable doesn't exist")||i.includes("npx playwright install");return{success:!1,passed:s.expected||0,failed:s.unexpected||0,error:r,errorDetails:r,isEnvironmentError:u}}catch{let s=i.match(/Error: (.+)/),r=s?s[1]:"Test execution failed",u=r.includes("Executable doesn't exist")||r.includes("browserType.launch")||r.includes("Please run the following command")||r.includes("npx playwright install")||i.includes("Executable doesn't exist")||i.includes("npx playwright install");return{success:!1,passed:0,failed:1,error:r,errorDetails:r,isEnvironmentError:u}}}}};var f=class{constructor(){this.strategies=[new l],this.strategies.sort((t,e)=>e.getPriority()-t.getPriority())}registerStrategy(t){this.strategies.push(t),this.strategies.sort((e,n)=>n.getPriority()-e.getPriority())}async verify(t){console.log(`
2
+ \u{1F4CB} Available verification strategies (${this.strategies.length}):`),this.strategies.forEach(e=>{let n=e.canVerify(t);console.log(` ${n?"\u2713":"\u2717"} ${e.getName()} (priority: ${e.getPriority()})`)});for(let e of this.strategies)if(e.canVerify(t))return console.log(`
3
+ \u{1F3AF} Selected: ${e.getName()}`),e.verify(t);throw new Error("No verification strategy available for this context")}getStrategy(t){return this.strategies.find(e=>e.getName().includes(t))||null}},E=new f,$=E;export{l as PlaywrightJsonVerificationStrategy,c as TestVerificationStrategy,f as TestVerificationStrategyManager,$ as default,E as testVerificationManager};
@@ -1 +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};
1
+ var c=class{async verify(n){throw new Error("TestVerificationStrategy.verify() must be implemented")}canVerify(n){throw new Error("TestVerificationStrategy.canVerify() must be implemented")}getName(){throw new Error("TestVerificationStrategy.getName() must be implemented")}getPriority(){return 0}};import{execSync as y}from"child_process";import{existsSync as h}from"fs";var d=class extends c{getName(){return"Playwright JSON Reporter"}getPriority(){return 100}canVerify(n){let{testFilePath:i}=n;return h(i)}async verify(n){let{testFilePath:i,cwd:g,timeout:m=3e4}=n;try{console.log(`\u{1F9EA} Running test: ${i}`);let o=`npx playwright test ${i} --reporter=json --timeout=${m}`,s=y(o,{cwd:g,encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:m+1e4}),t=JSON.parse(s).stats||{};return{success:t.unexpected===0,passed:t.expected||0,failed:t.unexpected||0,error:null,errorDetails:null}}catch(o){let s=o.stdout||o.stderr||o.message;try{let r=JSON.parse(s),t=r.stats||{},e="Test execution failed";if(r.suites&&r.suites.length>0){let a=r.suites[0];if(a.specs&&a.specs.length>0){let u=a.specs[0];if(u.tests&&u.tests.length>0){let p=u.tests[0];if(p.results&&p.results.length>0){let x=p.results[0];x.error&&(e=x.error.message||e)}}}}let l=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:l}}catch{let t=s.match(/Error: (.+)/),e=t?t[1]:"Test execution failed",l=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:l}}}}},T=d;export{d as PlaywrightJsonVerificationStrategy,T as default};
@@ -1 +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};
1
+ var b=class{static async step(i,t){let{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);let 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,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{let e=await i.boundingBox();if(!e)return;let 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){let n=Date.now(),o=t.map(async(c,u)=>{try{let f=await this.getLocator(i,c).all();return f.length===0?[]:(await Promise.all(f.map(async(l,d)=>{try{if(!await l.isVisible({timeout:100}))return null;let m=await this.scoreCandidate(l,c,i);return{element:l,strategy:c,score:m,strategyIdx:u,elIdx:d}}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);let 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{let o=await i.boundingBox();o&&o.y<1e3&&(a+=10)}catch{}try{let 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:{let 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{b as ZibbyRuntime};
@@ -1 +1 @@
1
- import{ZibbyUploader as o,createUploader as a}from"./uploader.js";export{o as ZibbyUploader,a as createUploader};
1
+ var e=class{constructor(t,s={}){this.apiKey=t,this.baseUrl=s.baseUrl||process.env.ZIBBY_API_URL||"https://api-prod.zibby.app",this.enabled=!!t}isEnabled(){return this.enabled}};function a(){let r=process.env.ZIBBY_API_KEY;return new e(r)}export{e as ZibbyUploader,a as createUploader};
@@ -1 +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};
1
+ var e=class{constructor(t,r={}){this.apiKey=t,this.baseUrl=r.baseUrl||process.env.ZIBBY_API_URL||"https://api-prod.zibby.app",this.enabled=!!t}isEnabled(){return this.enabled}};function n(){let s=process.env.ZIBBY_API_KEY;return new e(s)}export{e as ZibbyUploader,n as createUploader};
@@ -1,5 +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}
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";var 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){let 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.`};let 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=>{let j=k(e),u=T("npx",["playwright","test",e,"--reporter=line"],{cwd:h,env:{...process.env,FORCE_COLOR:"0"}}),c="",f="";u.stdout.on("data",s=>{c+=s.toString()}),u.stderr.on("data",s=>{f+=s.toString()});let 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);let p=`${c}
2
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}
3
+ `),g="",C=null;for(let a=0;a<p.length;a++){let r=p[a];if(r.includes("Error:")||r.includes("error:")||r.includes("\u2718")){g+=`${r}
4
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};
5
+ `}if(r.includes("at ")&&r.includes(".spec.")){let 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(let i of m.keys())i.startsWith(`${o}:`)&&m.delete(i)}};function b(o){M.resetCount(o)}export{b as resetExecutionCount,M as runPlaywrightTestTool};
@@ -2,6 +2,6 @@ function e(t){return!t||typeof t!="object"?String(t||""):t.type==="doc"&&Array.i
2
2
 
3
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
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||""}
5
+ `);if(t.type==="listItem"&&Array.isArray(t.content))return t.content.map(r).join("");if(t.type==="codeBlock"&&Array.isArray(t.content)){let n=t.content.map(r).join("");return`\`\`\`${t.attrs?.language||""}
6
6
  ${n}
7
7
  \`\`\``}return Array.isArray(t.content)?t.content.map(r).join(""):""}export{e as adfToText};