@jackwener/opencli 1.5.6 → 1.5.8
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 +34 -0
- package/README.md +4 -2
- package/README.zh-CN.md +4 -1
- package/SKILL.md +879 -0
- package/dist/browser/cdp.d.ts +1 -0
- package/dist/browser/cdp.js +30 -27
- package/dist/browser/daemon-client.d.ts +7 -1
- package/dist/browser/daemon-client.js +3 -0
- package/dist/browser/dom-helpers.js +1 -0
- package/dist/browser/dom-helpers.test.js +14 -1
- package/dist/browser/mcp.js +18 -13
- package/dist/browser/page.js +22 -2
- package/dist/browser/page.test.d.ts +1 -0
- package/dist/browser/page.test.js +44 -0
- package/dist/browser/stealth.js +198 -0
- package/dist/browser/stealth.test.d.ts +1 -0
- package/dist/browser/stealth.test.js +134 -0
- package/dist/browser.test.js +1 -1
- package/dist/build-manifest.d.ts +1 -0
- package/dist/build-manifest.js +5 -1
- package/dist/build-manifest.test.js +2 -0
- package/dist/cli-manifest.json +544 -137
- package/dist/cli.js +20 -3
- package/dist/clis/antigravity/serve.d.ts +1 -1
- package/dist/clis/antigravity/serve.js +5 -8
- package/dist/clis/bilibili/subtitle.js +4 -0
- package/dist/clis/bilibili/subtitle.test.d.ts +1 -0
- package/dist/clis/bilibili/subtitle.test.js +48 -0
- package/dist/clis/chatwise/ask.js +0 -2
- package/dist/clis/chatwise/export.js +0 -2
- package/dist/clis/chatwise/history.js +0 -2
- package/dist/clis/chatwise/model.js +0 -2
- package/dist/clis/chatwise/new.js +1 -2
- package/dist/clis/chatwise/read.js +0 -2
- package/dist/clis/chatwise/screenshot.js +1 -2
- package/dist/clis/chatwise/send.js +0 -2
- package/dist/clis/chatwise/status.js +1 -2
- package/dist/clis/ctrip/search.d.ts +13 -0
- package/dist/clis/ctrip/search.js +73 -48
- package/dist/clis/ctrip/search.test.d.ts +1 -0
- package/dist/clis/ctrip/search.test.js +64 -0
- package/dist/clis/douyin/_shared/sts2.js +8 -2
- package/dist/clis/douyin/_shared/sts2.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/sts2.test.js +27 -0
- package/dist/clis/douyin/activities.js +4 -2
- package/dist/clis/douyin/activities.test.js +34 -1
- package/dist/clis/douyin/collections.js +1 -1
- package/dist/clis/douyin/collections.test.js +24 -2
- package/dist/clis/douyin/draft.d.ts +8 -11
- package/dist/clis/douyin/draft.js +302 -185
- package/dist/clis/douyin/draft.test.d.ts +1 -1
- package/dist/clis/douyin/draft.test.js +357 -2
- package/dist/clis/douyin/hashtag.js +9 -2
- package/dist/clis/douyin/hashtag.test.js +35 -2
- package/dist/clis/douyin/profile.js +1 -1
- package/dist/clis/douyin/profile.test.js +36 -1
- package/dist/clis/douyin/videos.js +22 -5
- package/dist/clis/douyin/videos.test.js +45 -2
- package/dist/clis/facebook/search.test.d.ts +5 -0
- package/dist/clis/facebook/search.test.js +60 -0
- package/dist/clis/facebook/search.yaml +4 -3
- package/dist/clis/instagram/download.d.ts +16 -0
- package/dist/clis/instagram/download.js +225 -0
- package/dist/clis/instagram/download.test.d.ts +1 -0
- package/dist/clis/instagram/download.test.js +118 -0
- package/dist/clis/notebooklm/bind-current.d.ts +1 -0
- package/dist/clis/notebooklm/bind-current.js +29 -0
- package/dist/clis/notebooklm/bind-current.test.d.ts +1 -0
- package/dist/clis/notebooklm/bind-current.test.js +35 -0
- package/dist/clis/notebooklm/binding.test.d.ts +1 -0
- package/dist/clis/notebooklm/binding.test.js +44 -0
- package/dist/clis/notebooklm/compat.test.d.ts +3 -0
- package/dist/clis/notebooklm/compat.test.js +16 -0
- package/dist/clis/notebooklm/current.d.ts +1 -0
- package/dist/clis/notebooklm/current.js +28 -0
- package/dist/clis/notebooklm/get.d.ts +1 -0
- package/dist/clis/notebooklm/get.js +37 -0
- package/dist/clis/notebooklm/history.d.ts +1 -0
- package/dist/clis/notebooklm/history.js +25 -0
- package/dist/clis/notebooklm/history.test.d.ts +1 -0
- package/dist/clis/notebooklm/history.test.js +58 -0
- package/dist/clis/notebooklm/list.d.ts +1 -0
- package/dist/clis/notebooklm/list.js +35 -0
- package/dist/clis/notebooklm/note-list.d.ts +1 -0
- package/dist/clis/notebooklm/note-list.js +28 -0
- package/dist/clis/notebooklm/note-list.test.d.ts +1 -0
- package/dist/clis/notebooklm/note-list.test.js +56 -0
- package/dist/clis/notebooklm/notes-get.d.ts +1 -0
- package/dist/clis/notebooklm/notes-get.js +47 -0
- package/dist/clis/notebooklm/notes-get.test.d.ts +1 -0
- package/dist/clis/notebooklm/notes-get.test.js +72 -0
- package/dist/clis/notebooklm/rpc.d.ts +36 -0
- package/dist/clis/notebooklm/rpc.js +189 -0
- package/dist/clis/notebooklm/rpc.test.d.ts +1 -0
- package/dist/clis/notebooklm/rpc.test.js +105 -0
- package/dist/clis/notebooklm/shared.d.ts +87 -0
- package/dist/clis/notebooklm/shared.js +3 -0
- package/dist/clis/notebooklm/source-fulltext.d.ts +1 -0
- package/dist/clis/notebooklm/source-fulltext.js +44 -0
- package/dist/clis/notebooklm/source-fulltext.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-fulltext.test.js +106 -0
- package/dist/clis/notebooklm/source-get.d.ts +1 -0
- package/dist/clis/notebooklm/source-get.js +40 -0
- package/dist/clis/notebooklm/source-get.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-get.test.js +84 -0
- package/dist/clis/notebooklm/source-guide.d.ts +1 -0
- package/dist/clis/notebooklm/source-guide.js +44 -0
- package/dist/clis/notebooklm/source-guide.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-guide.test.js +104 -0
- package/dist/clis/notebooklm/source-list.d.ts +1 -0
- package/dist/clis/notebooklm/source-list.js +30 -0
- package/dist/clis/notebooklm/status.d.ts +1 -0
- package/dist/clis/notebooklm/status.js +31 -0
- package/dist/clis/notebooklm/summary.d.ts +1 -0
- package/dist/clis/notebooklm/summary.js +30 -0
- package/dist/clis/notebooklm/summary.test.d.ts +1 -0
- package/dist/clis/notebooklm/summary.test.js +78 -0
- package/dist/clis/notebooklm/utils.d.ts +37 -0
- package/dist/clis/notebooklm/utils.js +739 -0
- package/dist/clis/notebooklm/utils.test.d.ts +1 -0
- package/dist/clis/notebooklm/utils.test.js +390 -0
- package/dist/clis/substack/utils.d.ts +4 -0
- package/dist/clis/substack/utils.js +8 -2
- package/dist/clis/substack/utils.test.d.ts +1 -0
- package/dist/clis/substack/utils.test.js +46 -0
- package/dist/clis/v2ex/hot.yaml +4 -1
- package/dist/clis/v2ex/latest.yaml +4 -1
- package/dist/clis/v2ex/topic.yaml +6 -1
- package/dist/clis/weixin/download.d.ts +9 -0
- package/dist/clis/weixin/download.js +76 -6
- package/dist/clis/weread/book.js +108 -2
- package/dist/clis/weread/commands.test.js +262 -152
- package/dist/clis/weread/utils.d.ts +10 -0
- package/dist/clis/weread/utils.js +27 -7
- package/dist/clis/xiaohongshu/comments.d.ts +3 -0
- package/dist/clis/xiaohongshu/comments.js +76 -17
- package/dist/clis/xiaohongshu/comments.test.js +70 -9
- package/dist/clis/xiaohongshu/download.d.ts +4 -1
- package/dist/clis/xiaohongshu/download.js +83 -22
- package/dist/clis/xiaohongshu/download.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/download.test.js +75 -0
- package/dist/clis/xiaohongshu/note-helpers.d.ts +12 -0
- package/dist/clis/xiaohongshu/note-helpers.js +23 -0
- package/dist/clis/xiaohongshu/note.d.ts +7 -0
- package/dist/clis/xiaohongshu/note.js +76 -0
- package/dist/clis/xiaohongshu/note.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/note.test.js +136 -0
- package/dist/clis/xiaohongshu/search.js +9 -0
- package/dist/clis/xiaohongshu/search.test.js +10 -4
- package/dist/clis/youtube/search.js +57 -17
- package/dist/clis/zhihu/question.js +19 -17
- package/dist/clis/zhihu/question.test.d.ts +1 -0
- package/dist/clis/zhihu/question.test.js +54 -0
- package/dist/commanderAdapter.js +9 -0
- package/dist/commanderAdapter.test.js +25 -0
- package/dist/commands/daemon.d.ts +9 -0
- package/dist/commands/daemon.js +124 -0
- package/dist/commands/daemon.test.d.ts +1 -0
- package/dist/commands/daemon.test.js +185 -0
- package/dist/completion.js +3 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/daemon.d.ts +1 -1
- package/dist/daemon.js +25 -14
- package/dist/daemon.test.d.ts +1 -0
- package/dist/daemon.test.js +65 -0
- package/dist/discovery.d.ts +9 -0
- package/dist/discovery.js +47 -2
- package/dist/electron-apps.d.ts +29 -0
- package/dist/electron-apps.js +65 -0
- package/dist/electron-apps.test.d.ts +1 -0
- package/dist/electron-apps.test.js +43 -0
- package/dist/engine.test.js +41 -9
- package/dist/execution.js +20 -16
- package/dist/extension-manifest-regression.test.js +1 -0
- package/dist/idle-manager.d.ts +19 -0
- package/dist/idle-manager.js +54 -0
- package/dist/launcher.d.ts +36 -0
- package/dist/launcher.js +152 -0
- package/dist/launcher.test.d.ts +1 -0
- package/dist/launcher.test.js +57 -0
- package/dist/main.js +3 -3
- package/dist/registry.d.ts +1 -0
- package/dist/registry.js +31 -3
- package/dist/registry.test.js +13 -0
- package/dist/runtime.d.ts +5 -3
- package/dist/runtime.js +12 -5
- package/dist/serialization.d.ts +1 -0
- package/dist/serialization.js +3 -0
- package/dist/serialization.test.js +17 -1
- package/dist/tui.d.ts +7 -0
- package/dist/tui.js +52 -0
- package/dist/tui.test.d.ts +1 -0
- package/dist/tui.test.js +19 -0
- package/dist/weixin-download.test.js +14 -0
- package/docs/.vitepress/config.mts +1 -0
- package/docs/adapters/browser/notebooklm.md +69 -0
- package/docs/adapters/browser/xiaohongshu.md +19 -10
- package/docs/adapters/index.md +67 -66
- package/docs/guide/browser-bridge.md +12 -0
- package/docs/guide/troubleshooting.md +9 -4
- package/docs/superpowers/plans/2026-03-31-daemon-lifecycle-redesign.md +857 -0
- package/docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md +208 -0
- package/docs/zh/guide/browser-bridge.md +12 -0
- package/extension/dist/background.js +250 -11
- package/extension/manifest.json +2 -1
- package/extension/src/background.test.ts +202 -2
- package/extension/src/background.ts +175 -10
- package/extension/src/cdp.test.ts +75 -0
- package/extension/src/cdp.ts +89 -3
- package/extension/src/protocol.ts +7 -5
- package/package.json +1 -1
- package/src/browser/cdp.ts +24 -17
- package/src/browser/daemon-client.ts +7 -1
- package/src/browser/dom-helpers.test.ts +15 -1
- package/src/browser/dom-helpers.ts +1 -0
- package/src/browser/mcp.ts +18 -13
- package/src/browser/page.test.ts +58 -0
- package/src/browser/page.ts +18 -2
- package/src/browser/stealth.test.ts +153 -0
- package/src/browser/stealth.ts +198 -0
- package/src/browser.test.ts +1 -1
- package/src/build-manifest.test.ts +2 -0
- package/src/build-manifest.ts +6 -1
- package/src/cli.ts +21 -3
- package/src/clis/antigravity/SKILL.md +3 -12
- package/src/clis/antigravity/serve.ts +5 -10
- package/src/clis/bilibili/subtitle.test.ts +60 -0
- package/src/clis/bilibili/subtitle.ts +4 -0
- package/src/clis/chatwise/ask.ts +0 -2
- package/src/clis/chatwise/export.ts +0 -2
- package/src/clis/chatwise/history.ts +0 -2
- package/src/clis/chatwise/model.ts +0 -2
- package/src/clis/chatwise/new.ts +1 -2
- package/src/clis/chatwise/read.ts +0 -2
- package/src/clis/chatwise/screenshot.ts +1 -2
- package/src/clis/chatwise/send.ts +0 -2
- package/src/clis/chatwise/status.ts +1 -2
- package/src/clis/ctrip/search.test.ts +73 -0
- package/src/clis/ctrip/search.ts +97 -47
- package/src/clis/douyin/_shared/sts2.test.ts +31 -0
- package/src/clis/douyin/_shared/sts2.ts +11 -3
- package/src/clis/douyin/activities.test.ts +41 -1
- package/src/clis/douyin/activities.ts +12 -3
- package/src/clis/douyin/collections.test.ts +35 -2
- package/src/clis/douyin/collections.ts +1 -1
- package/src/clis/douyin/draft.test.ts +444 -2
- package/src/clis/douyin/draft.ts +382 -218
- package/src/clis/douyin/hashtag.test.ts +42 -2
- package/src/clis/douyin/hashtag.ts +11 -3
- package/src/clis/douyin/profile.test.ts +43 -1
- package/src/clis/douyin/profile.ts +9 -2
- package/src/clis/douyin/videos.test.ts +52 -2
- package/src/clis/douyin/videos.ts +49 -15
- package/src/clis/facebook/search.test.ts +70 -0
- package/src/clis/facebook/search.yaml +4 -3
- package/src/clis/instagram/download.test.ts +159 -0
- package/src/clis/instagram/download.ts +286 -0
- package/src/clis/notebooklm/bind-current.test.ts +43 -0
- package/src/clis/notebooklm/bind-current.ts +36 -0
- package/src/clis/notebooklm/binding.test.ts +53 -0
- package/src/clis/notebooklm/compat.test.ts +19 -0
- package/src/clis/notebooklm/current.ts +38 -0
- package/src/clis/notebooklm/get.ts +53 -0
- package/src/clis/notebooklm/history.test.ts +70 -0
- package/src/clis/notebooklm/history.ts +36 -0
- package/src/clis/notebooklm/list.ts +40 -0
- package/src/clis/notebooklm/note-list.test.ts +64 -0
- package/src/clis/notebooklm/note-list.ts +42 -0
- package/src/clis/notebooklm/notes-get.test.ts +88 -0
- package/src/clis/notebooklm/notes-get.ts +67 -0
- package/src/clis/notebooklm/rpc.test.ts +126 -0
- package/src/clis/notebooklm/rpc.ts +286 -0
- package/src/clis/notebooklm/shared.ts +98 -0
- package/src/clis/notebooklm/source-fulltext.test.ts +123 -0
- package/src/clis/notebooklm/source-fulltext.ts +69 -0
- package/src/clis/notebooklm/source-get.test.ts +100 -0
- package/src/clis/notebooklm/source-get.ts +60 -0
- package/src/clis/notebooklm/source-guide.test.ts +121 -0
- package/src/clis/notebooklm/source-guide.ts +69 -0
- package/src/clis/notebooklm/source-list.ts +45 -0
- package/src/clis/notebooklm/status.ts +34 -0
- package/src/clis/notebooklm/summary.test.ts +94 -0
- package/src/clis/notebooklm/summary.ts +45 -0
- package/src/clis/notebooklm/utils.test.ts +446 -0
- package/src/clis/notebooklm/utils.ts +893 -0
- package/src/clis/substack/utils.test.ts +54 -0
- package/src/clis/substack/utils.ts +10 -2
- package/src/clis/v2ex/hot.yaml +4 -1
- package/src/clis/v2ex/latest.yaml +4 -1
- package/src/clis/v2ex/topic.yaml +6 -1
- package/src/clis/weixin/download.ts +95 -6
- package/src/clis/weread/book.ts +142 -2
- package/src/clis/weread/commands.test.ts +314 -154
- package/src/clis/weread/utils.ts +33 -4
- package/src/clis/xiaohongshu/comments.test.ts +85 -9
- package/src/clis/xiaohongshu/comments.ts +76 -17
- package/src/clis/xiaohongshu/download.test.ts +96 -0
- package/src/clis/xiaohongshu/download.ts +83 -22
- package/src/clis/xiaohongshu/note-helpers.ts +25 -0
- package/src/clis/xiaohongshu/note.test.ts +164 -0
- package/src/clis/xiaohongshu/note.ts +86 -0
- package/src/clis/xiaohongshu/search.test.ts +11 -4
- package/src/clis/xiaohongshu/search.ts +13 -0
- package/src/clis/youtube/search.ts +57 -17
- package/src/clis/zhihu/question.test.ts +71 -0
- package/src/clis/zhihu/question.ts +27 -15
- package/src/commanderAdapter.test.ts +30 -0
- package/src/commanderAdapter.ts +7 -0
- package/src/commands/daemon.test.ts +238 -0
- package/src/commands/daemon.ts +135 -0
- package/src/completion.ts +2 -1
- package/src/constants.ts +3 -0
- package/src/daemon.test.ts +88 -0
- package/src/daemon.ts +26 -14
- package/src/discovery.ts +52 -2
- package/src/electron-apps.test.ts +50 -0
- package/src/electron-apps.ts +89 -0
- package/src/engine.test.ts +45 -9
- package/src/execution.ts +24 -19
- package/src/extension-manifest-regression.test.ts +1 -0
- package/src/idle-manager.ts +60 -0
- package/src/launcher.test.ts +67 -0
- package/src/launcher.ts +185 -0
- package/src/main.ts +3 -2
- package/src/registry.test.ts +15 -0
- package/src/registry.ts +32 -3
- package/src/runtime.ts +13 -7
- package/src/serialization.test.ts +19 -1
- package/src/serialization.ts +2 -0
- package/src/tui.test.ts +23 -0
- package/src/tui.ts +65 -0
- package/src/weixin-download.test.ts +27 -0
- package/tests/e2e/browser-public-extended.test.ts +6 -2
- package/chatwise-opencli.ps1 +0 -82
- package/dist/clis/chatwise/shared.d.ts +0 -2
- package/dist/clis/chatwise/shared.js +0 -6
- package/src/clis/chatwise/shared.ts +0 -8
package/dist/registry.js
CHANGED
|
@@ -13,9 +13,11 @@ const _registry = globalThis.__opencli_registry__ ??= new Map();
|
|
|
13
13
|
export function cli(opts) {
|
|
14
14
|
const strategy = opts.strategy ?? (opts.browser === false ? Strategy.PUBLIC : Strategy.COOKIE);
|
|
15
15
|
const browser = opts.browser ?? (strategy !== Strategy.PUBLIC);
|
|
16
|
+
const aliases = normalizeAliases(opts.aliases, opts.name);
|
|
16
17
|
const cmd = {
|
|
17
18
|
site: opts.site,
|
|
18
19
|
name: opts.name,
|
|
20
|
+
aliases,
|
|
19
21
|
description: opts.description ?? '',
|
|
20
22
|
domain: opts.domain,
|
|
21
23
|
strategy,
|
|
@@ -31,8 +33,7 @@ export function cli(opts) {
|
|
|
31
33
|
replacedBy: opts.replacedBy,
|
|
32
34
|
navigateBefore: opts.navigateBefore,
|
|
33
35
|
};
|
|
34
|
-
|
|
35
|
-
_registry.set(key, cmd);
|
|
36
|
+
registerCommand(cmd);
|
|
36
37
|
return cmd;
|
|
37
38
|
}
|
|
38
39
|
export function getRegistry() {
|
|
@@ -45,5 +46,32 @@ export function strategyLabel(cmd) {
|
|
|
45
46
|
return cmd.strategy ?? Strategy.PUBLIC;
|
|
46
47
|
}
|
|
47
48
|
export function registerCommand(cmd) {
|
|
48
|
-
|
|
49
|
+
const canonicalKey = fullName(cmd);
|
|
50
|
+
const existing = _registry.get(canonicalKey);
|
|
51
|
+
if (existing) {
|
|
52
|
+
for (const [key, value] of _registry.entries()) {
|
|
53
|
+
if (value === existing && key !== canonicalKey)
|
|
54
|
+
_registry.delete(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const aliases = normalizeAliases(cmd.aliases, cmd.name);
|
|
58
|
+
cmd.aliases = aliases.length > 0 ? aliases : undefined;
|
|
59
|
+
_registry.set(canonicalKey, cmd);
|
|
60
|
+
for (const alias of aliases) {
|
|
61
|
+
_registry.set(`${cmd.site}/${alias}`, cmd);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function normalizeAliases(aliases, commandName) {
|
|
65
|
+
if (!Array.isArray(aliases) || aliases.length === 0)
|
|
66
|
+
return [];
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
const normalized = [];
|
|
69
|
+
for (const alias of aliases) {
|
|
70
|
+
const value = typeof alias === 'string' ? alias.trim() : '';
|
|
71
|
+
if (!value || value === commandName || seen.has(value))
|
|
72
|
+
continue;
|
|
73
|
+
seen.add(value);
|
|
74
|
+
normalized.push(value);
|
|
75
|
+
}
|
|
76
|
+
return normalized;
|
|
49
77
|
}
|
package/dist/registry.test.js
CHANGED
|
@@ -49,6 +49,19 @@ describe('cli() registration', () => {
|
|
|
49
49
|
const reg = getRegistry();
|
|
50
50
|
expect(reg.get('test-registry/overwrite')?.description).toBe('v2');
|
|
51
51
|
});
|
|
52
|
+
it('registers aliases as alternate registry keys for the same command', () => {
|
|
53
|
+
const cmd = cli({
|
|
54
|
+
site: 'test-registry',
|
|
55
|
+
name: 'canonical',
|
|
56
|
+
description: 'test aliases',
|
|
57
|
+
aliases: ['compat', 'legacy-name'],
|
|
58
|
+
});
|
|
59
|
+
const registry = getRegistry();
|
|
60
|
+
expect(cmd.aliases).toEqual(['compat', 'legacy-name']);
|
|
61
|
+
expect(registry.get('test-registry/canonical')).toBe(cmd);
|
|
62
|
+
expect(registry.get('test-registry/compat')).toBe(cmd);
|
|
63
|
+
expect(registry.get('test-registry/legacy-name')).toBe(cmd);
|
|
64
|
+
});
|
|
52
65
|
});
|
|
53
66
|
describe('fullName', () => {
|
|
54
67
|
it('returns site/name', () => {
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { IPage } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Returns the appropriate browser factory based on
|
|
4
|
-
* Uses CDPBridge
|
|
3
|
+
* Returns the appropriate browser factory based on site type.
|
|
4
|
+
* Uses CDPBridge for registered Electron apps, otherwise BrowserBridge.
|
|
5
5
|
*/
|
|
6
|
-
export declare function getBrowserFactory(): new () => IBrowserFactory;
|
|
6
|
+
export declare function getBrowserFactory(site?: string): new () => IBrowserFactory;
|
|
7
7
|
export declare const DEFAULT_BROWSER_CONNECT_TIMEOUT: number;
|
|
8
8
|
export declare const DEFAULT_BROWSER_COMMAND_TIMEOUT: number;
|
|
9
9
|
export declare const DEFAULT_BROWSER_EXPLORE_TIMEOUT: number;
|
|
@@ -26,9 +26,11 @@ export interface IBrowserFactory {
|
|
|
26
26
|
connect(opts?: {
|
|
27
27
|
timeout?: number;
|
|
28
28
|
workspace?: string;
|
|
29
|
+
cdpEndpoint?: string;
|
|
29
30
|
}): Promise<IPage>;
|
|
30
31
|
close(): Promise<void>;
|
|
31
32
|
}
|
|
32
33
|
export declare function browserSession<T>(BrowserFactory: new () => IBrowserFactory, fn: (page: IPage) => Promise<T>, opts?: {
|
|
33
34
|
workspace?: string;
|
|
35
|
+
cdpEndpoint?: string;
|
|
34
36
|
}): Promise<T>;
|
package/dist/runtime.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { BrowserBridge, CDPBridge } from './browser/index.js';
|
|
2
2
|
import { TimeoutError } from './errors.js';
|
|
3
|
+
import { isElectronApp } from './electron-apps.js';
|
|
3
4
|
/**
|
|
4
|
-
* Returns the appropriate browser factory based on
|
|
5
|
-
* Uses CDPBridge
|
|
5
|
+
* Returns the appropriate browser factory based on site type.
|
|
6
|
+
* Uses CDPBridge for registered Electron apps, otherwise BrowserBridge.
|
|
6
7
|
*/
|
|
7
|
-
export function getBrowserFactory() {
|
|
8
|
-
|
|
8
|
+
export function getBrowserFactory(site) {
|
|
9
|
+
if (site && isElectronApp(site))
|
|
10
|
+
return CDPBridge;
|
|
11
|
+
return BrowserBridge;
|
|
9
12
|
}
|
|
10
13
|
function parseEnvTimeout(envVar, fallback) {
|
|
11
14
|
const raw = process.env[envVar];
|
|
@@ -45,7 +48,11 @@ export function withTimeoutMs(promise, timeoutMs, makeError = 'Operation timed o
|
|
|
45
48
|
export async function browserSession(BrowserFactory, fn, opts = {}) {
|
|
46
49
|
const mcp = new BrowserFactory();
|
|
47
50
|
try {
|
|
48
|
-
const page = await mcp.connect({
|
|
51
|
+
const page = await mcp.connect({
|
|
52
|
+
timeout: DEFAULT_BROWSER_CONNECT_TIMEOUT,
|
|
53
|
+
workspace: opts.workspace,
|
|
54
|
+
cdpEndpoint: opts.cdpEndpoint,
|
|
55
|
+
});
|
|
49
56
|
return await fn(page);
|
|
50
57
|
}
|
|
51
58
|
finally {
|
package/dist/serialization.d.ts
CHANGED
package/dist/serialization.js
CHANGED
|
@@ -23,6 +23,7 @@ export function serializeCommand(cmd) {
|
|
|
23
23
|
command: fullName(cmd),
|
|
24
24
|
site: cmd.site,
|
|
25
25
|
name: cmd.name,
|
|
26
|
+
aliases: cmd.aliases ?? [],
|
|
26
27
|
description: cmd.description,
|
|
27
28
|
strategy: strategyLabel(cmd),
|
|
28
29
|
browser: !!cmd.browser,
|
|
@@ -67,6 +68,8 @@ export function formatRegistryHelpText(cmd) {
|
|
|
67
68
|
meta.push(`Deprecated: ${typeof cmd.deprecated === 'string' ? cmd.deprecated : 'yes'}`);
|
|
68
69
|
if (cmd.replacedBy)
|
|
69
70
|
meta.push(`Use instead: ${cmd.replacedBy}`);
|
|
71
|
+
if (cmd.aliases?.length)
|
|
72
|
+
meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
|
|
70
73
|
lines.push(meta.join(' | '));
|
|
71
74
|
if (cmd.columns?.length)
|
|
72
75
|
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { Strategy } from './registry.js';
|
|
3
|
-
import { formatRegistryHelpText } from './serialization.js';
|
|
3
|
+
import { formatRegistryHelpText, serializeCommand } from './serialization.js';
|
|
4
4
|
describe('formatRegistryHelpText', () => {
|
|
5
5
|
it('summarizes long choices lists so help text stays readable', () => {
|
|
6
6
|
const cmd = {
|
|
@@ -20,4 +20,20 @@ describe('formatRegistryHelpText', () => {
|
|
|
20
20
|
};
|
|
21
21
|
expect(formatRegistryHelpText(cmd)).toContain('--field: all-fields, topic, title, author, ... (+3 more)');
|
|
22
22
|
});
|
|
23
|
+
it('includes aliases in structured serialization and help text', () => {
|
|
24
|
+
const cmd = {
|
|
25
|
+
site: 'demo',
|
|
26
|
+
name: 'get',
|
|
27
|
+
aliases: ['metadata'],
|
|
28
|
+
description: 'Demo command',
|
|
29
|
+
strategy: Strategy.COOKIE,
|
|
30
|
+
browser: true,
|
|
31
|
+
args: [],
|
|
32
|
+
};
|
|
33
|
+
expect(serializeCommand(cmd)).toMatchObject({
|
|
34
|
+
command: 'demo/get',
|
|
35
|
+
aliases: ['metadata'],
|
|
36
|
+
});
|
|
37
|
+
expect(formatRegistryHelpText(cmd)).toContain('Aliases: metadata');
|
|
38
|
+
});
|
|
23
39
|
});
|
package/dist/tui.d.ts
CHANGED
|
@@ -20,3 +20,10 @@ export declare function checkboxPrompt(items: CheckboxItem[], opts?: {
|
|
|
20
20
|
title?: string;
|
|
21
21
|
hint?: string;
|
|
22
22
|
}): Promise<string[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Simple yes/no confirmation prompt.
|
|
25
|
+
*
|
|
26
|
+
* In non-TTY environments, returns `defaultYes` (defaults to true) without blocking.
|
|
27
|
+
* In TTY, waits for a single keypress: y/Enter → true, n/Esc/q → false.
|
|
28
|
+
*/
|
|
29
|
+
export declare function confirmPrompt(message: string, defaultYes?: boolean): Promise<boolean>;
|
package/dist/tui.js
CHANGED
|
@@ -138,3 +138,55 @@ export async function checkboxPrompt(items, opts = {}) {
|
|
|
138
138
|
draw();
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Simple yes/no confirmation prompt.
|
|
143
|
+
*
|
|
144
|
+
* In non-TTY environments, returns `defaultYes` (defaults to true) without blocking.
|
|
145
|
+
* In TTY, waits for a single keypress: y/Enter → true, n/Esc/q → false.
|
|
146
|
+
*/
|
|
147
|
+
export async function confirmPrompt(message, defaultYes = true) {
|
|
148
|
+
const { stdin, stdout } = process;
|
|
149
|
+
if (!stdin.isTTY)
|
|
150
|
+
return defaultYes;
|
|
151
|
+
const hint = defaultYes ? '[Y/n]' : '[y/N]';
|
|
152
|
+
stdout.write(` ${message} ${chalk.dim(hint)} `);
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
const wasRaw = stdin.isRaw;
|
|
155
|
+
stdin.setRawMode(true);
|
|
156
|
+
stdin.resume();
|
|
157
|
+
function cleanup() {
|
|
158
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
159
|
+
stdin.pause();
|
|
160
|
+
stdin.removeListener('data', onData);
|
|
161
|
+
stdout.write('\n');
|
|
162
|
+
}
|
|
163
|
+
function onData(data) {
|
|
164
|
+
const key = data.toString();
|
|
165
|
+
// Ctrl+C
|
|
166
|
+
if (key === '\x03') {
|
|
167
|
+
cleanup();
|
|
168
|
+
process.exit(EXIT_CODES.INTERRUPTED);
|
|
169
|
+
}
|
|
170
|
+
// Enter — use default
|
|
171
|
+
if (key === '\r' || key === '\n') {
|
|
172
|
+
cleanup();
|
|
173
|
+
resolve(defaultYes);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// y/Y — yes
|
|
177
|
+
if (key === 'y' || key === 'Y') {
|
|
178
|
+
cleanup();
|
|
179
|
+
resolve(true);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// n/N/q/Esc — no
|
|
183
|
+
if (key === 'n' || key === 'N' || key === 'q' || key === '\x1b') {
|
|
184
|
+
cleanup();
|
|
185
|
+
resolve(false);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Ignore other keys
|
|
189
|
+
}
|
|
190
|
+
stdin.on('data', onData);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tui.test.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { confirmPrompt } from './tui.js';
|
|
3
|
+
describe('confirmPrompt', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
vi.restoreAllMocks();
|
|
6
|
+
});
|
|
7
|
+
it('returns defaultYes when stdin is not TTY', async () => {
|
|
8
|
+
const result = await confirmPrompt('Restart?', true);
|
|
9
|
+
expect(result).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('returns false when defaultYes is false and non-TTY', async () => {
|
|
12
|
+
const result = await confirmPrompt('Restart?', false);
|
|
13
|
+
expect(result).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
it('defaults to true when defaultYes is omitted and non-TTY', async () => {
|
|
16
|
+
const result = await confirmPrompt('Restart?');
|
|
17
|
+
expect(result).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -27,4 +27,18 @@ describe('weixin publish time extraction', () => {
|
|
|
27
27
|
const extractInPage = eval(mod.buildExtractWechatPublishTimeJs());
|
|
28
28
|
expect(extractInPage('2026年3月24日 22:38', 'var create_time = "1711291080";')).toBe('2026年3月24日 22:38');
|
|
29
29
|
});
|
|
30
|
+
it('detects WeChat verification gate pages', async () => {
|
|
31
|
+
const mod = await loadModule();
|
|
32
|
+
expect(mod.detectWechatAccessIssue('环境异常 当前环境异常,完成验证后即可继续访问。 去验证', '<html><body><a id="js_verify">去验证</a></body></html>')).toBe('environment verification required');
|
|
33
|
+
});
|
|
34
|
+
it('browser access detector matches the server-side verifier', async () => {
|
|
35
|
+
const mod = await loadModule();
|
|
36
|
+
const detectInPage = eval(mod.buildDetectWechatAccessIssueJs());
|
|
37
|
+
expect(detectInPage('环境异常 当前环境异常,完成验证后即可继续访问。 去验证', '<html>secitptpage/verify.html<a id="js_verify">去验证</a></html>')).toBe('environment verification required');
|
|
38
|
+
});
|
|
39
|
+
it('picks the first non-empty WeChat metadata field', async () => {
|
|
40
|
+
const mod = await loadModule();
|
|
41
|
+
expect(mod.pickFirstWechatMetaText('', 'Name cleared', '数字生命卡兹克')).toBe('数字生命卡兹克');
|
|
42
|
+
expect(mod.pickFirstWechatMetaText('', ' 聊聊刚刚上线的PixVerse V6视频模型。 ')).toBe('聊聊刚刚上线的PixVerse V6视频模型。');
|
|
43
|
+
});
|
|
30
44
|
});
|
|
@@ -72,6 +72,7 @@ export default defineConfig({
|
|
|
72
72
|
{ text: 'Band', link: '/adapters/browser/band' },
|
|
73
73
|
{ text: 'Chaoxing', link: '/adapters/browser/chaoxing' },
|
|
74
74
|
{ text: 'Grok', link: '/adapters/browser/grok' },
|
|
75
|
+
{ text: 'NotebookLM', link: '/adapters/browser/notebooklm' },
|
|
75
76
|
{ text: 'WeRead', link: '/adapters/browser/weread' },
|
|
76
77
|
{ text: 'Douban', link: '/adapters/browser/douban' },
|
|
77
78
|
{ text: 'Sina Blog', link: '/adapters/browser/sinablog' },
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# NotebookLM
|
|
2
|
+
|
|
3
|
+
**Mode**: 🔐 Browser Bridge · **Domain**: `notebooklm.google.com`
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| `opencli notebooklm status` | Check whether NotebookLM is reachable in the current Chrome session |
|
|
10
|
+
| `opencli notebooklm list` | List notebooks visible from the NotebookLM home page |
|
|
11
|
+
| `opencli notebooklm current` | Show metadata for the currently opened notebook tab |
|
|
12
|
+
| `opencli notebooklm get` | Get richer metadata for the current notebook |
|
|
13
|
+
| `opencli notebooklm source-list` | List sources in the current notebook |
|
|
14
|
+
| `opencli notebooklm source-get <source>` | Resolve one source in the current notebook by id or title |
|
|
15
|
+
| `opencli notebooklm source-fulltext <source>` | Fetch extracted source fulltext through NotebookLM RPC |
|
|
16
|
+
| `opencli notebooklm source-guide <source>` | Fetch guide summary and keywords for one source |
|
|
17
|
+
| `opencli notebooklm history` | List conversation history threads for the current notebook |
|
|
18
|
+
| `opencli notebooklm note-list` | List Studio notes visible in the current notebook |
|
|
19
|
+
| `opencli notebooklm notes-get <note>` | Read the currently visible Studio note by title |
|
|
20
|
+
| `opencli notebooklm bind-current` | Bind the current active NotebookLM tab into the `site:notebooklm` workspace |
|
|
21
|
+
| `opencli notebooklm summary` | Read the current notebook summary |
|
|
22
|
+
|
|
23
|
+
## Compatibility Aliases
|
|
24
|
+
|
|
25
|
+
| Alias | Canonical command |
|
|
26
|
+
|-------|-------------------|
|
|
27
|
+
| `opencli notebooklm metadata` | `opencli notebooklm get` |
|
|
28
|
+
| `opencli notebooklm use` | `opencli notebooklm bind-current` |
|
|
29
|
+
| `opencli notebooklm notes-list` | `opencli notebooklm note-list` |
|
|
30
|
+
|
|
31
|
+
## Positioning
|
|
32
|
+
|
|
33
|
+
This adapter reuses the existing OpenCLI Browser Bridge runtime:
|
|
34
|
+
|
|
35
|
+
- no custom NotebookLM extension
|
|
36
|
+
- no exported cookie replay
|
|
37
|
+
- requests and page state stay in the real Chrome session
|
|
38
|
+
|
|
39
|
+
The current milestone focuses on a stable NotebookLM read surface in desktop Chrome with an already logged-in Google account.
|
|
40
|
+
|
|
41
|
+
## Usage Examples
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
opencli notebooklm status
|
|
45
|
+
opencli notebooklm list -f json
|
|
46
|
+
opencli notebooklm current -f json
|
|
47
|
+
opencli notebooklm metadata -f json
|
|
48
|
+
opencli notebooklm source-list -f json
|
|
49
|
+
opencli notebooklm source-get "Quarterly report" -f json
|
|
50
|
+
opencli notebooklm source-guide "Quarterly report" -f json
|
|
51
|
+
opencli notebooklm source-fulltext "Quarterly report" -f json
|
|
52
|
+
opencli notebooklm history -f json
|
|
53
|
+
opencli notebooklm notes-list -f json
|
|
54
|
+
opencli notebooklm notes-get "Draft note" -f json
|
|
55
|
+
opencli notebooklm summary -f json
|
|
56
|
+
opencli notebooklm use -f json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Prerequisites
|
|
60
|
+
|
|
61
|
+
- Chrome running and logged into Google / NotebookLM
|
|
62
|
+
- [Browser Bridge extension](/guide/browser-bridge) installed
|
|
63
|
+
- NotebookLM accessible in the current browser session
|
|
64
|
+
|
|
65
|
+
## Notes
|
|
66
|
+
|
|
67
|
+
- Notebook-oriented commands assume you already have the target notebook open in Chrome, or that `opencli notebooklm use` can bind an existing notebook tab into `site:notebooklm`.
|
|
68
|
+
- `list`, `get`, `source-list`, `history`, `source-fulltext`, and `source-guide` prefer NotebookLM RPC paths and fall back only when the richer path is unavailable.
|
|
69
|
+
- `notes-get` currently reads note content only from the visible Studio note editor; if the note is listed but not open, open it in NotebookLM first and then retry.
|
|
@@ -7,15 +7,18 @@
|
|
|
7
7
|
| Command | Description |
|
|
8
8
|
|---------|-------------|
|
|
9
9
|
| `opencli xiaohongshu search` | Search notes by keyword (returns title, author, likes, URL) |
|
|
10
|
-
| `opencli xiaohongshu
|
|
11
|
-
| `opencli xiaohongshu
|
|
12
|
-
| `opencli xiaohongshu
|
|
13
|
-
| `opencli xiaohongshu
|
|
14
|
-
| `opencli xiaohongshu
|
|
15
|
-
| `opencli xiaohongshu
|
|
16
|
-
| `opencli xiaohongshu
|
|
17
|
-
| `opencli xiaohongshu creator-
|
|
18
|
-
| `opencli xiaohongshu creator-
|
|
10
|
+
| `opencli xiaohongshu note` | Read full note content (title, author, description, likes, collects, comments, tags) |
|
|
11
|
+
| `opencli xiaohongshu comments` | Read comments from a note (`--with-replies` for nested 楼中楼 replies) |
|
|
12
|
+
| `opencli xiaohongshu feed` | Home feed recommendations (via Pinia store interception) |
|
|
13
|
+
| `opencli xiaohongshu notifications` | User notifications (mentions, likes, connections) |
|
|
14
|
+
| `opencli xiaohongshu user` | Get public notes from a user profile |
|
|
15
|
+
| `opencli xiaohongshu download` | Download images and videos from a note |
|
|
16
|
+
| `opencli xiaohongshu publish` | Publish image-text notes (creator center UI automation) |
|
|
17
|
+
| `opencli xiaohongshu creator-notes` | Creator's note list with per-note metrics |
|
|
18
|
+
| `opencli xiaohongshu creator-note-detail` | Detailed analytics for a single creator note |
|
|
19
|
+
| `opencli xiaohongshu creator-notes-summary` | Combined note list + detail analytics summary |
|
|
20
|
+
| `opencli xiaohongshu creator-profile` | Creator account info (followers, growth level) |
|
|
21
|
+
| `opencli xiaohongshu creator-stats` | Creator data overview (views, likes, collects, trends) |
|
|
19
22
|
|
|
20
23
|
## Usage Examples
|
|
21
24
|
|
|
@@ -23,13 +26,19 @@
|
|
|
23
26
|
# Search for notes
|
|
24
27
|
opencli xiaohongshu search 美食 --limit 10
|
|
25
28
|
|
|
29
|
+
# Read a note's full content (pass URL from search results to preserve xsec_token)
|
|
30
|
+
opencli xiaohongshu note "https://www.xiaohongshu.com/search_result/<id>?xsec_token=..."
|
|
31
|
+
|
|
32
|
+
# Read comments with nested replies (楼中楼)
|
|
33
|
+
opencli xiaohongshu comments "https://www.xiaohongshu.com/search_result/<id>?xsec_token=..." --with-replies --limit 20
|
|
34
|
+
|
|
26
35
|
# JSON output
|
|
27
36
|
opencli xiaohongshu search 旅行 -f json
|
|
28
37
|
|
|
29
38
|
# Other commands
|
|
30
39
|
opencli xiaohongshu feed
|
|
31
40
|
opencli xiaohongshu notifications
|
|
32
|
-
opencli xiaohongshu download <url>
|
|
41
|
+
opencli xiaohongshu download <note-id or url>
|
|
33
42
|
```
|
|
34
43
|
|
|
35
44
|
## Prerequisites
|
package/docs/adapters/index.md
CHANGED
|
@@ -6,79 +6,80 @@ Run `opencli list` for the live registry.
|
|
|
6
6
|
|
|
7
7
|
| Site | Commands | Mode |
|
|
8
8
|
|------|----------|------|
|
|
9
|
-
| **[twitter](
|
|
10
|
-
| **[reddit](
|
|
11
|
-
| **[tieba](
|
|
12
|
-
| **[bilibili](
|
|
13
|
-
| **[zhihu](
|
|
14
|
-
| **[xiaohongshu](
|
|
15
|
-
| **[xueqiu](
|
|
16
|
-
| **[youtube](
|
|
17
|
-
| **[v2ex](
|
|
18
|
-
| **[bloomberg](
|
|
19
|
-
| **[weibo](
|
|
20
|
-
| **[linkedin](
|
|
21
|
-
| **[coupang](
|
|
22
|
-
| **[boss](
|
|
23
|
-
| **[ctrip](
|
|
24
|
-
| **[reuters](
|
|
25
|
-
| **[smzdm](
|
|
26
|
-
| **[jike](
|
|
27
|
-
| **[jimeng](
|
|
28
|
-
| **[yollomi](
|
|
29
|
-
| **[linux-do](
|
|
30
|
-
| **[chaoxing](
|
|
31
|
-
| **[grok](
|
|
32
|
-
| **[
|
|
33
|
-
| **[
|
|
34
|
-
| **[
|
|
35
|
-
| **[
|
|
36
|
-
| **[
|
|
37
|
-
| **[
|
|
38
|
-
| **[
|
|
39
|
-
| **[
|
|
40
|
-
| **[
|
|
41
|
-
| **[
|
|
42
|
-
| **[
|
|
43
|
-
| **[
|
|
44
|
-
| **[
|
|
45
|
-
| **[
|
|
46
|
-
| **[
|
|
47
|
-
| **[
|
|
48
|
-
| **[
|
|
49
|
-
| **[
|
|
9
|
+
| **[twitter](./browser/twitter)** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` `block` `unblock` `hide-reply` | 🔐 Browser |
|
|
10
|
+
| **[reddit](./browser/reddit)** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser |
|
|
11
|
+
| **[tieba](./browser/tieba)** | `hot` `posts` `search` `read` | 🔐 Browser |
|
|
12
|
+
| **[bilibili](./browser/bilibili)** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser |
|
|
13
|
+
| **[zhihu](./browser/zhihu)** | `hot` `search` `question` `download` | 🔐 Browser |
|
|
14
|
+
| **[xiaohongshu](./browser/xiaohongshu)** | `search` `notifications` `feed` `user` `download` `publish` `creator-notes` `creator-note-detail` `creator-notes-summary` `creator-profile` `creator-stats` | 🔐 Browser |
|
|
15
|
+
| **[xueqiu](./browser/xueqiu)** | `feed` `hot-stock` `hot` `search` `stock` `comments` `watchlist` `earnings-date` `fund-holdings` `fund-snapshot` | 🔐 Browser |
|
|
16
|
+
| **[youtube](./browser/youtube)** | `search` `video` `transcript` | 🔐 Browser |
|
|
17
|
+
| **[v2ex](./browser/v2ex)** | `hot` `latest` `topic` `node` `user` `member` `replies` `nodes` `daily` `me` `notifications` | 🌐 / 🔐 |
|
|
18
|
+
| **[bloomberg](./browser/bloomberg)** | `main` `markets` `economics` `industries` `tech` `politics` `businessweek` `opinions` `feeds` `news` | 🌐 / 🔐 |
|
|
19
|
+
| **[weibo](./browser/weibo)** | `hot` `search` | 🔐 Browser |
|
|
20
|
+
| **[linkedin](./browser/linkedin)** | `search` `timeline` | 🔐 Browser |
|
|
21
|
+
| **[coupang](./browser/coupang)** | `search` `add-to-cart` | 🔐 Browser |
|
|
22
|
+
| **[boss](./browser/boss)** | `search` `detail` `recommend` `joblist` `greet` `batchgreet` `send` `chatlist` `chatmsg` `invite` `mark` `exchange` `resume` `stats` | 🔐 Browser |
|
|
23
|
+
| **[ctrip](./browser/ctrip)** | `search` | 🔐 Browser |
|
|
24
|
+
| **[reuters](./browser/reuters)** | `search` | 🔐 Browser |
|
|
25
|
+
| **[smzdm](./browser/smzdm)** | `search` | 🔐 Browser |
|
|
26
|
+
| **[jike](./browser/jike)** | `feed` `search` `post` `topic` `user` `create` `comment` `like` `repost` `notifications` | 🔐 Browser |
|
|
27
|
+
| **[jimeng](./browser/jimeng)** | `generate` `history` | 🔐 Browser |
|
|
28
|
+
| **[yollomi](./browser/yollomi)** | `generate` `video` `edit` `upload` `models` `remove-bg` `upscale` `face-swap` `restore` `try-on` `background` `object-remover` | 🔐 Browser |
|
|
29
|
+
| **[linux-do](./browser/linux-do)** | `feed` `categories` `tags` `search` `topic` `user-topics` `user-posts` | 🔐 Browser |
|
|
30
|
+
| **[chaoxing](./browser/chaoxing)** | `assignments` `exams` | 🔐 Browser |
|
|
31
|
+
| **[grok](./browser/grok)** | `ask` | 🔐 Browser |
|
|
32
|
+
| **[notebooklm](./browser/notebooklm)** | `status` `list` `current` `get` `metadata` `bind-current` `use` `source-list` `source-get` `source-fulltext` `source-guide` `history` `note-list` `notes-list` `notes-get` `summary` | 🔐 Browser |
|
|
33
|
+
| **[doubao](./browser/doubao)** | `status` `new` `send` `read` `ask` `history` `detail` `meeting-summary` `meeting-transcript` | 🔐 Browser |
|
|
34
|
+
| **[weread](./browser/weread)** | `shelf` `search` `book` `ranking` `notebooks` `highlights` `notes` | 🔐 Browser |
|
|
35
|
+
| **[douban](./browser/douban)** | `search` `top250` `subject` `photos` `download` `marks` `reviews` `movie-hot` `book-hot` | 🔐 Browser |
|
|
36
|
+
| **[facebook](./browser/facebook)** | `feed` `profile` `search` `friends` `groups` `events` `notifications` `memories` `add-friend` `join-group` | 🔐 Browser |
|
|
37
|
+
| **[imdb](./browser/imdb)** | `search` `title` `top` `trending` `person` `reviews` | 🌐 / 🔐 |
|
|
38
|
+
| **[instagram](./browser/instagram)** | `explore` `profile` `search` `user` `followers` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `saved` | 🔐 Browser |
|
|
39
|
+
| **[medium](./browser/medium)** | `feed` `search` `user` | 🔐 Browser |
|
|
40
|
+
| **[sinablog](./browser/sinablog)** | `hot` `search` `article` `user` | 🔐 Browser |
|
|
41
|
+
| **[substack](./browser/substack)** | `feed` `search` `publication` | 🔐 Browser |
|
|
42
|
+
| **[pixiv](./browser/pixiv)** | `ranking` `search` `user` `illusts` `detail` `download` | 🔐 Browser |
|
|
43
|
+
| **[tiktok](./browser/tiktok)** | `explore` `search` `profile` `user` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `live` `notifications` `friends` | 🔐 Browser |
|
|
44
|
+
| **[google](./browser/google)** | `news` `search` `suggest` `trends` | 🌐 / 🔐 |
|
|
45
|
+
| **[jd](./browser/jd)** | `item` | 🔐 Browser |
|
|
46
|
+
| **[web](./browser/web)** | `read` | 🔐 Browser |
|
|
47
|
+
| **[weixin](./browser/weixin)** | `download` | 🔐 Browser |
|
|
48
|
+
| **[36kr](./browser/36kr)** | `news` `hot` `search` `article` | 🌐 / 🔐 |
|
|
49
|
+
| **[producthunt](./browser/producthunt)** | `posts` `today` `hot` `browse` | 🌐 / 🔐 |
|
|
50
|
+
| **[ones](./browser/ones)** | `login` `me` `token-info` `tasks` `my-tasks` `task` `worklog` `logout` | 🔐 Browser Bridge + `ONES_BASE_URL` |
|
|
50
51
|
|
|
51
52
|
## Public API Adapters
|
|
52
53
|
|
|
53
54
|
| Site | Commands | Mode |
|
|
54
55
|
|------|----------|------|
|
|
55
|
-
| **[hackernews](
|
|
56
|
-
| **[bbc](
|
|
57
|
-
| **[devto](
|
|
58
|
-
| **[dictionary](
|
|
59
|
-
| **[apple-podcasts](
|
|
60
|
-
| **[xiaoyuzhou](
|
|
61
|
-
| **[yahoo-finance](
|
|
62
|
-
| **[arxiv](
|
|
63
|
-
| **[paperreview](
|
|
64
|
-
| **[barchart](
|
|
65
|
-
| **[hf](
|
|
66
|
-
| **[sinafinance](
|
|
67
|
-
| **[spotify](
|
|
68
|
-
| **[stackoverflow](
|
|
69
|
-
| **[wikipedia](
|
|
70
|
-
| **[lobsters](
|
|
71
|
-
| **[steam](
|
|
56
|
+
| **[hackernews](./browser/hackernews)** | `top` `new` `best` `ask` `show` `jobs` `search` `user` | 🌐 Public |
|
|
57
|
+
| **[bbc](./browser/bbc)** | `news` | 🌐 Public |
|
|
58
|
+
| **[devto](./browser/devto)** | `top` `tag` `user` | 🌐 Public |
|
|
59
|
+
| **[dictionary](./browser/dictionary)** | `search` `synonyms` `examples` | 🌐 Public |
|
|
60
|
+
| **[apple-podcasts](./browser/apple-podcasts)** | `search` `episodes` `top` | 🌐 Public |
|
|
61
|
+
| **[xiaoyuzhou](./browser/xiaoyuzhou)** | `podcast` `podcast-episodes` `episode` | 🌐 Public |
|
|
62
|
+
| **[yahoo-finance](./browser/yahoo-finance)** | `quote` | 🌐 Public |
|
|
63
|
+
| **[arxiv](./browser/arxiv)** | `search` `paper` | 🌐 Public |
|
|
64
|
+
| **[paperreview](./browser/paperreview)** | `submit` `review` `feedback` | 🌐 Public |
|
|
65
|
+
| **[barchart](./browser/barchart)** | `quote` `options` `greeks` `flow` | 🌐 Public |
|
|
66
|
+
| **[hf](./browser/hf)** | `top` | 🌐 Public |
|
|
67
|
+
| **[sinafinance](./browser/sinafinance)** | `news` | 🌐 Public |
|
|
68
|
+
| **[spotify](./browser/spotify)** | `auth` `status` `play` `pause` `next` `prev` `volume` `search` `queue` `shuffle` `repeat` | 🔑 OAuth API |
|
|
69
|
+
| **[stackoverflow](./browser/stackoverflow)** | `hot` `search` `bounties` `unanswered` | 🌐 Public |
|
|
70
|
+
| **[wikipedia](./browser/wikipedia)** | `search` `summary` `random` `trending` | 🌐 Public |
|
|
71
|
+
| **[lobsters](./browser/lobsters)** | `hot` `newest` `active` `tag` | 🌐 Public |
|
|
72
|
+
| **[steam](./browser/steam)** | `top-sellers` | 🌐 Public |
|
|
72
73
|
|
|
73
74
|
## Desktop Adapters
|
|
74
75
|
|
|
75
76
|
| App | Description | Commands |
|
|
76
77
|
|-----|-------------|----------|
|
|
77
|
-
| **[Cursor](
|
|
78
|
-
| **[Codex](
|
|
79
|
-
| **[Antigravity](
|
|
80
|
-
| **[ChatGPT](
|
|
81
|
-
| **[ChatWise](
|
|
82
|
-
| **[Notion](
|
|
83
|
-
| **[Discord](
|
|
84
|
-
| **[Doubao App](
|
|
78
|
+
| **[Cursor](./desktop/cursor)** | Control Cursor IDE | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` |
|
|
79
|
+
| **[Codex](./desktop/codex)** | Drive OpenAI Codex CLI agent | `status` `send` `read` `new` `extract-diff` `model` `ask` `screenshot` `history` `export` |
|
|
80
|
+
| **[Antigravity](./desktop/antigravity)** | Control Antigravity Ultra | `status` `send` `read` `new` `dump` `extract-code` `model` `watch` |
|
|
81
|
+
| **[ChatGPT](./desktop/chatgpt)** | Automate ChatGPT macOS app | `status` `new` `send` `read` `ask` |
|
|
82
|
+
| **[ChatWise](./desktop/chatwise)** | Multi-LLM client | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` |
|
|
83
|
+
| **[Notion](./desktop/notion)** | Search, read, write pages | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` |
|
|
84
|
+
| **[Discord](./desktop/discord)** | Desktop messages & channels | `status` `send` `read` `channels` `servers` `search` `members` |
|
|
85
|
+
| **[Doubao App](./desktop/doubao-app)** | Doubao AI desktop app via CDP | `status` `new` `send` `read` `ask` `screenshot` `dump` |
|
|
@@ -35,3 +35,15 @@ opencli doctor # Check extension + daemon connectivity
|
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
The daemon manages the WebSocket connection between your CLI commands and the Chrome extension. The extension executes JavaScript in the context of web pages, with access to the logged-in session.
|
|
38
|
+
|
|
39
|
+
## Daemon Lifecycle
|
|
40
|
+
|
|
41
|
+
The daemon auto-starts on first browser command and stays alive for **4 hours** by default. It exits only when both conditions are met: no CLI requests for the timeout period AND no Chrome extension connected.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
opencli daemon status # Check daemon state (PID, uptime, extension, memory)
|
|
45
|
+
opencli daemon stop # Graceful shutdown
|
|
46
|
+
opencli daemon restart # Stop + restart
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Override the timeout via the `OPENCLI_DAEMON_TIMEOUT` environment variable (milliseconds). Set to `0` to keep the daemon alive indefinitely.
|