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,189 +0,0 @@
|
|
|
1
|
-
# Quick Test: Session Debugging
|
|
2
|
-
|
|
3
|
-
## 1. Load Extension (Fresh Start)
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
# Location: chrome://extensions
|
|
7
|
-
# 1. Remove old version if exists
|
|
8
|
-
# 2. Click "Load unpacked"
|
|
9
|
-
# 3. Select: /Users/minh/Documents/btcp/btcp-browser-agent/examples/chrome-extension/dist
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## 2. Open Background Console
|
|
13
|
-
|
|
14
|
-
1. In `chrome://extensions`, find **BTCP Browser Agent**
|
|
15
|
-
2. Click **service worker** (under "Inspect views")
|
|
16
|
-
3. This opens the background script DevTools
|
|
17
|
-
|
|
18
|
-
## 3. Run This Test in Background Console
|
|
19
|
-
|
|
20
|
-
Copy and paste this entire block:
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
console.log('=== BTCP Session Debug Test ===');
|
|
24
|
-
|
|
25
|
-
// Test 1: Check API availability
|
|
26
|
-
console.log('1. Chrome APIs:');
|
|
27
|
-
console.log(' - chrome.tabs:', typeof chrome.tabs);
|
|
28
|
-
console.log(' - chrome.tabGroups:', typeof chrome.tabGroups);
|
|
29
|
-
console.log(' - chrome.windows:', typeof chrome.windows);
|
|
30
|
-
|
|
31
|
-
// Test 2: Check SessionManager
|
|
32
|
-
console.log('\n2. SessionManager:');
|
|
33
|
-
console.log(' - SessionManager class:', typeof SessionManager);
|
|
34
|
-
|
|
35
|
-
// Test 3: Check BackgroundAgent
|
|
36
|
-
console.log('\n3. BackgroundAgent:');
|
|
37
|
-
const agent = getBackgroundAgent();
|
|
38
|
-
console.log(' - Agent exists:', !!agent);
|
|
39
|
-
console.log(' - Has sessionManager:', !!agent?.sessionManager);
|
|
40
|
-
|
|
41
|
-
// Test 4: Check tabs
|
|
42
|
-
console.log('\n4. Current tabs:');
|
|
43
|
-
chrome.tabs.query({}, (tabs) => {
|
|
44
|
-
console.log(' - Total tabs:', tabs.length);
|
|
45
|
-
console.log(' - Active tabs:', tabs.filter(t => t.active).length);
|
|
46
|
-
const activeTab = tabs.find(t => t.active);
|
|
47
|
-
if (activeTab) {
|
|
48
|
-
console.log(' - Active tab ID:', activeTab.id);
|
|
49
|
-
console.log(' - Active tab URL:', activeTab.url);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Test 5: Try creating session
|
|
54
|
-
console.log('\n5. Attempting to create session...');
|
|
55
|
-
if (agent?.sessionManager) {
|
|
56
|
-
agent.sessionManager.createGroup({ title: 'Test Session' })
|
|
57
|
-
.then(group => {
|
|
58
|
-
console.log('✅ SUCCESS! Group created:');
|
|
59
|
-
console.log(' - ID:', group.id);
|
|
60
|
-
console.log(' - Title:', group.title);
|
|
61
|
-
console.log(' - Color:', group.color);
|
|
62
|
-
return chrome.tabs.query({ groupId: group.id });
|
|
63
|
-
})
|
|
64
|
-
.then(tabs => {
|
|
65
|
-
console.log(' - Tabs in group:', tabs.length);
|
|
66
|
-
console.log('\n🎉 Session working! Check your tabs for a blue group.');
|
|
67
|
-
})
|
|
68
|
-
.catch(err => {
|
|
69
|
-
console.error('❌ FAILED! Error:', err.message);
|
|
70
|
-
console.error(' Stack:', err.stack);
|
|
71
|
-
});
|
|
72
|
-
} else {
|
|
73
|
-
console.error('❌ SessionManager not available!');
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## 4. What to Look For
|
|
78
|
-
|
|
79
|
-
### SUCCESS looks like:
|
|
80
|
-
```
|
|
81
|
-
=== BTCP Session Debug Test ===
|
|
82
|
-
1. Chrome APIs:
|
|
83
|
-
- chrome.tabs: object
|
|
84
|
-
- chrome.tabGroups: object
|
|
85
|
-
- chrome.windows: object
|
|
86
|
-
|
|
87
|
-
2. SessionManager:
|
|
88
|
-
- SessionManager class: function
|
|
89
|
-
|
|
90
|
-
3. BackgroundAgent:
|
|
91
|
-
- Agent exists: true
|
|
92
|
-
- Has sessionManager: true
|
|
93
|
-
|
|
94
|
-
4. Current tabs:
|
|
95
|
-
- Total tabs: 3
|
|
96
|
-
- Active tabs: 1
|
|
97
|
-
- Active tab ID: 123
|
|
98
|
-
- Active tab URL: https://example.com/
|
|
99
|
-
|
|
100
|
-
5. Attempting to create session...
|
|
101
|
-
[SessionManager] createGroup called with options: {title: "Test Session"}
|
|
102
|
-
[SessionManager] No tabIds provided, getting active tab...
|
|
103
|
-
[SessionManager] Active tab: {id: 123, ...}
|
|
104
|
-
[SessionManager] Creating group with tabs: [123]
|
|
105
|
-
[SessionManager] Group created with ID: 456
|
|
106
|
-
[SessionManager] Group updated with title: Test Session
|
|
107
|
-
[SessionManager] Group info: {id: 456, title: "Test Session", ...}
|
|
108
|
-
✅ SUCCESS! Group created:
|
|
109
|
-
- ID: 456
|
|
110
|
-
- Title: Test Session
|
|
111
|
-
- Color: blue
|
|
112
|
-
- Tabs in group: 1
|
|
113
|
-
|
|
114
|
-
🎉 Session working! Check your tabs for a blue group.
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### FAILURE might show:
|
|
118
|
-
```
|
|
119
|
-
❌ FAILED! Error: No active tab available to create session
|
|
120
|
-
```
|
|
121
|
-
**Fix:** Open a regular webpage (not chrome:// page)
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
- chrome.tabGroups: undefined
|
|
125
|
-
```
|
|
126
|
-
**Fix:** Update Chrome to version 89+
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
❌ SessionManager not available!
|
|
130
|
-
```
|
|
131
|
-
**Fix:** Extension not built correctly, run: `npm run build`
|
|
132
|
-
|
|
133
|
-
## 5. Test from Popup
|
|
134
|
-
|
|
135
|
-
If background test works, test the popup:
|
|
136
|
-
|
|
137
|
-
1. Click extension icon
|
|
138
|
-
2. Right-click in popup → Inspect
|
|
139
|
-
3. In popup console, run:
|
|
140
|
-
|
|
141
|
-
```javascript
|
|
142
|
-
// Quick popup test
|
|
143
|
-
const client = createClient();
|
|
144
|
-
client.groupCreate({ title: 'Popup Test' })
|
|
145
|
-
.then(result => console.log('✅ Popup works:', result))
|
|
146
|
-
.catch(err => console.error('❌ Popup failed:', err));
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## 6. Common Issues Found
|
|
150
|
-
|
|
151
|
-
### Issue: "Cannot group extension page tabs"
|
|
152
|
-
**Symptom:** Error when popup tries to group itself
|
|
153
|
-
**Solution:** Make sure the ACTIVE tab is a regular webpage, not the popup or chrome:// page
|
|
154
|
-
|
|
155
|
-
### Issue: "activeTab is undefined"
|
|
156
|
-
**Symptom:** No tab found to add to group
|
|
157
|
-
**Solution:**
|
|
158
|
-
1. Click on a regular webpage tab FIRST
|
|
159
|
-
2. THEN open the extension popup
|
|
160
|
-
3. Try creating session
|
|
161
|
-
|
|
162
|
-
### Issue: "chrome.tabGroups is not defined"
|
|
163
|
-
**Symptom:** API not available
|
|
164
|
-
**Solution:**
|
|
165
|
-
1. Check Chrome version: `chrome://version`
|
|
166
|
-
2. Needs Chrome 89 or higher
|
|
167
|
-
3. Update Chrome if needed
|
|
168
|
-
|
|
169
|
-
## 7. Next Steps Based on Results
|
|
170
|
-
|
|
171
|
-
**If Test 5 succeeds but popup fails:**
|
|
172
|
-
→ Check popup console for errors
|
|
173
|
-
→ Verify popup.js has client.groupCreate method
|
|
174
|
-
→ Check communication between popup and background
|
|
175
|
-
|
|
176
|
-
**If Test 5 fails with "No active tab":**
|
|
177
|
-
→ Open a website in a tab
|
|
178
|
-
→ Click on that tab (make it active)
|
|
179
|
-
→ Run test again
|
|
180
|
-
|
|
181
|
-
**If SessionManager not found:**
|
|
182
|
-
→ Rebuild: `npm run build` in project root
|
|
183
|
-
→ Rebuild: `npm run build` in examples/chrome-extension
|
|
184
|
-
→ Reload extension
|
|
185
|
-
|
|
186
|
-
**If everything works in test but not in UI:**
|
|
187
|
-
→ Check popup console for JavaScript errors
|
|
188
|
-
→ Verify button event listeners attached
|
|
189
|
-
→ Check if updateSessionUI() is being called
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# Chrome Extension Example
|
|
2
|
-
|
|
3
|
-
Production-ready TypeScript example using `@btcp/browser-agent`.
|
|
4
|
-
|
|
5
|
-
## Project Structure
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
examples/chrome-extension/
|
|
9
|
-
├── src/
|
|
10
|
-
│ ├── content.ts # DOM agent + message listener
|
|
11
|
-
│ ├── background.ts # routes messages
|
|
12
|
-
│ └── popup.ts # UI using createClient
|
|
13
|
-
├── dist/ # Built output (gitignored)
|
|
14
|
-
├── manifest.json # Chrome extension manifest
|
|
15
|
-
├── popup.html # Popup UI
|
|
16
|
-
├── package.json # Build dependencies
|
|
17
|
-
├── tsconfig.json # TypeScript config
|
|
18
|
-
└── build.js # esbuild script
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Source Files
|
|
22
|
-
|
|
23
|
-
**src/content.ts** - registers DOM agent and message listener
|
|
24
|
-
```typescript
|
|
25
|
-
import { createContentAgent } from '@btcp/browser-agent/extension';
|
|
26
|
-
|
|
27
|
-
const agent = createContentAgent();
|
|
28
|
-
chrome.runtime.onMessage.addListener(agent.handleMessage);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**src/background.ts** - routes messages
|
|
32
|
-
```typescript
|
|
33
|
-
import { setupMessageListener } from '@btcp/browser-agent/extension';
|
|
34
|
-
setupMessageListener();
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**src/popup.ts** - sends commands
|
|
38
|
-
```typescript
|
|
39
|
-
import { createClient } from '@btcp/browser-agent/extension';
|
|
40
|
-
|
|
41
|
-
const client = createClient();
|
|
42
|
-
await client.navigate('https://example.com');
|
|
43
|
-
const { tree } = await client.snapshot();
|
|
44
|
-
await client.click('@ref:5');
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Setup
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# Install dependencies
|
|
51
|
-
npm install
|
|
52
|
-
|
|
53
|
-
# Build the extension
|
|
54
|
-
npm run build
|
|
55
|
-
|
|
56
|
-
# Or watch for changes
|
|
57
|
-
npm run watch
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Load Extension
|
|
61
|
-
|
|
62
|
-
1. Open `chrome://extensions`
|
|
63
|
-
2. Enable "Developer mode"
|
|
64
|
-
3. Click "Load unpacked"
|
|
65
|
-
4. Select this directory
|
|
66
|
-
|
|
67
|
-
## Architecture
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
Popup ──chrome.runtime.sendMessage──► Background (setupMessageListener)
|
|
71
|
-
│
|
|
72
|
-
chrome.tabs.sendMessage
|
|
73
|
-
▼
|
|
74
|
-
Content Script (auto-registered)
|
|
75
|
-
│
|
|
76
|
-
ContentAgent → DOM
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## API Usage
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { createClient } from '@btcp/browser-agent/extension';
|
|
83
|
-
|
|
84
|
-
const client = createClient();
|
|
85
|
-
|
|
86
|
-
// Navigation
|
|
87
|
-
await client.navigate('https://example.com');
|
|
88
|
-
await client.back();
|
|
89
|
-
await client.forward();
|
|
90
|
-
await client.reload();
|
|
91
|
-
|
|
92
|
-
// DOM operations
|
|
93
|
-
const { tree } = await client.snapshot();
|
|
94
|
-
await client.click('@ref:5');
|
|
95
|
-
await client.fill('@ref:3', 'hello@example.com');
|
|
96
|
-
await client.type('@ref:3', 'typing slowly', { delay: 50 });
|
|
97
|
-
const text = await client.getText('@ref:5');
|
|
98
|
-
const visible = await client.isVisible('@ref:5');
|
|
99
|
-
|
|
100
|
-
// Tab management
|
|
101
|
-
const tabs = await client.tabList();
|
|
102
|
-
const newTab = await client.tabNew({ url: 'https://github.com' });
|
|
103
|
-
await client.tabSwitch(newTab.tabId);
|
|
104
|
-
await client.tabClose(newTab.tabId);
|
|
105
|
-
|
|
106
|
-
// Screenshot
|
|
107
|
-
const base64 = await client.screenshot();
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Command Reference
|
|
111
|
-
|
|
112
|
-
### Browser Operations (BackgroundAgent)
|
|
113
|
-
|
|
114
|
-
| Method | Description |
|
|
115
|
-
|--------|-------------|
|
|
116
|
-
| `navigate(url)` | Navigate to URL |
|
|
117
|
-
| `back()` / `forward()` | History navigation |
|
|
118
|
-
| `reload()` | Reload page |
|
|
119
|
-
| `screenshot()` | Capture visible tab |
|
|
120
|
-
| `tabNew()` / `tabClose()` | Tab management |
|
|
121
|
-
| `tabSwitch()` / `tabList()` | Tab switching |
|
|
122
|
-
| `getUrl()` / `getTitle()` | Get page info |
|
|
123
|
-
|
|
124
|
-
### DOM Operations (ContentAgent)
|
|
125
|
-
|
|
126
|
-
| Method | Description |
|
|
127
|
-
|--------|-------------|
|
|
128
|
-
| `snapshot()` | Get accessibility tree with refs |
|
|
129
|
-
| `click(selector)` | Click element |
|
|
130
|
-
| `fill(selector, value)` | Set input value |
|
|
131
|
-
| `type(selector, text)` | Type text with events |
|
|
132
|
-
| `getText(selector)` | Get element text |
|
|
133
|
-
| `isVisible(selector)` | Check visibility |
|
|
134
|
-
|
|
135
|
-
## Selectors
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// Ref from snapshot (recommended)
|
|
139
|
-
await client.click('@ref:5');
|
|
140
|
-
|
|
141
|
-
// CSS selectors
|
|
142
|
-
await client.click('#submit');
|
|
143
|
-
await client.click('.btn-primary');
|
|
144
|
-
await client.click('[data-testid="login"]');
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## License
|
|
148
|
-
|
|
149
|
-
Apache-2.0
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
# Session-Only Mode
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The BTCP Browser Agent **only manages tabs within its session/tab group**. No operations are allowed outside of a session.
|
|
6
|
-
|
|
7
|
-
## Key Principle
|
|
8
|
-
|
|
9
|
-
**Session is Required** - All operations require an active session:
|
|
10
|
-
|
|
11
|
-
- ❌ Cannot list tabs without a session
|
|
12
|
-
- ❌ Cannot create tabs without a session
|
|
13
|
-
- ❌ Cannot navigate without a session
|
|
14
|
-
- ❌ Cannot perform DOM operations without a session
|
|
15
|
-
- ✅ Must create session first, then all operations work within that session
|
|
16
|
-
|
|
17
|
-
## How It Works
|
|
18
|
-
|
|
19
|
-
### 1. Session Must Be Created First
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
// Create a session to start working
|
|
23
|
-
await client.groupCreate({ title: "BTCP Session 1" });
|
|
24
|
-
|
|
25
|
-
// Now all operations work (scoped to session)
|
|
26
|
-
await client.tabNew({ url: "https://example.com" });
|
|
27
|
-
await client.listTabs(); // Only session tabs
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 2. Without Session = Error
|
|
31
|
-
|
|
32
|
-
```javascript
|
|
33
|
-
// Try to list tabs without session
|
|
34
|
-
await client.listTabs();
|
|
35
|
-
// ❌ Error: "No active session. Create a session first to manage tabs."
|
|
36
|
-
|
|
37
|
-
// Try to create tab without session
|
|
38
|
-
await client.tabNew({ url: "https://example.com" });
|
|
39
|
-
// ❌ Error: "No active session. Create a session first to manage tabs."
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### 3. Operations Are Session-Scoped
|
|
43
|
-
|
|
44
|
-
Once a session exists, all operations only affect tabs in that session:
|
|
45
|
-
|
|
46
|
-
```javascript
|
|
47
|
-
// Create session with tab A
|
|
48
|
-
await client.groupCreate(); // Tab A joins session
|
|
49
|
-
|
|
50
|
-
// Create new tabs (auto-added to session)
|
|
51
|
-
await client.tabNew({ url: "https://example.com" }); // Tab B
|
|
52
|
-
await client.tabNew({ url: "https://github.com" }); // Tab C
|
|
53
|
-
|
|
54
|
-
// List tabs (only shows A, B, C)
|
|
55
|
-
const tabs = await client.listTabs(); // [A, B, C]
|
|
56
|
-
|
|
57
|
-
// User manually opens Tab D outside session
|
|
58
|
-
|
|
59
|
-
// Try to list tabs (still only shows session tabs)
|
|
60
|
-
const tabs2 = await client.listTabs(); // [A, B, C] - no Tab D
|
|
61
|
-
|
|
62
|
-
// Try to access Tab D
|
|
63
|
-
await client.switchTab(tabD.id);
|
|
64
|
-
// ❌ Error: "Cannot switch to tab: tab is not in the active session"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Implementation Details
|
|
68
|
-
|
|
69
|
-
### Session Requirement Check
|
|
70
|
-
|
|
71
|
-
Every operation checks for active session:
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
async listTabs(): Promise<TabInfo[]> {
|
|
75
|
-
const sessionGroupId = this.sessionManager.getActiveSessionGroupId();
|
|
76
|
-
|
|
77
|
-
// Session is required
|
|
78
|
-
if (sessionGroupId === null) {
|
|
79
|
-
throw new Error('No active session. Create a session first.');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Only query tabs in the session group
|
|
83
|
-
const tabs = await chrome.tabs.query({ groupId: sessionGroupId });
|
|
84
|
-
return tabs.map(mapToTabInfo);
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Tab Validation
|
|
89
|
-
|
|
90
|
-
Operations validate tab membership:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
private async isTabInSession(tabId: number): Promise<boolean> {
|
|
94
|
-
const sessionGroupId = this.sessionManager.getActiveSessionGroupId();
|
|
95
|
-
|
|
96
|
-
// Session required
|
|
97
|
-
if (sessionGroupId === null) {
|
|
98
|
-
throw new Error('No active session.');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Check if tab is in session
|
|
102
|
-
const tab = await chrome.tabs.get(tabId);
|
|
103
|
-
return tab.groupId === sessionGroupId;
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### New Tab Creation
|
|
108
|
-
|
|
109
|
-
New tabs are automatically added to session:
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
async newTab(options?: { url?: string }): Promise<TabInfo> {
|
|
113
|
-
// Check session exists
|
|
114
|
-
if (!this.sessionManager.getActiveSessionGroupId()) {
|
|
115
|
-
throw new Error('No active session.');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Create tab
|
|
119
|
-
const tab = await chrome.tabs.create({ url: options?.url });
|
|
120
|
-
|
|
121
|
-
// Add to session
|
|
122
|
-
const added = await this.sessionManager.addTabToActiveSession(tab.id);
|
|
123
|
-
if (!added) {
|
|
124
|
-
// Cleanup if failed
|
|
125
|
-
await chrome.tabs.remove(tab.id);
|
|
126
|
-
throw new Error('Failed to add tab to session');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return mapToTabInfo(tab);
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Usage Example
|
|
134
|
-
|
|
135
|
-
### Complete Workflow
|
|
136
|
-
|
|
137
|
-
```javascript
|
|
138
|
-
// 1. Create session (required first step)
|
|
139
|
-
await client.groupCreate({ title: "Work Session" });
|
|
140
|
-
// Current tab joins blue group "Work Session"
|
|
141
|
-
|
|
142
|
-
// 2. Now can create tabs (auto-added to session)
|
|
143
|
-
await client.tabNew({ url: "https://example.com" });
|
|
144
|
-
await client.tabNew({ url: "https://github.com" });
|
|
145
|
-
|
|
146
|
-
// 3. List tabs (only shows session tabs)
|
|
147
|
-
const tabs = await client.listTabs();
|
|
148
|
-
console.log(tabs.length); // 3 tabs
|
|
149
|
-
|
|
150
|
-
// 4. Navigate, interact (only session tabs)
|
|
151
|
-
await client.navigate("https://newsite.com");
|
|
152
|
-
await client.click("#button");
|
|
153
|
-
await client.fill("#input", "value");
|
|
154
|
-
|
|
155
|
-
// 5. Close session (closes all tabs)
|
|
156
|
-
const session = await client.sessionGetCurrent();
|
|
157
|
-
await client.groupDelete(session.groupId);
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Error Handling
|
|
161
|
-
|
|
162
|
-
```javascript
|
|
163
|
-
try {
|
|
164
|
-
// Try operation without session
|
|
165
|
-
await client.listTabs();
|
|
166
|
-
} catch (err) {
|
|
167
|
-
if (err.message.includes('No active session')) {
|
|
168
|
-
// Create session first
|
|
169
|
-
await client.groupCreate();
|
|
170
|
-
|
|
171
|
-
// Now retry
|
|
172
|
-
const tabs = await client.listTabs();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Benefits
|
|
178
|
-
|
|
179
|
-
### 1. Security & Isolation
|
|
180
|
-
- Extension cannot access tabs outside its scope
|
|
181
|
-
- User's personal tabs are protected
|
|
182
|
-
- Clear boundaries enforced by code
|
|
183
|
-
|
|
184
|
-
### 2. Explicit Consent
|
|
185
|
-
- User must explicitly create session
|
|
186
|
-
- Visual indicator (tab group color/label)
|
|
187
|
-
- No accidental access to unrelated tabs
|
|
188
|
-
|
|
189
|
-
### 3. Clean Separation
|
|
190
|
-
- Each session is independent
|
|
191
|
-
- Easy to manage multiple workflows
|
|
192
|
-
- Clear visual organization
|
|
193
|
-
|
|
194
|
-
### 4. Predictable Behavior
|
|
195
|
-
- All operations scoped to one group
|
|
196
|
-
- No ambiguity about which tabs are managed
|
|
197
|
-
- Consistent error messages
|
|
198
|
-
|
|
199
|
-
## Visual Indicators
|
|
200
|
-
|
|
201
|
-
### Chrome Tab Groups
|
|
202
|
-
- Session tabs have **colored border** (e.g., blue)
|
|
203
|
-
- Group label shows session name (e.g., "BTCP Session 1")
|
|
204
|
-
- Can collapse/expand the group
|
|
205
|
-
- Easy to see which tabs are in scope
|
|
206
|
-
|
|
207
|
-
### Extension Popup
|
|
208
|
-
- Shows session status (active/inactive)
|
|
209
|
-
- Displays session name and tab count
|
|
210
|
-
- Info: "Extension only manages tabs within the active session"
|
|
211
|
-
- Buttons disabled when no session
|
|
212
|
-
|
|
213
|
-
## Comparison
|
|
214
|
-
|
|
215
|
-
### Before (Universal Access)
|
|
216
|
-
```javascript
|
|
217
|
-
// Could access any tab
|
|
218
|
-
const allTabs = await client.listTabs(); // All tabs in window
|
|
219
|
-
|
|
220
|
-
// Could navigate any tab
|
|
221
|
-
await client.switchTab(anyTabId); // Works
|
|
222
|
-
|
|
223
|
-
// Could close any tab
|
|
224
|
-
await client.tabClose(anyTabId); // Works
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### After (Session-Only)
|
|
228
|
-
```javascript
|
|
229
|
-
// Must create session first
|
|
230
|
-
await client.groupCreate();
|
|
231
|
-
|
|
232
|
-
// Only session tabs
|
|
233
|
-
const sessionTabs = await client.listTabs(); // Only grouped tabs
|
|
234
|
-
|
|
235
|
-
// Only session tabs accessible
|
|
236
|
-
await client.switchTab(sessionTabId); // ✅ Works
|
|
237
|
-
await client.switchTab(outsideTabId); // ❌ Error
|
|
238
|
-
|
|
239
|
-
// Only session tabs closable
|
|
240
|
-
await client.tabClose(sessionTabId); // ✅ Works
|
|
241
|
-
await client.tabClose(outsideTabId); // ❌ Error
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
## FAQ
|
|
245
|
-
|
|
246
|
-
**Q: Can I use the extension without creating a session?**
|
|
247
|
-
A: No. Session creation is required for all operations.
|
|
248
|
-
|
|
249
|
-
**Q: What if I manually move a tab out of the session group?**
|
|
250
|
-
A: The extension immediately loses access to that tab.
|
|
251
|
-
|
|
252
|
-
**Q: Can I manually add tabs to the session?**
|
|
253
|
-
A: Yes! Drag any tab into the session group, and it becomes accessible.
|
|
254
|
-
|
|
255
|
-
**Q: What happens if the session group is deleted?**
|
|
256
|
-
A: All operations will fail until a new session is created.
|
|
257
|
-
|
|
258
|
-
**Q: Can operations work across multiple sessions?**
|
|
259
|
-
A: No. Only one active session at a time, and operations are scoped to it.
|
|
260
|
-
|
|
261
|
-
**Q: Why is session required?**
|
|
262
|
-
A: Security, isolation, and explicit user consent. The extension should only manage what the user explicitly adds to the session.
|
|
263
|
-
|
|
264
|
-
## Testing
|
|
265
|
-
|
|
266
|
-
### Test Session Requirement
|
|
267
|
-
|
|
268
|
-
```javascript
|
|
269
|
-
// 1. Try without session (should fail)
|
|
270
|
-
try {
|
|
271
|
-
await client.listTabs();
|
|
272
|
-
console.error('❌ Should have failed');
|
|
273
|
-
} catch (err) {
|
|
274
|
-
console.log('✅ Correctly requires session:', err.message);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// 2. Create session
|
|
278
|
-
await client.groupCreate({ title: "Test" });
|
|
279
|
-
|
|
280
|
-
// 3. Operations now work
|
|
281
|
-
const tabs = await client.listTabs();
|
|
282
|
-
console.log('✅ Session allows operations:', tabs.length);
|
|
283
|
-
|
|
284
|
-
// 4. Try accessing outside tab (should fail)
|
|
285
|
-
// (manually open tab outside session first)
|
|
286
|
-
try {
|
|
287
|
-
await client.switchTab(outsideTabId);
|
|
288
|
-
console.error('❌ Should have blocked outside tab');
|
|
289
|
-
} catch (err) {
|
|
290
|
-
console.log('✅ Correctly blocks outside tab:', err.message);
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
## Summary
|
|
295
|
-
|
|
296
|
-
**Core Principle**: Session-first, session-only
|
|
297
|
-
|
|
298
|
-
- ✅ Session required for all operations
|
|
299
|
-
- ✅ All operations scoped to session tabs only
|
|
300
|
-
- ✅ Clear errors when session missing
|
|
301
|
-
- ✅ Visual boundaries via tab groups
|
|
302
|
-
- ✅ Explicit user consent required
|
|
303
|
-
- ✅ Maximum security and isolation
|
|
304
|
-
|
|
305
|
-
The extension is now a **pure session manager** - it only works within the boundaries of its explicitly created session.
|