@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
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: cross-project-adapter-migration
|
|
3
|
-
description: "Cross-project CLI command migration workflow for opencli. Use when importing commands from external CLI projects (python/node) like rdt-cli, twitter-cli, etc. Covers: source analysis → gap matrix → batch migration → README/SKILL.md update."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Cross-Project Adapter Migration
|
|
7
|
-
|
|
8
|
-
> 从外部 CLI 项目(Python/Node/Go 等)批量迁移命令到 opencli 的标准化流程。
|
|
9
|
-
|
|
10
|
-
## When to Use
|
|
11
|
-
|
|
12
|
-
- 用户说"把 xxx-cli 的命令迁移过来"
|
|
13
|
-
- 用户说"看看 xxx 项目有什么可以借鉴的"
|
|
14
|
-
- 用户说"对齐 xxx-cli 的功能"
|
|
15
|
-
- 在为新平台扩展 opencli 时,发现已有第三方 CLI 工具
|
|
16
|
-
|
|
17
|
-
## Prerequisites
|
|
18
|
-
|
|
19
|
-
- 熟悉 [CLI-EXPLORER.md](../../../CLI-EXPLORER.md)(adapter 开发决策树)
|
|
20
|
-
- 熟悉 [SKILL.md](../../../SKILL.md)(命令参考 & 模板)
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Phase 1: 源项目分析
|
|
25
|
-
|
|
26
|
-
### 1.1 克隆 & 理解源项目
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# 克隆源项目到 /tmp 做分析
|
|
30
|
-
git clone <source_repo_url> /tmp/<source-cli>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
分析重点:
|
|
34
|
-
- **命令列表**:找到所有可用命令(查看 CLI 入口文件、help 输出或 README)
|
|
35
|
-
- **认证方式**:Cookie?API Key?OAuth?浏览器自动化?
|
|
36
|
-
- **数据源**:公开 API?GraphQL?页面抓取?
|
|
37
|
-
- **输出字段**:每个命令返回哪些数据字段
|
|
38
|
-
|
|
39
|
-
### 1.2 生成命令清单
|
|
40
|
-
|
|
41
|
-
列出源项目所有命令,包括:
|
|
42
|
-
|
|
43
|
-
| 命令 | 类型 | API/方法 | 输出字段 |
|
|
44
|
-
|------|------|---------|---------|
|
|
45
|
-
| `xxx feed` | Read | `GET /api/feed` | title, author, time |
|
|
46
|
-
| `xxx post` | Write | `POST /api/tweet` | status, id |
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Phase 2: 功能对比矩阵
|
|
51
|
-
|
|
52
|
-
### 2.1 查看 opencli 现有命令
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
ls src/clis/<site>/ # 查看已有适配器
|
|
56
|
-
opencli list | grep <site> # 确认已注册命令
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### 2.2 生成对比矩阵
|
|
60
|
-
|
|
61
|
-
对每个源项目命令,标注三种状态:
|
|
62
|
-
|
|
63
|
-
| 功能 | 源项目 | opencli 现有 | 行动 |
|
|
64
|
-
|------|--------|-------------|------|
|
|
65
|
-
| feed | ✅ `xxx feed` | ❌ 无 | ✅ **新增** |
|
|
66
|
-
| search | ✅ `xxx search` | ✅ `search.ts` | ❌ 已有,跳过 |
|
|
67
|
-
| hot | ✅ `xxx hot` | ⚠️ `hot.yaml`(不完整) | ✅ **增强** |
|
|
68
|
-
| like | ✅ `xxx like` | ✅ `like.ts` | ❌ 已有,跳过 |
|
|
69
|
-
|
|
70
|
-
### 2.3 筛选迁移目标
|
|
71
|
-
|
|
72
|
-
去掉已有的、低价值的,保留高价值缺失命令,按 Read/Write 分类:
|
|
73
|
-
|
|
74
|
-
**筛选原则**:
|
|
75
|
-
- ✅ 高使用频率的命令优先
|
|
76
|
-
- ✅ 已有但不完整的命令标记为"增强"
|
|
77
|
-
- ❌ 源项目特有但 opencli 架构不支持的功能(如需要持久化存储的)跳过
|
|
78
|
-
- ❌ 与现有功能完全重复的跳过
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Phase 3: 批量实现
|
|
83
|
-
|
|
84
|
-
> [!IMPORTANT]
|
|
85
|
-
> 实现前必须查阅 [CLI-EXPLORER.md](../../../CLI-EXPLORER.md) 确认策略选择。
|
|
86
|
-
|
|
87
|
-
### 3.1 选择实现方式
|
|
88
|
-
|
|
89
|
-
基于决策树分类:
|
|
90
|
-
|
|
91
|
-
| 类别 | 方式 | 适用条件 |
|
|
92
|
-
|------|------|---------|
|
|
93
|
-
| **Read + 简单 API** | YAML pipeline | 纯 fetch/select/map,无复杂 JS |
|
|
94
|
-
| **Read + GraphQL/分页/签名** | TypeScript adapter | 需要 JS 逻辑 |
|
|
95
|
-
| **Write 操作** | TypeScript + `Strategy.UI` | 点击/输入等 DOM 操作 |
|
|
96
|
-
| **Write + API** | TypeScript + `Strategy.COOKIE/HEADER` | 直接 POST API |
|
|
97
|
-
|
|
98
|
-
### 3.2 实现顺序
|
|
99
|
-
|
|
100
|
-
**先 Read 后 Write,先 YAML 后 TS**:
|
|
101
|
-
|
|
102
|
-
1. **Phase A**: YAML Read 适配器(最快,通常每个 10-20 行)
|
|
103
|
-
2. **Phase B**: TS Read 适配器(需要 evaluate/intercept 的)
|
|
104
|
-
3. **Phase C**: TS Write 适配器(需 UI 自动化或 POST API)
|
|
105
|
-
|
|
106
|
-
### 3.3 实现模板
|
|
107
|
-
|
|
108
|
-
#### YAML Read 适配器模板(Cookie 策略)
|
|
109
|
-
|
|
110
|
-
```yaml
|
|
111
|
-
site: <site>
|
|
112
|
-
name: <command>
|
|
113
|
-
description: <描述>
|
|
114
|
-
domain: www.<site>.com
|
|
115
|
-
strategy: cookie
|
|
116
|
-
browser: true
|
|
117
|
-
|
|
118
|
-
args:
|
|
119
|
-
limit:
|
|
120
|
-
type: int
|
|
121
|
-
default: 20
|
|
122
|
-
|
|
123
|
-
pipeline:
|
|
124
|
-
- navigate: https://www.<site>.com
|
|
125
|
-
- evaluate: |
|
|
126
|
-
(async () => {
|
|
127
|
-
const res = await fetch('<api_endpoint>', { credentials: 'include' });
|
|
128
|
-
const d = await res.json();
|
|
129
|
-
return (d.data?.items || []).map(item => ({
|
|
130
|
-
title: item.title,
|
|
131
|
-
// ... map source fields
|
|
132
|
-
}));
|
|
133
|
-
})()
|
|
134
|
-
- map:
|
|
135
|
-
rank: ${{ index + 1 }}
|
|
136
|
-
title: ${{ item.title }}
|
|
137
|
-
- limit: ${{ args.limit }}
|
|
138
|
-
|
|
139
|
-
columns: [rank, title]
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
#### TS Write 适配器模板(UI 策略)
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
import { cli, Strategy } from '../../registry.js';
|
|
146
|
-
|
|
147
|
-
cli({
|
|
148
|
-
site: '<site>',
|
|
149
|
-
name: '<command>',
|
|
150
|
-
description: '<描述>',
|
|
151
|
-
strategy: Strategy.UI,
|
|
152
|
-
args: [{ name: 'target', required: true, help: '<参数说明>' }],
|
|
153
|
-
columns: ['status', 'message'],
|
|
154
|
-
func: async (page, kwargs) => {
|
|
155
|
-
await page.goto(`https://www.<site>.com/${kwargs.target}`);
|
|
156
|
-
await page.wait({ text: '<expected_text>', timeout: 10 });
|
|
157
|
-
|
|
158
|
-
// 获取 snapshot 找到目标按钮
|
|
159
|
-
const snapshot = await page.accessibility.snapshot();
|
|
160
|
-
// 点击按钮 ...
|
|
161
|
-
|
|
162
|
-
return [{ status: 'success', message: '<action> completed' }];
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### 3.4 公共模式复用
|
|
168
|
-
|
|
169
|
-
迁移过程中如果发现多个适配器共享逻辑,考虑提取到 `src/clis/<site>/utils.ts` 工具文件:
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
// src/clis/<site>/utils.ts
|
|
173
|
-
export async function fetchWithAuth(page, url) { ... }
|
|
174
|
-
export function parseItem(raw) { ... }
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Phase 4: 验证 & 发布
|
|
180
|
-
|
|
181
|
-
### 4.1 构建验证
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
npx tsc --noEmit # TypeScript 编译检查
|
|
185
|
-
opencli list | grep <site> # 确认所有命令已注册
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### 4.2 运行验证(关键!)
|
|
189
|
-
|
|
190
|
-
每个新命令必须实际运行:
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
# Read 命令
|
|
194
|
-
opencli <site> <command> --limit 3 -f json
|
|
195
|
-
opencli <site> <command> --limit 3 -v # verbose 查看 pipeline
|
|
196
|
-
|
|
197
|
-
# Write 命令(谨慎!会实际操作)
|
|
198
|
-
opencli <site> <command> <test_target>
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### 4.3 更新文档
|
|
202
|
-
|
|
203
|
-
迁移完成后必须更新以下文件:
|
|
204
|
-
|
|
205
|
-
1. **README.md** — 在对应平台区域添加新命令示例
|
|
206
|
-
2. **SKILL.md** — 在 Commands Reference 中添加新命令
|
|
207
|
-
|
|
208
|
-
### 4.4 提交 & 推送
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
git add -A
|
|
212
|
-
git commit -m "feat(<site>): migrate <N> commands from <source-cli>
|
|
213
|
-
|
|
214
|
-
- Phase A: <N> YAML adapters (read operations)
|
|
215
|
-
- Phase B: <N> TS adapters (write operations)
|
|
216
|
-
- Source: <source_repo_url>"
|
|
217
|
-
git push
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## Checklist
|
|
223
|
-
|
|
224
|
-
- [ ] 源项目命令清单已生成
|
|
225
|
-
- [ ] 对比矩阵已确认,高价值缺失命令已筛选
|
|
226
|
-
- [ ] 用户确认迁移范围
|
|
227
|
-
- [ ] Phase A: YAML Read 适配器已完成
|
|
228
|
-
- [ ] Phase B: TS Read 适配器已完成
|
|
229
|
-
- [ ] Phase C: TS Write 适配器已完成
|
|
230
|
-
- [ ] `npx tsc --noEmit` 编译通过
|
|
231
|
-
- [ ] 所有新命令已实际运行验证
|
|
232
|
-
- [ ] README.md 已更新
|
|
233
|
-
- [ ] SKILL.md 已更新
|
|
234
|
-
- [ ] 已 commit + push
|
|
235
|
-
|
|
236
|
-
## 实战案例参考
|
|
237
|
-
|
|
238
|
-
### rdt-cli → opencli Reddit(2026-03-16)
|
|
239
|
-
|
|
240
|
-
- **源项目**: `rdt-cli`(25 个 Python 命令)
|
|
241
|
-
- **筛选结果**: 13 个高价值命令
|
|
242
|
-
- **实现**: 7 个 YAML(read) + 6 个 TS(write)
|
|
243
|
-
- **产出**: +11 文件,+767 行代码,Reddit 适配器从 4 → 15(+275%)
|
|
244
|
-
|
|
245
|
-
### twitter-cli → opencli Twitter(2026-03-16)
|
|
246
|
-
|
|
247
|
-
- **源项目**: `twitter-cli`(20+ Python 命令)
|
|
248
|
-
- **筛选结果**: 11 个待实现
|
|
249
|
-
- **策略**: Read 用 `Strategy.COOKIE` + GraphQL fetch,Write 用 `Strategy.UI`
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Migrate commands from an external CLI project into opencli adapters
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
// turbo-all
|
|
6
|
-
|
|
7
|
-
## Steps
|
|
8
|
-
|
|
9
|
-
1. Clone the source CLI project for analysis:
|
|
10
|
-
```bash
|
|
11
|
-
git clone <source_repo_url> /tmp/<source-cli>
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
2. Analyze source project: list all commands, auth method, API endpoints, and output fields.
|
|
15
|
-
|
|
16
|
-
3. Check existing opencli adapters for the target site:
|
|
17
|
-
```bash
|
|
18
|
-
ls src/clis/<site>/
|
|
19
|
-
opencli list | grep <site>
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
4. Generate a comparison matrix table (source commands vs opencli existing). Mark each as: ✅ **New** / ✅ **Enhance** / ❌ **Skip**. Ask user to confirm which commands to migrate.
|
|
23
|
-
|
|
24
|
-
5. Implement YAML Read adapters first (highest ROI, 10-20 lines each). Place files in `src/clis/<site>/<name>.yaml`.
|
|
25
|
-
|
|
26
|
-
6. Implement TS Read adapters for complex cases (GraphQL, pagination, signing). Place files in `src/clis/<site>/<name>.ts`.
|
|
27
|
-
|
|
28
|
-
7. Implement TS Write adapters using `Strategy.UI` or `Strategy.COOKIE`. Place files in `src/clis/<site>/<name>.ts`.
|
|
29
|
-
|
|
30
|
-
8. Verify build:
|
|
31
|
-
```bash
|
|
32
|
-
npx tsc --noEmit
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
9. Verify all commands are registered:
|
|
36
|
-
```bash
|
|
37
|
-
opencli list | grep <site>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
10. Run each new command to verify it works:
|
|
41
|
-
```bash
|
|
42
|
-
opencli <site> <command> --limit 3 -f json
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
11. Update README.md with new command examples in the appropriate platform section.
|
|
46
|
-
|
|
47
|
-
12. Update SKILL.md Commands Reference with new commands.
|
|
48
|
-
|
|
49
|
-
13. Commit and push:
|
|
50
|
-
```bash
|
|
51
|
-
git add -A
|
|
52
|
-
git commit -m "feat(<site>): migrate <N> commands from <source-cli>"
|
|
53
|
-
git push
|
|
54
|
-
```
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { cli, Strategy } from '../../registry.js';
|
|
2
|
-
import { bindCurrentTab } from '../../browser/daemon-client.js';
|
|
3
|
-
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
-
import { parseNotebooklmIdFromUrl } from './utils.js';
|
|
5
|
-
cli({
|
|
6
|
-
site: NOTEBOOKLM_SITE,
|
|
7
|
-
name: 'bind-current',
|
|
8
|
-
aliases: ['use'],
|
|
9
|
-
description: 'Bind the current active NotebookLM notebook tab into the site:notebooklm workspace',
|
|
10
|
-
domain: NOTEBOOKLM_DOMAIN,
|
|
11
|
-
strategy: Strategy.COOKIE,
|
|
12
|
-
browser: true,
|
|
13
|
-
navigateBefore: false,
|
|
14
|
-
args: [],
|
|
15
|
-
columns: ['workspace', 'tab_id', 'notebook_id', 'title', 'url'],
|
|
16
|
-
func: async () => {
|
|
17
|
-
const result = await bindCurrentTab(`site:${NOTEBOOKLM_SITE}`, {
|
|
18
|
-
matchDomain: NOTEBOOKLM_DOMAIN,
|
|
19
|
-
matchPathPrefix: '/notebook/',
|
|
20
|
-
});
|
|
21
|
-
return [{
|
|
22
|
-
workspace: result.workspace ?? `site:${NOTEBOOKLM_SITE}`,
|
|
23
|
-
tab_id: result.tabId ?? null,
|
|
24
|
-
notebook_id: result.url ? parseNotebooklmIdFromUrl(result.url) : '',
|
|
25
|
-
title: result.title ?? '',
|
|
26
|
-
url: result.url ?? '',
|
|
27
|
-
}];
|
|
28
|
-
},
|
|
29
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import './bind-current.js';
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
const { mockBindCurrentTab } = vi.hoisted(() => ({
|
|
3
|
-
mockBindCurrentTab: vi.fn(),
|
|
4
|
-
}));
|
|
5
|
-
vi.mock('../../browser/daemon-client.js', () => ({
|
|
6
|
-
bindCurrentTab: mockBindCurrentTab,
|
|
7
|
-
}));
|
|
8
|
-
import { getRegistry } from '../../registry.js';
|
|
9
|
-
import './bind-current.js';
|
|
10
|
-
describe('notebooklm bind-current', () => {
|
|
11
|
-
const command = getRegistry().get('notebooklm/bind-current');
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
mockBindCurrentTab.mockReset();
|
|
14
|
-
});
|
|
15
|
-
it('binds the current notebook tab into site:notebooklm', async () => {
|
|
16
|
-
mockBindCurrentTab.mockResolvedValue({
|
|
17
|
-
workspace: 'site:notebooklm',
|
|
18
|
-
tabId: 123,
|
|
19
|
-
title: 'Bound Notebook',
|
|
20
|
-
url: 'https://notebooklm.google.com/notebook/nb-live',
|
|
21
|
-
});
|
|
22
|
-
const result = await command.func({}, {});
|
|
23
|
-
expect(mockBindCurrentTab).toHaveBeenCalledWith('site:notebooklm', {
|
|
24
|
-
matchDomain: 'notebooklm.google.com',
|
|
25
|
-
matchPathPrefix: '/notebook/',
|
|
26
|
-
});
|
|
27
|
-
expect(result).toEqual([{
|
|
28
|
-
workspace: 'site:notebooklm',
|
|
29
|
-
tab_id: 123,
|
|
30
|
-
notebook_id: 'nb-live',
|
|
31
|
-
title: 'Bound Notebook',
|
|
32
|
-
url: 'https://notebooklm.google.com/notebook/nb-live',
|
|
33
|
-
}]);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
const { mockBindCurrentTab } = vi.hoisted(() => ({
|
|
3
|
-
mockBindCurrentTab: vi.fn(),
|
|
4
|
-
}));
|
|
5
|
-
vi.mock('../../browser/daemon-client.js', () => ({
|
|
6
|
-
bindCurrentTab: mockBindCurrentTab,
|
|
7
|
-
}));
|
|
8
|
-
import { ensureNotebooklmNotebookBinding } from './utils.js';
|
|
9
|
-
describe('notebooklm automatic binding', () => {
|
|
10
|
-
const originalEndpoint = process.env.OPENCLI_CDP_ENDPOINT;
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
mockBindCurrentTab.mockReset();
|
|
13
|
-
if (originalEndpoint === undefined)
|
|
14
|
-
delete process.env.OPENCLI_CDP_ENDPOINT;
|
|
15
|
-
else
|
|
16
|
-
process.env.OPENCLI_CDP_ENDPOINT = originalEndpoint;
|
|
17
|
-
});
|
|
18
|
-
it('does nothing when the current page is already a notebook page', async () => {
|
|
19
|
-
const page = {
|
|
20
|
-
getCurrentUrl: async () => 'https://notebooklm.google.com/notebook/nb-demo',
|
|
21
|
-
};
|
|
22
|
-
await expect(ensureNotebooklmNotebookBinding(page)).resolves.toBe(false);
|
|
23
|
-
expect(mockBindCurrentTab).not.toHaveBeenCalled();
|
|
24
|
-
});
|
|
25
|
-
it('best-effort binds a notebook page through the browser bridge when currently on home', async () => {
|
|
26
|
-
const page = {
|
|
27
|
-
getCurrentUrl: async () => 'https://notebooklm.google.com/',
|
|
28
|
-
};
|
|
29
|
-
mockBindCurrentTab.mockResolvedValue({});
|
|
30
|
-
await expect(ensureNotebooklmNotebookBinding(page)).resolves.toBe(true);
|
|
31
|
-
expect(mockBindCurrentTab).toHaveBeenCalledWith('site:notebooklm', {
|
|
32
|
-
matchDomain: 'notebooklm.google.com',
|
|
33
|
-
matchPathPrefix: '/notebook/',
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
it('skips daemon binding in direct CDP mode', async () => {
|
|
37
|
-
process.env.OPENCLI_CDP_ENDPOINT = 'ws://127.0.0.1:9222/devtools/page/1';
|
|
38
|
-
const page = {
|
|
39
|
-
getCurrentUrl: async () => 'https://notebooklm.google.com/',
|
|
40
|
-
};
|
|
41
|
-
await expect(ensureNotebooklmNotebookBinding(page)).resolves.toBe(false);
|
|
42
|
-
expect(mockBindCurrentTab).not.toHaveBeenCalled();
|
|
43
|
-
});
|
|
44
|
-
});
|