btcp-browser-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CLAUDE.md +230 -0
  2. package/LICENSE +21 -0
  3. package/README.md +309 -0
  4. package/SKILL.md +143 -0
  5. package/SNAPSHOT_IMPROVEMENTS.md +302 -0
  6. package/USAGE.md +146 -0
  7. package/dist/index.d.ts +34 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +35 -0
  10. package/dist/index.js.map +1 -0
  11. package/docs/browser-cli-design.md +500 -0
  12. package/examples/chrome-extension/CHANGELOG.md +210 -0
  13. package/examples/chrome-extension/DEBUG.md +231 -0
  14. package/examples/chrome-extension/ERROR_FIXED.md +147 -0
  15. package/examples/chrome-extension/QUICK_TEST.md +189 -0
  16. package/examples/chrome-extension/README.md +149 -0
  17. package/examples/chrome-extension/SESSION_ONLY_MODE.md +305 -0
  18. package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +97 -0
  19. package/examples/chrome-extension/build.js +43 -0
  20. package/examples/chrome-extension/manifest.json +37 -0
  21. package/examples/chrome-extension/package-lock.json +1063 -0
  22. package/examples/chrome-extension/package.json +21 -0
  23. package/examples/chrome-extension/popup.html +195 -0
  24. package/examples/chrome-extension/src/background.ts +12 -0
  25. package/examples/chrome-extension/src/content.ts +7 -0
  26. package/examples/chrome-extension/src/popup.ts +303 -0
  27. package/examples/chrome-extension/src/scenario-google-github.ts +389 -0
  28. package/examples/chrome-extension/test-page.html +127 -0
  29. package/examples/chrome-extension/tests/README.md +206 -0
  30. package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +380 -0
  31. package/examples/chrome-extension/tsconfig.json +14 -0
  32. package/examples/snapshots/README.md +207 -0
  33. package/examples/snapshots/amazon-com-detail.html +9528 -0
  34. package/examples/snapshots/amazon-com-detail.snapshot.txt +997 -0
  35. package/examples/snapshots/convert-snapshots.ts +97 -0
  36. package/examples/snapshots/edition-cnn-com.html +13292 -0
  37. package/examples/snapshots/edition-cnn-com.snapshot.txt +562 -0
  38. package/examples/snapshots/github-com-microsoft-vscode.html +2916 -0
  39. package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +455 -0
  40. package/examples/snapshots/google-search.html +20012 -0
  41. package/examples/snapshots/google-search.snapshot.txt +195 -0
  42. package/examples/snapshots/metadata.json +86 -0
  43. package/examples/snapshots/npr-org-templates.html +2031 -0
  44. package/examples/snapshots/npr-org-templates.snapshot.txt +224 -0
  45. package/examples/snapshots/stackoverflow-com.html +5216 -0
  46. package/examples/snapshots/stackoverflow-com.snapshot.txt +2404 -0
  47. package/examples/snapshots/test-all-mode.html +46 -0
  48. package/examples/snapshots/test-all-mode.snapshot.txt +5 -0
  49. package/examples/snapshots/validate.test.ts +296 -0
  50. package/package.json +65 -0
  51. package/packages/cli/package.json +42 -0
  52. package/packages/cli/src/__tests__/cli.test.ts +434 -0
  53. package/packages/cli/src/__tests__/errors.test.ts +226 -0
  54. package/packages/cli/src/__tests__/executor.test.ts +275 -0
  55. package/packages/cli/src/__tests__/formatter.test.ts +260 -0
  56. package/packages/cli/src/__tests__/parser.test.ts +288 -0
  57. package/packages/cli/src/__tests__/suggestions.test.ts +255 -0
  58. package/packages/cli/src/commands/back.ts +22 -0
  59. package/packages/cli/src/commands/check.ts +33 -0
  60. package/packages/cli/src/commands/clear.ts +33 -0
  61. package/packages/cli/src/commands/click.ts +32 -0
  62. package/packages/cli/src/commands/closetab.ts +31 -0
  63. package/packages/cli/src/commands/eval.ts +41 -0
  64. package/packages/cli/src/commands/fill.ts +30 -0
  65. package/packages/cli/src/commands/focus.ts +33 -0
  66. package/packages/cli/src/commands/forward.ts +22 -0
  67. package/packages/cli/src/commands/goto.ts +34 -0
  68. package/packages/cli/src/commands/help.ts +162 -0
  69. package/packages/cli/src/commands/hover.ts +34 -0
  70. package/packages/cli/src/commands/index.ts +129 -0
  71. package/packages/cli/src/commands/newtab.ts +35 -0
  72. package/packages/cli/src/commands/press.ts +40 -0
  73. package/packages/cli/src/commands/reload.ts +25 -0
  74. package/packages/cli/src/commands/screenshot.ts +27 -0
  75. package/packages/cli/src/commands/scroll.ts +64 -0
  76. package/packages/cli/src/commands/select.ts +35 -0
  77. package/packages/cli/src/commands/snapshot.ts +21 -0
  78. package/packages/cli/src/commands/tab.ts +32 -0
  79. package/packages/cli/src/commands/tabs.ts +26 -0
  80. package/packages/cli/src/commands/text.ts +27 -0
  81. package/packages/cli/src/commands/title.ts +17 -0
  82. package/packages/cli/src/commands/type.ts +38 -0
  83. package/packages/cli/src/commands/uncheck.ts +33 -0
  84. package/packages/cli/src/commands/url.ts +17 -0
  85. package/packages/cli/src/commands/wait.ts +54 -0
  86. package/packages/cli/src/errors.ts +164 -0
  87. package/packages/cli/src/executor.ts +68 -0
  88. package/packages/cli/src/formatter.ts +215 -0
  89. package/packages/cli/src/index.ts +257 -0
  90. package/packages/cli/src/parser.ts +195 -0
  91. package/packages/cli/src/suggestions.ts +207 -0
  92. package/packages/cli/src/terminal/Terminal.ts +365 -0
  93. package/packages/cli/src/terminal/index.ts +5 -0
  94. package/packages/cli/src/types.ts +155 -0
  95. package/packages/cli/tsconfig.json +20 -0
  96. package/packages/core/package.json +35 -0
  97. package/packages/core/src/actions.ts +1210 -0
  98. package/packages/core/src/errors.ts +296 -0
  99. package/packages/core/src/index.test.ts +638 -0
  100. package/packages/core/src/index.ts +220 -0
  101. package/packages/core/src/ref-map.ts +107 -0
  102. package/packages/core/src/snapshot.ts +873 -0
  103. package/packages/core/src/types.ts +536 -0
  104. package/packages/core/tsconfig.json +23 -0
  105. package/packages/extension/README.md +129 -0
  106. package/packages/extension/package.json +43 -0
  107. package/packages/extension/src/background.ts +888 -0
  108. package/packages/extension/src/content.ts +172 -0
  109. package/packages/extension/src/index.ts +579 -0
  110. package/packages/extension/src/session-manager.ts +385 -0
  111. package/packages/extension/src/session-types.ts +144 -0
  112. package/packages/extension/src/types.ts +162 -0
  113. package/packages/extension/tsconfig.json +28 -0
  114. package/src/index.ts +64 -0
  115. package/tsconfig.build.json +12 -0
  116. package/tsconfig.json +26 -0
  117. package/vitest.config.ts +13 -0
