btcp-browser-agent 0.1.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.md +230 -0
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/SKILL.md +143 -0
- package/SNAPSHOT_IMPROVEMENTS.md +302 -0
- package/USAGE.md +146 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/docs/browser-cli-design.md +500 -0
- package/examples/chrome-extension/CHANGELOG.md +210 -0
- package/examples/chrome-extension/DEBUG.md +231 -0
- package/examples/chrome-extension/ERROR_FIXED.md +147 -0
- package/examples/chrome-extension/QUICK_TEST.md +189 -0
- package/examples/chrome-extension/README.md +149 -0
- package/examples/chrome-extension/SESSION_ONLY_MODE.md +305 -0
- package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +97 -0
- package/examples/chrome-extension/build.js +43 -0
- package/examples/chrome-extension/manifest.json +37 -0
- package/examples/chrome-extension/package-lock.json +1063 -0
- package/examples/chrome-extension/package.json +21 -0
- package/examples/chrome-extension/popup.html +195 -0
- package/examples/chrome-extension/src/background.ts +12 -0
- package/examples/chrome-extension/src/content.ts +7 -0
- package/examples/chrome-extension/src/popup.ts +303 -0
- package/examples/chrome-extension/src/scenario-google-github.ts +389 -0
- package/examples/chrome-extension/test-page.html +127 -0
- package/examples/chrome-extension/tests/README.md +206 -0
- package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +380 -0
- package/examples/chrome-extension/tsconfig.json +14 -0
- package/examples/snapshots/README.md +207 -0
- package/examples/snapshots/amazon-com-detail.html +9528 -0
- package/examples/snapshots/amazon-com-detail.snapshot.txt +997 -0
- package/examples/snapshots/convert-snapshots.ts +97 -0
- package/examples/snapshots/edition-cnn-com.html +13292 -0
- package/examples/snapshots/edition-cnn-com.snapshot.txt +562 -0
- package/examples/snapshots/github-com-microsoft-vscode.html +2916 -0
- package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +455 -0
- package/examples/snapshots/google-search.html +20012 -0
- package/examples/snapshots/google-search.snapshot.txt +195 -0
- package/examples/snapshots/metadata.json +86 -0
- package/examples/snapshots/npr-org-templates.html +2031 -0
- package/examples/snapshots/npr-org-templates.snapshot.txt +224 -0
- package/examples/snapshots/stackoverflow-com.html +5216 -0
- package/examples/snapshots/stackoverflow-com.snapshot.txt +2404 -0
- package/examples/snapshots/test-all-mode.html +46 -0
- package/examples/snapshots/test-all-mode.snapshot.txt +5 -0
- package/examples/snapshots/validate.test.ts +296 -0
- package/package.json +65 -0
- package/packages/cli/package.json +42 -0
- package/packages/cli/src/__tests__/cli.test.ts +434 -0
- package/packages/cli/src/__tests__/errors.test.ts +226 -0
- package/packages/cli/src/__tests__/executor.test.ts +275 -0
- package/packages/cli/src/__tests__/formatter.test.ts +260 -0
- package/packages/cli/src/__tests__/parser.test.ts +288 -0
- package/packages/cli/src/__tests__/suggestions.test.ts +255 -0
- package/packages/cli/src/commands/back.ts +22 -0
- package/packages/cli/src/commands/check.ts +33 -0
- package/packages/cli/src/commands/clear.ts +33 -0
- package/packages/cli/src/commands/click.ts +32 -0
- package/packages/cli/src/commands/closetab.ts +31 -0
- package/packages/cli/src/commands/eval.ts +41 -0
- package/packages/cli/src/commands/fill.ts +30 -0
- package/packages/cli/src/commands/focus.ts +33 -0
- package/packages/cli/src/commands/forward.ts +22 -0
- package/packages/cli/src/commands/goto.ts +34 -0
- package/packages/cli/src/commands/help.ts +162 -0
- package/packages/cli/src/commands/hover.ts +34 -0
- package/packages/cli/src/commands/index.ts +129 -0
- package/packages/cli/src/commands/newtab.ts +35 -0
- package/packages/cli/src/commands/press.ts +40 -0
- package/packages/cli/src/commands/reload.ts +25 -0
- package/packages/cli/src/commands/screenshot.ts +27 -0
- package/packages/cli/src/commands/scroll.ts +64 -0
- package/packages/cli/src/commands/select.ts +35 -0
- package/packages/cli/src/commands/snapshot.ts +21 -0
- package/packages/cli/src/commands/tab.ts +32 -0
- package/packages/cli/src/commands/tabs.ts +26 -0
- package/packages/cli/src/commands/text.ts +27 -0
- package/packages/cli/src/commands/title.ts +17 -0
- package/packages/cli/src/commands/type.ts +38 -0
- package/packages/cli/src/commands/uncheck.ts +33 -0
- package/packages/cli/src/commands/url.ts +17 -0
- package/packages/cli/src/commands/wait.ts +54 -0
- package/packages/cli/src/errors.ts +164 -0
- package/packages/cli/src/executor.ts +68 -0
- package/packages/cli/src/formatter.ts +215 -0
- package/packages/cli/src/index.ts +257 -0
- package/packages/cli/src/parser.ts +195 -0
- package/packages/cli/src/suggestions.ts +207 -0
- package/packages/cli/src/terminal/Terminal.ts +365 -0
- package/packages/cli/src/terminal/index.ts +5 -0
- package/packages/cli/src/types.ts +155 -0
- package/packages/cli/tsconfig.json +20 -0
- package/packages/core/package.json +35 -0
- package/packages/core/src/actions.ts +1210 -0
- package/packages/core/src/errors.ts +296 -0
- package/packages/core/src/index.test.ts +638 -0
- package/packages/core/src/index.ts +220 -0
- package/packages/core/src/ref-map.ts +107 -0
- package/packages/core/src/snapshot.ts +873 -0
- package/packages/core/src/types.ts +536 -0
- package/packages/core/tsconfig.json +23 -0
- package/packages/extension/README.md +129 -0
- package/packages/extension/package.json +43 -0
- package/packages/extension/src/background.ts +888 -0
- package/packages/extension/src/content.ts +172 -0
- package/packages/extension/src/index.ts +579 -0
- package/packages/extension/src/session-manager.ts +385 -0
- package/packages/extension/src/session-types.ts +144 -0
- package/packages/extension/src/types.ts +162 -0
- package/packages/extension/tsconfig.json +28 -0
- package/src/index.ts +64 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling utilities for BTCP Browser Agent
|
|
3
|
+
*
|
|
4
|
+
* Provides structured error types with machine-readable codes and
|
|
5
|
+
* actionable suggestions to help AI agents self-correct.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Machine-readable error codes for programmatic error handling
|
|
10
|
+
*/
|
|
11
|
+
export enum ErrorCode {
|
|
12
|
+
/** Element not found with given selector */
|
|
13
|
+
ELEMENT_NOT_FOUND = 'ELEMENT_NOT_FOUND',
|
|
14
|
+
|
|
15
|
+
/** Element exists but doesn't support the requested action */
|
|
16
|
+
ELEMENT_NOT_COMPATIBLE = 'ELEMENT_NOT_COMPATIBLE',
|
|
17
|
+
|
|
18
|
+
/** Ref ID has expired (cleared by new snapshot) */
|
|
19
|
+
REF_EXPIRED = 'REF_EXPIRED',
|
|
20
|
+
|
|
21
|
+
/** Invalid selector syntax or format */
|
|
22
|
+
INVALID_SELECTOR = 'INVALID_SELECTOR',
|
|
23
|
+
|
|
24
|
+
/** Operation timed out waiting for condition */
|
|
25
|
+
TIMEOUT = 'TIMEOUT',
|
|
26
|
+
|
|
27
|
+
/** Element exists but is not visible */
|
|
28
|
+
ELEMENT_NOT_VISIBLE = 'ELEMENT_NOT_VISIBLE',
|
|
29
|
+
|
|
30
|
+
/** Element exists but is disabled */
|
|
31
|
+
ELEMENT_DISABLED = 'ELEMENT_DISABLED',
|
|
32
|
+
|
|
33
|
+
/** Conflicting parameters provided to command */
|
|
34
|
+
INVALID_PARAMETERS = 'INVALID_PARAMETERS',
|
|
35
|
+
|
|
36
|
+
/** Element is not in the expected state */
|
|
37
|
+
INVALID_STATE = 'INVALID_STATE',
|
|
38
|
+
|
|
39
|
+
/** Network or navigation error */
|
|
40
|
+
NAVIGATION_ERROR = 'NAVIGATION_ERROR',
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Structured context information for errors
|
|
45
|
+
*/
|
|
46
|
+
export interface ErrorContext {
|
|
47
|
+
/** The selector that was used */
|
|
48
|
+
selector?: string;
|
|
49
|
+
|
|
50
|
+
/** Expected element type or role */
|
|
51
|
+
expectedType?: string;
|
|
52
|
+
|
|
53
|
+
/** Actual element type or role found */
|
|
54
|
+
actualType?: string;
|
|
55
|
+
|
|
56
|
+
/** Current state of the element */
|
|
57
|
+
elementState?: {
|
|
58
|
+
attached: boolean;
|
|
59
|
+
visible: boolean;
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Actions available for this element */
|
|
64
|
+
availableActions?: string[];
|
|
65
|
+
|
|
66
|
+
/** Similar selectors that were found */
|
|
67
|
+
similarSelectors?: Array<{
|
|
68
|
+
selector: string;
|
|
69
|
+
role: string;
|
|
70
|
+
name: string;
|
|
71
|
+
similarity?: number;
|
|
72
|
+
}>;
|
|
73
|
+
|
|
74
|
+
/** Nearby interactive elements */
|
|
75
|
+
nearbyElements?: Array<{
|
|
76
|
+
ref: string;
|
|
77
|
+
role: string;
|
|
78
|
+
name: string;
|
|
79
|
+
}>;
|
|
80
|
+
|
|
81
|
+
/** Additional context-specific data */
|
|
82
|
+
[key: string]: any;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Detailed error with structured data for AI agents
|
|
87
|
+
*
|
|
88
|
+
* Provides both human-readable messages and machine-readable
|
|
89
|
+
* error codes, context, and recovery suggestions.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* throw new DetailedError(
|
|
94
|
+
* ErrorCode.ELEMENT_NOT_FOUND,
|
|
95
|
+
* "Element not found: #submit-btn",
|
|
96
|
+
* {
|
|
97
|
+
* selector: "#submit-btn",
|
|
98
|
+
* similarSelectors: [
|
|
99
|
+
* { selector: "#submit-button", role: "button", name: "Submit" }
|
|
100
|
+
* ]
|
|
101
|
+
* },
|
|
102
|
+
* [
|
|
103
|
+
* "Try using selector: #submit-button",
|
|
104
|
+
* "Run snapshot({ interactive: true }) to see all clickable elements"
|
|
105
|
+
* ]
|
|
106
|
+
* );
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export class DetailedError extends Error {
|
|
110
|
+
public readonly code: ErrorCode;
|
|
111
|
+
public readonly context: ErrorContext;
|
|
112
|
+
public readonly suggestions: string[];
|
|
113
|
+
|
|
114
|
+
constructor(
|
|
115
|
+
code: ErrorCode,
|
|
116
|
+
message: string,
|
|
117
|
+
context: ErrorContext = {},
|
|
118
|
+
suggestions: string[] = []
|
|
119
|
+
) {
|
|
120
|
+
// Build enhanced message with suggestions
|
|
121
|
+
let fullMessage = message;
|
|
122
|
+
|
|
123
|
+
if (suggestions.length > 0) {
|
|
124
|
+
fullMessage += '\n\nSuggestions:';
|
|
125
|
+
suggestions.forEach(suggestion => {
|
|
126
|
+
fullMessage += `\n - ${suggestion}`;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
super(fullMessage);
|
|
131
|
+
this.name = 'DetailedError';
|
|
132
|
+
this.code = code;
|
|
133
|
+
this.context = context;
|
|
134
|
+
this.suggestions = suggestions;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Convert to structured object for API responses
|
|
139
|
+
*/
|
|
140
|
+
toJSON() {
|
|
141
|
+
return {
|
|
142
|
+
name: this.name,
|
|
143
|
+
message: this.message,
|
|
144
|
+
code: this.code,
|
|
145
|
+
context: this.context,
|
|
146
|
+
suggestions: this.suggestions,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Helper function to create element not found error with suggestions
|
|
153
|
+
*/
|
|
154
|
+
export function createElementNotFoundError(
|
|
155
|
+
selector: string,
|
|
156
|
+
options: {
|
|
157
|
+
similarSelectors?: Array<{ selector: string; role: string; name: string }>;
|
|
158
|
+
nearbyElements?: Array<{ ref: string; role: string; name: string }>;
|
|
159
|
+
isRef?: boolean;
|
|
160
|
+
} = {}
|
|
161
|
+
): DetailedError {
|
|
162
|
+
const { similarSelectors = [], nearbyElements = [], isRef = false } = options;
|
|
163
|
+
|
|
164
|
+
const suggestions: string[] = [];
|
|
165
|
+
|
|
166
|
+
if (isRef) {
|
|
167
|
+
suggestions.push(
|
|
168
|
+
'Ref may have expired. Refs are cleared on snapshot() calls and page navigation.',
|
|
169
|
+
'Call snapshot() again to get fresh refs.'
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (similarSelectors.length > 0) {
|
|
174
|
+
suggestions.push(
|
|
175
|
+
`Similar selectors found: ${similarSelectors.map(s => s.selector).join(', ')}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (nearbyElements.length > 0) {
|
|
180
|
+
suggestions.push(
|
|
181
|
+
'Run snapshot({ interactive: true }) to see all clickable elements'
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return new DetailedError(
|
|
186
|
+
isRef ? ErrorCode.REF_EXPIRED : ErrorCode.ELEMENT_NOT_FOUND,
|
|
187
|
+
`Element not found: ${selector}`,
|
|
188
|
+
{
|
|
189
|
+
selector,
|
|
190
|
+
similarSelectors,
|
|
191
|
+
nearbyElements,
|
|
192
|
+
},
|
|
193
|
+
suggestions
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Helper function to create element not compatible error
|
|
199
|
+
*/
|
|
200
|
+
export function createElementNotCompatibleError(
|
|
201
|
+
selector: string,
|
|
202
|
+
action: string,
|
|
203
|
+
actualType: string,
|
|
204
|
+
expectedTypes: string[],
|
|
205
|
+
availableActions: string[] = []
|
|
206
|
+
): DetailedError {
|
|
207
|
+
const suggestions: string[] = [];
|
|
208
|
+
|
|
209
|
+
if (availableActions.length > 0) {
|
|
210
|
+
suggestions.push(
|
|
211
|
+
`Available actions for ${actualType}: ${availableActions.join(', ')}`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
suggestions.push(
|
|
216
|
+
`Use snapshot() to verify element type before attempting action`
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
return new DetailedError(
|
|
220
|
+
ErrorCode.ELEMENT_NOT_COMPATIBLE,
|
|
221
|
+
`Element ${selector} is ${actualType}, cannot perform action: ${action}`,
|
|
222
|
+
{
|
|
223
|
+
selector,
|
|
224
|
+
actualType,
|
|
225
|
+
expectedType: expectedTypes.join(' or '),
|
|
226
|
+
availableActions,
|
|
227
|
+
},
|
|
228
|
+
suggestions
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Helper function to create timeout error with state information
|
|
234
|
+
*/
|
|
235
|
+
export function createTimeoutError(
|
|
236
|
+
selector: string | undefined,
|
|
237
|
+
expectedState: string,
|
|
238
|
+
currentState?: {
|
|
239
|
+
attached: boolean;
|
|
240
|
+
visible: boolean;
|
|
241
|
+
enabled: boolean;
|
|
242
|
+
}
|
|
243
|
+
): DetailedError {
|
|
244
|
+
const suggestions: string[] = [];
|
|
245
|
+
|
|
246
|
+
if (currentState) {
|
|
247
|
+
if (currentState.attached && !currentState.visible && expectedState === 'visible') {
|
|
248
|
+
suggestions.push(
|
|
249
|
+
'Element is attached but not visible. Check CSS display/visibility properties.',
|
|
250
|
+
'Try state="attached" if you just need element to exist in DOM.'
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (currentState.attached && currentState.visible && !currentState.enabled && expectedState === 'enabled') {
|
|
255
|
+
suggestions.push(
|
|
256
|
+
'Element is visible but disabled. Check disabled attribute or aria-disabled.',
|
|
257
|
+
'Wait for the condition that enables the element, or use force option if available.'
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
suggestions.push('Increase timeout value if element appears slowly.');
|
|
263
|
+
|
|
264
|
+
const message = selector
|
|
265
|
+
? `Timeout waiting for ${selector} to be ${expectedState}`
|
|
266
|
+
: `Timeout waiting for page to be ${expectedState}`;
|
|
267
|
+
|
|
268
|
+
return new DetailedError(
|
|
269
|
+
ErrorCode.TIMEOUT,
|
|
270
|
+
message,
|
|
271
|
+
{
|
|
272
|
+
selector,
|
|
273
|
+
expectedType: expectedState,
|
|
274
|
+
elementState: currentState,
|
|
275
|
+
},
|
|
276
|
+
suggestions
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Helper function to create invalid parameters error
|
|
282
|
+
*/
|
|
283
|
+
export function createInvalidParametersError(
|
|
284
|
+
message: string,
|
|
285
|
+
conflictingParams: string[],
|
|
286
|
+
suggestion: string
|
|
287
|
+
): DetailedError {
|
|
288
|
+
return new DetailedError(
|
|
289
|
+
ErrorCode.INVALID_PARAMETERS,
|
|
290
|
+
message,
|
|
291
|
+
{
|
|
292
|
+
conflictingParams,
|
|
293
|
+
},
|
|
294
|
+
[suggestion]
|
|
295
|
+
);
|
|
296
|
+
}
|