btcp-browser-agent 0.1.14 → 0.1.16
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 +1 -1
- package/packages/extension/dist/index.d.ts +37 -10
- package/packages/extension/dist/index.js +23 -58
- package/packages/extension/dist/transport/base-transport.d.ts +65 -0
- package/packages/extension/dist/transport/base-transport.js +115 -0
- package/packages/extension/dist/transport/chrome-extension.d.ts +71 -0
- package/packages/extension/dist/transport/chrome-extension.js +131 -0
- package/packages/extension/dist/transport/direct.d.ts +69 -0
- package/packages/extension/dist/transport/direct.js +90 -0
- package/packages/extension/dist/transport/index.d.ts +10 -0
- package/packages/extension/dist/transport/index.js +12 -0
- package/packages/extension/dist/transport/types.d.ts +73 -0
- package/packages/extension/dist/transport/types.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "btcp-browser-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Give AI agents the power to control browsers. A foundation for building agentic systems with smart DOM snapshots and stable element references.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
42
|
import type { Command, Response } from './types.js';
|
|
43
|
+
import type { Transport } from './transport/types.js';
|
|
43
44
|
import { BackgroundAgent as _BackgroundAgent, getBackgroundAgent as _getBackgroundAgent, setupMessageListener as _setupMessageListener, BrowserAgent as _BrowserAgent, getBrowserAgent as _getBrowserAgent } from './background.js';
|
|
44
45
|
export * from './types.js';
|
|
45
46
|
export { createScriptMessenger, createMethodMessenger, type MessageDefinitions, type ScriptMessenger, type MethodMessenger, type ScriptMessengerOptions, type PayloadOf, type ResultOf, } from './script-messenger.js';
|
|
@@ -47,6 +48,7 @@ export { createRemoteAgent, getBrowserToolDefinitions, mapToolToCommand, formatR
|
|
|
47
48
|
export { _BackgroundAgent as BackgroundAgent, _getBackgroundAgent as getBackgroundAgent, _setupMessageListener as setupMessageListener, _BrowserAgent as BrowserAgent, _getBrowserAgent as getBrowserAgent, };
|
|
48
49
|
export { createContentAgent, type ContentAgent } from '../../core/dist/index.js';
|
|
49
50
|
export type { SnapshotData, BoundingBox, Modifier, } from '../../core/dist/index.js';
|
|
51
|
+
export * from './transport/index.js';
|
|
50
52
|
/**
|
|
51
53
|
* Client for sending commands to the extension background script
|
|
52
54
|
*/
|
|
@@ -147,6 +149,24 @@ export interface Client {
|
|
|
147
149
|
*/
|
|
148
150
|
evaluate(expression: string): Promise<unknown>;
|
|
149
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Options for creating a client
|
|
154
|
+
*/
|
|
155
|
+
export interface CreateClientOptions {
|
|
156
|
+
/**
|
|
157
|
+
* Transport to use for sending commands.
|
|
158
|
+
* Defaults to ChromeExtensionTransport.
|
|
159
|
+
*
|
|
160
|
+
* @example Using direct transport in background script:
|
|
161
|
+
* ```typescript
|
|
162
|
+
* import { createClient, createDirectTransport, getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
163
|
+
*
|
|
164
|
+
* const transport = createDirectTransport({ agent: getBackgroundAgent() });
|
|
165
|
+
* const client = createClient({ transport });
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
transport?: Transport;
|
|
169
|
+
}
|
|
150
170
|
/**
|
|
151
171
|
* Generate a unique command ID for BTCP commands
|
|
152
172
|
*/
|
|
@@ -154,24 +174,31 @@ export declare function generateCommandId(): string;
|
|
|
154
174
|
/**
|
|
155
175
|
* Create a client for communicating with the extension
|
|
156
176
|
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* - In background scripts: Uses BackgroundAgent directly for better performance
|
|
177
|
+
* By default uses ChromeExtensionTransport for popup/content script contexts.
|
|
178
|
+
* Pass a custom transport for different communication mechanisms.
|
|
160
179
|
*
|
|
161
|
-
* @example
|
|
180
|
+
* @example Default (Chrome Extension):
|
|
162
181
|
* ```typescript
|
|
163
182
|
* import { createClient } from '@btcp/browser-agent/extension';
|
|
164
183
|
* const client = createClient();
|
|
165
184
|
* await client.navigate('https://example.com');
|
|
166
185
|
* ```
|
|
167
186
|
*
|
|
168
|
-
* @example
|
|
187
|
+
* @example With explicit transport:
|
|
169
188
|
* ```typescript
|
|
170
|
-
* import { createClient } from '@btcp/browser-agent/extension';
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
189
|
+
* import { createClient, createChromeExtensionTransport } from '@btcp/browser-agent/extension';
|
|
190
|
+
*
|
|
191
|
+
* const transport = createChromeExtensionTransport({ debug: true });
|
|
192
|
+
* const client = createClient({ transport });
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @example Direct transport (background script):
|
|
196
|
+
* ```typescript
|
|
197
|
+
* import { createClient, createDirectTransport, getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
198
|
+
*
|
|
199
|
+
* const transport = createDirectTransport({ agent: getBackgroundAgent() });
|
|
200
|
+
* const client = createClient({ transport });
|
|
174
201
|
* ```
|
|
175
202
|
*/
|
|
176
|
-
export declare function createClient(): Client;
|
|
203
|
+
export declare function createClient(options?: CreateClientOptions): Client;
|
|
177
204
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
* await client.click('@ref:5');
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
+
import { ChromeExtensionTransport } from './transport/chrome-extension.js';
|
|
42
43
|
// Import for local use (and re-export below)
|
|
43
44
|
import { BackgroundAgent as _BackgroundAgent, getBackgroundAgent as _getBackgroundAgent, setupMessageListener as _setupMessageListener, BrowserAgent as _BrowserAgent, getBrowserAgent as _getBrowserAgent, } from './background.js';
|
|
44
45
|
export * from './types.js';
|
|
@@ -52,6 +53,8 @@ export { _BackgroundAgent as BackgroundAgent, _getBackgroundAgent as getBackgrou
|
|
|
52
53
|
_BrowserAgent as BrowserAgent, _getBrowserAgent as getBrowserAgent, };
|
|
53
54
|
// Re-export ContentAgent for content script usage
|
|
54
55
|
export { createContentAgent } from '../../core/dist/index.js';
|
|
56
|
+
// Re-export transport module
|
|
57
|
+
export * from './transport/index.js';
|
|
55
58
|
let commandIdCounter = 0;
|
|
56
59
|
/**
|
|
57
60
|
* Generate a unique command ID for BTCP commands
|
|
@@ -59,79 +62,41 @@ let commandIdCounter = 0;
|
|
|
59
62
|
export function generateCommandId() {
|
|
60
63
|
return `cmd_${Date.now()}_${commandIdCounter++}`;
|
|
61
64
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Check if we're running in a background/service worker context
|
|
64
|
-
*/
|
|
65
|
-
function isBackgroundContext() {
|
|
66
|
-
// In Manifest V3, background scripts run as service workers
|
|
67
|
-
return typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope;
|
|
68
|
-
}
|
|
69
65
|
/**
|
|
70
66
|
* Create a client for communicating with the extension
|
|
71
67
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* - In background scripts: Uses BackgroundAgent directly for better performance
|
|
68
|
+
* By default uses ChromeExtensionTransport for popup/content script contexts.
|
|
69
|
+
* Pass a custom transport for different communication mechanisms.
|
|
75
70
|
*
|
|
76
|
-
* @example
|
|
71
|
+
* @example Default (Chrome Extension):
|
|
77
72
|
* ```typescript
|
|
78
73
|
* import { createClient } from '@btcp/browser-agent/extension';
|
|
79
74
|
* const client = createClient();
|
|
80
75
|
* await client.navigate('https://example.com');
|
|
81
76
|
* ```
|
|
82
77
|
*
|
|
83
|
-
* @example
|
|
78
|
+
* @example With explicit transport:
|
|
84
79
|
* ```typescript
|
|
85
|
-
* import { createClient } from '@btcp/browser-agent/extension';
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
80
|
+
* import { createClient, createChromeExtensionTransport } from '@btcp/browser-agent/extension';
|
|
81
|
+
*
|
|
82
|
+
* const transport = createChromeExtensionTransport({ debug: true });
|
|
83
|
+
* const client = createClient({ transport });
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example Direct transport (background script):
|
|
87
|
+
* ```typescript
|
|
88
|
+
* import { createClient, createDirectTransport, getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
89
|
+
*
|
|
90
|
+
* const transport = createDirectTransport({ agent: getBackgroundAgent() });
|
|
91
|
+
* const client = createClient({ transport });
|
|
89
92
|
* ```
|
|
90
93
|
*/
|
|
91
|
-
export function createClient() {
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
// Lazily get the background agent to avoid circular dependency issues
|
|
95
|
-
let bgAgent = null;
|
|
96
|
-
function getAgent() {
|
|
97
|
-
if (!bgAgent) {
|
|
98
|
-
// Use the singleton getter from background.js
|
|
99
|
-
bgAgent = _getBackgroundAgent();
|
|
100
|
-
}
|
|
101
|
-
return bgAgent;
|
|
102
|
-
}
|
|
94
|
+
export function createClient(options = {}) {
|
|
95
|
+
// Default to Chrome extension transport
|
|
96
|
+
const transport = options.transport ?? new ChromeExtensionTransport();
|
|
103
97
|
async function sendCommand(command) {
|
|
104
|
-
// In background context, use BackgroundAgent directly
|
|
105
|
-
if (inBackground) {
|
|
106
|
-
return getAgent().execute(command);
|
|
107
|
-
}
|
|
108
|
-
// In popup/content context, use message passing
|
|
109
98
|
const id = command.id || generateCommandId();
|
|
110
|
-
return
|
|
111
|
-
chrome.runtime.sendMessage({ type: 'btcp:command', command: { ...command, id } }, (response) => {
|
|
112
|
-
if (chrome.runtime.lastError) {
|
|
113
|
-
resolve({
|
|
114
|
-
id,
|
|
115
|
-
success: false,
|
|
116
|
-
error: chrome.runtime.lastError.message || 'Unknown error',
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
const resp = response;
|
|
121
|
-
if (resp.type === 'btcp:response') {
|
|
122
|
-
resolve(resp.response);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Unexpected pong response
|
|
126
|
-
resolve({
|
|
127
|
-
id,
|
|
128
|
-
success: false,
|
|
129
|
-
error: 'Unexpected response type',
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
});
|
|
99
|
+
return transport.send({ ...command, id });
|
|
135
100
|
}
|
|
136
101
|
function assertSuccess(response) {
|
|
137
102
|
if (!response.success) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base transport class with shared functionality
|
|
3
|
+
*
|
|
4
|
+
* Provides event handling, state management, and utility methods for transports.
|
|
5
|
+
*/
|
|
6
|
+
import type { Command, Response } from '../types.js';
|
|
7
|
+
import type { Transport, TransportEvents, TransportOptions, TransportState } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Abstract base class for transports
|
|
10
|
+
*
|
|
11
|
+
* Provides common functionality for event handling and state management.
|
|
12
|
+
* Subclasses must implement `send()`, `connect()`, and `disconnect()`.
|
|
13
|
+
*/
|
|
14
|
+
export declare abstract class BaseTransport implements Transport {
|
|
15
|
+
abstract readonly name: string;
|
|
16
|
+
protected state: TransportState;
|
|
17
|
+
protected debug: boolean;
|
|
18
|
+
private eventHandlers;
|
|
19
|
+
constructor(options?: TransportOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Send a command - must be implemented by subclasses
|
|
22
|
+
*/
|
|
23
|
+
abstract send(command: Command): Promise<Response>;
|
|
24
|
+
/**
|
|
25
|
+
* Connect the transport - must be implemented by subclasses
|
|
26
|
+
*/
|
|
27
|
+
abstract connect(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Disconnect the transport - must be implemented by subclasses
|
|
30
|
+
*/
|
|
31
|
+
abstract disconnect(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current connection state
|
|
34
|
+
*/
|
|
35
|
+
getState(): TransportState;
|
|
36
|
+
/**
|
|
37
|
+
* Check if the transport is connected
|
|
38
|
+
*/
|
|
39
|
+
isConnected(): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Register an event handler
|
|
42
|
+
*/
|
|
43
|
+
on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
|
|
44
|
+
/**
|
|
45
|
+
* Unregister an event handler
|
|
46
|
+
*/
|
|
47
|
+
off<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
|
|
48
|
+
/**
|
|
49
|
+
* Emit an event to all registered handlers
|
|
50
|
+
*/
|
|
51
|
+
protected emit<K extends keyof TransportEvents>(event: K, ...args: Parameters<TransportEvents[K]>): void;
|
|
52
|
+
/**
|
|
53
|
+
* Update the transport state and emit stateChange event
|
|
54
|
+
*/
|
|
55
|
+
protected setState(newState: TransportState): void;
|
|
56
|
+
/**
|
|
57
|
+
* Log a message if debug is enabled
|
|
58
|
+
*/
|
|
59
|
+
protected log(level: 'debug' | 'info' | 'warn' | 'error', ...args: unknown[]): void;
|
|
60
|
+
/**
|
|
61
|
+
* Create an error response with the given message
|
|
62
|
+
*/
|
|
63
|
+
protected createErrorResponse(id: string, error: string): Response;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=base-transport.d.ts.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base transport class with shared functionality
|
|
3
|
+
*
|
|
4
|
+
* Provides event handling, state management, and utility methods for transports.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Abstract base class for transports
|
|
8
|
+
*
|
|
9
|
+
* Provides common functionality for event handling and state management.
|
|
10
|
+
* Subclasses must implement `send()`, `connect()`, and `disconnect()`.
|
|
11
|
+
*/
|
|
12
|
+
export class BaseTransport {
|
|
13
|
+
state = 'disconnected';
|
|
14
|
+
debug;
|
|
15
|
+
eventHandlers = new Map();
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.debug = options.debug ?? false;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the current connection state
|
|
21
|
+
*/
|
|
22
|
+
getState() {
|
|
23
|
+
return this.state;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if the transport is connected
|
|
27
|
+
*/
|
|
28
|
+
isConnected() {
|
|
29
|
+
return this.state === 'connected';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register an event handler
|
|
33
|
+
*/
|
|
34
|
+
on(event, handler) {
|
|
35
|
+
if (!this.eventHandlers.has(event)) {
|
|
36
|
+
this.eventHandlers.set(event, new Set());
|
|
37
|
+
}
|
|
38
|
+
this.eventHandlers.get(event).add(handler);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Unregister an event handler
|
|
42
|
+
*/
|
|
43
|
+
off(event, handler) {
|
|
44
|
+
const handlers = this.eventHandlers.get(event);
|
|
45
|
+
if (handlers) {
|
|
46
|
+
handlers.delete(handler);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Emit an event to all registered handlers
|
|
51
|
+
*/
|
|
52
|
+
emit(event, ...args) {
|
|
53
|
+
const handlers = this.eventHandlers.get(event);
|
|
54
|
+
if (handlers) {
|
|
55
|
+
for (const handler of handlers) {
|
|
56
|
+
try {
|
|
57
|
+
handler(...args);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
this.log('error', `Error in event handler for "${event}":`, error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Update the transport state and emit stateChange event
|
|
67
|
+
*/
|
|
68
|
+
setState(newState) {
|
|
69
|
+
if (this.state !== newState) {
|
|
70
|
+
const oldState = this.state;
|
|
71
|
+
this.state = newState;
|
|
72
|
+
this.log('debug', `State changed: ${oldState} -> ${newState}`);
|
|
73
|
+
this.emit('stateChange', newState);
|
|
74
|
+
// Also emit specific events
|
|
75
|
+
if (newState === 'connected') {
|
|
76
|
+
this.emit('connected');
|
|
77
|
+
}
|
|
78
|
+
else if (newState === 'disconnected') {
|
|
79
|
+
this.emit('disconnected');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Log a message if debug is enabled
|
|
85
|
+
*/
|
|
86
|
+
log(level, ...args) {
|
|
87
|
+
if (!this.debug && level === 'debug') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const prefix = `[${this.name}]`;
|
|
91
|
+
switch (level) {
|
|
92
|
+
case 'debug':
|
|
93
|
+
case 'info':
|
|
94
|
+
console.log(prefix, ...args);
|
|
95
|
+
break;
|
|
96
|
+
case 'warn':
|
|
97
|
+
console.warn(prefix, ...args);
|
|
98
|
+
break;
|
|
99
|
+
case 'error':
|
|
100
|
+
console.error(prefix, ...args);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create an error response with the given message
|
|
106
|
+
*/
|
|
107
|
+
createErrorResponse(id, error) {
|
|
108
|
+
return {
|
|
109
|
+
id,
|
|
110
|
+
success: false,
|
|
111
|
+
error,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=base-transport.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome Extension Transport
|
|
3
|
+
*
|
|
4
|
+
* Transport implementation that uses chrome.runtime.sendMessage to communicate
|
|
5
|
+
* with the background script.
|
|
6
|
+
*/
|
|
7
|
+
import type { Command, Response } from '../types.js';
|
|
8
|
+
import { BaseTransport } from './base-transport.js';
|
|
9
|
+
import type { TransportOptions } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Options for the Chrome extension transport
|
|
12
|
+
*/
|
|
13
|
+
export interface ChromeExtensionTransportOptions extends TransportOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Whether to auto-connect on first send
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
autoConnect?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Chrome Extension Transport
|
|
22
|
+
*
|
|
23
|
+
* Uses chrome.runtime.sendMessage to send commands to the background script.
|
|
24
|
+
* This is the default transport for popup and content script contexts.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const transport = new ChromeExtensionTransport({ debug: true });
|
|
29
|
+
* await transport.connect();
|
|
30
|
+
* const response = await transport.send({ action: 'navigate', url: 'https://example.com' });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare class ChromeExtensionTransport extends BaseTransport {
|
|
34
|
+
readonly name = "chrome-extension";
|
|
35
|
+
private autoConnect;
|
|
36
|
+
private initPromise;
|
|
37
|
+
constructor(options?: ChromeExtensionTransportOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Connect to the background script
|
|
40
|
+
*
|
|
41
|
+
* Sends a popupInitialize command to reconnect to any existing session.
|
|
42
|
+
*/
|
|
43
|
+
connect(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Disconnect the transport
|
|
46
|
+
*/
|
|
47
|
+
disconnect(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Send a command to the background script
|
|
50
|
+
*/
|
|
51
|
+
send(command: Command): Promise<Response>;
|
|
52
|
+
/**
|
|
53
|
+
* Ensure the transport is connected (lazy initialization)
|
|
54
|
+
*/
|
|
55
|
+
private ensureConnected;
|
|
56
|
+
/**
|
|
57
|
+
* Send a command without auto-connect (used for popupInitialize itself)
|
|
58
|
+
*/
|
|
59
|
+
private sendRaw;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a Chrome extension transport
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const transport = createChromeExtensionTransport({ debug: true });
|
|
67
|
+
* const client = createClient({ transport });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function createChromeExtensionTransport(options?: ChromeExtensionTransportOptions): ChromeExtensionTransport;
|
|
71
|
+
//# sourceMappingURL=chrome-extension.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome Extension Transport
|
|
3
|
+
*
|
|
4
|
+
* Transport implementation that uses chrome.runtime.sendMessage to communicate
|
|
5
|
+
* with the background script.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseTransport } from './base-transport.js';
|
|
8
|
+
let commandIdCounter = 0;
|
|
9
|
+
/**
|
|
10
|
+
* Generate a unique command ID for BTCP commands
|
|
11
|
+
*/
|
|
12
|
+
function generateCommandId() {
|
|
13
|
+
return `cmd_${Date.now()}_${commandIdCounter++}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Chrome Extension Transport
|
|
17
|
+
*
|
|
18
|
+
* Uses chrome.runtime.sendMessage to send commands to the background script.
|
|
19
|
+
* This is the default transport for popup and content script contexts.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const transport = new ChromeExtensionTransport({ debug: true });
|
|
24
|
+
* await transport.connect();
|
|
25
|
+
* const response = await transport.send({ action: 'navigate', url: 'https://example.com' });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class ChromeExtensionTransport extends BaseTransport {
|
|
29
|
+
name = 'chrome-extension';
|
|
30
|
+
autoConnect;
|
|
31
|
+
initPromise = null;
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
super(options);
|
|
34
|
+
this.autoConnect = options.autoConnect ?? true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Connect to the background script
|
|
38
|
+
*
|
|
39
|
+
* Sends a popupInitialize command to reconnect to any existing session.
|
|
40
|
+
*/
|
|
41
|
+
async connect() {
|
|
42
|
+
if (this.state === 'connected' || this.state === 'connecting') {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.setState('connecting');
|
|
46
|
+
try {
|
|
47
|
+
// Send popupInitialize to reconnect to existing session
|
|
48
|
+
await this.sendRaw({
|
|
49
|
+
id: generateCommandId(),
|
|
50
|
+
action: 'popupInitialize',
|
|
51
|
+
});
|
|
52
|
+
this.setState('connected');
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Silent fail - session will be created on first tool use if needed
|
|
56
|
+
// Still mark as connected since messaging works
|
|
57
|
+
this.log('debug', 'popupInitialize failed (session will be created on demand):', error);
|
|
58
|
+
this.setState('connected');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Disconnect the transport
|
|
63
|
+
*/
|
|
64
|
+
disconnect() {
|
|
65
|
+
if (this.state === 'disconnected') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.initPromise = null;
|
|
69
|
+
this.setState('disconnected');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Send a command to the background script
|
|
73
|
+
*/
|
|
74
|
+
async send(command) {
|
|
75
|
+
// Auto-connect on first send if enabled
|
|
76
|
+
if (this.autoConnect && this.state === 'disconnected') {
|
|
77
|
+
await this.ensureConnected();
|
|
78
|
+
}
|
|
79
|
+
const id = command.id || generateCommandId();
|
|
80
|
+
return this.sendRaw({ ...command, id });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Ensure the transport is connected (lazy initialization)
|
|
84
|
+
*/
|
|
85
|
+
async ensureConnected() {
|
|
86
|
+
if (this.state === 'connected') {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.initPromise === null) {
|
|
90
|
+
this.initPromise = this.connect();
|
|
91
|
+
}
|
|
92
|
+
return this.initPromise;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Send a command without auto-connect (used for popupInitialize itself)
|
|
96
|
+
*/
|
|
97
|
+
sendRaw(command) {
|
|
98
|
+
const id = command.id || generateCommandId();
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
chrome.runtime.sendMessage({ type: 'btcp:command', command: { ...command, id } }, (response) => {
|
|
101
|
+
if (chrome.runtime.lastError) {
|
|
102
|
+
const error = chrome.runtime.lastError.message || 'Unknown error';
|
|
103
|
+
this.log('debug', 'sendMessage error:', error);
|
|
104
|
+
resolve(this.createErrorResponse(id, error));
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const resp = response;
|
|
108
|
+
if (resp?.type === 'btcp:response') {
|
|
109
|
+
resolve(resp.response);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
resolve(this.createErrorResponse(id, 'Unexpected response type'));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Create a Chrome extension transport
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const transport = createChromeExtensionTransport({ debug: true });
|
|
125
|
+
* const client = createClient({ transport });
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export function createChromeExtensionTransport(options = {}) {
|
|
129
|
+
return new ChromeExtensionTransport(options);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=chrome-extension.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct Transport
|
|
3
|
+
*
|
|
4
|
+
* Transport implementation that calls BackgroundAgent.execute() directly,
|
|
5
|
+
* bypassing message passing. Use this in background script context for
|
|
6
|
+
* better performance.
|
|
7
|
+
*/
|
|
8
|
+
import type { BackgroundAgent } from '../background.js';
|
|
9
|
+
import type { Command, Response } from '../types.js';
|
|
10
|
+
import { BaseTransport } from './base-transport.js';
|
|
11
|
+
import type { TransportOptions } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Options for the direct transport
|
|
14
|
+
*/
|
|
15
|
+
export interface DirectTransportOptions extends TransportOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The BackgroundAgent instance to use for executing commands.
|
|
18
|
+
* This is required since DirectTransport calls execute() directly.
|
|
19
|
+
*/
|
|
20
|
+
agent: BackgroundAgent;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Direct Transport
|
|
24
|
+
*
|
|
25
|
+
* Executes commands directly via BackgroundAgent.execute() without
|
|
26
|
+
* any message passing. This is more efficient for background script
|
|
27
|
+
* contexts where the agent is available in-process.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
32
|
+
* import { createDirectTransport } from '@btcp/browser-agent/extension/transport';
|
|
33
|
+
*
|
|
34
|
+
* const agent = getBackgroundAgent();
|
|
35
|
+
* const transport = createDirectTransport({ agent });
|
|
36
|
+
* const client = createClient({ transport });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class DirectTransport extends BaseTransport {
|
|
40
|
+
readonly name = "direct";
|
|
41
|
+
private agent;
|
|
42
|
+
constructor(options: DirectTransportOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Connect the transport (no-op for direct transport)
|
|
45
|
+
*/
|
|
46
|
+
connect(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Disconnect the transport
|
|
49
|
+
*/
|
|
50
|
+
disconnect(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Send a command directly to the BackgroundAgent
|
|
53
|
+
*/
|
|
54
|
+
send(command: Command): Promise<Response>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a direct transport
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* import { getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
62
|
+
* import { createDirectTransport } from '@btcp/browser-agent/extension/transport';
|
|
63
|
+
*
|
|
64
|
+
* const transport = createDirectTransport({ agent: getBackgroundAgent() });
|
|
65
|
+
* const client = createClient({ transport });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function createDirectTransport(options: DirectTransportOptions): DirectTransport;
|
|
69
|
+
//# sourceMappingURL=direct.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct Transport
|
|
3
|
+
*
|
|
4
|
+
* Transport implementation that calls BackgroundAgent.execute() directly,
|
|
5
|
+
* bypassing message passing. Use this in background script context for
|
|
6
|
+
* better performance.
|
|
7
|
+
*/
|
|
8
|
+
import { BaseTransport } from './base-transport.js';
|
|
9
|
+
let commandIdCounter = 0;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a unique command ID for BTCP commands
|
|
12
|
+
*/
|
|
13
|
+
function generateCommandId() {
|
|
14
|
+
return `direct_${Date.now()}_${commandIdCounter++}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Direct Transport
|
|
18
|
+
*
|
|
19
|
+
* Executes commands directly via BackgroundAgent.execute() without
|
|
20
|
+
* any message passing. This is more efficient for background script
|
|
21
|
+
* contexts where the agent is available in-process.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
26
|
+
* import { createDirectTransport } from '@btcp/browser-agent/extension/transport';
|
|
27
|
+
*
|
|
28
|
+
* const agent = getBackgroundAgent();
|
|
29
|
+
* const transport = createDirectTransport({ agent });
|
|
30
|
+
* const client = createClient({ transport });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class DirectTransport extends BaseTransport {
|
|
34
|
+
name = 'direct';
|
|
35
|
+
agent;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
super(options);
|
|
38
|
+
this.agent = options.agent;
|
|
39
|
+
// Direct transport is always "connected" since it's in-process
|
|
40
|
+
this.setState('connected');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Connect the transport (no-op for direct transport)
|
|
44
|
+
*/
|
|
45
|
+
async connect() {
|
|
46
|
+
// Direct transport is always connected
|
|
47
|
+
this.setState('connected');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Disconnect the transport
|
|
51
|
+
*/
|
|
52
|
+
disconnect() {
|
|
53
|
+
this.setState('disconnected');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Send a command directly to the BackgroundAgent
|
|
57
|
+
*/
|
|
58
|
+
async send(command) {
|
|
59
|
+
if (this.state !== 'connected') {
|
|
60
|
+
const id = command.id || generateCommandId();
|
|
61
|
+
return this.createErrorResponse(id, 'Transport is not connected');
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const id = command.id || generateCommandId();
|
|
65
|
+
return await this.agent.execute({ ...command, id });
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const id = command.id || generateCommandId();
|
|
69
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
70
|
+
this.log('error', 'Direct execute error:', error);
|
|
71
|
+
return this.createErrorResponse(id, message);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a direct transport
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* import { getBackgroundAgent } from '@btcp/browser-agent/extension';
|
|
81
|
+
* import { createDirectTransport } from '@btcp/browser-agent/extension/transport';
|
|
82
|
+
*
|
|
83
|
+
* const transport = createDirectTransport({ agent: getBackgroundAgent() });
|
|
84
|
+
* const client = createClient({ transport });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function createDirectTransport(options) {
|
|
88
|
+
return new DirectTransport(options);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=direct.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport module re-exports
|
|
3
|
+
*
|
|
4
|
+
* This module exports all transport-related types and implementations.
|
|
5
|
+
*/
|
|
6
|
+
export type { Transport, TransportState, TransportEvents, TransportOptions, } from './types.js';
|
|
7
|
+
export { BaseTransport } from './base-transport.js';
|
|
8
|
+
export { ChromeExtensionTransport, createChromeExtensionTransport, type ChromeExtensionTransportOptions, } from './chrome-extension.js';
|
|
9
|
+
export { DirectTransport, createDirectTransport, type DirectTransportOptions, } from './direct.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport module re-exports
|
|
3
|
+
*
|
|
4
|
+
* This module exports all transport-related types and implementations.
|
|
5
|
+
*/
|
|
6
|
+
// Base class (for custom transport implementations)
|
|
7
|
+
export { BaseTransport } from './base-transport.js';
|
|
8
|
+
// Chrome extension transport
|
|
9
|
+
export { ChromeExtensionTransport, createChromeExtensionTransport, } from './chrome-extension.js';
|
|
10
|
+
// Direct transport (in-process, for background scripts)
|
|
11
|
+
export { DirectTransport, createDirectTransport, } from './direct.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport abstraction for the client API
|
|
3
|
+
*
|
|
4
|
+
* This module defines the transport interface that allows the client to use
|
|
5
|
+
* different communication mechanisms (Chrome extension messaging, HTTP, WebSocket, etc.)
|
|
6
|
+
*/
|
|
7
|
+
import type { Command, Response } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Transport connection state
|
|
10
|
+
*/
|
|
11
|
+
export type TransportState = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
12
|
+
/**
|
|
13
|
+
* Events emitted by transports
|
|
14
|
+
*/
|
|
15
|
+
export interface TransportEvents {
|
|
16
|
+
/** Transport connected successfully */
|
|
17
|
+
connected: () => void;
|
|
18
|
+
/** Transport disconnected */
|
|
19
|
+
disconnected: (reason?: string) => void;
|
|
20
|
+
/** Transport encountered an error */
|
|
21
|
+
error: (error: Error) => void;
|
|
22
|
+
/** Transport state changed */
|
|
23
|
+
stateChange: (state: TransportState) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Base transport options shared by all transports
|
|
27
|
+
*/
|
|
28
|
+
export interface TransportOptions {
|
|
29
|
+
/** Enable debug logging */
|
|
30
|
+
debug?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Transport interface for sending commands to the backend
|
|
34
|
+
*
|
|
35
|
+
* Transports handle the communication layer between the client and the
|
|
36
|
+
* command execution backend (background script, HTTP server, etc.)
|
|
37
|
+
*/
|
|
38
|
+
export interface Transport {
|
|
39
|
+
/**
|
|
40
|
+
* Human-readable name for this transport (e.g., 'chrome-extension', 'http')
|
|
41
|
+
*/
|
|
42
|
+
readonly name: string;
|
|
43
|
+
/**
|
|
44
|
+
* Send a command and wait for the response
|
|
45
|
+
*/
|
|
46
|
+
send(command: Command): Promise<Response>;
|
|
47
|
+
/**
|
|
48
|
+
* Connect the transport (if applicable)
|
|
49
|
+
* Some transports may be stateless and not require connection
|
|
50
|
+
*/
|
|
51
|
+
connect(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Disconnect the transport and clean up resources
|
|
54
|
+
*/
|
|
55
|
+
disconnect(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Get the current connection state
|
|
58
|
+
*/
|
|
59
|
+
getState(): TransportState;
|
|
60
|
+
/**
|
|
61
|
+
* Check if the transport is currently connected
|
|
62
|
+
*/
|
|
63
|
+
isConnected(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Register an event handler
|
|
66
|
+
*/
|
|
67
|
+
on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
|
|
68
|
+
/**
|
|
69
|
+
* Unregister an event handler
|
|
70
|
+
*/
|
|
71
|
+
off<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport abstraction for the client API
|
|
3
|
+
*
|
|
4
|
+
* This module defines the transport interface that allows the client to use
|
|
5
|
+
* different communication mechanisms (Chrome extension messaging, HTTP, WebSocket, etc.)
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=types.js.map
|