@@ -0,0 +1,385 @@
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
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Session and Tab Group types for BTCP Browser Agent
3
+ */
4
+
5
+ import type { ExtensionBaseCommand } from './types.js';
6
+
7
+ /**
8
+ * Chrome tab group color options
9
+ */
10
+ export type GroupColor =
11
+ | 'grey'
12
+ | 'blue'
13
+ | 'red'
14
+ | 'yellow'
15
+ | 'green'
16
+ | 'pink'
17
+ | 'purple'
18
+ | 'cyan'
19
+ | 'orange';
20
+
21
+ /**
22
+ * Tab group information
23
+ */
24
+ export interface GroupInfo {
25
+ id: number;
26
+ title?: string;
27
+ color: GroupColor;
28
+ collapsed: boolean;
29
+ windowId: number;
30
+ }
31
+
32
+ /**
33
+ * Session information
34
+ */
35
+ export interface SessionInfo {
36
+ groupId: number;
37
+ title: string;
38
+ color: GroupColor;
39
+ tabCount: number;
40
+ tabIds: number[];
41
+ windowId: number;
42
+ createdAt: number;
43
+ }
44
+
45
+ /**
46
+ * Options for creating a new tab group
47
+ */
48
+ export interface GroupCreateOptions {
49
+ tabIds?: number[];
50
+ title?: string;
51
+ color?: GroupColor;
52
+ collapsed?: boolean;
53
+ }
54
+
55
+ /**
56
+ * Options for updating a tab group
57
+ */
58
+ export interface GroupUpdateOptions {
59
+ title?: string;
60
+ color?: GroupColor;
61
+ collapsed?: boolean;
62
+ }
63
+
64
+ /**
65
+ * Command to create a new tab group
66
+ */
67
+ export interface GroupCreateCommand extends ExtensionBaseCommand {
68
+ action: 'groupCreate';
69
+ tabIds?: number[];
70
+ title?: string;
71
+ color?: GroupColor;
72
+ collapsed?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Command to update a tab group
77
+ */
78
+ export interface GroupUpdateCommand extends ExtensionBaseCommand {
79
+ action: 'groupUpdate';
80
+ groupId: number;
81
+ title?: string;
82
+ color?: GroupColor;
83
+ collapsed?: boolean;
84
+ }
85
+
86
+ /**
87
+ * Command to delete a tab group (closes all tabs)
88
+ */
89
+ export interface GroupDeleteCommand extends ExtensionBaseCommand {
90
+ action: 'groupDelete';
91
+ groupId: number;
92
+ }
93
+
94
+ /**
95
+ * Command to list all tab groups
96
+ */
97
+ export interface GroupListCommand extends ExtensionBaseCommand {
98
+ action: 'groupList';
99
+ }
100
+
101
+ /**
102
+ * Command to add tabs to a group
103
+ */
104
+ export interface GroupAddTabsCommand extends ExtensionBaseCommand {
105
+ action: 'groupAddTabs';
106
+ groupId: number;
107
+ tabIds: number[];
108
+ }
109
+
110
+ /**
111
+ * Command to remove tabs from a group
112
+ */
113
+ export interface GroupRemoveTabsCommand extends ExtensionBaseCommand {
114
+ action: 'groupRemoveTabs';
115
+ tabIds: number[];
116
+ }
117
+
118
+ /**
119
+ * Command to get a specific tab group
120
+ */
121
+ export interface GroupGetCommand extends ExtensionBaseCommand {
122
+ action: 'groupGet';
123
+ groupId: number;
124
+ }
125
+
126
+ /**
127
+ * Command to get current active session
128
+ */
129
+ export interface SessionGetCurrentCommand extends ExtensionBaseCommand {
130
+ action: 'sessionGetCurrent';
131
+ }
132
+
133
+ /**
134
+ * Union type of all session-related commands
135
+ */
136
+ export type SessionCommand =
137
+ | GroupCreateCommand
138
+ | GroupUpdateCommand
139
+ | GroupDeleteCommand
140
+ | GroupListCommand
141
+ | GroupAddTabsCommand
142
+ | GroupRemoveTabsCommand
143
+ | GroupGetCommand
144
+ | SessionGetCurrentCommand;
@@ -0,0 +1,162 @@
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;
@@ -0,0 +1,28 @@
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
+ }