@zibby/core 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/agents/base.js +17 -0
  2. package/dist/backend-client.js +1 -0
  3. package/dist/constants/tool-names.js +1 -0
  4. package/dist/constants/zibby-scratch.js +1 -0
  5. package/dist/constants.js +1 -0
  6. package/dist/enrichment/base.js +1 -0
  7. package/dist/enrichment/enrichers/accessibility-enricher.js +1 -0
  8. package/dist/enrichment/enrichers/dom-enricher.js +1 -0
  9. package/dist/enrichment/enrichers/page-state-enricher.js +1 -0
  10. package/dist/enrichment/enrichers/position-enricher.js +1 -0
  11. package/dist/enrichment/index.js +1 -0
  12. package/dist/enrichment/mcp-integration.js +1 -0
  13. package/dist/enrichment/mcp-ref-enricher.js +1 -0
  14. package/dist/enrichment/pipeline.js +3 -0
  15. package/dist/enrichment/trace-text-enricher.js +1 -0
  16. package/dist/framework/agents/assistant-strategy.js +5 -0
  17. package/dist/framework/agents/base.js +1 -0
  18. package/dist/framework/agents/claude-strategy.js +4 -0
  19. package/dist/framework/agents/codex-strategy.js +4 -0
  20. package/dist/framework/agents/cursor-strategy.js +32 -0
  21. package/dist/framework/agents/gemini-strategy.js +11 -0
  22. package/dist/framework/agents/index.js +13 -0
  23. package/dist/framework/agents/middleware/assistant-round-pipeline.js +3 -0
  24. package/dist/framework/agents/providers/base.js +1 -0
  25. package/dist/framework/agents/providers/index.js +1 -0
  26. package/dist/framework/agents/providers/openai-transport.js +2 -0
  27. package/dist/framework/agents/providers/openai.js +1 -0
  28. package/dist/framework/agents/providers/transport-base.js +1 -0
  29. package/dist/framework/agents/utils/auth-resolver.js +1 -0
  30. package/dist/framework/agents/utils/cursor-output-formatter.js +1 -0
  31. package/dist/framework/agents/utils/openai-proxy-formatter.js +9 -0
  32. package/dist/framework/agents/utils/payload-budget.js +3 -0
  33. package/dist/framework/agents/utils/structured-output-formatter.js +21 -0
  34. package/dist/framework/code-generator.js +10 -0
  35. package/dist/framework/constants.js +1 -0
  36. package/dist/framework/context-loader.js +5 -0
  37. package/dist/framework/function-bridge.js +2 -0
  38. package/dist/framework/function-skill-registry.js +1 -0
  39. package/dist/framework/graph-compiler.js +1 -0
  40. package/dist/framework/graph.js +5 -0
  41. package/dist/framework/index.js +1 -0
  42. package/dist/framework/mcp-client.js +2 -0
  43. package/dist/framework/node-registry.js +9 -0
  44. package/dist/framework/node.js +5 -0
  45. package/dist/framework/output-parser.js +3 -0
  46. package/dist/framework/skill-registry.js +1 -0
  47. package/dist/framework/state-utils.js +1 -0
  48. package/dist/framework/state.js +1 -0
  49. package/dist/framework/tool-resolver.js +1 -0
  50. package/dist/index.js +8 -0
  51. package/dist/runtime/generation/base.js +1 -0
  52. package/dist/runtime/generation/index.js +3 -0
  53. package/dist/runtime/generation/mcp-ref-strategy.js +41 -0
  54. package/dist/runtime/generation/stable-id-strategy.js +16 -0
  55. package/dist/runtime/stable-id-runtime.js +1 -0
  56. package/dist/runtime/verification/base.js +1 -0
  57. package/dist/runtime/verification/index.js +3 -0
  58. package/dist/runtime/verification/playwright-json-strategy.js +1 -0
  59. package/dist/runtime/zibby-runtime.js +1 -0
  60. package/dist/sync/index.js +1 -0
  61. package/dist/sync/uploader.js +1 -0
  62. package/dist/tools/run-playwright-test.js +5 -0
  63. package/dist/utils/adf-converter.js +7 -0
  64. package/dist/utils/ast-utils.js +1 -0
  65. package/dist/utils/ci-setup.js +5 -0
  66. package/dist/utils/cursor-mcp-isolated-home.js +1 -0
  67. package/dist/utils/cursor-utils.js +18 -0
  68. package/dist/utils/live-frame-discovery.js +1 -0
  69. package/dist/utils/logger.js +1 -0
  70. package/dist/utils/mcp-config-writer.js +10 -0
  71. package/dist/utils/mission-control-from-run-states.js +1 -0
  72. package/dist/utils/node-schema-parser.js +1 -0
  73. package/dist/utils/parallel-config.js +1 -0
  74. package/dist/utils/post-process-events.js +1 -0
  75. package/dist/utils/result-handler.js +1 -0
  76. package/{src → dist}/utils/ripple-effect.js +3 -12
  77. package/dist/utils/run-capacity-coordinator.js +1 -0
  78. package/dist/utils/run-capacity-queue.js +2 -0
  79. package/dist/utils/run-index-merge.js +1 -0
  80. package/dist/utils/run-index-post-cli.js +1 -0
  81. package/dist/utils/run-registry.js +3 -0
  82. package/dist/utils/run-state-session.js +2 -0
  83. package/dist/utils/selector-generator.js +4 -0
  84. package/dist/utils/session-state-constants.js +1 -0
  85. package/dist/utils/session-state-live-runs.js +1 -0
  86. package/dist/utils/streaming-parser.js +4 -0
  87. package/dist/utils/test-post-processor.js +18 -0
  88. package/dist/utils/timeline.js +14 -0
  89. package/dist/utils/trace-parser.js +2 -0
  90. package/dist/utils/video-organizer.js +3 -0
  91. package/package.json +49 -35
  92. package/templates/browser-test-automation/README.md +29 -7
  93. package/templates/browser-test-automation/chat.mjs +36 -0
  94. package/templates/browser-test-automation/graph.mjs +5 -9
  95. package/templates/browser-test-automation/nodes/execute-live.mjs +30 -58
  96. package/templates/browser-test-automation/nodes/generate-script.mjs +32 -12
  97. package/templates/browser-test-automation/nodes/utils.mjs +153 -10
  98. package/templates/browser-test-automation/pipeline-ids.js +12 -0
  99. package/templates/browser-test-automation/result-handler.mjs +78 -2
  100. package/templates/browser-test-automation/run-index.mjs +418 -0
  101. package/scripts/export-default-workflows.js +0 -51
  102. package/scripts/patch-cursor-mcp.js +0 -174
  103. package/scripts/setup-ci.sh +0 -115
  104. package/scripts/setup-official-playwright-mcp.sh +0 -226
  105. package/scripts/test-with-video.sh +0 -49
  106. package/src/agents/base.js +0 -361
  107. package/src/constants.js +0 -47
  108. package/src/enrichment/base.js +0 -49
  109. package/src/enrichment/enrichers/accessibility-enricher.js +0 -197
  110. package/src/enrichment/enrichers/dom-enricher.js +0 -171
  111. package/src/enrichment/enrichers/page-state-enricher.js +0 -129
  112. package/src/enrichment/enrichers/position-enricher.js +0 -67
  113. package/src/enrichment/index.js +0 -96
  114. package/src/enrichment/mcp-integration.js +0 -149
  115. package/src/enrichment/mcp-ref-enricher.js +0 -78
  116. package/src/enrichment/pipeline.js +0 -192
  117. package/src/enrichment/trace-text-enricher.js +0 -115
  118. package/src/framework/AGENTS.md +0 -98
  119. package/src/framework/agents/base.js +0 -72
  120. package/src/framework/agents/claude-strategy.js +0 -278
  121. package/src/framework/agents/cursor-strategy.js +0 -544
  122. package/src/framework/agents/index.js +0 -105
  123. package/src/framework/agents/utils/cursor-output-formatter.js +0 -67
  124. package/src/framework/agents/utils/openai-proxy-formatter.js +0 -249
  125. package/src/framework/code-generator.js +0 -301
  126. package/src/framework/constants.js +0 -33
  127. package/src/framework/context-loader.js +0 -101
  128. package/src/framework/function-bridge.js +0 -78
  129. package/src/framework/function-skill-registry.js +0 -20
  130. package/src/framework/graph-compiler.js +0 -342
  131. package/src/framework/graph.js +0 -610
  132. package/src/framework/index.js +0 -28
  133. package/src/framework/node-registry.js +0 -163
  134. package/src/framework/node.js +0 -259
  135. package/src/framework/output-parser.js +0 -71
  136. package/src/framework/skill-registry.js +0 -55
  137. package/src/framework/state-utils.js +0 -52
  138. package/src/framework/state.js +0 -67
  139. package/src/framework/tool-resolver.js +0 -65
  140. package/src/index.js +0 -345
  141. package/src/runtime/generation/base.js +0 -46
  142. package/src/runtime/generation/index.js +0 -70
  143. package/src/runtime/generation/mcp-ref-strategy.js +0 -197
  144. package/src/runtime/generation/stable-id-strategy.js +0 -170
  145. package/src/runtime/stable-id-runtime.js +0 -248
  146. package/src/runtime/verification/base.js +0 -44
  147. package/src/runtime/verification/index.js +0 -67
  148. package/src/runtime/verification/playwright-json-strategy.js +0 -119
  149. package/src/runtime/zibby-runtime.js +0 -299
  150. package/src/sync/index.js +0 -2
  151. package/src/sync/uploader.js +0 -29
  152. package/src/tools/run-playwright-test.js +0 -158
  153. package/src/utils/adf-converter.js +0 -68
  154. package/src/utils/ast-utils.js +0 -37
  155. package/src/utils/ci-setup.js +0 -124
  156. package/src/utils/cursor-utils.js +0 -71
  157. package/src/utils/logger.js +0 -144
  158. package/src/utils/mcp-config-writer.js +0 -115
  159. package/src/utils/node-schema-parser.js +0 -522
  160. package/src/utils/post-process-events.js +0 -55
  161. package/src/utils/result-handler.js +0 -102
  162. package/src/utils/selector-generator.js +0 -239
  163. package/src/utils/streaming-parser.js +0 -387
  164. package/src/utils/test-post-processor.js +0 -211
  165. package/src/utils/timeline.js +0 -217
  166. package/src/utils/trace-parser.js +0 -325
  167. package/src/utils/video-organizer.js +0 -91
