testchimp-runner-core 0.0.35 → 0.0.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.
- package/package.json +6 -1
- package/plandocs/BEFORE_AFTER_VERIFICATION.md +0 -148
- package/plandocs/COORDINATE_MODE_DIAGNOSIS.md +0 -144
- package/plandocs/CREDIT_CALLBACK_ARCHITECTURE.md +0 -253
- package/plandocs/HUMAN_LIKE_IMPROVEMENTS.md +0 -642
- package/plandocs/IMPLEMENTATION_STATUS.md +0 -108
- package/plandocs/INTEGRATION_COMPLETE.md +0 -322
- package/plandocs/MULTI_AGENT_ARCHITECTURE_REVIEW.md +0 -844
- package/plandocs/ORCHESTRATOR_MVP_SUMMARY.md +0 -539
- package/plandocs/PHASE1_ABSTRACTION_COMPLETE.md +0 -241
- package/plandocs/PHASE1_FINAL_STATUS.md +0 -210
- package/plandocs/PHASE_1_COMPLETE.md +0 -165
- package/plandocs/PHASE_1_SUMMARY.md +0 -184
- package/plandocs/PLANNING_SESSION_SUMMARY.md +0 -372
- package/plandocs/PROMPT_OPTIMIZATION_ANALYSIS.md +0 -120
- package/plandocs/PROMPT_SANITY_CHECK.md +0 -120
- package/plandocs/SCRIPT_CLEANUP_FEATURE.md +0 -201
- package/plandocs/SCRIPT_GENERATION_ARCHITECTURE.md +0 -364
- package/plandocs/SELECTOR_IMPROVEMENTS.md +0 -139
- package/plandocs/SESSION_SUMMARY_v0.0.33.md +0 -151
- package/plandocs/TROUBLESHOOTING_SESSION.md +0 -72
- package/plandocs/VISION_DIAGNOSTICS_IMPROVEMENTS.md +0 -336
- package/plandocs/VISUAL_AGENT_EVOLUTION_PLAN.md +0 -396
- package/plandocs/WHATS_NEW_v0.0.33.md +0 -183
- package/plandocs/exploratory-mode-support-v2.plan.md +0 -953
- package/plandocs/exploratory-mode-support.plan.md +0 -928
- package/plandocs/journey-id-tracking-addendum.md +0 -227
- package/releasenotes/RELEASE_0.0.26.md +0 -165
- package/releasenotes/RELEASE_0.0.27.md +0 -236
- package/releasenotes/RELEASE_0.0.28.md +0 -286
- package/src/auth-config.ts +0 -84
- package/src/credit-usage-service.ts +0 -188
- package/src/env-loader.ts +0 -103
- package/src/execution-service.ts +0 -996
- package/src/file-handler.ts +0 -104
- package/src/index.ts +0 -432
- package/src/llm-facade.ts +0 -821
- package/src/llm-provider.ts +0 -53
- package/src/model-constants.ts +0 -35
- package/src/orchestrator/decision-parser.ts +0 -139
- package/src/orchestrator/index.ts +0 -58
- package/src/orchestrator/orchestrator-agent.ts +0 -1282
- package/src/orchestrator/orchestrator-prompts.ts +0 -786
- package/src/orchestrator/page-som-handler.ts +0 -1565
- package/src/orchestrator/som-types.ts +0 -188
- package/src/orchestrator/tool-registry.ts +0 -184
- package/src/orchestrator/tools/check-page-ready.ts +0 -75
- package/src/orchestrator/tools/extract-data.ts +0 -92
- package/src/orchestrator/tools/index.ts +0 -15
- package/src/orchestrator/tools/inspect-page.ts +0 -42
- package/src/orchestrator/tools/recall-history.ts +0 -72
- package/src/orchestrator/tools/refresh-som-markers.ts +0 -69
- package/src/orchestrator/tools/take-screenshot.ts +0 -128
- package/src/orchestrator/tools/verify-action-result.ts +0 -159
- package/src/orchestrator/tools/view-previous-screenshot.ts +0 -103
- package/src/orchestrator/types.ts +0 -291
- package/src/playwright-mcp-service.ts +0 -224
- package/src/progress-reporter.ts +0 -144
- package/src/prompts.ts +0 -842
- package/src/providers/backend-proxy-llm-provider.ts +0 -91
- package/src/providers/local-llm-provider.ts +0 -38
- package/src/scenario-service.ts +0 -252
- package/src/scenario-worker-class.ts +0 -1110
- package/src/script-utils.ts +0 -203
- package/src/types.ts +0 -239
- package/src/utils/browser-utils.ts +0 -348
- package/src/utils/coordinate-converter.ts +0 -162
- package/src/utils/page-info-retry.ts +0 -65
- package/src/utils/page-info-utils.ts +0 -285
- package/testchimp-runner-core-0.0.35.tgz +0 -0
- package/tsconfig.json +0 -19
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced Page Info Utilities
|
|
3
|
-
* Extracts ARIA tree, interactive elements with bounding boxes, and suggested selectors
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface InteractiveElement {
|
|
7
|
-
tag: string;
|
|
8
|
-
id: string | null;
|
|
9
|
-
text: string;
|
|
10
|
-
type: string;
|
|
11
|
-
name: string; // name attribute (critical for form inputs)
|
|
12
|
-
role: string;
|
|
13
|
-
ariaLabel: string;
|
|
14
|
-
placeholder: string;
|
|
15
|
-
bbox: {x: number; y: number; width: number; height: number};
|
|
16
|
-
selectors: string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PageInfo {
|
|
20
|
-
url: string;
|
|
21
|
-
title: string;
|
|
22
|
-
ariaSnapshot: any; // Raw ARIA tree for hierarchical structure
|
|
23
|
-
interactiveElements: InteractiveElement[]; // All interactive elements with position and selectors
|
|
24
|
-
formattedElements: string; // Human-readable summary for logging
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function getEnhancedPageInfo(page: any): Promise<PageInfo>;
|
|
28
|
-
export async function getEnhancedPageInfo(domSnapshot: { url: string; title: string; accessibilityTree: any }): Promise<PageInfo>;
|
|
29
|
-
export async function getEnhancedPageInfo(input: any | { url: string; title: string; accessibilityTree: any }): Promise<PageInfo> {
|
|
30
|
-
let domSnapshot: { url: string; title: string; accessibilityTree: any } = { url: 'Unknown', title: 'Unknown', accessibilityTree: null };
|
|
31
|
-
let interactiveElements: InteractiveElement[] = [];
|
|
32
|
-
let hasPageObject = false;
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
if ('accessibility' in input) {
|
|
36
|
-
// Input is a Page object
|
|
37
|
-
hasPageObject = true;
|
|
38
|
-
// CRITICAL: Use interestingOnly: false to get FULL ARIA tree like Playwright MCP
|
|
39
|
-
// This includes all structural nodes (generic, paragraph, etc.) not just interactive ones
|
|
40
|
-
const snapshot = await input.accessibility.snapshot({ interestingOnly: false });
|
|
41
|
-
const url = input.url();
|
|
42
|
-
const title = await input.title();
|
|
43
|
-
domSnapshot = { url, title, accessibilityTree: snapshot };
|
|
44
|
-
|
|
45
|
-
// Extract ALL interactive elements with bounding boxes and selectors
|
|
46
|
-
try {
|
|
47
|
-
interactiveElements = await input.evaluate(() => {
|
|
48
|
-
const doc = (globalThis as any).document;
|
|
49
|
-
const elements: any[] = [];
|
|
50
|
-
|
|
51
|
-
// Get all interactive elements
|
|
52
|
-
const interactiveSelectors = [
|
|
53
|
-
'button',
|
|
54
|
-
'input',
|
|
55
|
-
'textarea',
|
|
56
|
-
'select',
|
|
57
|
-
'a[href]',
|
|
58
|
-
'[role="button"]',
|
|
59
|
-
'[role="link"]',
|
|
60
|
-
'[role="textbox"]',
|
|
61
|
-
'[role="checkbox"]',
|
|
62
|
-
'[role="radio"]',
|
|
63
|
-
'[onclick]',
|
|
64
|
-
'[type="submit"]'
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
const allInteractive = new Set<any>();
|
|
68
|
-
interactiveSelectors.forEach((selector: string) => {
|
|
69
|
-
doc.querySelectorAll(selector).forEach((el: any) => allInteractive.add(el));
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// CRITICAL: Also detect elements that are styled/behave as interactive
|
|
73
|
-
// (e.g., divs/spans with cursor:pointer, click handlers)
|
|
74
|
-
// This catches modern web apps that use non-semantic HTML
|
|
75
|
-
const allElements = doc.querySelectorAll('div, span, p, li, td');
|
|
76
|
-
allElements.forEach((el: any) => {
|
|
77
|
-
const styles = (globalThis as any).window.getComputedStyle(el);
|
|
78
|
-
const hasClickHandler = el.onclick ||
|
|
79
|
-
el.getAttribute('onclick') ||
|
|
80
|
-
el.hasAttribute('data-action') ||
|
|
81
|
-
el.hasAttribute('data-click');
|
|
82
|
-
|
|
83
|
-
// Include if: cursor is pointer, has click handler, or has tabindex (keyboard focusable)
|
|
84
|
-
if (styles.cursor === 'pointer' || hasClickHandler || el.tabIndex >= 0) {
|
|
85
|
-
allInteractive.add(el);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
allInteractive.forEach((el: any) => {
|
|
90
|
-
const rect = el.getBoundingClientRect();
|
|
91
|
-
|
|
92
|
-
// Skip invisible elements
|
|
93
|
-
if (rect.width === 0 || rect.height === 0) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const id = el.id || null;
|
|
98
|
-
const tag = el.tagName.toLowerCase();
|
|
99
|
-
const text = el.textContent?.trim().substring(0, 40) || '';
|
|
100
|
-
const type = el.type || '';
|
|
101
|
-
const role = el.getAttribute('role') || el.tagName.toLowerCase();
|
|
102
|
-
const ariaLabel = el.getAttribute('aria-label') || '';
|
|
103
|
-
const placeholder = el.placeholder || '';
|
|
104
|
-
|
|
105
|
-
// Build possible selectors - PRIORITIZE SEMANTIC SELECTORS (Playwright best practices)
|
|
106
|
-
const selectors: string[] = [];
|
|
107
|
-
|
|
108
|
-
// 1. BEST: getByLabel for form inputs with associated labels
|
|
109
|
-
if ((tag === 'input' || tag === 'textarea' || tag === 'select') && el.labels && el.labels.length > 0) {
|
|
110
|
-
const labelText = el.labels[0].textContent?.trim();
|
|
111
|
-
if (labelText && labelText.length > 0 && labelText.length < 50) {
|
|
112
|
-
selectors.push(`getByLabel('${labelText}')`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 2. BEST: getByRole with name (semantic and accessible)
|
|
117
|
-
if (text && text.length > 0 && text.length < 30) {
|
|
118
|
-
selectors.push(`getByRole('${role}', {name: '${text}'})`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// 2b. BEST: getByRole for buttons with type attribute (more specific)
|
|
122
|
-
if (tag === 'button' && el.type) {
|
|
123
|
-
selectors.push(`getByRole('button', {name: '${text}'})`);
|
|
124
|
-
selectors.push(`button[type="${el.type}"]`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 3. BEST: getByPlaceholder for inputs with placeholders
|
|
128
|
-
if (placeholder && placeholder.length > 0 && placeholder.length < 50) {
|
|
129
|
-
selectors.push(`getByPlaceholder('${placeholder}')`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 4. GOOD: getByText for elements with visible text (fallback for non-role elements)
|
|
133
|
-
if (text && text.length > 0 && text.length < 30 && !selectors.some(s => s.includes('getByRole'))) {
|
|
134
|
-
selectors.push(`getByText('${text}')`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// 5. GOOD: data-testid attributes (stable, explicit)
|
|
138
|
-
const dataTestId = el.getAttribute('data-testid') || el.getAttribute('data-test-id') ||
|
|
139
|
-
el.getAttribute('data-id') || el.getAttribute('data-test');
|
|
140
|
-
if (dataTestId) selectors.push(`getByTestId('${dataTestId}')`);
|
|
141
|
-
|
|
142
|
-
// 6. GOOD: name attribute (especially for form inputs - very common and stable)
|
|
143
|
-
const nameAttr = el.getAttribute('name');
|
|
144
|
-
if (nameAttr && (tag === 'input' || tag === 'textarea' || tag === 'select')) {
|
|
145
|
-
selectors.push(`input[name="${nameAttr}"]`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// 6b. GOOD: class-based selectors for buttons (common in modern frameworks)
|
|
149
|
-
if (tag === 'button' && el.className) {
|
|
150
|
-
const classes = el.className.split(' ').filter((c: string) => c.length > 0 && !c.includes('userfront-'));
|
|
151
|
-
if (classes.length > 0) {
|
|
152
|
-
selectors.push(`button.${classes[0]}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 7. LAST RESORT: ID selector (only if stable - avoid auto-generated IDs with unicode)
|
|
157
|
-
// Skip auto-generated Ant Design IDs like «r3»-form-item or rc_select_xxx
|
|
158
|
-
if (id && !id.includes('«') && !id.match(/^(rc_|:r[0-9]+:|__)/)) {
|
|
159
|
-
selectors.push(`#${id}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
elements.push({
|
|
163
|
-
tag,
|
|
164
|
-
id,
|
|
165
|
-
text,
|
|
166
|
-
type,
|
|
167
|
-
name: nameAttr || '', // CRITICAL: Capture name attribute for form inputs
|
|
168
|
-
role,
|
|
169
|
-
ariaLabel,
|
|
170
|
-
placeholder,
|
|
171
|
-
bbox: {
|
|
172
|
-
x: Math.round(rect.x),
|
|
173
|
-
y: Math.round(rect.y),
|
|
174
|
-
width: Math.round(rect.width),
|
|
175
|
-
height: Math.round(rect.height)
|
|
176
|
-
},
|
|
177
|
-
selectors
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
return elements;
|
|
182
|
-
});
|
|
183
|
-
} catch (evalError: any) {
|
|
184
|
-
// Error extracting interactive elements - continue with empty array
|
|
185
|
-
console.error('[getEnhancedPageInfo] Failed to extract interactive elements:', evalError.message);
|
|
186
|
-
interactiveElements = [];
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
189
|
-
// Input is already a domSnapshot
|
|
190
|
-
domSnapshot = input;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Log extraction results for debugging
|
|
194
|
-
if (hasPageObject) {
|
|
195
|
-
console.log(`[getEnhancedPageInfo] Extracted ${interactiveElements.length} interactive elements from ${domSnapshot.url}`);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Create smart summary prioritizing important elements over repetitive lists
|
|
199
|
-
let formattedElements = '';
|
|
200
|
-
|
|
201
|
-
if (interactiveElements.length > 0) {
|
|
202
|
-
// Prioritize: forms/buttons > unique elements > list items
|
|
203
|
-
const prioritized: InteractiveElement[] = [];
|
|
204
|
-
const listItems: InteractiveElement[] = [];
|
|
205
|
-
|
|
206
|
-
// Group elements
|
|
207
|
-
for (const el of interactiveElements) {
|
|
208
|
-
// High priority: forms, buttons, unique interactive elements
|
|
209
|
-
if (['input', 'textarea', 'select', 'button'].includes(el.tag) ||
|
|
210
|
-
(el.tag === 'a' && el.text.length > 0 && el.text.length < 50)) {
|
|
211
|
-
prioritized.push(el);
|
|
212
|
-
} else {
|
|
213
|
-
listItems.push(el);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Take top 25 prioritized
|
|
218
|
-
const selectedElements = prioritized.slice(0, 25);
|
|
219
|
-
|
|
220
|
-
// Add sample of list items if space remains (show diversity, not just first N)
|
|
221
|
-
if (selectedElements.length < 30 && listItems.length > 0) {
|
|
222
|
-
const step = Math.max(1, Math.floor(listItems.length / 5)); // Sample 5 from list
|
|
223
|
-
for (let i = 0; i < Math.min(5, listItems.length); i++) {
|
|
224
|
-
selectedElements.push(listItems[i * step]);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
formattedElements = selectedElements.map((e, i) => {
|
|
229
|
-
const idInfo = e.id ? `#${e.id}` : '';
|
|
230
|
-
const typeInfo = e.type ? ` type="${e.type}"` : '';
|
|
231
|
-
const nameInfo = e.name ? ` name="${e.name}"` : '';
|
|
232
|
-
const placeholderInfo = e.placeholder ? ` placeholder="${e.placeholder}"` : '';
|
|
233
|
-
const roleInfo = e.role ? ` role="${e.role}"` : '';
|
|
234
|
-
|
|
235
|
-
// Compact format: show all relevant attributes for LLM to construct selectors
|
|
236
|
-
return `${i + 1}. [${e.bbox.x},${e.bbox.y} ${e.bbox.width}x${e.bbox.height}] <${e.tag}>${idInfo}${typeInfo}${nameInfo}${placeholderInfo}${roleInfo} "${e.text}"`;
|
|
237
|
-
}).join('\n');
|
|
238
|
-
|
|
239
|
-
// Show stats for omitted elements
|
|
240
|
-
const omitted = interactiveElements.length - selectedElements.length;
|
|
241
|
-
if (omitted > 0) {
|
|
242
|
-
formattedElements += `\n\n... (+${omitted} more elements)`;
|
|
243
|
-
|
|
244
|
-
// Show pattern summary for lists/tables
|
|
245
|
-
const linkCount = interactiveElements.filter(e => e.tag === 'a').length;
|
|
246
|
-
const listItemPatterns: Record<string, number> = {};
|
|
247
|
-
|
|
248
|
-
for (const el of interactiveElements) {
|
|
249
|
-
if (el.tag === 'a' || el.tag === 'li' || el.tag === 'div') {
|
|
250
|
-
const pattern = `${el.tag}${el.role ? `[${el.role}]` : ''}`;
|
|
251
|
-
listItemPatterns[pattern] = (listItemPatterns[pattern] || 0) + 1;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (Object.keys(listItemPatterns).length > 0) {
|
|
256
|
-
formattedElements += `\nPattern summary: `;
|
|
257
|
-
formattedElements += Object.entries(listItemPatterns)
|
|
258
|
-
.filter(([_, count]) => count > 5)
|
|
259
|
-
.map(([pattern, count]) => `${count}x ${pattern}`)
|
|
260
|
-
.join(', ');
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
} else {
|
|
264
|
-
formattedElements = 'No interactive elements found (page may not be loaded or extraction failed)';
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
url: domSnapshot.url,
|
|
269
|
-
title: domSnapshot.title,
|
|
270
|
-
ariaSnapshot: domSnapshot.accessibilityTree,
|
|
271
|
-
interactiveElements,
|
|
272
|
-
formattedElements
|
|
273
|
-
};
|
|
274
|
-
} catch (error: any) {
|
|
275
|
-
// Error extracting page info - return defaults
|
|
276
|
-
console.error('[getEnhancedPageInfo] Top-level error:', error.message);
|
|
277
|
-
return {
|
|
278
|
-
url: domSnapshot?.url || 'Unknown',
|
|
279
|
-
title: 'Unknown',
|
|
280
|
-
ariaSnapshot: null,
|
|
281
|
-
interactiveElements: [],
|
|
282
|
-
formattedElements: `Unable to extract: ${error.message}`
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
}
|
|
Binary file
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": ["ES2020"],
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"declaration": true,
|
|
13
|
-
"declarationMap": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"resolveJsonModule": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
19
|
-
}
|