@jackwener/opencli 1.5.8 → 1.6.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.
- package/CHANGELOG.md +42 -0
- package/README.md +35 -1
- package/README.zh-CN.md +17 -1
- package/SKILL.md +31 -851
- package/autoresearch/baseline-browse.txt +1 -0
- package/autoresearch/baseline-skill.txt +1 -0
- package/autoresearch/browse-tasks.json +688 -0
- package/autoresearch/eval-browse.ts +185 -0
- package/autoresearch/eval-skill.ts +248 -0
- package/autoresearch/run-browse.sh +9 -0
- package/autoresearch/run-skill.sh +9 -0
- package/dist/browser/base-page.d.ts +48 -0
- package/dist/browser/base-page.js +160 -0
- package/dist/browser/cdp.js +4 -106
- package/dist/browser/daemon-client.d.ts +20 -7
- package/dist/browser/daemon-client.js +39 -39
- package/dist/browser/daemon-client.test.js +77 -0
- package/dist/browser/discover.d.ts +1 -4
- package/dist/browser/discover.js +9 -23
- package/dist/browser/errors.d.ts +4 -0
- package/dist/browser/errors.js +20 -0
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/page.d.ts +10 -35
- package/dist/browser/page.js +55 -187
- package/dist/browser/tabs.js +5 -5
- package/dist/browser.test.js +15 -15
- package/dist/cli-manifest.json +294 -22
- package/dist/cli.js +392 -0
- package/dist/clis/amazon/bestsellers.d.ts +21 -0
- package/dist/clis/amazon/bestsellers.js +130 -0
- package/dist/clis/amazon/bestsellers.test.js +20 -0
- package/dist/clis/amazon/discussion.d.ts +20 -0
- package/dist/clis/amazon/discussion.js +91 -0
- package/dist/clis/amazon/discussion.test.d.ts +1 -0
- package/dist/clis/amazon/discussion.test.js +36 -0
- package/dist/clis/amazon/offer.d.ts +23 -0
- package/dist/clis/amazon/offer.js +140 -0
- package/dist/clis/amazon/offer.test.d.ts +1 -0
- package/dist/clis/amazon/offer.test.js +29 -0
- package/dist/clis/amazon/product.d.ts +18 -0
- package/dist/clis/amazon/product.js +92 -0
- package/dist/clis/amazon/product.test.d.ts +1 -0
- package/dist/clis/amazon/product.test.js +24 -0
- package/dist/clis/amazon/search.d.ts +18 -0
- package/dist/clis/amazon/search.js +87 -0
- package/dist/clis/amazon/search.test.d.ts +1 -0
- package/dist/clis/amazon/search.test.js +22 -0
- package/dist/clis/amazon/shared.d.ts +64 -0
- package/dist/clis/amazon/shared.js +255 -0
- package/dist/clis/amazon/shared.test.d.ts +1 -0
- package/dist/clis/amazon/shared.test.js +33 -0
- package/dist/clis/gemini/ask.d.ts +1 -0
- package/dist/clis/gemini/ask.js +40 -0
- package/dist/clis/gemini/image.d.ts +1 -0
- package/dist/clis/gemini/image.js +105 -0
- package/dist/clis/gemini/new.d.ts +1 -0
- package/dist/clis/gemini/new.js +20 -0
- package/dist/clis/gemini/utils.d.ts +34 -0
- package/dist/clis/gemini/utils.js +463 -0
- package/dist/clis/gemini/utils.test.d.ts +1 -0
- package/dist/clis/gemini/utils.test.js +31 -0
- package/dist/clis/notebooklm/compat.test.d.ts +1 -1
- package/dist/clis/notebooklm/compat.test.js +3 -3
- package/dist/clis/notebooklm/current.js +2 -3
- package/dist/clis/notebooklm/get.js +2 -3
- package/dist/clis/notebooklm/history.js +2 -3
- package/dist/clis/notebooklm/note-list.js +2 -3
- package/dist/clis/notebooklm/notes-get.js +2 -3
- package/dist/clis/notebooklm/open.d.ts +1 -0
- package/dist/clis/notebooklm/open.js +41 -0
- package/dist/clis/notebooklm/open.test.d.ts +1 -0
- package/dist/clis/notebooklm/open.test.js +63 -0
- package/dist/clis/notebooklm/source-fulltext.js +2 -3
- package/dist/clis/notebooklm/source-get.js +2 -3
- package/dist/clis/notebooklm/source-guide.js +2 -3
- package/dist/clis/notebooklm/source-list.js +2 -3
- package/dist/clis/notebooklm/status.js +1 -2
- package/dist/clis/notebooklm/summary.js +2 -3
- package/dist/clis/notebooklm/utils.d.ts +2 -1
- package/dist/clis/notebooklm/utils.js +20 -21
- package/dist/clis/twitter/article.js +28 -1
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +11 -11
- package/dist/clis/xiaohongshu/creator-notes-summary.test.js +6 -6
- package/dist/clis/xiaohongshu/creator-notes.test.js +22 -22
- package/dist/clis/xiaohongshu/note.js +11 -0
- package/dist/clis/xiaohongshu/note.test.js +49 -0
- package/dist/commanderAdapter.js +7 -4
- package/dist/commanderAdapter.test.js +76 -0
- package/dist/commands/daemon.js +8 -47
- package/dist/commands/daemon.test.js +45 -70
- package/dist/discovery.js +27 -0
- package/dist/doctor.d.ts +1 -2
- package/dist/doctor.js +7 -8
- package/dist/explore.js +1 -1
- package/dist/output.js +28 -0
- package/dist/output.test.js +15 -0
- package/dist/pipeline/executor.js +2 -7
- package/dist/pipeline/steps/browser.js +1 -1
- package/dist/pipeline/template.js +25 -3
- package/dist/record.d.ts +50 -0
- package/dist/record.js +298 -57
- package/dist/record.test.d.ts +1 -0
- package/dist/record.test.js +293 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +1 -0
- package/dist/registry.test.js +10 -0
- package/dist/runtime.js +3 -3
- package/dist/snapshotFormatter.d.ts +1 -1
- package/dist/snapshotFormatter.js +4 -4
- package/dist/snapshotFormatter.test.d.ts +1 -1
- package/dist/snapshotFormatter.test.js +2 -2
- package/dist/types.d.ts +11 -1
- package/dist/types.js +1 -1
- package/docs/.vitepress/config.mts +2 -0
- package/docs/adapters/browser/amazon.md +53 -0
- package/docs/adapters/browser/gemini.md +72 -0
- package/docs/adapters/browser/notebooklm.md +5 -5
- package/docs/adapters/index.md +3 -1
- package/docs/guide/getting-started.md +21 -0
- package/docs/superpowers/specs/2026-04-02-browse-skill-testing-design.md +144 -0
- package/docs/zh/guide/getting-started.md +21 -0
- package/extension/package-lock.json +2 -2
- package/extension/src/background.test.ts +7 -163
- package/extension/src/background.ts +58 -161
- package/extension/src/cdp.ts +77 -124
- package/extension/src/protocol.ts +5 -5
- package/package.json +1 -1
- package/skills/opencli-explorer/SKILL.md +853 -0
- package/skills/opencli-oneshot/SKILL.md +222 -0
- package/skills/opencli-operate/SKILL.md +213 -0
- package/skills/opencli-usage/SKILL.md +152 -0
- package/skills/opencli-usage/browser.md +429 -0
- package/skills/opencli-usage/desktop.md +118 -0
- package/skills/opencli-usage/plugins.md +82 -0
- package/skills/opencli-usage/public-api.md +149 -0
- package/src/browser/base-page.ts +197 -0
- package/src/browser/cdp.ts +7 -131
- package/src/browser/daemon-client.test.ts +103 -0
- package/src/browser/daemon-client.ts +55 -43
- package/src/browser/discover.ts +9 -21
- package/src/browser/errors.ts +22 -0
- package/src/browser/index.ts +1 -1
- package/src/browser/page.ts +57 -209
- package/src/browser/tabs.ts +5 -5
- package/src/browser.test.ts +15 -15
- package/src/cli.ts +392 -0
- package/src/clis/amazon/bestsellers.test.ts +22 -0
- package/src/clis/amazon/bestsellers.ts +180 -0
- package/src/clis/amazon/discussion.test.ts +38 -0
- package/src/clis/amazon/discussion.ts +131 -0
- package/src/clis/amazon/offer.test.ts +35 -0
- package/src/clis/amazon/offer.ts +185 -0
- package/src/clis/amazon/product.test.ts +26 -0
- package/src/clis/amazon/product.ts +131 -0
- package/src/clis/amazon/search.test.ts +24 -0
- package/src/clis/amazon/search.ts +128 -0
- package/src/clis/amazon/shared.test.ts +37 -0
- package/src/clis/amazon/shared.ts +316 -0
- package/src/clis/gemini/ask.ts +46 -0
- package/src/clis/gemini/image.ts +115 -0
- package/src/clis/gemini/new.ts +22 -0
- package/src/clis/gemini/utils.test.ts +36 -0
- package/src/clis/gemini/utils.ts +523 -0
- package/src/clis/notebooklm/compat.test.ts +3 -3
- package/src/clis/notebooklm/current.ts +2 -3
- package/src/clis/notebooklm/get.ts +1 -3
- package/src/clis/notebooklm/history.ts +1 -3
- package/src/clis/notebooklm/note-list.ts +1 -3
- package/src/clis/notebooklm/notes-get.ts +1 -3
- package/src/clis/notebooklm/open.test.ts +78 -0
- package/src/clis/notebooklm/open.ts +61 -0
- package/src/clis/notebooklm/source-fulltext.ts +1 -3
- package/src/clis/notebooklm/source-get.ts +1 -3
- package/src/clis/notebooklm/source-guide.ts +1 -3
- package/src/clis/notebooklm/source-list.ts +1 -3
- package/src/clis/notebooklm/status.ts +1 -2
- package/src/clis/notebooklm/summary.ts +1 -3
- package/src/clis/notebooklm/utils.ts +29 -20
- package/src/clis/twitter/article.ts +31 -1
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +11 -11
- package/src/clis/xiaohongshu/creator-notes-summary.test.ts +6 -6
- package/src/clis/xiaohongshu/creator-notes.test.ts +22 -22
- package/src/clis/xiaohongshu/note.test.ts +51 -0
- package/src/clis/xiaohongshu/note.ts +18 -0
- package/src/commanderAdapter.test.ts +109 -0
- package/src/commanderAdapter.ts +8 -4
- package/src/commands/daemon.test.ts +50 -84
- package/src/commands/daemon.ts +8 -56
- package/src/discovery.ts +22 -0
- package/src/doctor.ts +8 -9
- package/src/explore.ts +1 -1
- package/src/output.test.ts +17 -0
- package/src/output.ts +27 -0
- package/src/pipeline/executor.ts +2 -7
- package/src/pipeline/steps/browser.ts +1 -1
- package/src/pipeline/template.ts +27 -4
- package/src/record.test.ts +362 -0
- package/src/record.ts +341 -62
- package/src/registry.test.ts +12 -0
- package/src/registry.ts +3 -0
- package/src/runtime.ts +3 -3
- package/src/snapshotFormatter.test.ts +2 -2
- package/src/snapshotFormatter.ts +4 -4
- package/src/types.ts +11 -1
- package/.agents/skills/cross-project-adapter-migration/SKILL.md +0 -249
- package/.agents/workflows/cross-project-adapter-migration.md +0 -54
- package/dist/clis/notebooklm/bind-current.js +0 -29
- package/dist/clis/notebooklm/bind-current.test.d.ts +0 -1
- package/dist/clis/notebooklm/bind-current.test.js +0 -35
- package/dist/clis/notebooklm/binding.test.js +0 -44
- package/extension/dist/background.js +0 -819
- package/src/clis/notebooklm/bind-current.test.ts +0 -43
- package/src/clis/notebooklm/bind-current.ts +0 -36
- package/src/clis/notebooklm/binding.test.ts +0 -53
- /package/dist/browser/{mcp.d.ts → bridge.d.ts} +0 -0
- /package/dist/browser/{mcp.js → bridge.js} +0 -0
- /package/dist/{clis/notebooklm/bind-current.d.ts → browser/daemon-client.test.d.ts} +0 -0
- /package/dist/clis/{notebooklm/binding.test.d.ts → amazon/bestsellers.test.d.ts} +0 -0
- /package/src/browser/{mcp.ts → bridge.ts} +0 -0
|
@@ -48,6 +48,27 @@ opencli bilibili hot -f csv # CSV
|
|
|
48
48
|
opencli bilibili hot -v # Verbose: show pipeline debug
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
### Tab Completion
|
|
52
|
+
|
|
53
|
+
OpenCLI supports intelligent tab completion to speed up command input:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Add shell completion to your startup config
|
|
57
|
+
echo 'eval "$(opencli completion zsh)"' >> ~/.zshrc # Zsh
|
|
58
|
+
echo 'eval "$(opencli completion bash)"' >> ~/.bashrc # Bash
|
|
59
|
+
echo 'opencli completion fish | source' >> ~/.config/fish/config.fish # Fish
|
|
60
|
+
|
|
61
|
+
# Restart your shell, then press Tab to complete:
|
|
62
|
+
opencli [Tab] # Complete site names (bilibili, zhihu, twitter...)
|
|
63
|
+
opencli bilibili [Tab] # Complete commands (hot, search, me, download...)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The completion includes:
|
|
67
|
+
- All available sites and adapters
|
|
68
|
+
- Built-in commands (list, explore, validate...)
|
|
69
|
+
- Command aliases
|
|
70
|
+
- Real-time updates as you add new adapters
|
|
71
|
+
|
|
51
72
|
## Next Steps
|
|
52
73
|
|
|
53
74
|
- [Installation details](/guide/installation)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Browse Skill Testing Design
|
|
2
|
+
|
|
3
|
+
Two-layer testing framework for `opencli browse` commands and the
|
|
4
|
+
Claude Code skill integration.
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Verify that `opencli browse` works reliably on real websites and that
|
|
9
|
+
Claude Code can use the skill to complete browser tasks end-to-end.
|
|
10
|
+
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
autoresearch/
|
|
15
|
+
├── browse-tasks.json ← 59 task definitions with browse command sequences
|
|
16
|
+
├── eval-browse.ts ← Layer 1: deterministic browse command testing
|
|
17
|
+
├── eval-skill.ts ← Layer 2: Claude Code skill E2E testing
|
|
18
|
+
├── run-browse.sh ← Launch Layer 1
|
|
19
|
+
├── run-skill.sh ← Launch Layer 2
|
|
20
|
+
├── baseline-browse.txt ← Layer 1 best score
|
|
21
|
+
├── baseline-skill.txt ← Layer 2 best score
|
|
22
|
+
└── results/ ← Per-run results (gitignored)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Layer 1: Deterministic Browse Command Testing
|
|
26
|
+
|
|
27
|
+
Tests `opencli browse` commands directly on real websites. No LLM
|
|
28
|
+
involved — pure command reliability testing.
|
|
29
|
+
|
|
30
|
+
### How It Works
|
|
31
|
+
|
|
32
|
+
Each task defines a sequence of browse commands and a judge for the
|
|
33
|
+
last command's output:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"name": "hn-top-stories",
|
|
38
|
+
"steps": [
|
|
39
|
+
"opencli browse open https://news.ycombinator.com",
|
|
40
|
+
"opencli browse eval \"JSON.stringify([...document.querySelectorAll('.titleline a')].slice(0,5).map(a=>({title:a.textContent,url:a.href})))\""
|
|
41
|
+
],
|
|
42
|
+
"judge": { "type": "arrayMinLength", "minLength": 5 }
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Execution
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
./autoresearch/run-browse.sh
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- Runs all 59 tasks serially
|
|
53
|
+
- Each task: execute steps → judge last step output → pass/fail
|
|
54
|
+
- `opencli browse close` between tasks for clean state
|
|
55
|
+
- Expected: ~2 minutes, $0 cost
|
|
56
|
+
|
|
57
|
+
### Task Categories
|
|
58
|
+
|
|
59
|
+
| Category | Count | Example |
|
|
60
|
+
|----------|-------|---------|
|
|
61
|
+
| extract | 9 | Open page, eval JS to extract data |
|
|
62
|
+
| list | 10 | Open page, eval JS to extract array |
|
|
63
|
+
| search | 6 | Open, type query, keys Enter, eval results |
|
|
64
|
+
| nav | 7 | Open, click link, eval new page title |
|
|
65
|
+
| scroll | 5 | Open, scroll, eval footer/hidden content |
|
|
66
|
+
| form | 6 | Open, type into fields, eval field values |
|
|
67
|
+
| complex | 6 | Multi-step: open → click → navigate → extract |
|
|
68
|
+
| bench | 10 | Test set (various) |
|
|
69
|
+
|
|
70
|
+
## Layer 2: Claude Code Skill E2E Testing
|
|
71
|
+
|
|
72
|
+
Spawns Claude Code with the opencli-operate skill to complete tasks
|
|
73
|
+
autonomously using browse commands.
|
|
74
|
+
|
|
75
|
+
### How It Works
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
claude -p \
|
|
79
|
+
--system-prompt "$(cat skills/opencli-operate/SKILL.md)" \
|
|
80
|
+
--dangerously-skip-permissions \
|
|
81
|
+
--allowedTools "Bash(opencli:*)" \
|
|
82
|
+
--output-format json \
|
|
83
|
+
"用 opencli browse 完成任务:Extract the top 5 stories from Hacker News with title and score. Start URL: https://news.ycombinator.com"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Execution
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
./autoresearch/run-skill.sh
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Runs all 59 tasks serially
|
|
93
|
+
- Each task: spawn Claude Code → it uses browse commands autonomously → judge output
|
|
94
|
+
- Expected: ~20 minutes, ~$5-10
|
|
95
|
+
|
|
96
|
+
### Judge
|
|
97
|
+
|
|
98
|
+
Both layers use the same judge types:
|
|
99
|
+
|
|
100
|
+
| Type | Description |
|
|
101
|
+
|------|-------------|
|
|
102
|
+
| `contains` | Output contains a substring |
|
|
103
|
+
| `arrayMinLength` | Output is an array with ≥ N items |
|
|
104
|
+
| `arrayFieldsPresent` | Array items have required fields |
|
|
105
|
+
| `nonEmpty` | Output is non-empty |
|
|
106
|
+
| `matchesPattern` | Output matches a regex |
|
|
107
|
+
|
|
108
|
+
## Output Format
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
🔬 Layer 1: Browse Commands — 59 tasks
|
|
112
|
+
|
|
113
|
+
[1/59] extract-title-example... ✓ (0.5s)
|
|
114
|
+
[2/59] hn-top-stories... ✓ (1.2s)
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
Score: 55/59 (93%)
|
|
118
|
+
Time: 2min
|
|
119
|
+
Cost: $0
|
|
120
|
+
|
|
121
|
+
🔬 Layer 2: Skill E2E — 59 tasks
|
|
122
|
+
|
|
123
|
+
[1/59] extract-title-example... ✓ (8s, $0.01)
|
|
124
|
+
[2/59] hn-top-stories... ✓ (15s, $0.08)
|
|
125
|
+
...
|
|
126
|
+
|
|
127
|
+
Score: 52/59 (88%)
|
|
128
|
+
Time: 20min
|
|
129
|
+
Cost: $6.50
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Constraints
|
|
133
|
+
|
|
134
|
+
- All 59 tasks run on real websites (no mocks)
|
|
135
|
+
- Layer 1: zero LLM cost, ~2 min
|
|
136
|
+
- Layer 2: ~$5-10 LLM cost, ~20 min
|
|
137
|
+
- Results saved to `autoresearch/results/` (gitignored)
|
|
138
|
+
- Baselines tracked in `baseline-browse.txt` and `baseline-skill.txt`
|
|
139
|
+
|
|
140
|
+
## Success Criteria
|
|
141
|
+
|
|
142
|
+
- Layer 1 ≥ 90% (browse commands work on real sites)
|
|
143
|
+
- Layer 2 ≥ 85% (Claude Code can use skill effectively)
|
|
144
|
+
- Both layers cover all 8 task categories
|
|
@@ -32,6 +32,27 @@ opencli bilibili hot -f md # Markdown
|
|
|
32
32
|
opencli bilibili hot -f csv # CSV
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## 终端自动补全
|
|
36
|
+
|
|
37
|
+
OpenCLI 支持智能的 Tab 自动补全,加快命令输入:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 把自动补全加入 shell 启动配置
|
|
41
|
+
echo 'eval "$(opencli completion zsh)"' >> ~/.zshrc # Zsh
|
|
42
|
+
echo 'eval "$(opencli completion bash)"' >> ~/.bashrc # Bash
|
|
43
|
+
echo 'opencli completion fish | source' >> ~/.config/fish/config.fish # Fish
|
|
44
|
+
|
|
45
|
+
# 重启 shell 后,按 Tab 键补全:
|
|
46
|
+
opencli [Tab] # 补全站点名称(bilibili、zhihu、twitter...)
|
|
47
|
+
opencli bilibili [Tab] # 补全命令(hot、search、me、download...)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
补全功能包含:
|
|
51
|
+
- 所有可用的站点和适配器
|
|
52
|
+
- 内置命令(list、explore、validate...)
|
|
53
|
+
- 命令别名
|
|
54
|
+
- 新增适配器时的实时更新
|
|
55
|
+
|
|
35
56
|
## 下一步
|
|
36
57
|
|
|
37
58
|
- [安装详情](/zh/guide/installation)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencli-extension",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.5",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "opencli-extension",
|
|
9
|
-
"version": "1.5.
|
|
9
|
+
"version": "1.5.5",
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"@types/chrome": "^0.0.287",
|
|
12
12
|
"typescript": "^5.7.0",
|
|
@@ -200,7 +200,7 @@ describe('background tab isolation', () => {
|
|
|
200
200
|
]));
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
-
it('
|
|
203
|
+
it('keeps site:notebooklm inside its owned automation window instead of rebinding to a user tab', async () => {
|
|
204
204
|
const { chrome, tabs } = createChromeMock();
|
|
205
205
|
tabs[0].url = 'https://notebooklm.google.com/';
|
|
206
206
|
tabs[0].title = 'NotebookLM Home';
|
|
@@ -213,184 +213,28 @@ describe('background tab isolation', () => {
|
|
|
213
213
|
|
|
214
214
|
const tabId = await mod.__test__.resolveTabId(undefined, 'site:notebooklm');
|
|
215
215
|
|
|
216
|
-
expect(tabId).toBe(
|
|
216
|
+
expect(tabId).toBe(1);
|
|
217
217
|
expect(mod.__test__.getSession('site:notebooklm')).toEqual(expect.objectContaining({
|
|
218
|
-
windowId:
|
|
219
|
-
preferredTabId: 2,
|
|
220
|
-
owned: false,
|
|
218
|
+
windowId: 1,
|
|
221
219
|
}));
|
|
222
220
|
});
|
|
223
221
|
|
|
224
|
-
it('
|
|
222
|
+
it('idle timeout closes the automation window for site:notebooklm', async () => {
|
|
225
223
|
const { chrome, tabs } = createChromeMock();
|
|
226
224
|
tabs[0].url = 'https://notebooklm.google.com/';
|
|
227
225
|
tabs[0].title = 'NotebookLM Home';
|
|
228
226
|
tabs[0].active = true;
|
|
229
|
-
tabs[1].url = 'https://notebooklm.google.com/notebook/nb-passive';
|
|
230
|
-
tabs[1].title = 'Notebook';
|
|
231
|
-
tabs[1].active = false;
|
|
232
|
-
vi.stubGlobal('chrome', chrome);
|
|
233
|
-
|
|
234
|
-
const mod = await import('./background');
|
|
235
|
-
mod.__test__.setAutomationWindowId('site:notebooklm', 1);
|
|
236
|
-
|
|
237
|
-
const tabId = await mod.__test__.resolveTabId(undefined, 'site:notebooklm');
|
|
238
|
-
|
|
239
|
-
expect(tabId).toBe(2);
|
|
240
|
-
expect(mod.__test__.getSession('site:notebooklm')).toEqual(expect.objectContaining({
|
|
241
|
-
windowId: 2,
|
|
242
|
-
preferredTabId: 2,
|
|
243
|
-
owned: false,
|
|
244
|
-
}));
|
|
245
|
-
});
|
|
246
227
|
|
|
247
|
-
it('detaches an adopted workspace session on idle instead of closing the user window', async () => {
|
|
248
|
-
const { chrome } = createChromeMock();
|
|
249
|
-
vi.stubGlobal('chrome', chrome);
|
|
250
228
|
vi.useFakeTimers();
|
|
229
|
+
vi.stubGlobal('chrome', chrome);
|
|
251
230
|
|
|
252
231
|
const mod = await import('./background');
|
|
253
|
-
mod.__test__.
|
|
254
|
-
windowId: 2,
|
|
255
|
-
preferredTabId: 2,
|
|
256
|
-
owned: false,
|
|
257
|
-
});
|
|
232
|
+
mod.__test__.setAutomationWindowId('site:notebooklm', 1);
|
|
258
233
|
|
|
259
234
|
mod.__test__.resetWindowIdleTimer('site:notebooklm');
|
|
260
235
|
await vi.advanceTimersByTimeAsync(30001);
|
|
261
236
|
|
|
262
|
-
expect(chrome.windows.remove).
|
|
237
|
+
expect(chrome.windows.remove).toHaveBeenCalledWith(1);
|
|
263
238
|
expect(mod.__test__.getSession('site:notebooklm')).toBeNull();
|
|
264
239
|
});
|
|
265
|
-
|
|
266
|
-
it('binds the active NotebookLM tab into the workspace explicitly', async () => {
|
|
267
|
-
const { chrome, tabs } = createChromeMock();
|
|
268
|
-
tabs[1].url = 'https://notebooklm.google.com/notebook/nb-active';
|
|
269
|
-
tabs[1].title = 'Bound Notebook';
|
|
270
|
-
tabs[1].active = true;
|
|
271
|
-
vi.stubGlobal('chrome', chrome);
|
|
272
|
-
|
|
273
|
-
const mod = await import('./background');
|
|
274
|
-
const result = await mod.__test__.handleBindCurrent(
|
|
275
|
-
{
|
|
276
|
-
id: 'bind-current',
|
|
277
|
-
action: 'bind-current',
|
|
278
|
-
workspace: 'site:notebooklm',
|
|
279
|
-
matchDomain: 'notebooklm.google.com',
|
|
280
|
-
matchPathPrefix: '/notebook/',
|
|
281
|
-
},
|
|
282
|
-
'site:notebooklm',
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
expect(result).toEqual({
|
|
286
|
-
id: 'bind-current',
|
|
287
|
-
ok: true,
|
|
288
|
-
data: expect.objectContaining({
|
|
289
|
-
tabId: 2,
|
|
290
|
-
windowId: 2,
|
|
291
|
-
url: 'https://notebooklm.google.com/notebook/nb-active',
|
|
292
|
-
title: 'Bound Notebook',
|
|
293
|
-
workspace: 'site:notebooklm',
|
|
294
|
-
}),
|
|
295
|
-
});
|
|
296
|
-
expect(mod.__test__.getSession('site:notebooklm')).toEqual(expect.objectContaining({
|
|
297
|
-
windowId: 2,
|
|
298
|
-
preferredTabId: 2,
|
|
299
|
-
owned: false,
|
|
300
|
-
}));
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it('bind-current falls back to another matching notebook tab in the current window', async () => {
|
|
304
|
-
const { chrome, tabs } = createChromeMock();
|
|
305
|
-
tabs[0].windowId = 2;
|
|
306
|
-
tabs[0].url = 'https://notebooklm.google.com/';
|
|
307
|
-
tabs[0].title = 'NotebookLM Home';
|
|
308
|
-
tabs[0].active = true;
|
|
309
|
-
tabs[1].url = 'https://notebooklm.google.com/notebook/nb-passive';
|
|
310
|
-
tabs[1].title = 'Passive Notebook';
|
|
311
|
-
tabs[1].active = false;
|
|
312
|
-
vi.stubGlobal('chrome', chrome);
|
|
313
|
-
|
|
314
|
-
const mod = await import('./background');
|
|
315
|
-
const result = await mod.__test__.handleBindCurrent(
|
|
316
|
-
{
|
|
317
|
-
id: 'bind-fallback',
|
|
318
|
-
action: 'bind-current',
|
|
319
|
-
workspace: 'site:notebooklm',
|
|
320
|
-
matchDomain: 'notebooklm.google.com',
|
|
321
|
-
matchPathPrefix: '/notebook/',
|
|
322
|
-
},
|
|
323
|
-
'site:notebooklm',
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
expect(result).toEqual({
|
|
327
|
-
id: 'bind-fallback',
|
|
328
|
-
ok: true,
|
|
329
|
-
data: expect.objectContaining({
|
|
330
|
-
tabId: 2,
|
|
331
|
-
windowId: 2,
|
|
332
|
-
url: 'https://notebooklm.google.com/notebook/nb-passive',
|
|
333
|
-
title: 'Passive Notebook',
|
|
334
|
-
}),
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('bind-current falls back to a matching notebook tab in another window of the same profile', async () => {
|
|
339
|
-
const { chrome, tabs } = createChromeMock();
|
|
340
|
-
tabs[0].windowId = 3;
|
|
341
|
-
tabs[0].url = 'https://notebooklm.google.com/';
|
|
342
|
-
tabs[0].title = 'NotebookLM Home';
|
|
343
|
-
tabs[0].active = true;
|
|
344
|
-
tabs[1].windowId = 2;
|
|
345
|
-
tabs[1].url = 'https://notebooklm.google.com/notebook/nb-other-window';
|
|
346
|
-
tabs[1].title = 'Notebook In Other Window';
|
|
347
|
-
tabs[1].active = false;
|
|
348
|
-
vi.stubGlobal('chrome', chrome);
|
|
349
|
-
|
|
350
|
-
const mod = await import('./background');
|
|
351
|
-
const result = await mod.__test__.handleBindCurrent(
|
|
352
|
-
{
|
|
353
|
-
id: 'bind-cross-window',
|
|
354
|
-
action: 'bind-current',
|
|
355
|
-
workspace: 'site:notebooklm',
|
|
356
|
-
matchDomain: 'notebooklm.google.com',
|
|
357
|
-
matchPathPrefix: '/notebook/',
|
|
358
|
-
},
|
|
359
|
-
'site:notebooklm',
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
expect(result).toEqual({
|
|
363
|
-
id: 'bind-cross-window',
|
|
364
|
-
ok: true,
|
|
365
|
-
data: expect.objectContaining({
|
|
366
|
-
tabId: 2,
|
|
367
|
-
windowId: 2,
|
|
368
|
-
url: 'https://notebooklm.google.com/notebook/nb-other-window',
|
|
369
|
-
title: 'Notebook In Other Window',
|
|
370
|
-
}),
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
it('rejects bind-current when the active tab is not NotebookLM', async () => {
|
|
375
|
-
const { chrome } = createChromeMock();
|
|
376
|
-
vi.stubGlobal('chrome', chrome);
|
|
377
|
-
|
|
378
|
-
const mod = await import('./background');
|
|
379
|
-
const result = await mod.__test__.handleBindCurrent(
|
|
380
|
-
{
|
|
381
|
-
id: 'bind-miss',
|
|
382
|
-
action: 'bind-current',
|
|
383
|
-
workspace: 'site:notebooklm',
|
|
384
|
-
matchDomain: 'notebooklm.google.com',
|
|
385
|
-
matchPathPrefix: '/notebook/',
|
|
386
|
-
},
|
|
387
|
-
'site:notebooklm',
|
|
388
|
-
);
|
|
389
|
-
|
|
390
|
-
expect(result).toEqual({
|
|
391
|
-
id: 'bind-miss',
|
|
392
|
-
ok: false,
|
|
393
|
-
error: 'No visible tab matching notebooklm.google.com /notebook/',
|
|
394
|
-
});
|
|
395
|
-
});
|
|
396
240
|
});
|