@@ -1,171 +0,0 @@
1
- /**
2
- * DOM Enricher - Captures DOM path, XPath, and element attributes
3
- * This file contains browser code executed via element.evaluate() where browser globals are available
4
- */
5
- /* global document, window */
6
- import { EventEnricher } from '../base.js';
7
-
8
- export class DOMEnricher extends EventEnricher {
9
- getName() {
10
- return 'DOMEnricher';
11
- }
12
-
13
- getPriority() {
14
- return 85; // High priority - structural data
15
- }
16
-
17
- canEnrich(context) {
18
- if (!this.enabled) return false;
19
- if (!context.element) return false;
20
- if (!context.event) return false;
21
-
22
- return ['click', 'fill', 'type', 'selectOption', 'hover'].includes(context.event.type);
23
- }
24
-
25
- async enrich(event, context) {
26
- try {
27
- const { element } = context;
28
-
29
- // Get DOM path, XPath, and attributes
30
- const domData = await element.evaluate(el => {
31
- // Build CSS path
32
- const getCssPath = (innerEl) => {
33
- const path = [];
34
- let current = innerEl;
35
-
36
- while (current && current !== document.body) {
37
- let selector = current.tagName.toLowerCase();
38
-
39
- // Add nth-child if there are siblings of same type
40
- const parent = current.parentElement;
41
- if (parent) {
42
- const siblings = Array.from(parent.children).filter(
43
- child => child.tagName === current.tagName
44
- );
45
- if (siblings.length > 1) {
46
- const index = siblings.indexOf(current) + 1;
47
- selector += `:nth-child(${index})`;
48
- }
49
- }
50
-
51
- path.unshift(selector);
52
- current = current.parentElement;
53
- }
54
-
55
- return `body > ${path.join(' > ')}`;
56
- };
57
-
58
- // Build XPath
59
- const getXPath = (innerEl) => {
60
- const path = [];
61
- let current = innerEl;
62
-
63
- while (current && current !== document.body) {
64
- let index = 1;
65
- let sibling = current.previousSibling;
66
-
67
- while (sibling) {
68
- if (sibling.nodeType === 1 && sibling.tagName === current.tagName) {
69
- index++;
70
- }
71
- sibling = sibling.previousSibling;
72
- }
73
-
74
- const tag = current.tagName.toLowerCase();
75
- path.unshift(`${tag}[${index}]`);
76
- current = current.parentElement;
77
- }
78
-
79
- return `/html/body/${path.join('/')}`;
80
- };
81
-
82
- // Get all attributes
83
- const attributes = {};
84
- for (const attr of el.attributes) {
85
- attributes[attr.name] = attr.value;
86
- }
87
-
88
- // Get computed style (only essential properties)
89
- const computed = window.getComputedStyle(el);
90
- const state = {
91
- display: computed.display,
92
- visibility: computed.visibility,
93
- opacity: computed.opacity,
94
- pointerEvents: computed.pointerEvents
95
- };
96
-
97
- // Calculate depth
98
- let depth = 0;
99
- let parent = el.parentElement;
100
- while (parent) {
101
- depth++;
102
- parent = parent.parentElement;
103
- }
104
-
105
- return {
106
- path: getCssPath(el),
107
- xpath: getXPath(el),
108
- depth,
109
- parent: el.parentElement ? el.parentElement.tagName.toLowerCase() : null,
110
- tagName: el.tagName.toLowerCase(),
111
- attributes,
112
- state: {
113
- visible: computed.display !== 'none' && computed.visibility !== 'hidden',
114
- enabled: !el.disabled,
115
- focused: document.activeElement === el,
116
- ...state
117
- }
118
- };
119
- });
120
-
121
- return {
122
- dom: {
123
- path: domData.path,
124
- xpath: domData.xpath,
125
- depth: domData.depth,
126
- parent: domData.parent,
127
- selector: this.buildSmartSelector(domData)
128
- },
129
- attributes: domData.attributes,
130
- state: domData.state
131
- };
132
- } catch (error) {
133
- return this.handleError(error, event);
134
- }
135
- }
136
-
137
- /**
138
- * Build a smart CSS selector from DOM data
139
- */
140
- buildSmartSelector(domData) {
141
- let selector = domData.tagName;
142
-
143
- // Add ID if available
144
- if (domData.attributes.id) {
145
- return `#${domData.attributes.id}`;
146
- }
147
-
148
- // Add data-test-id if available
149
- if (domData.attributes['data-test-id']) {
150
- return `[data-test-id="${domData.attributes['data-test-id']}"]`;
151
- }
152
-
153
- // Add class if available
154
- if (domData.attributes.class) {
155
- const classes = domData.attributes.class.split(' ')
156
- .filter(c => c && !c.match(/^(active|focus|hover|disabled)/)); // Skip state classes
157
- if (classes.length > 0) {
158
- selector += `.${classes.slice(0, 2).join('.')}`;
159
- }
160
- }
161
-
162
- // Add parent context
163
- if (domData.parent) {
164
- selector = `${domData.parent} > ${selector}`;
165
- }
166
-
167
- return selector;
168
- }
169
- }
170
-
171
- export default DOMEnricher;
@@ -1,129 +0,0 @@
1
- /**
2
- * Page State Enricher - Captures network and page stability state
3
- * This file contains browser code executed via page.evaluate() where browser globals are available
4
- */
5
- /* global document, MutationObserver */
6
- import { EventEnricher } from '../base.js';
7
-
8
- export class PageStateEnricher extends EventEnricher {
9
- constructor(config = {}) {
10
- super(config);
11
- this.pendingRequests = new Set();
12
- this.setupNetworkTracking = false;
13
- }
14
-
15
- getName() {
16
- return 'PageStateEnricher';
17
- }
18
-
19
- getPriority() {
20
- return 95; // Very high priority - critical for timing
21
- }
22
-
23
- canEnrich(context) {
24
- return this.enabled && context.page;
25
- }
26
-
27
- /**
28
- * Setup network request tracking (call once per page)
29
- */
30
- async setupTracking(page) {
31
- if (this.setupNetworkTracking) return;
32
-
33
- page.on('request', (request) => {
34
- if (['document', 'xhr', 'fetch'].includes(request.resourceType())) {
35
- this.pendingRequests.add(request.url());
36
- }
37
- });
38
-
39
- page.on('requestfinished', (request) => {
40
- this.pendingRequests.delete(request.url());
41
- });
42
-
43
- page.on('requestfailed', (request) => {
44
- this.pendingRequests.delete(request.url());
45
- });
46
-
47
- this.setupNetworkTracking = true;
48
- }
49
-
50
- async enrich(event, context) {
51
- try {
52
- const { page } = context;
53
-
54
- // Setup tracking if not done
55
- await this.setupTracking(page);
56
-
57
- // Get page load state
58
- const pageState = await page.evaluate(() => ({
59
- readyState: document.readyState,
60
- domContentLoaded: document.readyState !== 'loading',
61
- loadComplete: document.readyState === 'complete',
62
- url: document.location.href
63
- }));
64
-
65
- // Check if DOM is stable (no mutations for 500ms)
66
- const domStable = await this.checkDOMStability(page);
67
-
68
- return {
69
- page: {
70
- networkIdle: this.pendingRequests.size === 0,
71
- pendingRequests: this.pendingRequests.size,
72
- domStable,
73
- ...pageState
74
- }
75
- };
76
- } catch (error) {
77
- return this.handleError(error, event);
78
- }
79
- }
80
-
81
- /**
82
- * Check if DOM hasn't mutated for 500ms
83
- */
84
- async checkDOMStability(page, timeoutMs = 500) {
85
- try {
86
- const stable = await page.evaluate((timeout) => {
87
- return new Promise((resolve) => {
88
- let timer;
89
- let mutations = 0;
90
-
91
- const observer = new MutationObserver(() => {
92
- mutations++;
93
- clearTimeout(timer);
94
- timer = setTimeout(() => {
95
- observer.disconnect();
96
- resolve(mutations === 0);
97
- }, timeout);
98
- });
99
-
100
- observer.observe(document.body, {
101
- childList: true,
102
- subtree: true,
103
- attributes: true
104
- });
105
-
106
- // Initial timer
107
- timer = setTimeout(() => {
108
- observer.disconnect();
109
- resolve(true);
110
- }, timeout);
111
- });
112
- }, timeoutMs);
113
-
114
- return stable;
115
- } catch (_error) {
116
- return false; // Assume not stable on error
117
- }
118
- }
119
-
120
- /**
121
- * Reset tracking for new page navigation
122
- */
123
- reset() {
124
- this.pendingRequests.clear();
125
- this.setupNetworkTracking = false;
126
- }
127
- }
128
-
129
- export default PageStateEnricher;
@@ -1,67 +0,0 @@
1
- /**
2
- * Position Enricher - Captures element bounding box and viewport state
3
- * This file contains browser code executed via element.evaluate() where browser globals are available
4
- */
5
- /* global window */
6
- import { EventEnricher } from '../base.js';
7
-
8
- export class PositionEnricher extends EventEnricher {
9
- getName() {
10
- return 'PositionEnricher';
11
- }
12
-
13
- getPriority() {
14
- return 90; // High priority - cheap and useful
15
- }
16
-
17
- canEnrich(context) {
18
- // Only enrich interactive actions that have an element
19
- if (!this.enabled) return false;
20
- if (!context.element) return false;
21
- if (!context.event) return false;
22
-
23
- return ['click', 'fill', 'type', 'selectOption', 'hover'].includes(context.event.type);
24
- }
25
-
26
- async enrich(event, context) {
27
- try {
28
- const { page, element } = context;
29
-
30
- // Get bounding box
31
- const box = await element.boundingBox();
32
- if (!box) return null; // Element not visible
33
-
34
- // Get viewport state
35
- const viewport = await page.evaluate(() => ({
36
- scrollX: window.scrollX,
37
- scrollY: window.scrollY,
38
- width: window.innerWidth,
39
- height: window.innerHeight
40
- }));
41
-
42
- // Check if in viewport
43
- const inViewport = (
44
- box.y >= viewport.scrollY &&
45
- box.y + box.height <= viewport.scrollY + viewport.height &&
46
- box.x >= 0 &&
47
- box.x + box.width <= viewport.width
48
- );
49
-
50
- return {
51
- position: {
52
- boundingBox: box,
53
- viewport,
54
- inViewport,
55
- centerPoint: {
56
- x: Math.round(box.x + box.width / 2),
57
- y: Math.round(box.y + box.height / 2)
58
- }
59
- }
60
- };
61
- } catch (error) {
62
- return this.handleError(error, event);
63
- }
64
- }
65
- }
66
-
67
- export default PositionEnricher;
@@ -1,96 +0,0 @@
1
- /**
2
- * Event Enrichment System
3
- * Modular pipeline for adding data to MCP events
4
- */
5
-
6
- export { EventEnricher } from './base.js';
7
- export { EnrichmentPipeline } from './pipeline.js';
8
-
9
- // Enrichers
10
- export { PositionEnricher } from './enrichers/position-enricher.js';
11
- export { AccessibilityEnricher } from './enrichers/accessibility-enricher.js';
12
- export { PageStateEnricher } from './enrichers/page-state-enricher.js';
13
- export { DOMEnricher } from './enrichers/dom-enricher.js';
14
- export { MCPRefEnricher } from './mcp-ref-enricher.js';
15
- export { TraceTextEnricher } from './trace-text-enricher.js';
16
-
17
- import { EnrichmentPipeline } from './pipeline.js';
18
- import { PositionEnricher } from './enrichers/position-enricher.js';
19
- import { AccessibilityEnricher } from './enrichers/accessibility-enricher.js';
20
- import { PageStateEnricher } from './enrichers/page-state-enricher.js';
21
- import { DOMEnricher } from './enrichers/dom-enricher.js';
22
- import { MCPRefEnricher } from './mcp-ref-enricher.js';
23
- import { TraceTextEnricher } from './trace-text-enricher.js';
24
-
25
- /**
26
- * Create a default enrichment pipeline with all enrichers
27
- * @param {Object} config - Configuration options
28
- * @param {boolean} config.enablePosition - Enable position enricher (default: true)
29
- * @param {boolean} config.enableAccessibility - Enable accessibility enricher (default: true)
30
- * @param {boolean} config.enablePageState - Enable page state enricher (default: true)
31
- * @param {boolean} config.enableDOM - Enable DOM enricher (default: true)
32
- * @returns {EnrichmentPipeline}
33
- */
34
- export function createDefaultPipeline(config = {}) {
35
- const pipeline = new EnrichmentPipeline(config);
36
-
37
- // Register enrichers (they'll auto-sort by priority)
38
- // MCPRefEnricher has highest priority (200) - captures exact MCP refs
39
- if (config.enableMCPRef !== false) {
40
- pipeline.register(new MCPRefEnricher(config));
41
- }
42
-
43
- // TraceTextEnricher (190) - extracts ACTUAL text from trace (for Chinese/multi-language)
44
- if (config.enableTraceText !== false) {
45
- pipeline.register(new TraceTextEnricher(config));
46
- }
47
-
48
- if (config.enableAccessibility !== false) {
49
- pipeline.register(new AccessibilityEnricher(config));
50
- }
51
-
52
- if (config.enablePageState !== false) {
53
- pipeline.register(new PageStateEnricher(config));
54
- }
55
-
56
- if (config.enablePosition !== false) {
57
- pipeline.register(new PositionEnricher(config));
58
- }
59
-
60
- if (config.enableDOM !== false) {
61
- pipeline.register(new DOMEnricher(config));
62
- }
63
-
64
- return pipeline;
65
- }
66
-
67
- /**
68
- * Create a minimal pipeline (only critical enrichers)
69
- * @param {Object} config
70
- * @returns {EnrichmentPipeline}
71
- */
72
- export function createMinimalPipeline(config = {}) {
73
- const pipeline = new EnrichmentPipeline(config);
74
-
75
- // Only most critical enrichers
76
- pipeline.register(new AccessibilityEnricher(config));
77
- pipeline.register(new PageStateEnricher(config));
78
-
79
- return pipeline;
80
- }
81
-
82
- /**
83
- * Create a custom pipeline
84
- * @param {Array} enrichers - Array of enricher instances
85
- * @param {Object} config
86
- * @returns {EnrichmentPipeline}
87
- */
88
- export function createCustomPipeline(enrichers, config = {}) {
89
- const pipeline = new EnrichmentPipeline(config);
90
-
91
- for (const enricher of enrichers) {
92
- pipeline.register(enricher);
93
- }
94
-
95
- return pipeline;
96
- }
@@ -1,149 +0,0 @@
1
- /**
2
- * MCP Recorder Integration with Enrichment Pipeline
3
- *
4
- * This module provides utilities to enrich MCP-recorded events
5
- * after test execution (when we have access to trace data)
6
- */
7
-
8
- import { createDefaultPipeline, createMinimalPipeline } from './index.js';
9
- import { readFileSync, writeFileSync } from 'fs';
10
- import { join } from 'path';
11
-
12
- /**
13
- * Enrich recorded events.json file with data from Playwright trace
14
- *
15
- * @param {string} sessionPath - Path to session directory
16
- * @param {Object} config - Enrichment configuration
17
- * @returns {Promise<Object>} - { enrichedCount, skippedCount, errors }
18
- */
19
- export async function enrichRecordedEvents(sessionPath, _config = {}) {
20
- const eventsPath = join(sessionPath, 'events.json');
21
- const _tracePath = join(sessionPath, 'trace.zip');
22
-
23
- try {
24
- // Read events
25
- const events = JSON.parse(readFileSync(eventsPath, 'utf-8'));
26
-
27
- // For now, we add placeholder enrichment metadata
28
- // Full enrichment requires re-playing with Playwright access
29
- const enriched = events.map(event => ({
30
- ...event,
31
- _enrichmentNote: 'Full enrichment requires live Playwright access. Use EnrichmentPipeline during test execution.'
32
- }));
33
-
34
- // Save enriched events
35
- const backupPath = `${eventsPath }.backup`;
36
- writeFileSync(backupPath, JSON.stringify(events, null, 2));
37
- writeFileSync(eventsPath, JSON.stringify(enriched, null, 2));
38
-
39
- return {
40
- enrichedCount: enriched.length,
41
- skippedCount: 0,
42
- errors: []
43
- };
44
- } catch (error) {
45
- console.error('[EnrichmentIntegration] Failed to enrich events:', error.message);
46
- return {
47
- enrichedCount: 0,
48
- skippedCount: 0,
49
- errors: [error.message]
50
- };
51
- }
52
- }
53
-
54
- /**
55
- * Example: How to use enrichment pipeline during live test execution
56
- *
57
- * This is a reference implementation for integrating enrichment
58
- * into your test execution flow where you have Playwright access.
59
- */
60
- export class LiveEnrichmentRecorder {
61
- constructor(config = {}) {
62
- // Create enrichment pipeline
63
- this.pipeline = config.minimal
64
- ? createMinimalPipeline(config)
65
- : createDefaultPipeline(config);
66
-
67
- this.events = [];
68
- this.config = config;
69
- }
70
-
71
- /**
72
- * Record and enrich an event during test execution
73
- *
74
- * @param {string} type - Event type (click, fill, etc)
75
- * @param {Object} data - Event data
76
- * @param {Object} context - { page, element, ref }
77
- * @returns {Promise<Object>} - Enriched event
78
- */
79
- async recordEvent(type, data, context) {
80
- // Create base event (MCP format)
81
- const baseEvent = {
82
- id: this.events.length,
83
- type,
84
- timestamp: new Date().toISOString(),
85
- data
86
- };
87
-
88
- // Enrich with pipeline
89
- const enriched = await this.pipeline.enrich(baseEvent, {
90
- ...context,
91
- event: baseEvent
92
- });
93
-
94
- this.events.push(enriched);
95
- return enriched;
96
- }
97
-
98
- /**
99
- * Save enriched events to file
100
- * @param {string} filePath
101
- */
102
- saveEvents(filePath) {
103
- writeFileSync(filePath, JSON.stringify(this.events, null, 2));
104
- console.log(`[LiveEnrichment] Saved ${this.events.length} enriched events to ${filePath}`);
105
-
106
- // Log statistics
107
- this.pipeline.logStatus();
108
- }
109
-
110
- /**
111
- * Get pipeline statistics
112
- */
113
- getStats() {
114
- return this.pipeline.getStats();
115
- }
116
- }
117
-
118
- /**
119
- * Example integration with Cursor Agent workflow
120
- *
121
- * Usage in execute_live node:
122
- *
123
- * ```javascript
124
- * import { LiveEnrichmentRecorder } from '@zibby/core';
125
- *
126
- * const recorder = new LiveEnrichmentRecorder({ minimal: true });
127
- *
128
- * // During test execution (when you have page/element access):
129
- * const page = await browser.newPage();
130
- * const element = await page.locator('button');
131
- *
132
- * // Record enriched event
133
- * await recorder.recordEvent('click', {
134
- * tool: 'browser_click',
135
- * params: { element: 'Submit button', ref: 'k123' }
136
- * }, {
137
- * page,
138
- * element
139
- * });
140
- *
141
- * // Save at end
142
- * recorder.saveEvents('enriched-events.json');
143
- * ```
144
- */
145
-
146
- export default {
147
- enrichRecordedEvents,
148
- LiveEnrichmentRecorder
149
- };
@@ -1,78 +0,0 @@
1
- import { EventEnricher } from './base.js';
2
-
3
- /**
4
- * MCPRefEnricher - Captures ACTUAL element text from trace DOM snapshots
5
- *
6
- * Problem: AI might say "Login button" but actual button text is "登录" (Chinese)
7
- * Solution: Extract the REAL text from trace DOM snapshot at action time
8
- *
9
- * Priority order:
10
- * 1. Extract actual text/label from trace DOM snapshot (handles Chinese/any language)
11
- * 2. Fall back to MCP element description (AI's description)
12
- *
13
- * This ensures Chinese, Arabic, Japanese, etc. apps work perfectly!
14
- */
15
- export class MCPRefEnricher extends EventEnricher {
16
- constructor(config = {}) {
17
- super(config);
18
- this.priority = 200; // Highest priority
19
- }
20
-
21
- getName() {
22
- return 'MCPRef';
23
- }
24
-
25
- getPriority() {
26
- return this.priority;
27
- }
28
-
29
- async enrich(event, context) {
30
- const ref = event.data?.params?.ref;
31
- const mcpElement = event.data?.params?.element; // What AI said
32
-
33
- if (!ref && !mcpElement) {
34
- return null;
35
- }
36
-
37
- // Try to extract ACTUAL element properties from the DOM (if we have element access)
38
- let actualText = null;
39
- let actualRole = null;
40
- let actualLabel = null;
41
-
42
- if (context?.element) {
43
- try {
44
- // Extract the REAL text that user sees (not what AI said)
45
- const elementData = await context.element.evaluate(el => {
46
- return {
47
- text: el.textContent?.trim() || '',
48
- innerText: el.innerText?.trim() || '',
49
- value: el.value || '',
50
- label: el.getAttribute('aria-label') || el.getAttribute('label') || '',
51
- role: el.getAttribute('role') || el.tagName.toLowerCase(),
52
- placeholder: el.getAttribute('placeholder') || '',
53
- title: el.getAttribute('title') || ''
54
- };
55
- });
56
-
57
- // Use the most specific text we can find
58
- actualText = elementData.text || elementData.innerText || elementData.value || elementData.placeholder;
59
- actualRole = elementData.role;
60
- actualLabel = elementData.label || elementData.title;
61
-
62
- console.log(`[MCPRefEnricher] ✅ Captured actual text: "${actualText}" (AI said: "${mcpElement}")`);
63
- } catch (e) {
64
- console.log(`[MCPRefEnricher] ⚠️ Could not extract actual text: ${e.message}`);
65
- }
66
- }
67
-
68
- return {
69
- mcpRef: ref,
70
- mcpElement, // What AI said (might be translated)
71
- actualText, // ✅ REAL text from DOM (Chinese/any language)
72
- actualRole, // ✅ REAL role (button, link, textbox)
73
- actualLabel, // ✅ REAL aria-label
74
- // Use actual text if available, otherwise fall back to AI's description
75
- recordedSelector: actualText || mcpElement
76
- };
77
- }
78
- }