@browsercash/chase 1.0.0
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/.claude/settings.local.json +14 -0
- package/.dockerignore +34 -0
- package/README.md +256 -0
- package/api-1 (3).json +831 -0
- package/dist/browser-cash.js +128 -0
- package/dist/claude-runner.js +285 -0
- package/dist/cli-install.js +104 -0
- package/dist/cli.js +503 -0
- package/dist/codegen/bash-generator.js +104 -0
- package/dist/config.js +112 -0
- package/dist/errors/error-classifier.js +351 -0
- package/dist/hooks/capture-hook.js +57 -0
- package/dist/index.js +180 -0
- package/dist/iterative-tester.js +407 -0
- package/dist/logger/command-log.js +38 -0
- package/dist/prompts/agentic-prompt.js +78 -0
- package/dist/prompts/fix-prompt.js +477 -0
- package/dist/prompts/helpers.js +214 -0
- package/dist/prompts/system-prompt.js +282 -0
- package/dist/script-runner.js +429 -0
- package/dist/server.js +1934 -0
- package/dist/types/iteration-history.js +139 -0
- package/openapi.json +1131 -0
- package/package.json +44 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration history tracking for fix attempts.
|
|
3
|
+
* Provides context to Claude about what was already tried.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Extract CSS selectors from a bash script containing agent-browser eval commands.
|
|
7
|
+
* Looks for common selector patterns used in querySelector/querySelectorAll.
|
|
8
|
+
*/
|
|
9
|
+
export function extractSelectorsFromScript(scriptContent) {
|
|
10
|
+
const selectors = new Set();
|
|
11
|
+
// Pattern 1: querySelector/querySelectorAll with string literal
|
|
12
|
+
// Matches: querySelector("selector"), querySelectorAll('selector')
|
|
13
|
+
const querySelectorPattern = /querySelectorAll?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
14
|
+
let match;
|
|
15
|
+
while ((match = querySelectorPattern.exec(scriptContent)) !== null) {
|
|
16
|
+
selectors.add(match[1]);
|
|
17
|
+
}
|
|
18
|
+
// Pattern 2: Variable assignments that look like selectors
|
|
19
|
+
// Matches: var SELECTOR = "..."; const selector = '...'
|
|
20
|
+
const selectorVarPattern = /(?:var|let|const)\s+\w*[Ss]elector\w*\s*=\s*['"`]([^'"`]+)['"`]/g;
|
|
21
|
+
while ((match = selectorVarPattern.exec(scriptContent)) !== null) {
|
|
22
|
+
selectors.add(match[1]);
|
|
23
|
+
}
|
|
24
|
+
// Pattern 3: Common selector patterns in strings
|
|
25
|
+
// Look for data attributes, class selectors, element selectors in quoted strings
|
|
26
|
+
const genericSelectorPattern = /['"`](\[data-[^\]]+\]|\.[\w-]+|\#[\w-]+|[a-z]+\[[\w-]+=)['"`]/gi;
|
|
27
|
+
while ((match = genericSelectorPattern.exec(scriptContent)) !== null) {
|
|
28
|
+
// Only add if it looks like a real selector (not just any string)
|
|
29
|
+
const candidate = match[1];
|
|
30
|
+
if (candidate.length > 2 && (candidate.startsWith('[') ||
|
|
31
|
+
candidate.startsWith('.') ||
|
|
32
|
+
candidate.startsWith('#') ||
|
|
33
|
+
/^[a-z]+\[/.test(candidate))) {
|
|
34
|
+
selectors.add(candidate);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return Array.from(selectors);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format iteration history for inclusion in a fix prompt.
|
|
41
|
+
* Provides Claude with context about previous attempts.
|
|
42
|
+
*/
|
|
43
|
+
export function formatIterationHistory(history) {
|
|
44
|
+
if (history.attempts.length === 0) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
let output = `\n## Previous Fix Attempts (${history.attempts.length} so far)\n\n`;
|
|
48
|
+
output += `**IMPORTANT**: These approaches have already been tried and FAILED. Do NOT repeat them.\n\n`;
|
|
49
|
+
for (const attempt of history.attempts) {
|
|
50
|
+
output += `### Attempt ${attempt.iteration}\n`;
|
|
51
|
+
// Show selectors that were tried
|
|
52
|
+
if (attempt.selectorsUsed.length > 0) {
|
|
53
|
+
output += `**Selectors tried:** ${attempt.selectorsUsed.slice(0, 5).map(s => `\`${s}\``).join(', ')}`;
|
|
54
|
+
if (attempt.selectorsUsed.length > 5) {
|
|
55
|
+
output += ` (and ${attempt.selectorsUsed.length - 5} more)`;
|
|
56
|
+
}
|
|
57
|
+
output += '\n';
|
|
58
|
+
}
|
|
59
|
+
// Show syntax error if any
|
|
60
|
+
if (attempt.syntaxError) {
|
|
61
|
+
output += `**Syntax error:** ${attempt.syntaxError.substring(0, 200)}\n`;
|
|
62
|
+
}
|
|
63
|
+
// Summarize the error (truncated)
|
|
64
|
+
const errorSummary = summarizeError(attempt.errorOutput);
|
|
65
|
+
output += `**Result:** ${errorSummary}\n\n`;
|
|
66
|
+
}
|
|
67
|
+
output += `---\n\n`;
|
|
68
|
+
output += `**What to try differently:**\n`;
|
|
69
|
+
output += `- Use DIFFERENT selectors than those listed above\n`;
|
|
70
|
+
output += `- If selectors keep failing, use findProductGrid() to discover the main container\n`;
|
|
71
|
+
output += `- If data quality is low, inspect the actual DOM structure with agent-browser snapshot\n`;
|
|
72
|
+
output += `- If pagination isn't working, verify items actually change between pages\n\n`;
|
|
73
|
+
return output;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a short summary of an error for display in history.
|
|
77
|
+
*/
|
|
78
|
+
function summarizeError(errorOutput) {
|
|
79
|
+
// Extract the most relevant part of the error
|
|
80
|
+
const lines = errorOutput.split('\n').filter(l => l.trim());
|
|
81
|
+
// Look for semantic error line
|
|
82
|
+
const semanticMatch = errorOutput.match(/\[SEMANTIC ERROR\]\s*(.+)/);
|
|
83
|
+
if (semanticMatch) {
|
|
84
|
+
return semanticMatch[1].substring(0, 150);
|
|
85
|
+
}
|
|
86
|
+
// Look for data quality issues
|
|
87
|
+
const dataQualityMatch = errorOutput.match(/\[DATA QUALITY ISSUES\]\s*([\s\S]*?)(?:\n\n|\[)/);
|
|
88
|
+
if (dataQualityMatch) {
|
|
89
|
+
const issues = dataQualityMatch[1].trim().split('\n').slice(0, 2);
|
|
90
|
+
return issues.join('; ').substring(0, 150);
|
|
91
|
+
}
|
|
92
|
+
// Look for common error patterns
|
|
93
|
+
if (errorOutput.includes('extracted 0') || errorOutput.includes('No items extracted')) {
|
|
94
|
+
return 'No items extracted - selector likely wrong';
|
|
95
|
+
}
|
|
96
|
+
if (errorOutput.includes('jq: error')) {
|
|
97
|
+
return 'JSON parsing error - double-encoded JSON issue';
|
|
98
|
+
}
|
|
99
|
+
if (errorOutput.includes('WRONG_SELECTOR')) {
|
|
100
|
+
return 'Wrong selector - targeting ads/carousel instead of main grid';
|
|
101
|
+
}
|
|
102
|
+
if (errorOutput.includes('INCOMPLETE')) {
|
|
103
|
+
return 'Incomplete extraction - need more scrolling or pagination';
|
|
104
|
+
}
|
|
105
|
+
if (errorOutput.includes('valid prices')) {
|
|
106
|
+
return 'Low price extraction rate - price selectors failing';
|
|
107
|
+
}
|
|
108
|
+
if (errorOutput.includes('valid ratings')) {
|
|
109
|
+
return 'Low rating extraction rate - rating selectors failing';
|
|
110
|
+
}
|
|
111
|
+
// Default: first meaningful line
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
if (line.length > 10 && !line.startsWith('[STDOUT]')) {
|
|
114
|
+
return line.substring(0, 150);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return 'Script execution failed';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Create a new empty iteration history.
|
|
121
|
+
*/
|
|
122
|
+
export function createIterationHistory(originalTask) {
|
|
123
|
+
return {
|
|
124
|
+
originalTask,
|
|
125
|
+
attempts: [],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Add an attempt to the iteration history.
|
|
130
|
+
*/
|
|
131
|
+
export function addAttemptToHistory(history, iteration, scriptContent, errorOutput, syntaxError) {
|
|
132
|
+
history.attempts.push({
|
|
133
|
+
iteration,
|
|
134
|
+
scriptContent,
|
|
135
|
+
errorOutput,
|
|
136
|
+
syntaxError,
|
|
137
|
+
selectorsUsed: extractSelectorsFromScript(scriptContent),
|
|
138
|
+
});
|
|
139
|
+
}
|