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
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SessionManager - Manages tab groups and sessions for BTCP Browser Agent
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
GroupInfo,
|
|
7
|
-
SessionInfo,
|
|
8
|
-
GroupCreateOptions,
|
|
9
|
-
GroupUpdateOptions,
|
|
10
|
-
GroupColor,
|
|
11
|
-
} from './session-types.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Storage key for session persistence
|
|
15
|
-
*/
|
|
16
|
-
const SESSION_STORAGE_KEY = 'btcp_active_session';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Stored session data
|
|
20
|
-
*/
|
|
21
|
-
interface StoredSessionData {
|
|
22
|
-
groupId: number;
|
|
23
|
-
sessionCounter: number;
|
|
24
|
-
timestamp: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* SessionManager handles Chrome tab group operations and session state
|
|
29
|
-
*/
|
|
30
|
-
export class SessionManager {
|
|
31
|
-
private activeSessionGroupId: number | null = null;
|
|
32
|
-
private sessionCounter = 0;
|
|
33
|
-
private initialized = false;
|
|
34
|
-
|
|
35
|
-
constructor() {
|
|
36
|
-
// Restore session on creation
|
|
37
|
-
this.restoreSession();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Restore session from storage
|
|
42
|
-
*/
|
|
43
|
-
private async restoreSession(): Promise<void> {
|
|
44
|
-
if (this.initialized) return;
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
console.log('[SessionManager] Restoring session from storage...');
|
|
48
|
-
const result = await chrome.storage.session.get(SESSION_STORAGE_KEY);
|
|
49
|
-
const data = result[SESSION_STORAGE_KEY] as StoredSessionData | undefined;
|
|
50
|
-
|
|
51
|
-
if (data?.groupId) {
|
|
52
|
-
console.log('[SessionManager] Found stored session:', data);
|
|
53
|
-
|
|
54
|
-
// Verify the group still exists
|
|
55
|
-
try {
|
|
56
|
-
const group = await chrome.tabGroups.get(data.groupId);
|
|
57
|
-
console.log('[SessionManager] Group still exists:', group);
|
|
58
|
-
|
|
59
|
-
// Restore session state
|
|
60
|
-
this.activeSessionGroupId = data.groupId;
|
|
61
|
-
this.sessionCounter = data.sessionCounter;
|
|
62
|
-
|
|
63
|
-
console.log('[SessionManager] Session restored successfully');
|
|
64
|
-
} catch (err) {
|
|
65
|
-
console.log('[SessionManager] Stored group no longer exists, clearing...');
|
|
66
|
-
await this.clearStoredSession();
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
console.log('[SessionManager] No stored session found');
|
|
70
|
-
}
|
|
71
|
-
} catch (err) {
|
|
72
|
-
console.error('[SessionManager] Failed to restore session:', err);
|
|
73
|
-
} finally {
|
|
74
|
-
this.initialized = true;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Persist session to storage
|
|
80
|
-
*/
|
|
81
|
-
private async persistSession(): Promise<void> {
|
|
82
|
-
if (this.activeSessionGroupId === null) {
|
|
83
|
-
await this.clearStoredSession();
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const data: StoredSessionData = {
|
|
88
|
-
groupId: this.activeSessionGroupId,
|
|
89
|
-
sessionCounter: this.sessionCounter,
|
|
90
|
-
timestamp: Date.now(),
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
await chrome.storage.session.set({ [SESSION_STORAGE_KEY]: data });
|
|
95
|
-
console.log('[SessionManager] Session persisted:', data);
|
|
96
|
-
} catch (err) {
|
|
97
|
-
console.error('[SessionManager] Failed to persist session:', err);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Clear stored session
|
|
103
|
-
*/
|
|
104
|
-
private async clearStoredSession(): Promise<void> {
|
|
105
|
-
try {
|
|
106
|
-
await chrome.storage.session.remove(SESSION_STORAGE_KEY);
|
|
107
|
-
console.log('[SessionManager] Cleared stored session');
|
|
108
|
-
} catch (err) {
|
|
109
|
-
console.error('[SessionManager] Failed to clear stored session:', err);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Reconnect to a specific session group
|
|
115
|
-
* Used when popup detects a stored session that isn't currently active
|
|
116
|
-
*/
|
|
117
|
-
async reconnectSession(groupId: number): Promise<boolean> {
|
|
118
|
-
try {
|
|
119
|
-
console.log('[SessionManager] Attempting to reconnect to session group:', groupId);
|
|
120
|
-
|
|
121
|
-
// Verify the group still exists
|
|
122
|
-
const group = await chrome.tabGroups.get(groupId);
|
|
123
|
-
console.log('[SessionManager] Group found:', group);
|
|
124
|
-
|
|
125
|
-
// Get stored session data for counter
|
|
126
|
-
const result = await chrome.storage.session.get(SESSION_STORAGE_KEY);
|
|
127
|
-
const data = result[SESSION_STORAGE_KEY] as StoredSessionData | undefined;
|
|
128
|
-
|
|
129
|
-
// Restore session state
|
|
130
|
-
this.activeSessionGroupId = groupId;
|
|
131
|
-
this.sessionCounter = data?.sessionCounter ?? this.sessionCounter;
|
|
132
|
-
|
|
133
|
-
console.log('[SessionManager] Session reconnected successfully');
|
|
134
|
-
return true;
|
|
135
|
-
} catch (err) {
|
|
136
|
-
console.error('[SessionManager] Failed to reconnect session:', err);
|
|
137
|
-
// Clear invalid stored session
|
|
138
|
-
await this.clearStoredSession();
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Create a new tab group
|
|
145
|
-
*/
|
|
146
|
-
async createGroup(options: GroupCreateOptions = {}): Promise<GroupInfo> {
|
|
147
|
-
console.log('[SessionManager] createGroup called with options:', options);
|
|
148
|
-
|
|
149
|
-
const {
|
|
150
|
-
tabIds = [],
|
|
151
|
-
title = this.generateSessionName(),
|
|
152
|
-
color = 'blue',
|
|
153
|
-
collapsed = false,
|
|
154
|
-
} = options;
|
|
155
|
-
|
|
156
|
-
// If no tabIds provided, create a new blank tab for the session
|
|
157
|
-
let targetTabIds = tabIds;
|
|
158
|
-
if (targetTabIds.length === 0) {
|
|
159
|
-
console.log('[SessionManager] No tabIds provided, creating new blank tab...');
|
|
160
|
-
const newTab = await chrome.tabs.create({
|
|
161
|
-
url: 'about:blank',
|
|
162
|
-
active: true
|
|
163
|
-
});
|
|
164
|
-
console.log('[SessionManager] Created new tab:', newTab.id);
|
|
165
|
-
if (newTab?.id) {
|
|
166
|
-
targetTabIds = [newTab.id];
|
|
167
|
-
} else {
|
|
168
|
-
console.error('[SessionManager] Failed to create new tab');
|
|
169
|
-
throw new Error('Failed to create new tab for session');
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
console.log('[SessionManager] Creating group with tabs:', targetTabIds);
|
|
174
|
-
|
|
175
|
-
// Get the window for the tab (must be a normal window)
|
|
176
|
-
const tabs = await chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT });
|
|
177
|
-
const targetTab = tabs.find(t => targetTabIds.includes(t.id!));
|
|
178
|
-
|
|
179
|
-
if (!targetTab || !targetTab.windowId) {
|
|
180
|
-
console.error('[SessionManager] Could not find valid window for tab');
|
|
181
|
-
throw new Error('Could not find a normal window for the tab');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Verify it's a normal window, not popup/devtools/etc
|
|
185
|
-
const window = await chrome.windows.get(targetTab.windowId);
|
|
186
|
-
if (window.type !== 'normal') {
|
|
187
|
-
console.error('[SessionManager] Window is not normal type:', window.type);
|
|
188
|
-
throw new Error(`Tabs can only be grouped in normal windows, not ${window.type} windows`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Create the group
|
|
192
|
-
const groupId = await chrome.tabs.group({
|
|
193
|
-
tabIds: targetTabIds,
|
|
194
|
-
createProperties: {
|
|
195
|
-
windowId: targetTab.windowId,
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
console.log('[SessionManager] Group created with ID:', groupId);
|
|
200
|
-
|
|
201
|
-
// Update group properties
|
|
202
|
-
await chrome.tabGroups.update(groupId, {
|
|
203
|
-
title,
|
|
204
|
-
color,
|
|
205
|
-
collapsed,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
console.log('[SessionManager] Group updated with title:', title);
|
|
209
|
-
|
|
210
|
-
// Set as active session
|
|
211
|
-
this.activeSessionGroupId = groupId;
|
|
212
|
-
|
|
213
|
-
// Persist to storage
|
|
214
|
-
await this.persistSession();
|
|
215
|
-
|
|
216
|
-
// Get group info
|
|
217
|
-
const group = await chrome.tabGroups.get(groupId);
|
|
218
|
-
console.log('[SessionManager] Group info:', group);
|
|
219
|
-
|
|
220
|
-
return this.mapChromeGroupToGroupInfo(group);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Update an existing tab group
|
|
225
|
-
*/
|
|
226
|
-
async updateGroup(groupId: number, options: GroupUpdateOptions): Promise<GroupInfo> {
|
|
227
|
-
await chrome.tabGroups.update(groupId, {
|
|
228
|
-
...(options.title !== undefined && { title: options.title }),
|
|
229
|
-
...(options.color !== undefined && { color: options.color }),
|
|
230
|
-
...(options.collapsed !== undefined && { collapsed: options.collapsed }),
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
const group = await chrome.tabGroups.get(groupId);
|
|
234
|
-
return this.mapChromeGroupToGroupInfo(group);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Delete a tab group (closes all tabs in the group)
|
|
239
|
-
*/
|
|
240
|
-
async deleteGroup(groupId: number): Promise<void> {
|
|
241
|
-
// Get all tabs in the group
|
|
242
|
-
const tabs = await chrome.tabs.query({ groupId });
|
|
243
|
-
const tabIds = tabs.map((tab) => tab.id).filter((id): id is number => id !== undefined);
|
|
244
|
-
|
|
245
|
-
// Close all tabs (this automatically removes the group)
|
|
246
|
-
if (tabIds.length > 0) {
|
|
247
|
-
await chrome.tabs.remove(tabIds);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Clear active session if this was the active group
|
|
251
|
-
if (this.activeSessionGroupId === groupId) {
|
|
252
|
-
this.activeSessionGroupId = null;
|
|
253
|
-
// Clear from storage
|
|
254
|
-
await this.clearStoredSession();
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* List all tab groups
|
|
260
|
-
*/
|
|
261
|
-
async listGroups(): Promise<GroupInfo[]> {
|
|
262
|
-
const groups = await chrome.tabGroups.query({});
|
|
263
|
-
return groups.map((group) => this.mapChromeGroupToGroupInfo(group));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get a specific tab group
|
|
268
|
-
*/
|
|
269
|
-
async getGroup(groupId: number): Promise<GroupInfo> {
|
|
270
|
-
const group = await chrome.tabGroups.get(groupId);
|
|
271
|
-
return this.mapChromeGroupToGroupInfo(group);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Add tabs to a group
|
|
276
|
-
*/
|
|
277
|
-
async addTabsToGroup(groupId: number, tabIds: number[]): Promise<void> {
|
|
278
|
-
await chrome.tabs.group({
|
|
279
|
-
groupId,
|
|
280
|
-
tabIds,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Remove tabs from their group (ungroup them)
|
|
286
|
-
*/
|
|
287
|
-
async removeTabsFromGroup(tabIds: number[]): Promise<void> {
|
|
288
|
-
await chrome.tabs.ungroup(tabIds);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Get current active session info
|
|
293
|
-
*/
|
|
294
|
-
async getCurrentSession(): Promise<SessionInfo | null> {
|
|
295
|
-
if (this.activeSessionGroupId === null) {
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
const group = await chrome.tabGroups.get(this.activeSessionGroupId);
|
|
301
|
-
const tabs = await chrome.tabs.query({ groupId: this.activeSessionGroupId });
|
|
302
|
-
const tabIds = tabs.map((tab) => tab.id).filter((id): id is number => id !== undefined);
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
groupId: this.activeSessionGroupId,
|
|
306
|
-
title: group.title || 'Untitled Session',
|
|
307
|
-
color: group.color as GroupColor,
|
|
308
|
-
tabCount: tabs.length,
|
|
309
|
-
tabIds,
|
|
310
|
-
windowId: group.windowId,
|
|
311
|
-
createdAt: Date.now(),
|
|
312
|
-
};
|
|
313
|
-
} catch (error) {
|
|
314
|
-
// Group no longer exists
|
|
315
|
-
this.activeSessionGroupId = null;
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Get the active session group ID
|
|
322
|
-
*/
|
|
323
|
-
getActiveSessionGroupId(): number | null {
|
|
324
|
-
return this.activeSessionGroupId;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Set the active session group ID
|
|
329
|
-
*/
|
|
330
|
-
setActiveSessionGroupId(groupId: number | null): void {
|
|
331
|
-
this.activeSessionGroupId = groupId;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Add a tab to the active session (if one exists)
|
|
336
|
-
*/
|
|
337
|
-
async addTabToActiveSession(tabId: number): Promise<boolean> {
|
|
338
|
-
if (this.activeSessionGroupId === null) {
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
try {
|
|
343
|
-
await this.addTabsToGroup(this.activeSessionGroupId, [tabId]);
|
|
344
|
-
return true;
|
|
345
|
-
} catch (error) {
|
|
346
|
-
// Group may no longer exist
|
|
347
|
-
this.activeSessionGroupId = null;
|
|
348
|
-
return false;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Generate a session name
|
|
354
|
-
*/
|
|
355
|
-
private generateSessionName(): string {
|
|
356
|
-
this.sessionCounter++;
|
|
357
|
-
return `BTCP Session ${this.sessionCounter}`;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Map Chrome tab group to GroupInfo
|
|
362
|
-
*/
|
|
363
|
-
private mapChromeGroupToGroupInfo(group: chrome.tabGroups.TabGroup): GroupInfo {
|
|
364
|
-
return {
|
|
365
|
-
id: group.id,
|
|
366
|
-
title: group.title,
|
|
367
|
-
color: group.color as GroupColor,
|
|
368
|
-
collapsed: group.collapsed,
|
|
369
|
-
windowId: group.windowId,
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Singleton instance
|
|
375
|
-
let sessionManagerInstance: SessionManager | null = null;
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Get the singleton SessionManager instance
|
|
379
|
-
*/
|
|
380
|
-
export function getSessionManager(): SessionManager {
|
|
381
|
-
if (!sessionManagerInstance) {
|
|
382
|
-
sessionManagerInstance = new SessionManager();
|
|
383
|
-
}
|
|
384
|
-
return sessionManagerInstance;
|
|
385
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @btcp/extension - Type definitions
|
|
3
|
-
*
|
|
4
|
-
* Types for extension commands and Chrome API wrappers.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Command as CoreCommand, Response } from '@btcp/core';
|
|
8
|
-
import type { SessionCommand } from './session-types.js';
|
|
9
|
-
|
|
10
|
-
// Extension-specific actions
|
|
11
|
-
export type ExtensionAction =
|
|
12
|
-
| 'navigate'
|
|
13
|
-
| 'back'
|
|
14
|
-
| 'forward'
|
|
15
|
-
| 'reload'
|
|
16
|
-
| 'getUrl'
|
|
17
|
-
| 'getTitle'
|
|
18
|
-
| 'screenshot'
|
|
19
|
-
| 'tabNew'
|
|
20
|
-
| 'tabClose'
|
|
21
|
-
| 'tabSwitch'
|
|
22
|
-
| 'tabList'
|
|
23
|
-
| 'groupCreate'
|
|
24
|
-
| 'groupUpdate'
|
|
25
|
-
| 'groupDelete'
|
|
26
|
-
| 'groupList'
|
|
27
|
-
| 'groupAddTabs'
|
|
28
|
-
| 'groupRemoveTabs'
|
|
29
|
-
| 'groupGet'
|
|
30
|
-
| 'sessionGetCurrent'
|
|
31
|
-
| 'popupInitialize';
|
|
32
|
-
|
|
33
|
-
// Base extension command
|
|
34
|
-
export interface ExtensionBaseCommand {
|
|
35
|
-
id: string;
|
|
36
|
-
action: ExtensionAction;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface NavigateCommand extends ExtensionBaseCommand {
|
|
40
|
-
action: 'navigate';
|
|
41
|
-
url: string;
|
|
42
|
-
waitUntil?: 'load' | 'domcontentloaded';
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface BackCommand extends ExtensionBaseCommand {
|
|
46
|
-
action: 'back';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ForwardCommand extends ExtensionBaseCommand {
|
|
50
|
-
action: 'forward';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface ReloadCommand extends ExtensionBaseCommand {
|
|
54
|
-
action: 'reload';
|
|
55
|
-
bypassCache?: boolean;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface GetUrlCommand extends ExtensionBaseCommand {
|
|
59
|
-
action: 'getUrl';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface GetTitleCommand extends ExtensionBaseCommand {
|
|
63
|
-
action: 'getTitle';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface ScreenshotCommand extends ExtensionBaseCommand {
|
|
67
|
-
action: 'screenshot';
|
|
68
|
-
format?: 'png' | 'jpeg';
|
|
69
|
-
quality?: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface TabNewCommand extends ExtensionBaseCommand {
|
|
73
|
-
action: 'tabNew';
|
|
74
|
-
url?: string;
|
|
75
|
-
active?: boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface TabCloseCommand extends ExtensionBaseCommand {
|
|
79
|
-
action: 'tabClose';
|
|
80
|
-
tabId?: number;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export interface TabSwitchCommand extends ExtensionBaseCommand {
|
|
84
|
-
action: 'tabSwitch';
|
|
85
|
-
tabId: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface TabListCommand extends ExtensionBaseCommand {
|
|
89
|
-
action: 'tabList';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface PopupInitializeCommand extends ExtensionBaseCommand {
|
|
93
|
-
action: 'popupInitialize';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Union of extension commands
|
|
97
|
-
export type ExtensionCommand =
|
|
98
|
-
| NavigateCommand
|
|
99
|
-
| BackCommand
|
|
100
|
-
| ForwardCommand
|
|
101
|
-
| ReloadCommand
|
|
102
|
-
| GetUrlCommand
|
|
103
|
-
| GetTitleCommand
|
|
104
|
-
| ScreenshotCommand
|
|
105
|
-
| TabNewCommand
|
|
106
|
-
| TabCloseCommand
|
|
107
|
-
| TabSwitchCommand
|
|
108
|
-
| TabListCommand
|
|
109
|
-
| PopupInitializeCommand
|
|
110
|
-
| SessionCommand;
|
|
111
|
-
|
|
112
|
-
// Combined command type (core + extension)
|
|
113
|
-
export type Command = CoreCommand | ExtensionCommand;
|
|
114
|
-
|
|
115
|
-
// Re-export Response type
|
|
116
|
-
export type { Response };
|
|
117
|
-
|
|
118
|
-
// Re-export session types
|
|
119
|
-
export type {
|
|
120
|
-
SessionCommand,
|
|
121
|
-
GroupInfo,
|
|
122
|
-
SessionInfo,
|
|
123
|
-
GroupCreateOptions,
|
|
124
|
-
GroupUpdateOptions,
|
|
125
|
-
} from './session-types.js';
|
|
126
|
-
|
|
127
|
-
// Message types for extension communication
|
|
128
|
-
export interface ExtensionCommandMessage {
|
|
129
|
-
type: 'btcp:command';
|
|
130
|
-
command: Command;
|
|
131
|
-
tabId?: number;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface ExtensionPingMessage {
|
|
135
|
-
type: 'btcp:ping';
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export type ExtensionMessage = ExtensionCommandMessage | ExtensionPingMessage;
|
|
139
|
-
|
|
140
|
-
export interface ExtensionResponseMessage {
|
|
141
|
-
type: 'btcp:response';
|
|
142
|
-
response: Response;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export interface ExtensionPongResponse {
|
|
146
|
-
type: 'btcp:pong';
|
|
147
|
-
ready: boolean;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export type ExtensionResponse = ExtensionResponseMessage | ExtensionPongResponse;
|
|
151
|
-
|
|
152
|
-
// Tab info
|
|
153
|
-
export interface TabInfo {
|
|
154
|
-
id: number;
|
|
155
|
-
url?: string;
|
|
156
|
-
title?: string;
|
|
157
|
-
active: boolean;
|
|
158
|
-
index: number;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Chrome tab type alias (uses @types/chrome)
|
|
162
|
-
export type ChromeTab = chrome.tabs.Tab;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable", "WebWorker"],
|
|
7
|
-
"types": ["chrome"],
|
|
8
|
-
"outDir": "dist",
|
|
9
|
-
"rootDir": "src",
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"declarationMap": true,
|
|
12
|
-
"sourceMap": true,
|
|
13
|
-
"strict": true,
|
|
14
|
-
"noImplicitAny": true,
|
|
15
|
-
"strictNullChecks": true,
|
|
16
|
-
"noUnusedLocals": true,
|
|
17
|
-
"noUnusedParameters": true,
|
|
18
|
-
"esModuleInterop": true,
|
|
19
|
-
"skipLibCheck": true,
|
|
20
|
-
"forceConsistentCasingInFileNames": true,
|
|
21
|
-
"baseUrl": ".",
|
|
22
|
-
"paths": {
|
|
23
|
-
"@btcp/core": ["../core/dist/index.d.ts"]
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"include": ["src/**/*"],
|
|
27
|
-
"exclude": ["node_modules", "dist"]
|
|
28
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BTCP Browser Agent
|
|
3
|
-
*
|
|
4
|
-
* Browser automation with clean separation of concerns:
|
|
5
|
-
* - ContentAgent (@btcp/core): DOM operations in content scripts
|
|
6
|
-
* - BackgroundAgent (@btcp/extension): Tab management in background scripts
|
|
7
|
-
* - Client: API for sending commands from popup/external scripts
|
|
8
|
-
*
|
|
9
|
-
* @example Extension usage
|
|
10
|
-
* ```typescript
|
|
11
|
-
* // background.ts
|
|
12
|
-
* import { BackgroundAgent, setupMessageListener } from '@btcp/browser-agent/extension';
|
|
13
|
-
* setupMessageListener();
|
|
14
|
-
*
|
|
15
|
-
* // content.ts
|
|
16
|
-
* import { createContentAgent } from '@btcp/browser-agent/core';
|
|
17
|
-
* const agent = createContentAgent();
|
|
18
|
-
*
|
|
19
|
-
* // popup.ts
|
|
20
|
-
* import { createClient } from '@btcp/browser-agent/extension';
|
|
21
|
-
* const client = createClient();
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* @example Standalone usage (no extension)
|
|
25
|
-
* ```typescript
|
|
26
|
-
* import { createContentAgent } from '@btcp/browser-agent';
|
|
27
|
-
* const agent = createContentAgent();
|
|
28
|
-
* await agent.execute({ id: '1', action: 'snapshot' });
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
// Re-export everything from core (for standalone usage)
|
|
33
|
-
export {
|
|
34
|
-
createContentAgent,
|
|
35
|
-
type ContentAgent,
|
|
36
|
-
DOMActions,
|
|
37
|
-
createSnapshot,
|
|
38
|
-
createRefMap,
|
|
39
|
-
createSimpleRefMap,
|
|
40
|
-
type Command,
|
|
41
|
-
type Response,
|
|
42
|
-
type SnapshotData,
|
|
43
|
-
type BoundingBox,
|
|
44
|
-
type RefMap,
|
|
45
|
-
type Modifier,
|
|
46
|
-
} from '../packages/core/dist/index.js';
|
|
47
|
-
|
|
48
|
-
// Re-export extension types and utilities
|
|
49
|
-
export type {
|
|
50
|
-
ExtensionMessage,
|
|
51
|
-
ExtensionResponse,
|
|
52
|
-
TabInfo,
|
|
53
|
-
ChromeTab,
|
|
54
|
-
ExtensionCommand,
|
|
55
|
-
} from '../packages/extension/dist/index.js';
|
|
56
|
-
|
|
57
|
-
// Re-export extension functions
|
|
58
|
-
export {
|
|
59
|
-
BackgroundAgent,
|
|
60
|
-
getBackgroundAgent,
|
|
61
|
-
setupMessageListener,
|
|
62
|
-
createClient,
|
|
63
|
-
type Client,
|
|
64
|
-
} from '../packages/extension/dist/index.js';
|
package/tsconfig.build.json
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"declarationMap": true,
|
|
6
|
-
"sourceMap": true,
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src"
|
|
9
|
-
},
|
|
10
|
-
"include": ["src/**/*"],
|
|
11
|
-
"exclude": ["node_modules", "dist", "packages", "**/*.test.ts"]
|
|
12
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
-
"baseUrl": ".",
|
|
8
|
-
"paths": {
|
|
9
|
-
"@btcp/core": ["./packages/core/dist/index.d.ts"],
|
|
10
|
-
"@btcp/extension": ["./packages/extension/dist/index.d.ts"]
|
|
11
|
-
},
|
|
12
|
-
"strict": true,
|
|
13
|
-
"noImplicitAny": true,
|
|
14
|
-
"strictNullChecks": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"noImplicitReturns": true,
|
|
18
|
-
"esModuleInterop": true,
|
|
19
|
-
"skipLibCheck": true,
|
|
20
|
-
"forceConsistentCasingInFileNames": true,
|
|
21
|
-
"resolveJsonModule": true,
|
|
22
|
-
"isolatedModules": true
|
|
23
|
-
},
|
|
24
|
-
"include": ["src/**/*"],
|
|
25
|
-
"exclude": ["node_modules", "dist", "packages"]
|
|
26
|
-
}
|
package/vitest.config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
test: {
|
|
5
|
-
environment: 'jsdom',
|
|
6
|
-
globals: true,
|
|
7
|
-
include: ['src/**/*.test.ts', 'packages/**/*.test.ts'],
|
|
8
|
-
coverage: {
|
|
9
|
-
provider: 'v8',
|
|
10
|
-
reporter: ['text', 'json', 'html'],
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
});
|