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,500 @@
1
+ # Browser-Based CLI Design Document
2
+
3
+ ## Overview
4
+
5
+ This document proposes an approach to implement a browser-based CLI for btcp-browser-agent, inspired by [vercel-labs/agent-browser](https://github.com/vercel-labs/agent-browser).
6
+
7
+ ## Goals
8
+
9
+ 1. Provide a command-line interface for browser automation within the browser context
10
+ 2. Enable AI agents to control browsers using simple text commands
11
+ 3. Maintain compatibility with existing @btcp/core and @btcp/extension packages
12
+ 4. Support both interactive and programmatic usage
13
+
14
+ ## Reference: agent-browser CLI
15
+
16
+ The agent-browser project provides these command patterns:
17
+
18
+ ```bash
19
+ agent-browser open example.com # Navigate to URL
20
+ agent-browser click @e2 # Click element by ref
21
+ agent-browser type @e3 "hello" # Type into element
22
+ agent-browser snapshot # Get accessibility tree
23
+ agent-browser screenshot page.png # Capture screenshot
24
+ agent-browser fill @e5 "value" # Fill form field
25
+ agent-browser scroll down 200 # Scroll page
26
+ agent-browser press Enter # Press key
27
+ ```
28
+
29
+ ## Architecture
30
+
31
+ ### In-Browser CLI (Chrome Extension Only)
32
+
33
+ Commands are sent directly from the Chrome extension - no external processes or WebSocket bridges needed.
34
+
35
+ ```
36
+ ┌─────────────────────────────────────────────────────────────┐
37
+ │ Chrome Extension │
38
+ │ │
39
+ │ ┌─────────────────────────────────────────────────────────┐│
40
+ │ │ Terminal UI (Popup/Panel) ││
41
+ │ │ $ snapshot ││
42
+ │ │ - button 'Submit' [@ref:1] ││
43
+ │ │ - textbox 'Email' [@ref:2] ││
44
+ │ │ ││
45
+ │ │ $ click @ref:1 ││
46
+ │ │ ✓ Clicked element: button 'Submit' ││
47
+ │ └─────────────────────────────────────────────────────────┘│
48
+ │ │ │
49
+ │ ▼ │
50
+ │ ┌─────────────────────────────────────────────────────────┐│
51
+ │ │ CLI Parser & Executor (@btcp/cli) ││
52
+ │ │ parseCommand() → executeCommand() ││
53
+ │ └─────────────────────────────────────────────────────────┘│
54
+ │ │ │
55
+ │ ▼ │
56
+ │ ┌─────────────────────────────────────────────────────────┐│
57
+ │ │ BackgroundAgent (@btcp/extension) ││
58
+ │ │ Tab management, navigation, routing ││
59
+ │ └─────────────────────────────────────────────────────────┘│
60
+ │ │ │
61
+ │ chrome.tabs.sendMessage() │
62
+ │ ▼ │
63
+ │ ┌─────────────────────────────────────────────────────────┐│
64
+ │ │ ContentAgent (@btcp/core) ││
65
+ │ │ DOM operations, snapshots, interactions ││
66
+ │ └─────────────────────────────────────────────────────────┘│
67
+ └─────────────────────────────────────────────────────────────┘
68
+ ```
69
+
70
+ **Benefits:**
71
+ - Pure browser-native approach
72
+ - No external dependencies
73
+ - Direct integration with existing @btcp packages
74
+ - Real-time command execution
75
+ - Works entirely within extension context
76
+
77
+ ## Implementation Plan
78
+
79
+ ### Phase 1: Command Parser & Executor
80
+
81
+ Create a new package `@btcp/cli` that provides command parsing and execution.
82
+
83
+ ```
84
+ packages/
85
+ cli/
86
+ src/
87
+ index.ts # Main exports
88
+ parser.ts # Command line parser
89
+ executor.ts # Command executor
90
+ commands/ # Individual command implementations
91
+ goto.ts
92
+ click.ts
93
+ type.ts
94
+ snapshot.ts
95
+ screenshot.ts
96
+ ...
97
+ formatter.ts # Output formatting
98
+ types.ts # TypeScript types
99
+ ```
100
+
101
+ #### Command Syntax
102
+
103
+ ```typescript
104
+ // Command structure
105
+ interface CLICommand {
106
+ name: string;
107
+ args: string[];
108
+ flags: Record<string, string | boolean>;
109
+ }
110
+
111
+ // Examples:
112
+ // "goto https://example.com" → { name: 'goto', args: ['https://example.com'], flags: {} }
113
+ // "click @ref:5 --wait 1000" → { name: 'click', args: ['@ref:5'], flags: { wait: '1000' } }
114
+ // "screenshot --full" → { name: 'screenshot', args: [], flags: { full: true } }
115
+ ```
116
+
117
+ #### Supported Commands
118
+
119
+ | Command | Syntax | Description |
120
+ |---------|--------|-------------|
121
+ | `goto` | `goto <url>` | Navigate to URL |
122
+ | `back` | `back` | Go back in history |
123
+ | `forward` | `forward` | Go forward in history |
124
+ | `reload` | `reload` | Reload current page |
125
+ | `snapshot` | `snapshot` | Get accessibility tree |
126
+ | `screenshot` | `screenshot [filename]` | Capture screenshot |
127
+ | `click` | `click <selector>` | Click element |
128
+ | `dblclick` | `dblclick <selector>` | Double-click element |
129
+ | `type` | `type <selector> <text>` | Type text into element |
130
+ | `fill` | `fill <selector> <value>` | Fill input field |
131
+ | `clear` | `clear <selector>` | Clear input field |
132
+ | `check` | `check <selector>` | Check checkbox |
133
+ | `uncheck` | `uncheck <selector>` | Uncheck checkbox |
134
+ | `select` | `select <selector> <value>` | Select dropdown option |
135
+ | `hover` | `hover <selector>` | Hover over element |
136
+ | `scroll` | `scroll <direction> [amount]` | Scroll page |
137
+ | `press` | `press <key>` | Press keyboard key |
138
+ | `wait` | `wait <ms>` | Wait for duration |
139
+ | `eval` | `eval <code>` | Execute JavaScript |
140
+ | `tabs` | `tabs` | List all tabs |
141
+ | `tab` | `tab <id>` | Switch to tab |
142
+ | `newtab` | `newtab [url]` | Open new tab |
143
+ | `closetab` | `closetab [id]` | Close tab |
144
+ | `help` | `help [command]` | Show help |
145
+
146
+ ### Phase 2: In-Browser Terminal UI
147
+
148
+ Create a terminal component for the extension popup or a dedicated panel.
149
+
150
+ #### Terminal Component
151
+
152
+ ```typescript
153
+ // packages/cli/src/terminal/
154
+ interface TerminalConfig {
155
+ theme: 'dark' | 'light';
156
+ fontSize: number;
157
+ historySize: number;
158
+ prompt: string;
159
+ }
160
+
161
+ interface TerminalState {
162
+ history: HistoryEntry[];
163
+ inputBuffer: string;
164
+ cursorPosition: number;
165
+ commandHistory: string[];
166
+ historyIndex: number;
167
+ }
168
+
169
+ interface HistoryEntry {
170
+ type: 'input' | 'output' | 'error';
171
+ content: string;
172
+ timestamp: number;
173
+ }
174
+ ```
175
+
176
+ #### UI Features
177
+
178
+ 1. **Command input** with cursor and editing
179
+ 2. **Command history** (up/down arrows)
180
+ 3. **Tab completion** for commands and refs
181
+ 4. **Syntax highlighting** for commands
182
+ 5. **Output formatting** (success/error/info)
183
+ 6. **Scrollable history**
184
+ 7. **Copy/paste support**
185
+
186
+ ### Phase 3: Integration with BackgroundAgent
187
+
188
+ Connect the CLI to the existing BackgroundAgent for execution.
189
+
190
+ ```typescript
191
+ // Example integration
192
+ import { BackgroundAgent } from '@btcp/extension';
193
+ import { parseCommand, executeCommand } from '@btcp/cli';
194
+
195
+ const agent = new BackgroundAgent();
196
+
197
+ async function handleCommand(input: string): Promise<string> {
198
+ const command = parseCommand(input);
199
+ const result = await executeCommand(agent, command);
200
+ return formatResult(result);
201
+ }
202
+ ```
203
+
204
+ ## Detailed Component Design
205
+
206
+ ### 1. Command Parser (`parser.ts`)
207
+
208
+ ```typescript
209
+ export function parseCommand(input: string): CLICommand {
210
+ const tokens = tokenize(input);
211
+ const name = tokens[0];
212
+ const { args, flags } = parseArgs(tokens.slice(1));
213
+ return { name, args, flags };
214
+ }
215
+
216
+ function tokenize(input: string): string[] {
217
+ // Handle quoted strings, escape characters
218
+ // "type @ref:1 \"hello world\"" → ['type', '@ref:1', 'hello world']
219
+ }
220
+
221
+ function parseArgs(tokens: string[]): { args: string[], flags: Record<string, string | boolean> } {
222
+ // Parse --flag and --flag=value patterns
223
+ }
224
+ ```
225
+
226
+ ### 2. Command Executor (`executor.ts`)
227
+
228
+ ```typescript
229
+ export async function executeCommand(
230
+ agent: BackgroundAgent,
231
+ command: CLICommand
232
+ ): Promise<CommandResult> {
233
+ const handler = commands[command.name];
234
+ if (!handler) {
235
+ throw new CLIError(`Unknown command: ${command.name}`);
236
+ }
237
+ return handler.execute(agent, command.args, command.flags);
238
+ }
239
+ ```
240
+
241
+ ### 3. Individual Commands (`commands/*.ts`)
242
+
243
+ ```typescript
244
+ // commands/goto.ts
245
+ export const gotoCommand: CommandHandler = {
246
+ name: 'goto',
247
+ description: 'Navigate to a URL',
248
+ usage: 'goto <url>',
249
+ examples: [
250
+ 'goto https://example.com',
251
+ 'goto github.com',
252
+ ],
253
+ async execute(agent, args, flags) {
254
+ const url = args[0];
255
+ if (!url) {
256
+ throw new CLIError('URL required');
257
+ }
258
+ await agent.navigate(url);
259
+ return { success: true, message: `Navigated to ${url}` };
260
+ }
261
+ };
262
+
263
+ // commands/snapshot.ts
264
+ export const snapshotCommand: CommandHandler = {
265
+ name: 'snapshot',
266
+ description: 'Get page accessibility tree',
267
+ usage: 'snapshot [--refs-only]',
268
+ async execute(agent, args, flags) {
269
+ const result = await agent.execute({
270
+ id: generateId(),
271
+ action: 'snapshot'
272
+ });
273
+ return {
274
+ success: true,
275
+ data: result.data.tree
276
+ };
277
+ }
278
+ };
279
+ ```
280
+
281
+ ### 4. Output Formatter (`formatter.ts`)
282
+
283
+ ```typescript
284
+ export function formatResult(result: CommandResult): FormattedOutput {
285
+ if (result.success) {
286
+ return {
287
+ type: 'success',
288
+ content: result.message || formatData(result.data)
289
+ };
290
+ }
291
+ return {
292
+ type: 'error',
293
+ content: `Error: ${result.error}`
294
+ };
295
+ }
296
+
297
+ function formatData(data: unknown): string {
298
+ // Format snapshots, screenshots, etc.
299
+ if (typeof data === 'string') return data;
300
+ return JSON.stringify(data, null, 2);
301
+ }
302
+ ```
303
+
304
+ ### 5. Terminal UI (`terminal/Terminal.ts`)
305
+
306
+ ```typescript
307
+ export class Terminal {
308
+ private state: TerminalState;
309
+ private config: TerminalConfig;
310
+ private onExecute: (command: string) => Promise<string>;
311
+
312
+ constructor(container: HTMLElement, config: Partial<TerminalConfig>) {
313
+ this.config = { ...defaultConfig, ...config };
314
+ this.state = initialState();
315
+ this.render(container);
316
+ this.bindEvents();
317
+ }
318
+
319
+ async handleInput(input: string): Promise<void> {
320
+ this.appendHistory({ type: 'input', content: `$ ${input}` });
321
+ try {
322
+ const output = await this.onExecute(input);
323
+ this.appendHistory({ type: 'output', content: output });
324
+ } catch (error) {
325
+ this.appendHistory({ type: 'error', content: error.message });
326
+ }
327
+ }
328
+
329
+ private bindEvents(): void {
330
+ // Keyboard handling: Enter, Up, Down, Tab, etc.
331
+ }
332
+
333
+ private render(container: HTMLElement): void {
334
+ // Create terminal UI elements
335
+ }
336
+ }
337
+ ```
338
+
339
+ ## File Structure
340
+
341
+ ```
342
+ packages/
343
+ cli/
344
+ package.json
345
+ tsconfig.json
346
+ src/
347
+ index.ts # Main exports
348
+ types.ts # TypeScript types
349
+ parser.ts # Command parser
350
+ executor.ts # Command executor
351
+ formatter.ts # Output formatting
352
+ errors.ts # CLI errors
353
+ commands/
354
+ index.ts # Command registry
355
+ goto.ts
356
+ back.ts
357
+ forward.ts
358
+ reload.ts
359
+ snapshot.ts
360
+ screenshot.ts
361
+ click.ts
362
+ dblclick.ts
363
+ type.ts
364
+ fill.ts
365
+ clear.ts
366
+ check.ts
367
+ uncheck.ts
368
+ select.ts
369
+ hover.ts
370
+ scroll.ts
371
+ press.ts
372
+ wait.ts
373
+ eval.ts
374
+ tabs.ts
375
+ tab.ts
376
+ newtab.ts
377
+ closetab.ts
378
+ help.ts
379
+ terminal/
380
+ index.ts # Terminal exports
381
+ Terminal.ts # Terminal class
382
+ renderer.ts # DOM rendering
383
+ history.ts # Command history
384
+ completion.ts # Tab completion
385
+ styles.css # Terminal styles
386
+ ```
387
+
388
+ ## Example Usage
389
+
390
+ ### Interactive Session
391
+
392
+ ```
393
+ $ goto https://github.com
394
+ ✓ Navigated to https://github.com
395
+
396
+ $ snapshot
397
+ - banner
398
+ - link 'Homepage' [@ref:1]
399
+ - navigation
400
+ - link 'Product' [@ref:2]
401
+ - link 'Solutions' [@ref:3]
402
+ - link 'Resources' [@ref:4]
403
+ - textbox 'Search or jump to...' [@ref:5]
404
+ - link 'Sign in' [@ref:6]
405
+ - link 'Sign up' [@ref:7]
406
+ - main
407
+ - heading 'Let's build from here' level=1
408
+ - textbox 'Search code...' [@ref:8]
409
+
410
+ $ click @ref:6
411
+ ✓ Clicked: link 'Sign in'
412
+
413
+ $ snapshot
414
+ - main
415
+ - heading 'Sign in to GitHub' level=1
416
+ - textbox 'Username or email' [@ref:1]
417
+ - textbox 'Password' [@ref:2]
418
+ - button 'Sign in' [@ref:3]
419
+ - link 'Forgot password?' [@ref:4]
420
+
421
+ $ type @ref:1 myusername
422
+ ✓ Typed "myusername" into: textbox 'Username or email'
423
+
424
+ $ fill @ref:2 mypassword
425
+ ✓ Filled: textbox 'Password'
426
+
427
+ $ click @ref:3
428
+ ✓ Clicked: button 'Sign in'
429
+ ```
430
+
431
+ ### Programmatic API (within extension)
432
+
433
+ ```typescript
434
+ // In popup.ts or background.ts
435
+ import { createCLI } from '@btcp/cli';
436
+ import { BackgroundAgent } from '@btcp/extension';
437
+
438
+ const agent = new BackgroundAgent();
439
+ const cli = createCLI(agent);
440
+
441
+ // Execute commands programmatically from extension code
442
+ await cli.execute('goto https://example.com');
443
+ const snapshot = await cli.execute('snapshot');
444
+ await cli.execute('click @ref:1');
445
+
446
+ // Or use the Client API for structured access
447
+ import { createClient } from '@btcp/extension';
448
+ const client = createClient();
449
+ await client.navigate('https://example.com');
450
+ const result = await client.snapshot();
451
+ await client.click('@ref:1');
452
+ ```
453
+
454
+ ## Implementation Timeline
455
+
456
+ ### Milestone 1: Core CLI Package
457
+ - [ ] Set up @btcp/cli package structure
458
+ - [ ] Implement command parser
459
+ - [ ] Implement command executor
460
+ - [ ] Implement core navigation commands (goto, back, forward, reload)
461
+ - [ ] Implement snapshot command
462
+ - [ ] Add basic output formatting
463
+
464
+ ### Milestone 2: DOM Commands
465
+ - [ ] Implement click, dblclick
466
+ - [ ] Implement type, fill, clear
467
+ - [ ] Implement check, uncheck, select
468
+ - [ ] Implement hover, scroll
469
+ - [ ] Implement press (keyboard)
470
+ - [ ] Implement wait, eval
471
+
472
+ ### Milestone 3: Tab Management
473
+ - [ ] Implement tabs, tab, newtab, closetab
474
+ - [ ] Add multi-tab command support
475
+
476
+ ### Milestone 4: Terminal UI
477
+ - [ ] Create terminal component
478
+ - [ ] Implement command input handling
479
+ - [ ] Add command history (up/down)
480
+ - [ ] Add tab completion
481
+ - [ ] Style terminal UI
482
+ - [ ] Integrate with extension popup
483
+
484
+ ### Milestone 5: Polish & Documentation
485
+ - [ ] Add help command with usage info
486
+ - [ ] Add command validation and helpful errors
487
+ - [ ] Write documentation
488
+ - [ ] Add tests
489
+
490
+ ## Conclusion
491
+
492
+ This design provides a pure in-browser CLI implementation that:
493
+
494
+ 1. **Mimics agent-browser** with similar command syntax
495
+ 2. **Runs entirely within Chrome extension** - no external processes
496
+ 3. **Integrates seamlessly** with existing @btcp/core and @btcp/extension packages
497
+ 4. **Provides terminal UI** in extension popup/panel for interactive use
498
+ 5. **Supports programmatic API** for AI agents within the browser
499
+
500
+ The implementation starts with the core CLI package (parser, executor, commands), then adds the terminal UI component for the extension.
@@ -0,0 +1,210 @@
1
+ # Changelog
2
+
3
+ ## Latest Changes
4
+
5
+ ### Session Management with Auto-Created Blank Tab
6
+
7
+ **What Changed:**
8
+ - When you click "Start New Session", it now **creates a new blank tab** and adds it to the session
9
+ - Previously used the current active tab, which could interrupt your workflow
10
+ - The new blank tab is ready for automation without affecting existing tabs
11
+
12
+ **Why:**
13
+ - Clean slate for each session
14
+ - Doesn't interfere with tabs you already have open
15
+ - Clear starting point for automation
16
+
17
+ **How It Works:**
18
+ ```javascript
19
+ // User clicks "Start New Session"
20
+ await client.groupCreate({ title: "BTCP Session 1" });
21
+
22
+ // This now:
23
+ // 1. Creates a new blank tab (about:blank)
24
+ // 2. Adds it to a blue tab group labeled "BTCP Session 1"
25
+ // 3. Makes it the active tab
26
+ // 4. Ready for navigation/automation
27
+ ```
28
+
29
+ **User Experience:**
30
+ 1. Click "Start New Session"
31
+ 2. New blank tab opens in a blue group
32
+ 3. All subsequent operations work in this session
33
+ 4. Your existing tabs remain untouched
34
+
35
+ ### Session-Only Mode
36
+
37
+ **What Changed:**
38
+ - Extension **only manages tabs within its session/tab group**
39
+ - All operations require an active session
40
+ - No operations allowed outside the session
41
+
42
+ **Operations Affected:**
43
+ - `listTabs()` - Only shows session tabs
44
+ - `tabNew()` - Only creates in session
45
+ - `closeTab()` - Only closes session tabs
46
+ - `switchTab()` - Only switches to session tabs
47
+ - `navigate()` - Only navigates session tabs
48
+ - All DOM operations - Only in session tabs
49
+
50
+ **Error Messages:**
51
+ Without a session:
52
+ ```
53
+ Error: "No active session. Create a session first to manage tabs."
54
+ ```
55
+
56
+ Trying to access outside tabs:
57
+ ```
58
+ Error: "Cannot switch to tab: tab is not in the active session"
59
+ ```
60
+
61
+ **Benefits:**
62
+ - ✅ Better security and isolation
63
+ - ✅ Clear visual boundaries (tab groups)
64
+ - ✅ Explicit user consent required
65
+ - ✅ Protects personal tabs from automation
66
+ - ✅ Clean separation of contexts
67
+
68
+ ## Testing the Changes
69
+
70
+ ### Test 1: New Blank Tab on Session Start
71
+ ```
72
+ 1. Open extension popup
73
+ 2. Click "Start New Session"
74
+ 3. Expected: New blank tab opens in blue group
75
+ 4. Verify: Tab shows "about:blank" URL
76
+ 5. Verify: Tab group labeled "BTCP Session 1"
77
+ ```
78
+
79
+ ### Test 2: Session Isolation
80
+ ```
81
+ 1. Have 3 regular tabs open (A, B, C)
82
+ 2. Start new session → new blank tab D in group
83
+ 3. Click "List Tabs" → should only show tab D
84
+ 4. Create new tab → should join session with D
85
+ 5. Tabs A, B, C remain untouched
86
+ ```
87
+
88
+ ### Test 3: Operations Require Session
89
+ ```
90
+ 1. Open popup without starting session
91
+ 2. Click "List Tabs" → Error shown
92
+ 3. Click "New Tab" → Error shown
93
+ 4. Start session → Operations now work
94
+ ```
95
+
96
+ ## Migration Guide
97
+
98
+ ### Before
99
+ ```javascript
100
+ // Extension used current active tab
101
+ await client.groupCreate();
102
+ // Your current tab got grouped
103
+
104
+ // Could access any tab
105
+ const tabs = await client.listTabs(); // All tabs
106
+ ```
107
+
108
+ ### After
109
+ ```javascript
110
+ // Extension creates new blank tab
111
+ await client.groupCreate();
112
+ // New blank tab created in group
113
+ // Your existing tabs untouched
114
+
115
+ // Only session tabs accessible
116
+ const tabs = await client.listTabs(); // Only session tabs
117
+ ```
118
+
119
+ ### If You Want to Group Existing Tab
120
+ ```javascript
121
+ // Get tab you want to add
122
+ const targetTab = await chrome.tabs.get(tabId);
123
+
124
+ // Create session with that tab
125
+ await client.groupCreate({ tabIds: [targetTab.id] });
126
+
127
+ // Or add to existing session
128
+ const session = await client.sessionGetCurrent();
129
+ await client.groupAddTabs(session.groupId, [targetTab.id]);
130
+ ```
131
+
132
+ ## Visual Guide
133
+
134
+ ### Session Start Flow
135
+
136
+ **Before:**
137
+ ```
138
+ Browser tabs: [Gmail] [GitHub] [YouTube*]
139
+ ↑ active
140
+ User clicks "Start New Session"
141
+ Result: [Gmail] [GitHub] [(YouTube* in blue group)]
142
+ ↑ YouTube grouped, disrupts workflow
143
+ ```
144
+
145
+ **After:**
146
+ ```
147
+ Browser tabs: [Gmail] [GitHub] [YouTube]
148
+ User clicks "Start New Session"
149
+ Result: [Gmail] [GitHub] [YouTube] [(blank* in blue group)]
150
+ ↑ New tab, clean slate
151
+ ```
152
+
153
+ ### Session Isolation
154
+
155
+ ```
156
+ Before session:
157
+ [Tab A] [Tab B] [Tab C] [Tab D] [Tab E]
158
+ ↑ Extension could access all tabs
159
+
160
+ After session:
161
+ [Tab A] [Tab B] [Tab C] | [Session: Tab D] [Tab E*]
162
+ ↑ Blue group boundary
163
+ Extension only accesses D and E
164
+ ```
165
+
166
+ ## Breaking Changes
167
+
168
+ ### 1. Session Required
169
+ **Before:** Could use extension without session
170
+ **After:** Must create session first
171
+
172
+ **Fix:** Always call `groupCreate()` before other operations
173
+
174
+ ### 2. No Universal Tab Access
175
+ **Before:** Could access any tab in window
176
+ **After:** Can only access tabs in session
177
+
178
+ **Fix:** Add tabs to session explicitly or create new tabs via extension
179
+
180
+ ### 3. Active Tab Behavior
181
+ **Before:** Session used current active tab
182
+ **After:** Session creates new blank tab
183
+
184
+ **Fix:** If you need to add existing tab, use `groupCreate({ tabIds: [existingTabId] })`
185
+
186
+ ## Rollback
187
+
188
+ If you need the old behavior, you can modify the source:
189
+
190
+ **Remove session requirement:**
191
+ In `background.ts`, change validation:
192
+ ```typescript
193
+ if (sessionGroupId === null) {
194
+ return true; // Allow without session
195
+ }
196
+ ```
197
+
198
+ **Use current tab instead of new:**
199
+ In `session-manager.ts`, revert to:
200
+ ```typescript
201
+ const [activeTab] = await chrome.tabs.query({ active: true });
202
+ targetTabIds = [activeTab.id];
203
+ ```
204
+
205
+ ## Version Info
206
+
207
+ - **Build Date:** 2026-01-16
208
+ - **Session Manager:** Creates blank tab by default
209
+ - **Access Mode:** Session-only (no universal access)
210
+ - **Backward Compatible:** No (requires session for all operations)