btcp-browser-agent 0.1.0 → 0.1.1
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 +8 -9
- package/packages/core/dist/actions.d.ts +97 -0
- package/packages/core/dist/actions.js +940 -0
- package/packages/core/dist/errors.d.ts +138 -0
- package/packages/core/dist/errors.js +157 -0
- package/packages/core/dist/index.d.ts +120 -0
- package/packages/core/dist/index.js +134 -0
- package/packages/core/dist/ref-map.d.ts +16 -0
- package/packages/core/dist/ref-map.js +91 -0
- package/packages/core/dist/snapshot.d.ts +37 -0
- package/packages/core/dist/snapshot.js +751 -0
- package/packages/core/dist/types.d.ts +396 -0
- package/packages/core/dist/types.js +7 -0
- package/packages/extension/dist/background.d.ts +227 -0
- package/packages/extension/dist/background.js +737 -0
- package/packages/extension/dist/content.d.ts +18 -0
- package/packages/extension/dist/content.js +149 -0
- package/packages/extension/dist/index.d.ts +228 -0
- package/packages/extension/dist/index.js +350 -0
- package/packages/extension/dist/session-manager.d.ts +87 -0
- package/packages/extension/dist/session-manager.js +322 -0
- package/packages/extension/{src/session-types.ts → dist/session-types.d.ts} +113 -144
- package/packages/extension/dist/session-types.js +5 -0
- package/packages/extension/dist/types.d.ts +88 -0
- package/packages/extension/dist/types.js +7 -0
- package/CLAUDE.md +0 -230
- package/SKILL.md +0 -143
- package/SNAPSHOT_IMPROVEMENTS.md +0 -302
- package/USAGE.md +0 -146
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/docs/browser-cli-design.md +0 -500
- package/examples/chrome-extension/CHANGELOG.md +0 -210
- package/examples/chrome-extension/DEBUG.md +0 -231
- package/examples/chrome-extension/ERROR_FIXED.md +0 -147
- package/examples/chrome-extension/QUICK_TEST.md +0 -189
- package/examples/chrome-extension/README.md +0 -149
- package/examples/chrome-extension/SESSION_ONLY_MODE.md +0 -305
- package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +0 -97
- package/examples/chrome-extension/build.js +0 -43
- package/examples/chrome-extension/manifest.json +0 -37
- package/examples/chrome-extension/package-lock.json +0 -1063
- package/examples/chrome-extension/package.json +0 -21
- package/examples/chrome-extension/popup.html +0 -195
- package/examples/chrome-extension/src/background.ts +0 -12
- package/examples/chrome-extension/src/content.ts +0 -7
- package/examples/chrome-extension/src/popup.ts +0 -303
- package/examples/chrome-extension/src/scenario-google-github.ts +0 -389
- package/examples/chrome-extension/test-page.html +0 -127
- package/examples/chrome-extension/tests/README.md +0 -206
- package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +0 -380
- package/examples/chrome-extension/tsconfig.json +0 -14
- package/examples/snapshots/README.md +0 -207
- package/examples/snapshots/amazon-com-detail.html +0 -9528
- package/examples/snapshots/amazon-com-detail.snapshot.txt +0 -997
- package/examples/snapshots/convert-snapshots.ts +0 -97
- package/examples/snapshots/edition-cnn-com.html +0 -13292
- package/examples/snapshots/edition-cnn-com.snapshot.txt +0 -562
- package/examples/snapshots/github-com-microsoft-vscode.html +0 -2916
- package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +0 -455
- package/examples/snapshots/google-search.html +0 -20012
- package/examples/snapshots/google-search.snapshot.txt +0 -195
- package/examples/snapshots/metadata.json +0 -86
- package/examples/snapshots/npr-org-templates.html +0 -2031
- package/examples/snapshots/npr-org-templates.snapshot.txt +0 -224
- package/examples/snapshots/stackoverflow-com.html +0 -5216
- package/examples/snapshots/stackoverflow-com.snapshot.txt +0 -2404
- package/examples/snapshots/test-all-mode.html +0 -46
- package/examples/snapshots/test-all-mode.snapshot.txt +0 -5
- package/examples/snapshots/validate.test.ts +0 -296
- package/packages/cli/package.json +0 -42
- package/packages/cli/src/__tests__/cli.test.ts +0 -434
- package/packages/cli/src/__tests__/errors.test.ts +0 -226
- package/packages/cli/src/__tests__/executor.test.ts +0 -275
- package/packages/cli/src/__tests__/formatter.test.ts +0 -260
- package/packages/cli/src/__tests__/parser.test.ts +0 -288
- package/packages/cli/src/__tests__/suggestions.test.ts +0 -255
- package/packages/cli/src/commands/back.ts +0 -22
- package/packages/cli/src/commands/check.ts +0 -33
- package/packages/cli/src/commands/clear.ts +0 -33
- package/packages/cli/src/commands/click.ts +0 -32
- package/packages/cli/src/commands/closetab.ts +0 -31
- package/packages/cli/src/commands/eval.ts +0 -41
- package/packages/cli/src/commands/fill.ts +0 -30
- package/packages/cli/src/commands/focus.ts +0 -33
- package/packages/cli/src/commands/forward.ts +0 -22
- package/packages/cli/src/commands/goto.ts +0 -34
- package/packages/cli/src/commands/help.ts +0 -162
- package/packages/cli/src/commands/hover.ts +0 -34
- package/packages/cli/src/commands/index.ts +0 -129
- package/packages/cli/src/commands/newtab.ts +0 -35
- package/packages/cli/src/commands/press.ts +0 -40
- package/packages/cli/src/commands/reload.ts +0 -25
- package/packages/cli/src/commands/screenshot.ts +0 -27
- package/packages/cli/src/commands/scroll.ts +0 -64
- package/packages/cli/src/commands/select.ts +0 -35
- package/packages/cli/src/commands/snapshot.ts +0 -21
- package/packages/cli/src/commands/tab.ts +0 -32
- package/packages/cli/src/commands/tabs.ts +0 -26
- package/packages/cli/src/commands/text.ts +0 -27
- package/packages/cli/src/commands/title.ts +0 -17
- package/packages/cli/src/commands/type.ts +0 -38
- package/packages/cli/src/commands/uncheck.ts +0 -33
- package/packages/cli/src/commands/url.ts +0 -17
- package/packages/cli/src/commands/wait.ts +0 -54
- package/packages/cli/src/errors.ts +0 -164
- package/packages/cli/src/executor.ts +0 -68
- package/packages/cli/src/formatter.ts +0 -215
- package/packages/cli/src/index.ts +0 -257
- package/packages/cli/src/parser.ts +0 -195
- package/packages/cli/src/suggestions.ts +0 -207
- package/packages/cli/src/terminal/Terminal.ts +0 -365
- package/packages/cli/src/terminal/index.ts +0 -5
- package/packages/cli/src/types.ts +0 -155
- package/packages/cli/tsconfig.json +0 -20
- package/packages/core/package.json +0 -35
- package/packages/core/src/actions.ts +0 -1210
- package/packages/core/src/errors.ts +0 -296
- package/packages/core/src/index.test.ts +0 -638
- package/packages/core/src/index.ts +0 -220
- package/packages/core/src/ref-map.ts +0 -107
- package/packages/core/src/snapshot.ts +0 -873
- package/packages/core/src/types.ts +0 -536
- package/packages/core/tsconfig.json +0 -23
- package/packages/extension/README.md +0 -129
- package/packages/extension/package.json +0 -43
- package/packages/extension/src/background.ts +0 -888
- package/packages/extension/src/content.ts +0 -172
- package/packages/extension/src/index.ts +0 -579
- package/packages/extension/src/session-manager.ts +0 -385
- package/packages/extension/src/types.ts +0 -162
- package/packages/extension/tsconfig.json +0 -28
- package/src/index.ts +0 -64
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -26
- package/vitest.config.ts +0 -13
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
* Machine-readable error codes for programmatic error handling
|
|
9
|
+
*/
|
|
10
|
+
export declare enum ErrorCode {
|
|
11
|
+
/** Element not found with given selector */
|
|
12
|
+
ELEMENT_NOT_FOUND = "ELEMENT_NOT_FOUND",
|
|
13
|
+
/** Element exists but doesn't support the requested action */
|
|
14
|
+
ELEMENT_NOT_COMPATIBLE = "ELEMENT_NOT_COMPATIBLE",
|
|
15
|
+
/** Ref ID has expired (cleared by new snapshot) */
|
|
16
|
+
REF_EXPIRED = "REF_EXPIRED",
|
|
17
|
+
/** Invalid selector syntax or format */
|
|
18
|
+
INVALID_SELECTOR = "INVALID_SELECTOR",
|
|
19
|
+
/** Operation timed out waiting for condition */
|
|
20
|
+
TIMEOUT = "TIMEOUT",
|
|
21
|
+
/** Element exists but is not visible */
|
|
22
|
+
ELEMENT_NOT_VISIBLE = "ELEMENT_NOT_VISIBLE",
|
|
23
|
+
/** Element exists but is disabled */
|
|
24
|
+
ELEMENT_DISABLED = "ELEMENT_DISABLED",
|
|
25
|
+
/** Conflicting parameters provided to command */
|
|
26
|
+
INVALID_PARAMETERS = "INVALID_PARAMETERS",
|
|
27
|
+
/** Element is not in the expected state */
|
|
28
|
+
INVALID_STATE = "INVALID_STATE",
|
|
29
|
+
/** Network or navigation error */
|
|
30
|
+
NAVIGATION_ERROR = "NAVIGATION_ERROR"
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Structured context information for errors
|
|
34
|
+
*/
|
|
35
|
+
export interface ErrorContext {
|
|
36
|
+
/** The selector that was used */
|
|
37
|
+
selector?: string;
|
|
38
|
+
/** Expected element type or role */
|
|
39
|
+
expectedType?: string;
|
|
40
|
+
/** Actual element type or role found */
|
|
41
|
+
actualType?: string;
|
|
42
|
+
/** Current state of the element */
|
|
43
|
+
elementState?: {
|
|
44
|
+
attached: boolean;
|
|
45
|
+
visible: boolean;
|
|
46
|
+
enabled: boolean;
|
|
47
|
+
};
|
|
48
|
+
/** Actions available for this element */
|
|
49
|
+
availableActions?: string[];
|
|
50
|
+
/** Similar selectors that were found */
|
|
51
|
+
similarSelectors?: Array<{
|
|
52
|
+
selector: string;
|
|
53
|
+
role: string;
|
|
54
|
+
name: string;
|
|
55
|
+
similarity?: number;
|
|
56
|
+
}>;
|
|
57
|
+
/** Nearby interactive elements */
|
|
58
|
+
nearbyElements?: Array<{
|
|
59
|
+
ref: string;
|
|
60
|
+
role: string;
|
|
61
|
+
name: string;
|
|
62
|
+
}>;
|
|
63
|
+
/** Additional context-specific data */
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Detailed error with structured data for AI agents
|
|
68
|
+
*
|
|
69
|
+
* Provides both human-readable messages and machine-readable
|
|
70
|
+
* error codes, context, and recovery suggestions.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* throw new DetailedError(
|
|
75
|
+
* ErrorCode.ELEMENT_NOT_FOUND,
|
|
76
|
+
* "Element not found: #submit-btn",
|
|
77
|
+
* {
|
|
78
|
+
* selector: "#submit-btn",
|
|
79
|
+
* similarSelectors: [
|
|
80
|
+
* { selector: "#submit-button", role: "button", name: "Submit" }
|
|
81
|
+
* ]
|
|
82
|
+
* },
|
|
83
|
+
* [
|
|
84
|
+
* "Try using selector: #submit-button",
|
|
85
|
+
* "Run snapshot({ interactive: true }) to see all clickable elements"
|
|
86
|
+
* ]
|
|
87
|
+
* );
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare class DetailedError extends Error {
|
|
91
|
+
readonly code: ErrorCode;
|
|
92
|
+
readonly context: ErrorContext;
|
|
93
|
+
readonly suggestions: string[];
|
|
94
|
+
constructor(code: ErrorCode, message: string, context?: ErrorContext, suggestions?: string[]);
|
|
95
|
+
/**
|
|
96
|
+
* Convert to structured object for API responses
|
|
97
|
+
*/
|
|
98
|
+
toJSON(): {
|
|
99
|
+
name: string;
|
|
100
|
+
message: string;
|
|
101
|
+
code: ErrorCode;
|
|
102
|
+
context: ErrorContext;
|
|
103
|
+
suggestions: string[];
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Helper function to create element not found error with suggestions
|
|
108
|
+
*/
|
|
109
|
+
export declare function createElementNotFoundError(selector: string, options?: {
|
|
110
|
+
similarSelectors?: Array<{
|
|
111
|
+
selector: string;
|
|
112
|
+
role: string;
|
|
113
|
+
name: string;
|
|
114
|
+
}>;
|
|
115
|
+
nearbyElements?: Array<{
|
|
116
|
+
ref: string;
|
|
117
|
+
role: string;
|
|
118
|
+
name: string;
|
|
119
|
+
}>;
|
|
120
|
+
isRef?: boolean;
|
|
121
|
+
}): DetailedError;
|
|
122
|
+
/**
|
|
123
|
+
* Helper function to create element not compatible error
|
|
124
|
+
*/
|
|
125
|
+
export declare function createElementNotCompatibleError(selector: string, action: string, actualType: string, expectedTypes: string[], availableActions?: string[]): DetailedError;
|
|
126
|
+
/**
|
|
127
|
+
* Helper function to create timeout error with state information
|
|
128
|
+
*/
|
|
129
|
+
export declare function createTimeoutError(selector: string | undefined, expectedState: string, currentState?: {
|
|
130
|
+
attached: boolean;
|
|
131
|
+
visible: boolean;
|
|
132
|
+
enabled: boolean;
|
|
133
|
+
}): DetailedError;
|
|
134
|
+
/**
|
|
135
|
+
* Helper function to create invalid parameters error
|
|
136
|
+
*/
|
|
137
|
+
export declare function createInvalidParametersError(message: string, conflictingParams: string[], suggestion: string): DetailedError;
|
|
138
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,157 @@
|
|
|
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
|
+
* Machine-readable error codes for programmatic error handling
|
|
9
|
+
*/
|
|
10
|
+
export var ErrorCode;
|
|
11
|
+
(function (ErrorCode) {
|
|
12
|
+
/** Element not found with given selector */
|
|
13
|
+
ErrorCode["ELEMENT_NOT_FOUND"] = "ELEMENT_NOT_FOUND";
|
|
14
|
+
/** Element exists but doesn't support the requested action */
|
|
15
|
+
ErrorCode["ELEMENT_NOT_COMPATIBLE"] = "ELEMENT_NOT_COMPATIBLE";
|
|
16
|
+
/** Ref ID has expired (cleared by new snapshot) */
|
|
17
|
+
ErrorCode["REF_EXPIRED"] = "REF_EXPIRED";
|
|
18
|
+
/** Invalid selector syntax or format */
|
|
19
|
+
ErrorCode["INVALID_SELECTOR"] = "INVALID_SELECTOR";
|
|
20
|
+
/** Operation timed out waiting for condition */
|
|
21
|
+
ErrorCode["TIMEOUT"] = "TIMEOUT";
|
|
22
|
+
/** Element exists but is not visible */
|
|
23
|
+
ErrorCode["ELEMENT_NOT_VISIBLE"] = "ELEMENT_NOT_VISIBLE";
|
|
24
|
+
/** Element exists but is disabled */
|
|
25
|
+
ErrorCode["ELEMENT_DISABLED"] = "ELEMENT_DISABLED";
|
|
26
|
+
/** Conflicting parameters provided to command */
|
|
27
|
+
ErrorCode["INVALID_PARAMETERS"] = "INVALID_PARAMETERS";
|
|
28
|
+
/** Element is not in the expected state */
|
|
29
|
+
ErrorCode["INVALID_STATE"] = "INVALID_STATE";
|
|
30
|
+
/** Network or navigation error */
|
|
31
|
+
ErrorCode["NAVIGATION_ERROR"] = "NAVIGATION_ERROR";
|
|
32
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
33
|
+
/**
|
|
34
|
+
* Detailed error with structured data for AI agents
|
|
35
|
+
*
|
|
36
|
+
* Provides both human-readable messages and machine-readable
|
|
37
|
+
* error codes, context, and recovery suggestions.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* throw new DetailedError(
|
|
42
|
+
* ErrorCode.ELEMENT_NOT_FOUND,
|
|
43
|
+
* "Element not found: #submit-btn",
|
|
44
|
+
* {
|
|
45
|
+
* selector: "#submit-btn",
|
|
46
|
+
* similarSelectors: [
|
|
47
|
+
* { selector: "#submit-button", role: "button", name: "Submit" }
|
|
48
|
+
* ]
|
|
49
|
+
* },
|
|
50
|
+
* [
|
|
51
|
+
* "Try using selector: #submit-button",
|
|
52
|
+
* "Run snapshot({ interactive: true }) to see all clickable elements"
|
|
53
|
+
* ]
|
|
54
|
+
* );
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export class DetailedError extends Error {
|
|
58
|
+
code;
|
|
59
|
+
context;
|
|
60
|
+
suggestions;
|
|
61
|
+
constructor(code, message, context = {}, suggestions = []) {
|
|
62
|
+
// Build enhanced message with suggestions
|
|
63
|
+
let fullMessage = message;
|
|
64
|
+
if (suggestions.length > 0) {
|
|
65
|
+
fullMessage += '\n\nSuggestions:';
|
|
66
|
+
suggestions.forEach(suggestion => {
|
|
67
|
+
fullMessage += `\n - ${suggestion}`;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
super(fullMessage);
|
|
71
|
+
this.name = 'DetailedError';
|
|
72
|
+
this.code = code;
|
|
73
|
+
this.context = context;
|
|
74
|
+
this.suggestions = suggestions;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Convert to structured object for API responses
|
|
78
|
+
*/
|
|
79
|
+
toJSON() {
|
|
80
|
+
return {
|
|
81
|
+
name: this.name,
|
|
82
|
+
message: this.message,
|
|
83
|
+
code: this.code,
|
|
84
|
+
context: this.context,
|
|
85
|
+
suggestions: this.suggestions,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Helper function to create element not found error with suggestions
|
|
91
|
+
*/
|
|
92
|
+
export function createElementNotFoundError(selector, options = {}) {
|
|
93
|
+
const { similarSelectors = [], nearbyElements = [], isRef = false } = options;
|
|
94
|
+
const suggestions = [];
|
|
95
|
+
if (isRef) {
|
|
96
|
+
suggestions.push('Ref may have expired. Refs are cleared on snapshot() calls and page navigation.', 'Call snapshot() again to get fresh refs.');
|
|
97
|
+
}
|
|
98
|
+
if (similarSelectors.length > 0) {
|
|
99
|
+
suggestions.push(`Similar selectors found: ${similarSelectors.map(s => s.selector).join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
if (nearbyElements.length > 0) {
|
|
102
|
+
suggestions.push('Run snapshot({ interactive: true }) to see all clickable elements');
|
|
103
|
+
}
|
|
104
|
+
return new DetailedError(isRef ? ErrorCode.REF_EXPIRED : ErrorCode.ELEMENT_NOT_FOUND, `Element not found: ${selector}`, {
|
|
105
|
+
selector,
|
|
106
|
+
similarSelectors,
|
|
107
|
+
nearbyElements,
|
|
108
|
+
}, suggestions);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Helper function to create element not compatible error
|
|
112
|
+
*/
|
|
113
|
+
export function createElementNotCompatibleError(selector, action, actualType, expectedTypes, availableActions = []) {
|
|
114
|
+
const suggestions = [];
|
|
115
|
+
if (availableActions.length > 0) {
|
|
116
|
+
suggestions.push(`Available actions for ${actualType}: ${availableActions.join(', ')}`);
|
|
117
|
+
}
|
|
118
|
+
suggestions.push(`Use snapshot() to verify element type before attempting action`);
|
|
119
|
+
return new DetailedError(ErrorCode.ELEMENT_NOT_COMPATIBLE, `Element ${selector} is ${actualType}, cannot perform action: ${action}`, {
|
|
120
|
+
selector,
|
|
121
|
+
actualType,
|
|
122
|
+
expectedType: expectedTypes.join(' or '),
|
|
123
|
+
availableActions,
|
|
124
|
+
}, suggestions);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Helper function to create timeout error with state information
|
|
128
|
+
*/
|
|
129
|
+
export function createTimeoutError(selector, expectedState, currentState) {
|
|
130
|
+
const suggestions = [];
|
|
131
|
+
if (currentState) {
|
|
132
|
+
if (currentState.attached && !currentState.visible && expectedState === 'visible') {
|
|
133
|
+
suggestions.push('Element is attached but not visible. Check CSS display/visibility properties.', 'Try state="attached" if you just need element to exist in DOM.');
|
|
134
|
+
}
|
|
135
|
+
if (currentState.attached && currentState.visible && !currentState.enabled && expectedState === 'enabled') {
|
|
136
|
+
suggestions.push('Element is visible but disabled. Check disabled attribute or aria-disabled.', 'Wait for the condition that enables the element, or use force option if available.');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
suggestions.push('Increase timeout value if element appears slowly.');
|
|
140
|
+
const message = selector
|
|
141
|
+
? `Timeout waiting for ${selector} to be ${expectedState}`
|
|
142
|
+
: `Timeout waiting for page to be ${expectedState}`;
|
|
143
|
+
return new DetailedError(ErrorCode.TIMEOUT, message, {
|
|
144
|
+
selector,
|
|
145
|
+
expectedType: expectedState,
|
|
146
|
+
elementState: currentState,
|
|
147
|
+
}, suggestions);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Helper function to create invalid parameters error
|
|
151
|
+
*/
|
|
152
|
+
export function createInvalidParametersError(message, conflictingParams, suggestion) {
|
|
153
|
+
return new DetailedError(ErrorCode.INVALID_PARAMETERS, message, {
|
|
154
|
+
conflictingParams,
|
|
155
|
+
}, [suggestion]);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @btcp/core
|
|
3
|
+
*
|
|
4
|
+
* Core DOM actions for browser automation.
|
|
5
|
+
* Runs in content script context (web page, extension content script, iframe).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createContentAgent } from '@btcp/core';
|
|
10
|
+
*
|
|
11
|
+
* const agent = createContentAgent(document, window);
|
|
12
|
+
*
|
|
13
|
+
* // Take a snapshot
|
|
14
|
+
* const snapshot = await agent.execute({
|
|
15
|
+
* id: '1',
|
|
16
|
+
* action: 'snapshot'
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Click an element
|
|
20
|
+
* await agent.execute({
|
|
21
|
+
* id: '2',
|
|
22
|
+
* action: 'click',
|
|
23
|
+
* selector: '@ref:5' // From snapshot
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import type { Command, Response, RefMap } from './types.js';
|
|
28
|
+
export * from './types.js';
|
|
29
|
+
export * from './errors.js';
|
|
30
|
+
export { createSnapshot } from './snapshot.js';
|
|
31
|
+
export { createRefMap, createSimpleRefMap } from './ref-map.js';
|
|
32
|
+
export { DOMActions } from './actions.js';
|
|
33
|
+
/**
|
|
34
|
+
* ContentAgent - DOM automation agent that runs in content script context
|
|
35
|
+
*
|
|
36
|
+
* This agent handles all DOM-level operations:
|
|
37
|
+
* - Element interaction (click, type, fill, etc.)
|
|
38
|
+
* - DOM queries (snapshot, getText, getAttribute, etc.)
|
|
39
|
+
* - Keyboard/mouse events
|
|
40
|
+
*
|
|
41
|
+
* Use this in content scripts or directly in web pages.
|
|
42
|
+
* For browser-level operations (tabs, navigation, screenshots),
|
|
43
|
+
* use BrowserAgent from @btcp/extension.
|
|
44
|
+
*/
|
|
45
|
+
export interface ContentAgent {
|
|
46
|
+
/**
|
|
47
|
+
* Execute a command and return a response
|
|
48
|
+
*/
|
|
49
|
+
execute(command: Command): Promise<Response>;
|
|
50
|
+
/**
|
|
51
|
+
* Execute a command from JSON string
|
|
52
|
+
*/
|
|
53
|
+
executeJson(json: string): Promise<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Get the element reference map
|
|
56
|
+
*/
|
|
57
|
+
getRefMap(): RefMap;
|
|
58
|
+
/**
|
|
59
|
+
* Clear all element references
|
|
60
|
+
*/
|
|
61
|
+
clearRefs(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Message handler for chrome.runtime.onMessage
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const agent = createContentAgent();
|
|
68
|
+
* chrome.runtime.onMessage.addListener(agent.handleMessage);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
handleMessage: (message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a ContentAgent for DOM automation
|
|
75
|
+
*
|
|
76
|
+
* @param doc - The document to operate on (defaults to current document)
|
|
77
|
+
* @param win - The window context (defaults to current window)
|
|
78
|
+
* @returns A ContentAgent instance
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // In content script
|
|
83
|
+
* const agent = createContentAgent();
|
|
84
|
+
*
|
|
85
|
+
* // Take a snapshot of the page
|
|
86
|
+
* const { data } = await agent.execute({ id: '1', action: 'snapshot' });
|
|
87
|
+
*
|
|
88
|
+
* // Click an element using ref from snapshot
|
|
89
|
+
* await agent.execute({ id: '2', action: 'click', selector: '@ref:5' });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function createContentAgent(doc?: Document, win?: Window): ContentAgent;
|
|
93
|
+
/**
|
|
94
|
+
* @deprecated Use createContentAgent instead
|
|
95
|
+
*/
|
|
96
|
+
export declare const createAgent: typeof createContentAgent;
|
|
97
|
+
/**
|
|
98
|
+
* @deprecated Use ContentAgent instead
|
|
99
|
+
*/
|
|
100
|
+
export type Agent = ContentAgent;
|
|
101
|
+
/**
|
|
102
|
+
* Message types for extension communication
|
|
103
|
+
*/
|
|
104
|
+
export interface AgentMessage {
|
|
105
|
+
type: 'aspect:command';
|
|
106
|
+
command: Command;
|
|
107
|
+
}
|
|
108
|
+
export interface AgentResponse {
|
|
109
|
+
type: 'aspect:response';
|
|
110
|
+
response: Response;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Install message listener for extension communication
|
|
114
|
+
* Call this in your content script to enable command execution via postMessage
|
|
115
|
+
*
|
|
116
|
+
* @param agent - The agent instance
|
|
117
|
+
* @returns Cleanup function to remove the listener
|
|
118
|
+
*/
|
|
119
|
+
export declare function installMessageListener(agent: Agent): () => void;
|
|
120
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @btcp/core
|
|
3
|
+
*
|
|
4
|
+
* Core DOM actions for browser automation.
|
|
5
|
+
* Runs in content script context (web page, extension content script, iframe).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createContentAgent } from '@btcp/core';
|
|
10
|
+
*
|
|
11
|
+
* const agent = createContentAgent(document, window);
|
|
12
|
+
*
|
|
13
|
+
* // Take a snapshot
|
|
14
|
+
* const snapshot = await agent.execute({
|
|
15
|
+
* id: '1',
|
|
16
|
+
* action: 'snapshot'
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Click an element
|
|
20
|
+
* await agent.execute({
|
|
21
|
+
* id: '2',
|
|
22
|
+
* action: 'click',
|
|
23
|
+
* selector: '@ref:5' // From snapshot
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import { DOMActions } from './actions.js';
|
|
28
|
+
import { createRefMap, createSimpleRefMap } from './ref-map.js';
|
|
29
|
+
export * from './types.js';
|
|
30
|
+
export * from './errors.js';
|
|
31
|
+
export { createSnapshot } from './snapshot.js';
|
|
32
|
+
export { createRefMap, createSimpleRefMap } from './ref-map.js';
|
|
33
|
+
export { DOMActions } from './actions.js';
|
|
34
|
+
/**
|
|
35
|
+
* Create a ContentAgent for DOM automation
|
|
36
|
+
*
|
|
37
|
+
* @param doc - The document to operate on (defaults to current document)
|
|
38
|
+
* @param win - The window context (defaults to current window)
|
|
39
|
+
* @returns A ContentAgent instance
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // In content script
|
|
44
|
+
* const agent = createContentAgent();
|
|
45
|
+
*
|
|
46
|
+
* // Take a snapshot of the page
|
|
47
|
+
* const { data } = await agent.execute({ id: '1', action: 'snapshot' });
|
|
48
|
+
*
|
|
49
|
+
* // Click an element using ref from snapshot
|
|
50
|
+
* await agent.execute({ id: '2', action: 'click', selector: '@ref:5' });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function createContentAgent(doc = document, win = window) {
|
|
54
|
+
// Use WeakRef-based map if available for better memory management
|
|
55
|
+
const refMap = typeof WeakRef !== 'undefined'
|
|
56
|
+
? createRefMap()
|
|
57
|
+
: createSimpleRefMap();
|
|
58
|
+
const actions = new DOMActions(doc, win, refMap);
|
|
59
|
+
const agent = {
|
|
60
|
+
async execute(command) {
|
|
61
|
+
return actions.execute(command);
|
|
62
|
+
},
|
|
63
|
+
async executeJson(json) {
|
|
64
|
+
try {
|
|
65
|
+
const command = JSON.parse(json);
|
|
66
|
+
const response = await actions.execute(command);
|
|
67
|
+
return JSON.stringify(response);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71
|
+
return JSON.stringify({
|
|
72
|
+
id: 'unknown',
|
|
73
|
+
success: false,
|
|
74
|
+
error: `Failed to parse command: ${message}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
getRefMap() {
|
|
79
|
+
return refMap;
|
|
80
|
+
},
|
|
81
|
+
clearRefs() {
|
|
82
|
+
refMap.clear();
|
|
83
|
+
actions.invalidateSnapshot();
|
|
84
|
+
},
|
|
85
|
+
handleMessage(message, _sender, sendResponse) {
|
|
86
|
+
const msg = message;
|
|
87
|
+
if (msg?.type !== 'btcp:command')
|
|
88
|
+
return false;
|
|
89
|
+
agent.execute(msg.command).then(response => {
|
|
90
|
+
sendResponse({ type: 'btcp:response', response });
|
|
91
|
+
}).catch(error => {
|
|
92
|
+
sendResponse({
|
|
93
|
+
type: 'btcp:response',
|
|
94
|
+
response: {
|
|
95
|
+
id: msg.command?.id ?? 'unknown',
|
|
96
|
+
success: false,
|
|
97
|
+
error: error instanceof Error ? error.message : String(error),
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
return true; // Keep channel open for async response
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
return agent;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @deprecated Use createContentAgent instead
|
|
108
|
+
*/
|
|
109
|
+
export const createAgent = createContentAgent;
|
|
110
|
+
/**
|
|
111
|
+
* Install message listener for extension communication
|
|
112
|
+
* Call this in your content script to enable command execution via postMessage
|
|
113
|
+
*
|
|
114
|
+
* @param agent - The agent instance
|
|
115
|
+
* @returns Cleanup function to remove the listener
|
|
116
|
+
*/
|
|
117
|
+
export function installMessageListener(agent) {
|
|
118
|
+
const handler = async (event) => {
|
|
119
|
+
// Only accept messages from same window
|
|
120
|
+
if (event.source !== window)
|
|
121
|
+
return;
|
|
122
|
+
const data = event.data;
|
|
123
|
+
if (data?.type !== 'aspect:command')
|
|
124
|
+
return;
|
|
125
|
+
const response = await agent.execute(data.command);
|
|
126
|
+
window.postMessage({
|
|
127
|
+
type: 'aspect:response',
|
|
128
|
+
response,
|
|
129
|
+
}, '*');
|
|
130
|
+
};
|
|
131
|
+
window.addEventListener('message', handler);
|
|
132
|
+
return () => window.removeEventListener('message', handler);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @btcp/core - Element Reference Map
|
|
3
|
+
*
|
|
4
|
+
* Maintains a mapping between string refs and DOM elements.
|
|
5
|
+
* Used by the snapshot system to enable @ref:xxx selectors.
|
|
6
|
+
*/
|
|
7
|
+
import type { RefMap } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create a new element reference map
|
|
10
|
+
*/
|
|
11
|
+
export declare function createRefMap(): RefMap;
|
|
12
|
+
/**
|
|
13
|
+
* Simple ref map without WeakRef (for environments that don't support it)
|
|
14
|
+
*/
|
|
15
|
+
export declare function createSimpleRefMap(): RefMap;
|
|
16
|
+
//# sourceMappingURL=ref-map.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @btcp/core - Element Reference Map
|
|
3
|
+
*
|
|
4
|
+
* Maintains a mapping between string refs and DOM elements.
|
|
5
|
+
* Used by the snapshot system to enable @ref:xxx selectors.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Create a new element reference map
|
|
9
|
+
*/
|
|
10
|
+
export function createRefMap() {
|
|
11
|
+
const map = new Map();
|
|
12
|
+
let counter = 0;
|
|
13
|
+
return {
|
|
14
|
+
get(ref) {
|
|
15
|
+
const weakRef = map.get(ref);
|
|
16
|
+
if (!weakRef)
|
|
17
|
+
return null;
|
|
18
|
+
const element = weakRef.deref();
|
|
19
|
+
if (!element) {
|
|
20
|
+
// Element was garbage collected
|
|
21
|
+
map.delete(ref);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// Check if element is still in DOM
|
|
25
|
+
if (!element.isConnected) {
|
|
26
|
+
map.delete(ref);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return element;
|
|
30
|
+
},
|
|
31
|
+
set(ref, element) {
|
|
32
|
+
map.set(ref, new WeakRef(element));
|
|
33
|
+
},
|
|
34
|
+
clear() {
|
|
35
|
+
map.clear();
|
|
36
|
+
counter = 0;
|
|
37
|
+
},
|
|
38
|
+
generateRef(element) {
|
|
39
|
+
// Check if element already has a ref
|
|
40
|
+
for (const [ref, weakRef] of map.entries()) {
|
|
41
|
+
if (weakRef.deref() === element) {
|
|
42
|
+
return ref;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Generate new ref
|
|
46
|
+
const ref = `@ref:${counter++}`;
|
|
47
|
+
map.set(ref, new WeakRef(element));
|
|
48
|
+
return ref;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Simple ref map without WeakRef (for environments that don't support it)
|
|
54
|
+
*/
|
|
55
|
+
export function createSimpleRefMap() {
|
|
56
|
+
const map = new Map();
|
|
57
|
+
let counter = 0;
|
|
58
|
+
return {
|
|
59
|
+
get(ref) {
|
|
60
|
+
const element = map.get(ref);
|
|
61
|
+
if (!element)
|
|
62
|
+
return null;
|
|
63
|
+
// Check if element is still in DOM
|
|
64
|
+
if (!element.isConnected) {
|
|
65
|
+
map.delete(ref);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return element;
|
|
69
|
+
},
|
|
70
|
+
set(ref, element) {
|
|
71
|
+
map.set(ref, element);
|
|
72
|
+
},
|
|
73
|
+
clear() {
|
|
74
|
+
map.clear();
|
|
75
|
+
counter = 0;
|
|
76
|
+
},
|
|
77
|
+
generateRef(element) {
|
|
78
|
+
// Check if element already has a ref
|
|
79
|
+
for (const [ref, el] of map.entries()) {
|
|
80
|
+
if (el === element) {
|
|
81
|
+
return ref;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Generate new ref
|
|
85
|
+
const ref = `@ref:${counter++}`;
|
|
86
|
+
map.set(ref, element);
|
|
87
|
+
return ref;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=ref-map.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @btcp/core - DOM Snapshot
|
|
3
|
+
*
|
|
4
|
+
* Generates a flat accessibility snapshot of the DOM.
|
|
5
|
+
* Produces a compact, AI-friendly list of interactive elements.
|
|
6
|
+
*/
|
|
7
|
+
import type { SnapshotData, RefMap } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Grep options (mirrors Unix grep flags)
|
|
10
|
+
*/
|
|
11
|
+
interface GrepOptions {
|
|
12
|
+
/** Pattern to search for */
|
|
13
|
+
pattern: string;
|
|
14
|
+
/** Case-insensitive matching (grep -i) */
|
|
15
|
+
ignoreCase?: boolean;
|
|
16
|
+
/** Invert match - return non-matching lines (grep -v) */
|
|
17
|
+
invert?: boolean;
|
|
18
|
+
/** Treat pattern as fixed string, not regex (grep -F) */
|
|
19
|
+
fixedStrings?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface SnapshotOptions {
|
|
22
|
+
root?: Element;
|
|
23
|
+
maxDepth?: number;
|
|
24
|
+
includeHidden?: boolean;
|
|
25
|
+
interactive?: boolean;
|
|
26
|
+
compact?: boolean;
|
|
27
|
+
all?: boolean;
|
|
28
|
+
format?: 'tree' | 'html';
|
|
29
|
+
/** Grep filter - string pattern or options object */
|
|
30
|
+
grep?: string | GrepOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate flat snapshot of the DOM
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSnapshot(document: Document, refMap: RefMap, options?: SnapshotOptions): SnapshotData;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=snapshot.d.ts.map
|