@jackwener/opencli 1.6.0 → 1.6.2
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 +8 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +27 -45
- package/README.zh-CN.md +32 -34
- package/autoresearch/browse-tasks.json +18 -20
- package/autoresearch/commands/debug.ts +163 -0
- package/autoresearch/commands/fix.ts +145 -0
- package/autoresearch/commands/plan.ts +88 -0
- package/autoresearch/commands/run.ts +138 -0
- package/autoresearch/config.ts +82 -0
- package/autoresearch/engine.ts +359 -0
- package/autoresearch/eval-all.ts +127 -0
- package/autoresearch/eval-browse.ts +1 -1
- package/autoresearch/eval-publish.ts +238 -0
- package/autoresearch/eval-save.ts +249 -0
- package/autoresearch/eval-skill.ts +14 -8
- package/autoresearch/eval-v2ex.ts +220 -0
- package/autoresearch/eval-zhihu.ts +230 -0
- package/autoresearch/logger.ts +69 -0
- package/autoresearch/presets/combined-reliability.ts +27 -0
- package/autoresearch/presets/index.ts +23 -0
- package/autoresearch/presets/operate-reliability.ts +24 -0
- package/autoresearch/presets/save-reliability.ts +26 -0
- package/autoresearch/presets/skill-quality.ts +20 -0
- package/autoresearch/presets/v2ex-reliability.ts +24 -0
- package/autoresearch/presets/zhihu-reliability.ts +25 -0
- package/autoresearch/publish-tasks.json +345 -0
- package/autoresearch/run-save.sh +11 -0
- package/autoresearch/save-adapters/xhs-explore-deep.ts +64 -0
- package/autoresearch/save-adapters/xhs-note-comments.ts +61 -0
- package/autoresearch/save-adapters/xhs-search-full.ts +62 -0
- package/autoresearch/save-adapters/zhihu-hot-detail.ts +52 -0
- package/autoresearch/save-adapters/zhihu-question-full.ts +57 -0
- package/autoresearch/save-adapters/zhihu-search-detail.ts +53 -0
- package/autoresearch/save-tasks.json +281 -0
- package/autoresearch/v2ex-tasks.json +899 -0
- package/autoresearch/zhihu-tasks.json +848 -0
- package/bun.lock +615 -0
- package/dist/browser/base-page.d.ts +4 -2
- package/dist/browser/base-page.js +37 -4
- package/dist/browser/bridge.js +10 -8
- package/dist/browser/cdp.js +2 -6
- package/dist/browser/daemon-client.d.ts +11 -1
- package/dist/browser/daemon-client.js +3 -0
- package/dist/browser/dom-helpers.d.ts +4 -2
- package/dist/browser/dom-helpers.js +42 -31
- package/dist/browser/dom-snapshot.js +23 -1
- package/dist/browser/page.d.ts +7 -2
- package/dist/browser/page.js +112 -30
- package/dist/browser.test.js +1 -1
- package/dist/build-manifest.d.ts +1 -0
- package/dist/build-manifest.js +1 -0
- package/dist/cli-manifest.json +1133 -182
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +48 -7
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +88 -0
- package/dist/clis/1688/item.d.ts +70 -0
- package/dist/clis/1688/item.js +187 -0
- package/dist/clis/1688/item.test.d.ts +1 -0
- package/dist/clis/1688/item.test.js +67 -0
- package/dist/clis/1688/search.d.ts +56 -0
- package/dist/clis/1688/search.js +309 -0
- package/dist/clis/1688/search.test.d.ts +1 -0
- package/dist/clis/1688/search.test.js +75 -0
- package/dist/clis/1688/shared.d.ts +112 -0
- package/dist/clis/1688/shared.js +514 -0
- package/dist/clis/1688/shared.test.d.ts +1 -0
- package/dist/clis/1688/shared.test.js +57 -0
- package/dist/clis/1688/store.d.ts +45 -0
- package/dist/clis/1688/store.js +226 -0
- package/dist/clis/1688/store.test.d.ts +1 -0
- package/dist/clis/1688/store.test.js +62 -0
- package/dist/clis/amazon/bestsellers.d.ts +0 -20
- package/dist/clis/amazon/bestsellers.js +6 -129
- package/dist/clis/amazon/bestsellers.test.js +12 -3
- package/dist/clis/amazon/movers-shakers.d.ts +1 -0
- package/dist/clis/amazon/movers-shakers.js +7 -0
- package/dist/clis/amazon/new-releases.d.ts +1 -0
- package/dist/clis/amazon/new-releases.js +7 -0
- package/dist/clis/amazon/rankings.d.ts +59 -0
- package/dist/clis/amazon/rankings.js +226 -0
- package/dist/clis/amazon/rankings.test.d.ts +1 -0
- package/dist/clis/amazon/rankings.test.js +41 -0
- package/dist/clis/amazon/shared.d.ts +11 -0
- package/dist/clis/amazon/shared.js +121 -11
- package/dist/clis/amazon/shared.test.js +11 -0
- package/dist/clis/bilibili/comments.js +2 -2
- package/dist/clis/bilibili/comments.test.js +3 -2
- package/dist/clis/bilibili/download.js +2 -1
- package/dist/clis/bilibili/subtitle.js +4 -3
- package/dist/clis/bilibili/subtitle.test.js +2 -1
- package/dist/clis/bilibili/utils.d.ts +5 -0
- package/dist/clis/bilibili/utils.js +30 -0
- package/dist/clis/bilibili/utils.test.d.ts +1 -0
- package/dist/clis/bilibili/utils.test.js +17 -0
- package/dist/clis/douban/marks.js +1 -1
- package/dist/clis/douban/subject.yaml +50 -19
- package/dist/clis/doubao/utils.js +32 -12
- package/dist/clis/douyin/_shared/browser-fetch.test.js +0 -1
- package/dist/clis/douyin/_shared/transcode.test.js +0 -2
- package/dist/clis/douyin/draft.test.js +0 -2
- package/dist/clis/facebook/search.test.js +0 -2
- package/dist/clis/gemini/ask.js +9 -3
- package/dist/clis/gemini/ask.test.d.ts +1 -0
- package/dist/clis/gemini/ask.test.js +100 -0
- package/dist/clis/gemini/reply-state.test.d.ts +1 -0
- package/dist/clis/gemini/reply-state.test.js +641 -0
- package/dist/clis/gemini/utils.d.ts +44 -1
- package/dist/clis/gemini/utils.js +528 -61
- package/dist/clis/gemini/utils.test.js +149 -2
- package/dist/clis/hupu/detail.d.ts +1 -0
- package/dist/clis/hupu/detail.js +72 -0
- package/dist/clis/hupu/hot.yaml +43 -0
- package/dist/clis/hupu/like.d.ts +1 -0
- package/dist/clis/hupu/like.js +75 -0
- package/dist/clis/hupu/reply.d.ts +1 -0
- package/dist/clis/hupu/reply.js +71 -0
- package/dist/clis/hupu/search.d.ts +1 -0
- package/dist/clis/hupu/search.js +59 -0
- package/dist/clis/hupu/unlike.d.ts +1 -0
- package/dist/clis/hupu/unlike.js +75 -0
- package/dist/clis/hupu/utils.d.ts +20 -0
- package/dist/clis/hupu/utils.js +319 -0
- package/dist/clis/instagram/_shared/private-publish.d.ts +138 -0
- package/dist/clis/instagram/_shared/private-publish.js +1030 -0
- package/dist/clis/instagram/_shared/private-publish.test.d.ts +1 -0
- package/dist/clis/instagram/_shared/private-publish.test.js +705 -0
- package/dist/clis/instagram/_shared/protocol-capture.d.ts +26 -0
- package/dist/clis/instagram/_shared/protocol-capture.js +282 -0
- package/dist/clis/instagram/_shared/protocol-capture.test.d.ts +1 -0
- package/dist/clis/instagram/_shared/protocol-capture.test.js +114 -0
- package/dist/clis/instagram/_shared/runtime-info.d.ts +9 -0
- package/dist/clis/instagram/_shared/runtime-info.js +81 -0
- package/dist/clis/instagram/note.d.ts +1 -0
- package/dist/clis/instagram/note.js +222 -0
- package/dist/clis/instagram/note.test.d.ts +1 -0
- package/dist/clis/instagram/note.test.js +81 -0
- package/dist/clis/instagram/post.d.ts +4 -0
- package/dist/clis/instagram/post.js +1496 -0
- package/dist/clis/instagram/post.test.d.ts +1 -0
- package/dist/clis/instagram/post.test.js +1647 -0
- package/dist/clis/instagram/reel.d.ts +1 -0
- package/dist/clis/instagram/reel.js +826 -0
- package/dist/clis/instagram/reel.test.d.ts +1 -0
- package/dist/clis/instagram/reel.test.js +167 -0
- package/dist/clis/instagram/story.d.ts +1 -0
- package/dist/clis/instagram/story.js +115 -0
- package/dist/clis/instagram/story.test.d.ts +1 -0
- package/dist/clis/instagram/story.test.js +167 -0
- package/dist/clis/sinafinance/stock-rank.d.ts +4 -0
- package/dist/clis/sinafinance/stock-rank.js +65 -0
- package/dist/clis/substack/utils.test.js +0 -2
- package/dist/clis/twitter/post.js +72 -45
- package/dist/clis/twitter/post.test.d.ts +1 -0
- package/dist/clis/twitter/post.test.js +116 -0
- package/dist/clis/twitter/reply.d.ts +12 -0
- package/dist/clis/twitter/reply.js +257 -35
- package/dist/clis/twitter/reply.test.d.ts +1 -0
- package/dist/clis/twitter/reply.test.js +151 -0
- package/dist/clis/twitter/search.js +67 -5
- package/dist/clis/twitter/search.test.js +83 -5
- package/dist/clis/xianyu/chat.d.ts +7 -0
- package/dist/clis/xianyu/chat.js +146 -0
- package/dist/clis/xianyu/chat.test.d.ts +1 -0
- package/dist/clis/xianyu/chat.test.js +15 -0
- package/dist/clis/xianyu/item.d.ts +7 -0
- package/dist/clis/xianyu/item.js +152 -0
- package/dist/clis/xianyu/item.test.d.ts +1 -0
- package/dist/clis/xianyu/item.test.js +56 -0
- package/dist/clis/xianyu/search.d.ts +10 -0
- package/dist/clis/xianyu/search.js +134 -0
- package/dist/clis/xianyu/search.test.d.ts +1 -0
- package/dist/clis/xianyu/search.test.js +17 -0
- package/dist/clis/xianyu/utils.d.ts +1 -0
- package/dist/clis/xianyu/utils.js +8 -0
- package/dist/clis/xiaoe/catalog.yaml +129 -0
- package/dist/clis/xiaoe/content.yaml +43 -0
- package/dist/clis/xiaoe/courses.yaml +73 -0
- package/dist/clis/xiaoe/detail.yaml +39 -0
- package/dist/clis/xiaoe/play-url.yaml +124 -0
- package/dist/clis/xiaohongshu/comments.test.js +0 -2
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +0 -2
- package/dist/clis/xiaohongshu/creator-notes.test.js +0 -2
- package/dist/clis/xiaohongshu/download.test.js +0 -2
- package/dist/clis/xiaohongshu/note.test.js +0 -2
- package/dist/clis/xiaohongshu/publish.test.js +0 -2
- package/dist/clis/xiaohongshu/search.js +29 -20
- package/dist/clis/xiaohongshu/search.test.js +56 -48
- package/dist/clis/yuanbao/ask.d.ts +21 -0
- package/dist/clis/yuanbao/ask.js +427 -0
- package/dist/clis/yuanbao/ask.test.d.ts +1 -0
- package/dist/clis/yuanbao/ask.test.js +124 -0
- package/dist/clis/yuanbao/new.d.ts +1 -0
- package/dist/clis/yuanbao/new.js +70 -0
- package/dist/clis/yuanbao/new.test.d.ts +1 -0
- package/dist/clis/yuanbao/new.test.js +30 -0
- package/dist/clis/yuanbao/shared.d.ts +13 -0
- package/dist/clis/yuanbao/shared.js +49 -0
- package/dist/clis/zhihu/question.js +30 -19
- package/dist/clis/zhihu/question.test.js +34 -16
- package/dist/commanderAdapter.js +8 -4
- package/dist/commanderAdapter.test.js +42 -0
- package/dist/completion.js +3 -1
- package/dist/completion.test.d.ts +1 -0
- package/dist/completion.test.js +23 -0
- package/dist/doctor.js +1 -1
- package/dist/electron-apps.d.ts +2 -0
- package/dist/electron-apps.js +7 -1
- package/dist/errors.js +1 -1
- package/dist/execution.js +25 -35
- package/dist/explore.js +1 -1
- package/dist/launcher.d.ts +4 -0
- package/dist/launcher.js +64 -8
- package/dist/launcher.test.js +88 -7
- package/dist/output.d.ts +2 -0
- package/dist/output.js +10 -1
- package/dist/output.test.d.ts +0 -3
- package/dist/output.test.js +59 -92
- package/dist/pipeline/executor.test.js +0 -2
- package/dist/pipeline/steps/download.test.js +0 -2
- package/dist/registry.d.ts +2 -0
- package/dist/serialization.d.ts +1 -0
- package/dist/serialization.js +1 -0
- package/dist/types.d.ts +9 -2
- package/docs/.vitepress/config.mts +4 -0
- package/docs/adapters/browser/1688.md +52 -0
- package/docs/adapters/browser/36kr.md +2 -1
- package/docs/adapters/browser/doubao.md +5 -1
- package/docs/adapters/browser/hupu.md +53 -0
- package/docs/adapters/browser/sinafinance.md +32 -2
- package/docs/adapters/browser/weibo.md +6 -1
- package/docs/adapters/browser/wikipedia.md +2 -0
- package/docs/adapters/browser/xianyu.md +42 -0
- package/docs/adapters/browser/xiaoe.md +44 -0
- package/docs/adapters/browser/yuanbao.md +64 -0
- package/docs/adapters/index.md +14 -5
- package/docs/comparison.md +1 -1
- package/docs/developer/ai-workflow.md +2 -2
- package/docs/developer/contributing.md +1 -1
- package/docs/developer/testing.md +2 -0
- package/docs/guide/plugins.md +1 -0
- package/docs/guide/troubleshooting.md +11 -0
- package/docs/superpowers/specs/2026-04-03-v2ex-autoresearch-design.md +41 -0
- package/docs/zh/guide/plugins.md +1 -0
- package/extension/dist/background.js +1127 -0
- package/extension/src/background.test.ts +39 -0
- package/extension/src/background.ts +223 -34
- package/extension/src/cdp.ts +194 -4
- package/extension/src/protocol.ts +22 -1
- package/package.json +3 -2
- package/scripts/postinstall.js +1 -1
- package/skills/opencli-explorer/SKILL.md +1 -1
- package/skills/opencli-oneshot/SKILL.md +2 -2
- package/skills/opencli-operate/SKILL.md +120 -27
- package/skills/opencli-usage/SKILL.md +31 -20
- package/skills/opencli-usage/browser.md +114 -16
- package/skills/opencli-usage/public-api.md +32 -3
- package/skills/smart-search/SKILL.md +156 -0
- package/skills/smart-search/references/sources-ai.md +74 -0
- package/skills/smart-search/references/sources-info.md +43 -0
- package/skills/smart-search/references/sources-media.md +50 -0
- package/skills/smart-search/references/sources-other.md +42 -0
- package/skills/smart-search/references/sources-shopping.md +31 -0
- package/skills/smart-search/references/sources-social.md +51 -0
- package/skills/smart-search/references/sources-tech.md +42 -0
- package/skills/smart-search/references/sources-travel.md +20 -0
- package/src/browser/base-page.ts +41 -6
- package/src/browser/bridge.ts +11 -8
- package/src/browser/cdp.ts +1 -8
- package/src/browser/daemon-client.ts +11 -1
- package/src/browser/dom-helpers.ts +43 -31
- package/src/browser/dom-snapshot.ts +23 -1
- package/src/browser/page.ts +115 -31
- package/src/browser.test.ts +1 -1
- package/src/build-manifest.ts +2 -0
- package/src/cli.test.ts +133 -0
- package/src/cli.ts +73 -11
- package/src/clis/1688/item.test.ts +69 -0
- package/src/clis/1688/item.ts +282 -0
- package/src/clis/1688/search.test.ts +81 -0
- package/src/clis/1688/search.ts +402 -0
- package/src/clis/1688/shared.test.ts +75 -0
- package/src/clis/1688/shared.ts +623 -0
- package/src/clis/1688/store.test.ts +69 -0
- package/src/clis/1688/store.ts +300 -0
- package/src/clis/amazon/bestsellers.test.ts +12 -3
- package/src/clis/amazon/bestsellers.ts +6 -178
- package/src/clis/amazon/movers-shakers.ts +8 -0
- package/src/clis/amazon/new-releases.ts +8 -0
- package/src/clis/amazon/rankings.test.ts +47 -0
- package/src/clis/amazon/rankings.ts +312 -0
- package/src/clis/amazon/shared.test.ts +16 -0
- package/src/clis/amazon/shared.ts +134 -12
- package/src/clis/bilibili/comments.test.ts +4 -3
- package/src/clis/bilibili/comments.ts +2 -2
- package/src/clis/bilibili/download.ts +2 -1
- package/src/clis/bilibili/subtitle.test.ts +2 -1
- package/src/clis/bilibili/subtitle.ts +4 -3
- package/src/clis/bilibili/utils.test.ts +21 -0
- package/src/clis/bilibili/utils.ts +27 -0
- package/src/clis/douban/marks.ts +1 -1
- package/src/clis/douban/subject.yaml +50 -19
- package/src/clis/doubao/utils.ts +32 -12
- package/src/clis/douyin/_shared/browser-fetch.test.ts +0 -1
- package/src/clis/douyin/_shared/transcode.test.ts +0 -2
- package/src/clis/douyin/draft.test.ts +0 -2
- package/src/clis/facebook/search.test.ts +0 -2
- package/src/clis/gemini/ask.test.ts +116 -0
- package/src/clis/gemini/ask.ts +10 -3
- package/src/clis/gemini/reply-state.test.ts +708 -0
- package/src/clis/gemini/utils.test.ts +184 -2
- package/src/clis/gemini/utils.ts +588 -60
- package/src/clis/hupu/detail.ts +126 -0
- package/src/clis/hupu/hot.yaml +43 -0
- package/src/clis/hupu/like.ts +76 -0
- package/src/clis/hupu/reply.ts +76 -0
- package/src/clis/hupu/search.ts +95 -0
- package/src/clis/hupu/unlike.ts +76 -0
- package/src/clis/hupu/utils.ts +381 -0
- package/src/clis/instagram/_shared/private-publish.test.ts +827 -0
- package/src/clis/instagram/_shared/private-publish.ts +1303 -0
- package/src/clis/instagram/_shared/protocol-capture.test.ts +148 -0
- package/src/clis/instagram/_shared/protocol-capture.ts +321 -0
- package/src/clis/instagram/_shared/runtime-info.ts +91 -0
- package/src/clis/instagram/note.test.ts +96 -0
- package/src/clis/instagram/note.ts +254 -0
- package/src/clis/instagram/post.test.ts +1716 -0
- package/src/clis/instagram/post.ts +1620 -0
- package/src/clis/instagram/reel.test.ts +191 -0
- package/src/clis/instagram/reel.ts +886 -0
- package/src/clis/instagram/story.test.ts +191 -0
- package/src/clis/instagram/story.ts +151 -0
- package/src/clis/sinafinance/stock-rank.ts +68 -0
- package/src/clis/substack/utils.test.ts +0 -2
- package/src/clis/twitter/post.test.ts +157 -0
- package/src/clis/twitter/post.ts +82 -48
- package/src/clis/twitter/reply.test.ts +177 -0
- package/src/clis/twitter/reply.ts +285 -39
- package/src/clis/twitter/search.test.ts +88 -5
- package/src/clis/twitter/search.ts +68 -5
- package/src/clis/xianyu/chat.test.ts +20 -0
- package/src/clis/xianyu/chat.ts +175 -0
- package/src/clis/xianyu/item.test.ts +67 -0
- package/src/clis/xianyu/item.ts +172 -0
- package/src/clis/xianyu/search.test.ts +22 -0
- package/src/clis/xianyu/search.ts +151 -0
- package/src/clis/xianyu/utils.ts +9 -0
- package/src/clis/xiaoe/catalog.yaml +129 -0
- package/src/clis/xiaoe/content.yaml +43 -0
- package/src/clis/xiaoe/courses.yaml +73 -0
- package/src/clis/xiaoe/detail.yaml +39 -0
- package/src/clis/xiaoe/play-url.yaml +124 -0
- package/src/clis/xiaohongshu/comments.test.ts +0 -2
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +0 -2
- package/src/clis/xiaohongshu/creator-notes.test.ts +0 -2
- package/src/clis/xiaohongshu/download.test.ts +0 -2
- package/src/clis/xiaohongshu/note.test.ts +0 -2
- package/src/clis/xiaohongshu/publish.test.ts +0 -2
- package/src/clis/xiaohongshu/search.test.ts +59 -48
- package/src/clis/xiaohongshu/search.ts +31 -21
- package/src/clis/yuanbao/ask.test.ts +156 -0
- package/src/clis/yuanbao/ask.ts +522 -0
- package/src/clis/yuanbao/new.test.ts +36 -0
- package/src/clis/yuanbao/new.ts +81 -0
- package/src/clis/yuanbao/shared.ts +57 -0
- package/src/clis/zhihu/question.test.ts +42 -17
- package/src/clis/zhihu/question.ts +31 -26
- package/src/commanderAdapter.test.ts +51 -0
- package/src/commanderAdapter.ts +8 -4
- package/src/completion.test.ts +30 -0
- package/src/completion.ts +3 -1
- package/src/doctor.ts +1 -1
- package/src/electron-apps.ts +9 -1
- package/src/errors.ts +1 -1
- package/src/execution.ts +26 -30
- package/src/explore.ts +1 -1
- package/src/launcher.test.ts +121 -7
- package/src/launcher.ts +87 -9
- package/src/output.test.ts +50 -90
- package/src/output.ts +10 -1
- package/src/pipeline/executor.test.ts +0 -2
- package/src/pipeline/steps/download.test.ts +0 -2
- package/src/registry.ts +2 -0
- package/src/serialization.ts +2 -0
- package/src/types.ts +9 -2
- package/tests/e2e/browser-auth.test.ts +9 -0
- package/CLI-EXPLORER.md +0 -724
- package/CLI-ONESHOT.md +0 -216
- package/SKILL.md +0 -59
package/dist/launcher.test.js
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { detectProcess, discoverAppPath, launchDetachedApp, launchElectronApp, probeCDP, resolveExecutableCandidates } from './launcher.js';
|
|
3
|
+
function createMockChildProcess() {
|
|
4
|
+
const listeners = new Map();
|
|
5
|
+
return {
|
|
6
|
+
once: vi.fn((event, handler) => {
|
|
7
|
+
listeners.set(event, [...(listeners.get(event) ?? []), handler]);
|
|
8
|
+
}),
|
|
9
|
+
off: vi.fn((event, handler) => {
|
|
10
|
+
listeners.set(event, (listeners.get(event) ?? []).filter((listener) => listener !== handler));
|
|
11
|
+
}),
|
|
12
|
+
unref: vi.fn(),
|
|
13
|
+
emit: (event, value) => {
|
|
14
|
+
for (const listener of listeners.get(event) ?? [])
|
|
15
|
+
listener(value);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
3
19
|
vi.mock('node:child_process', () => ({
|
|
4
20
|
execFileSync: vi.fn(),
|
|
5
|
-
spawn: vi.fn(
|
|
6
|
-
unref: vi.fn(),
|
|
7
|
-
pid: 12345,
|
|
8
|
-
on: vi.fn(),
|
|
9
|
-
})),
|
|
21
|
+
spawn: vi.fn(),
|
|
10
22
|
}));
|
|
11
23
|
const cp = vi.mocked(await import('node:child_process'));
|
|
12
24
|
describe('probeCDP', () => {
|
|
@@ -28,7 +40,7 @@ describe('detectProcess', () => {
|
|
|
28
40
|
const result = detectProcess('NonExistentApp');
|
|
29
41
|
expect(result).toBe(false);
|
|
30
42
|
});
|
|
31
|
-
it('returns true when pgrep finds a process', () => {
|
|
43
|
+
it.skipIf(process.platform === 'win32')('returns true when pgrep finds a process', () => {
|
|
32
44
|
cp.execFileSync.mockReturnValue('12345\n');
|
|
33
45
|
const result = detectProcess('Cursor');
|
|
34
46
|
expect(result).toBe(true);
|
|
@@ -55,3 +67,72 @@ describe('discoverAppPath', () => {
|
|
|
55
67
|
expect(result).toBeNull();
|
|
56
68
|
});
|
|
57
69
|
});
|
|
70
|
+
describe('launchDetachedApp', () => {
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
vi.restoreAllMocks();
|
|
73
|
+
cp.spawn.mockReset();
|
|
74
|
+
});
|
|
75
|
+
it('unrefs the process after spawn succeeds', async () => {
|
|
76
|
+
const child = createMockChildProcess();
|
|
77
|
+
cp.spawn.mockImplementation(() => {
|
|
78
|
+
queueMicrotask(() => child.emit('spawn'));
|
|
79
|
+
return child;
|
|
80
|
+
});
|
|
81
|
+
await expect(launchDetachedApp('/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], 'Antigravity'))
|
|
82
|
+
.resolves
|
|
83
|
+
.toBeUndefined();
|
|
84
|
+
expect(child.unref).toHaveBeenCalledTimes(1);
|
|
85
|
+
});
|
|
86
|
+
it('converts ENOENT into a controlled launch error', async () => {
|
|
87
|
+
const child = createMockChildProcess();
|
|
88
|
+
cp.spawn.mockImplementation(() => {
|
|
89
|
+
queueMicrotask(() => child.emit('error', Object.assign(new Error('missing binary'), { code: 'ENOENT' })));
|
|
90
|
+
return child;
|
|
91
|
+
});
|
|
92
|
+
await expect(launchDetachedApp('/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], 'Antigravity'))
|
|
93
|
+
.rejects
|
|
94
|
+
.toThrow('Could not launch Antigravity');
|
|
95
|
+
expect(child.unref).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('resolveExecutableCandidates', () => {
|
|
99
|
+
it('prefers explicit executable candidates over processName', () => {
|
|
100
|
+
const app = {
|
|
101
|
+
port: 9234,
|
|
102
|
+
processName: 'Antigravity',
|
|
103
|
+
executableNames: ['Electron', 'Antigravity'],
|
|
104
|
+
};
|
|
105
|
+
expect(resolveExecutableCandidates('/Applications/Antigravity.app', app)).toEqual([
|
|
106
|
+
'/Applications/Antigravity.app/Contents/MacOS/Electron',
|
|
107
|
+
'/Applications/Antigravity.app/Contents/MacOS/Antigravity',
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('launchElectronApp', () => {
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
vi.restoreAllMocks();
|
|
114
|
+
cp.spawn.mockReset();
|
|
115
|
+
});
|
|
116
|
+
it('falls back to the next executable candidate when the first is missing', async () => {
|
|
117
|
+
const firstChild = createMockChildProcess();
|
|
118
|
+
const secondChild = createMockChildProcess();
|
|
119
|
+
const app = {
|
|
120
|
+
port: 9234,
|
|
121
|
+
processName: 'Antigravity',
|
|
122
|
+
executableNames: ['Electron', 'Antigravity'],
|
|
123
|
+
};
|
|
124
|
+
cp.spawn
|
|
125
|
+
.mockImplementationOnce(() => {
|
|
126
|
+
queueMicrotask(() => firstChild.emit('error', Object.assign(new Error('missing binary'), { code: 'ENOENT' })));
|
|
127
|
+
return firstChild;
|
|
128
|
+
})
|
|
129
|
+
.mockImplementationOnce(() => {
|
|
130
|
+
queueMicrotask(() => secondChild.emit('spawn'));
|
|
131
|
+
return secondChild;
|
|
132
|
+
});
|
|
133
|
+
await expect(launchElectronApp('/Applications/Antigravity.app', app, ['--remote-debugging-port=9234'], 'Antigravity')).resolves.toBeUndefined();
|
|
134
|
+
expect(cp.spawn).toHaveBeenNthCalledWith(1, '/Applications/Antigravity.app/Contents/MacOS/Electron', ['--remote-debugging-port=9234'], { detached: true, stdio: 'ignore' });
|
|
135
|
+
expect(cp.spawn).toHaveBeenNthCalledWith(2, '/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], { detached: true, stdio: 'ignore' });
|
|
136
|
+
expect(secondChild.unref).toHaveBeenCalledTimes(1);
|
|
137
|
+
});
|
|
138
|
+
});
|
package/dist/output.d.ts
CHANGED
package/dist/output.js
CHANGED
|
@@ -15,7 +15,16 @@ function resolveColumns(rows, opts) {
|
|
|
15
15
|
return opts.columns ?? Object.keys(rows[0] ?? {});
|
|
16
16
|
}
|
|
17
17
|
export function render(data, opts = {}) {
|
|
18
|
-
|
|
18
|
+
let fmt = opts.fmt ?? 'table';
|
|
19
|
+
// Non-TTY auto-downgrade only when format was NOT explicitly passed by user.
|
|
20
|
+
// Priority: explicit -f (any value) > OUTPUT env var > TTY auto-detect > table
|
|
21
|
+
if (!opts.fmtExplicit) {
|
|
22
|
+
const envFmt = process.env.OUTPUT?.trim().toLowerCase();
|
|
23
|
+
if (envFmt)
|
|
24
|
+
fmt = envFmt;
|
|
25
|
+
else if (fmt === 'table' && !process.stdout.isTTY)
|
|
26
|
+
fmt = 'yaml';
|
|
27
|
+
}
|
|
19
28
|
if (data === null || data === undefined) {
|
|
20
29
|
console.log(data);
|
|
21
30
|
return;
|
package/dist/output.test.d.ts
CHANGED
package/dist/output.test.js
CHANGED
|
@@ -1,95 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
* Tests for output.ts: render function format coverage.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
5
2
|
import { render } from './output.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
expect(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(
|
|
40
|
-
});
|
|
41
|
-
it('
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
expect(
|
|
47
|
-
});
|
|
48
|
-
it('
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
expect(log).toHaveBeenCalledOnce();
|
|
65
|
-
expect(log.mock.calls[0]?.[0]).toContain('- title: Hello');
|
|
66
|
-
expect(log.mock.calls[0]?.[0]).toContain('rank: 1');
|
|
67
|
-
});
|
|
68
|
-
it('renders yml alias as YAML output', () => {
|
|
69
|
-
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
70
|
-
render({ title: 'Hello' }, { fmt: 'yml' });
|
|
71
|
-
expect(log).toHaveBeenCalledOnce();
|
|
72
|
-
expect(log.mock.calls[0]?.[0]).toContain('title: Hello');
|
|
73
|
-
});
|
|
74
|
-
it('handles null values in CSV cells', () => {
|
|
75
|
-
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
76
|
-
render([{ name: 'test', value: null }], { fmt: 'csv' });
|
|
77
|
-
const calls = log.mock.calls.map(c => c[0]);
|
|
78
|
-
expect(calls[1]).toBe('test,');
|
|
79
|
-
});
|
|
80
|
-
it('renders single-field rows in plain mode as the bare value', () => {
|
|
81
|
-
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
82
|
-
render([{ response: 'Gemini says hi' }], { fmt: 'plain' });
|
|
83
|
-
expect(log).toHaveBeenCalledWith('Gemini says hi');
|
|
84
|
-
});
|
|
85
|
-
it('renders multi-field rows in plain mode as key-value lines', () => {
|
|
86
|
-
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
87
|
-
render([{ status: 'ok', file: '~/tmp/a.png', link: 'https://example.com' }], { fmt: 'plain' });
|
|
88
|
-
const calls = log.mock.calls.map(c => c[0]);
|
|
89
|
-
expect(calls).toEqual([
|
|
90
|
-
'status: ok',
|
|
91
|
-
'file: ~/tmp/a.png',
|
|
92
|
-
'link: https://example.com',
|
|
93
|
-
]);
|
|
3
|
+
describe('output TTY detection', () => {
|
|
4
|
+
const originalIsTTY = process.stdout.isTTY;
|
|
5
|
+
const originalEnv = process.env.OUTPUT;
|
|
6
|
+
let logSpy;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
9
|
+
});
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: originalIsTTY, writable: true });
|
|
12
|
+
if (originalEnv === undefined)
|
|
13
|
+
delete process.env.OUTPUT;
|
|
14
|
+
else
|
|
15
|
+
process.env.OUTPUT = originalEnv;
|
|
16
|
+
logSpy.mockRestore();
|
|
17
|
+
});
|
|
18
|
+
it('outputs YAML in non-TTY when format is default table', () => {
|
|
19
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
20
|
+
// commanderAdapter always passes fmt:'table' as default — this must still trigger downgrade
|
|
21
|
+
render([{ name: 'alice', score: 10 }], { fmt: 'table', columns: ['name', 'score'] });
|
|
22
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
23
|
+
expect(out).toContain('name: alice');
|
|
24
|
+
expect(out).toContain('score: 10');
|
|
25
|
+
});
|
|
26
|
+
it('outputs table in TTY when format is default table', () => {
|
|
27
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, writable: true });
|
|
28
|
+
render([{ name: 'alice', score: 10 }], { fmt: 'table', columns: ['name', 'score'] });
|
|
29
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
30
|
+
expect(out).toContain('alice');
|
|
31
|
+
});
|
|
32
|
+
it('respects explicit -f json even in non-TTY', () => {
|
|
33
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
34
|
+
render([{ name: 'alice' }], { fmt: 'json' });
|
|
35
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
36
|
+
expect(JSON.parse(out)).toEqual([{ name: 'alice' }]);
|
|
37
|
+
});
|
|
38
|
+
it('OUTPUT env var overrides default table in non-TTY', () => {
|
|
39
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
40
|
+
process.env.OUTPUT = 'json';
|
|
41
|
+
render([{ name: 'alice' }], { fmt: 'table' });
|
|
42
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
43
|
+
expect(JSON.parse(out)).toEqual([{ name: 'alice' }]);
|
|
44
|
+
});
|
|
45
|
+
it('explicit -f flag takes precedence over OUTPUT env var', () => {
|
|
46
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
47
|
+
process.env.OUTPUT = 'json';
|
|
48
|
+
render([{ name: 'alice' }], { fmt: 'csv', fmtExplicit: true });
|
|
49
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
50
|
+
expect(out).toContain('name');
|
|
51
|
+
expect(out).toContain('alice');
|
|
52
|
+
expect(out).not.toContain('"name"'); // not JSON
|
|
53
|
+
});
|
|
54
|
+
it('explicit -f table overrides non-TTY auto-downgrade', () => {
|
|
55
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
56
|
+
render([{ name: 'alice' }], { fmt: 'table', fmtExplicit: true, columns: ['name'] });
|
|
57
|
+
const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
|
|
58
|
+
// Should be table output, not YAML
|
|
59
|
+
expect(out).not.toContain('name: alice');
|
|
60
|
+
expect(out).toContain('alice');
|
|
94
61
|
});
|
|
95
62
|
});
|
|
@@ -17,8 +17,6 @@ function createMockPage(overrides = {}) {
|
|
|
17
17
|
getFormState: vi.fn().mockResolvedValue({}),
|
|
18
18
|
wait: vi.fn(),
|
|
19
19
|
tabs: vi.fn().mockResolvedValue([]),
|
|
20
|
-
closeTab: vi.fn(),
|
|
21
|
-
newTab: vi.fn(),
|
|
22
20
|
selectTab: vi.fn(),
|
|
23
21
|
networkRequests: vi.fn().mockResolvedValue([]),
|
|
24
22
|
consoleMessages: vi.fn().mockResolvedValue(''),
|
|
@@ -29,8 +29,6 @@ function createMockPage(getCookies) {
|
|
|
29
29
|
getFormState: vi.fn().mockResolvedValue({}),
|
|
30
30
|
wait: vi.fn(),
|
|
31
31
|
tabs: vi.fn().mockResolvedValue([]),
|
|
32
|
-
closeTab: vi.fn(),
|
|
33
|
-
newTab: vi.fn(),
|
|
34
32
|
selectTab: vi.fn(),
|
|
35
33
|
networkRequests: vi.fn().mockResolvedValue([]),
|
|
36
34
|
consoleMessages: vi.fn().mockResolvedValue([]),
|
package/dist/registry.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface Arg {
|
|
|
14
14
|
type?: string;
|
|
15
15
|
default?: unknown;
|
|
16
16
|
required?: boolean;
|
|
17
|
+
valueRequired?: boolean;
|
|
17
18
|
positional?: boolean;
|
|
18
19
|
help?: string;
|
|
19
20
|
choices?: string[];
|
|
@@ -40,6 +41,7 @@ export interface CliCommand {
|
|
|
40
41
|
source?: string;
|
|
41
42
|
footerExtra?: (kwargs: CommandArgs) => string | undefined;
|
|
42
43
|
requiredEnv?: RequiredEnv[];
|
|
44
|
+
validateArgs?: (kwargs: CommandArgs) => void;
|
|
43
45
|
/** Deprecation note shown in help / execution warnings. */
|
|
44
46
|
deprecated?: boolean | string;
|
|
45
47
|
/** Preferred replacement command, if any. */
|
package/dist/serialization.d.ts
CHANGED
package/dist/serialization.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -56,8 +56,8 @@ export interface IPage {
|
|
|
56
56
|
getFormState(): Promise<any>;
|
|
57
57
|
wait(options: number | WaitOptions): Promise<void>;
|
|
58
58
|
tabs(): Promise<any>;
|
|
59
|
-
closeTab(index?: number): Promise<void>;
|
|
60
|
-
newTab(): Promise<void>;
|
|
59
|
+
closeTab?(index?: number): Promise<void>;
|
|
60
|
+
newTab?(): Promise<void>;
|
|
61
61
|
selectTab(index: number): Promise<void>;
|
|
62
62
|
networkRequests(includeStatic?: boolean): Promise<any>;
|
|
63
63
|
consoleMessages(level?: string): Promise<any>;
|
|
@@ -70,11 +70,18 @@ export interface IPage {
|
|
|
70
70
|
getInterceptedRequests(): Promise<any[]>;
|
|
71
71
|
waitForCapture(timeout?: number): Promise<void>;
|
|
72
72
|
screenshot(options?: ScreenshotOptions): Promise<string>;
|
|
73
|
+
startNetworkCapture?(pattern?: string): Promise<void>;
|
|
74
|
+
readNetworkCapture?(): Promise<unknown[]>;
|
|
73
75
|
/**
|
|
74
76
|
* Set local file paths on a file input element via CDP DOM.setFileInputFiles.
|
|
75
77
|
* Chrome reads the files directly — no base64 encoding or payload size limits.
|
|
76
78
|
*/
|
|
77
79
|
setFileInput?(files: string[], selector?: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Insert text via native CDP Input.insertText into the currently focused element.
|
|
82
|
+
* Useful for rich editors that ignore synthetic DOM value/text mutations.
|
|
83
|
+
*/
|
|
84
|
+
insertText?(text: string): Promise<void>;
|
|
78
85
|
closeWindow?(): Promise<void>;
|
|
79
86
|
/** Returns the current page URL, or null if unavailable. */
|
|
80
87
|
getCurrentUrl?(): Promise<string | null>;
|
|
@@ -54,6 +54,7 @@ export default defineConfig({
|
|
|
54
54
|
{ text: 'Bilibili', link: '/adapters/browser/bilibili' },
|
|
55
55
|
{ text: 'Zhihu', link: '/adapters/browser/zhihu' },
|
|
56
56
|
{ text: 'Xiaohongshu', link: '/adapters/browser/xiaohongshu' },
|
|
57
|
+
{ text: 'Xiaoe', link: '/adapters/browser/xiaoe' },
|
|
57
58
|
{ text: 'Weibo', link: '/adapters/browser/weibo' },
|
|
58
59
|
{ text: 'YouTube', link: '/adapters/browser/youtube' },
|
|
59
60
|
{ text: 'Xueqiu', link: '/adapters/browser/xueqiu' },
|
|
@@ -73,7 +74,9 @@ export default defineConfig({
|
|
|
73
74
|
{ text: 'Chaoxing', link: '/adapters/browser/chaoxing' },
|
|
74
75
|
{ text: 'Grok', link: '/adapters/browser/grok' },
|
|
75
76
|
{ text: 'Amazon', link: '/adapters/browser/amazon' },
|
|
77
|
+
{ text: '1688', link: '/adapters/browser/1688' },
|
|
76
78
|
{ text: 'Gemini', link: '/adapters/browser/gemini' },
|
|
79
|
+
{ text: 'Yuanbao', link: '/adapters/browser/yuanbao' },
|
|
77
80
|
{ text: 'NotebookLM', link: '/adapters/browser/notebooklm' },
|
|
78
81
|
{ text: 'WeRead', link: '/adapters/browser/weread' },
|
|
79
82
|
{ text: 'Douban', link: '/adapters/browser/douban' },
|
|
@@ -91,6 +94,7 @@ export default defineConfig({
|
|
|
91
94
|
{ text: 'TikTok', link: '/adapters/browser/tiktok' },
|
|
92
95
|
{ text: 'Web (Generic)', link: '/adapters/browser/web' },
|
|
93
96
|
{ text: 'Weixin', link: '/adapters/browser/weixin' },
|
|
97
|
+
{ text: 'Xianyu', link: '/adapters/browser/xianyu' },
|
|
94
98
|
],
|
|
95
99
|
},
|
|
96
100
|
{
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 1688
|
|
2
|
+
|
|
3
|
+
**Mode**: 🔐 Browser · **Domain**: `1688.com`
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| `opencli 1688 search "<query>" --limit <n>` | Search public product candidates with price, MOQ, seller link, and visible badges |
|
|
10
|
+
| `opencli 1688 item <url-or-offer-id>` | Read a public product detail page with price tiers, MOQ, delivery text, and seller basics |
|
|
11
|
+
| `opencli 1688 store <url-or-member-id>` | Read a public supplier/store page with company info, years on platform, categories, and visible service signals |
|
|
12
|
+
|
|
13
|
+
## Usage Examples
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Search products
|
|
17
|
+
opencli 1688 search "桌面置物架 宿舍 收纳" --limit 10
|
|
18
|
+
|
|
19
|
+
# JSON output
|
|
20
|
+
opencli 1688 search "桌面置物架 宿舍 收纳" --limit 10 -f json
|
|
21
|
+
|
|
22
|
+
# Read an item by offer id
|
|
23
|
+
opencli 1688 item 841141931191 -f json
|
|
24
|
+
|
|
25
|
+
# Read an item by URL
|
|
26
|
+
opencli 1688 item https://detail.1688.com/offer/841141931191.html -f json
|
|
27
|
+
|
|
28
|
+
# Read a supplier store
|
|
29
|
+
opencli 1688 store https://shop52908bfw19166.1688.com/ -f json
|
|
30
|
+
|
|
31
|
+
# Read a supplier by member id
|
|
32
|
+
opencli 1688 store b2b-22154705262941f196 -f json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Prerequisites
|
|
36
|
+
|
|
37
|
+
- Chrome running and **logged into** `1688.com`
|
|
38
|
+
- [Browser Bridge extension](/guide/browser-bridge) installed
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- This adapter only returns fields visible on public pages. It does not send inquiries, place orders, or access seller back office data.
|
|
43
|
+
- Prefer stable identifiers such as `offer_id`, `member_id`, and `shop_id` for follow-up workflows.
|
|
44
|
+
- `search --limit` defaults to `20` and is capped at `100`.
|
|
45
|
+
- `search` deduplicates with key priority: `offer_id` first, then canonical `item_url`.
|
|
46
|
+
- `item` can be more sensitive to the active browser target than `search` or `store`.
|
|
47
|
+
|
|
48
|
+
## Troubleshooting
|
|
49
|
+
|
|
50
|
+
- If `opencli 1688 item` reports `did not expose product context`, first make sure the open page is a real `detail.1688.com` item page.
|
|
51
|
+
- If the browser target is too broad, retry with `OPENCLI_CDP_TARGET=detail.1688.com`.
|
|
52
|
+
- If you hit a slider or verification page, refresh the real page in Chrome and retry.
|
|
@@ -11,12 +11,16 @@ Browser adapter for [Doubao Chat](https://www.doubao.com/chat).
|
|
|
11
11
|
| `opencli doubao send "..."` | Send a message to the current Doubao chat |
|
|
12
12
|
| `opencli doubao read` | Read the visible Doubao conversation |
|
|
13
13
|
| `opencli doubao ask "..."` | Send a prompt and wait for a reply |
|
|
14
|
+
| `opencli doubao detail <id>` | 对话详情 |
|
|
15
|
+
| `opencli doubao history` | 历史对话列表 |
|
|
16
|
+
| `opencli doubao meeting-summary <id>` | 会议总结 |
|
|
17
|
+
| `opencli doubao meeting-transcript <id>` | 会议记录 |
|
|
14
18
|
|
|
15
19
|
## Prerequisites
|
|
16
20
|
|
|
17
21
|
- Chrome is running
|
|
18
22
|
- You are already logged into [doubao.com](https://www.doubao.com/)
|
|
19
|
-
-
|
|
23
|
+
- Browser Bridge extension is installed and enabled for OpenCLI
|
|
20
24
|
|
|
21
25
|
## Examples
|
|
22
26
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Hupu (虎扑)
|
|
2
|
+
|
|
3
|
+
**Mode**: 🌐 Public / 🔐 Browser · **Domain**: `bbs.hupu.com`
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| `opencli hupu hot` | Read Hupu hot threads |
|
|
10
|
+
| `opencli hupu search <keyword>` | Search Hupu threads by keyword |
|
|
11
|
+
| `opencli hupu detail <tid>` | Read one thread and optional hot replies |
|
|
12
|
+
| `opencli hupu reply <tid> <text>` | Reply to a thread or quote one reply |
|
|
13
|
+
| `opencli hupu like <tid> <pid>` | Like one reply |
|
|
14
|
+
| `opencli hupu unlike <tid> <pid>` | Cancel like on one reply |
|
|
15
|
+
|
|
16
|
+
## Usage Examples
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Hot threads
|
|
20
|
+
opencli hupu hot --limit 5
|
|
21
|
+
|
|
22
|
+
# Search threads
|
|
23
|
+
opencli hupu search 湖人 --limit 10
|
|
24
|
+
|
|
25
|
+
# Read one thread and include hot replies
|
|
26
|
+
opencli hupu detail 638234927 --replies true
|
|
27
|
+
|
|
28
|
+
# Reply to the thread
|
|
29
|
+
opencli hupu reply 638234927 "hello from opencli" --topic_id 502
|
|
30
|
+
|
|
31
|
+
# Quote one hot reply by pid
|
|
32
|
+
opencli hupu reply 638234927 "replying to this comment" --topic_id 502 --quote_id 174908
|
|
33
|
+
|
|
34
|
+
# Like / unlike one reply
|
|
35
|
+
opencli hupu like 638234927 174908 --fid 4860
|
|
36
|
+
opencli hupu unlike 638234927 174908 --fid 4860
|
|
37
|
+
|
|
38
|
+
# JSON output
|
|
39
|
+
opencli hupu detail 638234927 -f json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Notes
|
|
43
|
+
|
|
44
|
+
- `reply --topic_id` maps to Hupu's API `topicId`, for example `502` for Basketball News
|
|
45
|
+
- `reply --quote_id` is the quoted reply `pid`
|
|
46
|
+
- `like` / `unlike --fid` uses the forum ID from thread metadata
|
|
47
|
+
- `detail --replies true` appends top hot replies to the content field
|
|
48
|
+
|
|
49
|
+
## Prerequisites
|
|
50
|
+
|
|
51
|
+
- Chrome running and able to open `bbs.hupu.com`
|
|
52
|
+
- [Browser Bridge extension](/guide/browser-bridge) installed
|
|
53
|
+
- For `reply`, `like`, and `unlike`, a valid Hupu login session in Chrome is required
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| `opencli sinafinance news` | 新浪财经 7×24 小时实时快讯 | 🌐 Public |
|
|
10
10
|
| `opencli sinafinance rolling-news` | 新浪财经滚动新闻 | 🔐 Browser |
|
|
11
11
|
| `opencli sinafinance stock` | 新浪财经行情(A股/港股/美股) | 🌐 Public |
|
|
12
|
+
| `opencli sinafinance stock-rank` | 新浪财经热搜榜 | 🔐 Browser |
|
|
12
13
|
|
|
13
14
|
## Usage Examples
|
|
14
15
|
|
|
@@ -56,6 +57,28 @@ opencli sinafinance stock 招商证券
|
|
|
56
57
|
opencli sinafinance stock 贵州茅台 -f json
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
### stock-rank - 热搜榜
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Default A股热搜榜
|
|
64
|
+
opencli sinafinance stock-rank
|
|
65
|
+
|
|
66
|
+
# 港股热搜榜
|
|
67
|
+
opencli sinafinance stock-rank --market hk
|
|
68
|
+
|
|
69
|
+
# 美股热搜榜
|
|
70
|
+
opencli sinafinance stock-rank --market us
|
|
71
|
+
|
|
72
|
+
# 外汇热搜榜
|
|
73
|
+
opencli sinafinance stock-rank --market ft
|
|
74
|
+
|
|
75
|
+
# 期货热搜榜
|
|
76
|
+
opencli sinafinance stock-rank --market wh
|
|
77
|
+
|
|
78
|
+
# JSON output
|
|
79
|
+
opencli sinafinance stock-rank -f json
|
|
80
|
+
```
|
|
81
|
+
|
|
59
82
|
## Options
|
|
60
83
|
|
|
61
84
|
### news
|
|
@@ -71,11 +94,17 @@ opencli sinafinance stock 贵州茅台 -f json
|
|
|
71
94
|
|--------|-------------|
|
|
72
95
|
| `--market` | Market: `cn`, `hk`, `us`, `auto` (default: auto). When `auto`, searches in cn, hk, us order |
|
|
73
96
|
|
|
97
|
+
### stock-rank
|
|
98
|
+
|
|
99
|
+
| Option | Description |
|
|
100
|
+
|--------|-------------|
|
|
101
|
+
| `--market` | Market: `cn` (A股, 默认), `ft` (期货), `us` (美股), `wh` (外汇), `hk` (港股) |
|
|
102
|
+
|
|
74
103
|
## Prerequisites
|
|
75
104
|
|
|
76
105
|
- `news` & `stock`: No browser required — uses public API
|
|
77
|
-
- `rolling-news`: Chrome running and **logged into** `finance.sina.com.cn`
|
|
78
|
-
- For `rolling-news`: [Browser Bridge extension](/guide/browser-bridge) installed
|
|
106
|
+
- `rolling-news` & `stock-rank`: Chrome running and **logged into** `finance.sina.com.cn`
|
|
107
|
+
- For `rolling-news` & `stock-rank`: [Browser Bridge extension](/guide/browser-bridge) installed
|
|
79
108
|
|
|
80
109
|
## Notes
|
|
81
110
|
|
|
@@ -83,3 +112,4 @@ opencli sinafinance stock 贵州茅台 -f json
|
|
|
83
112
|
- `stock` supports Chinese names, Chinese codes, and ticker symbols; auto-detects market
|
|
84
113
|
- Market priority for auto-detection: cn (A股) → hk (港股) → us (美股)
|
|
85
114
|
- US stock `High`/`Low` columns show 52-week range; A股/港股 show today's range
|
|
115
|
+
- `stock-rank` scrapes the hot search list from the Sina Finance homepage; requires browser login
|
|
@@ -6,8 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
| Command | Description |
|
|
8
8
|
|---------|-------------|
|
|
9
|
-
| `opencli weibo hot` | |
|
|
9
|
+
| `opencli weibo hot` | 微博热搜 |
|
|
10
10
|
| `opencli weibo search` | Search Weibo posts by keyword |
|
|
11
|
+
| `opencli weibo feed` | 首页时间线 |
|
|
12
|
+
| `opencli weibo user` | 用户信息 |
|
|
13
|
+
| `opencli weibo me` | 我的信息 |
|
|
14
|
+
| `opencli weibo post` | 发微博 |
|
|
15
|
+
| `opencli weibo comments` | 微博评论 |
|
|
11
16
|
|
|
12
17
|
## Usage Examples
|
|
13
18
|
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|---------|-------------|
|
|
9
9
|
| `opencli wikipedia search` | Search Wikipedia articles |
|
|
10
10
|
| `opencli wikipedia summary` | Get Wikipedia article summary |
|
|
11
|
+
| `opencli wikipedia random` | Random Wikipedia article |
|
|
12
|
+
| `opencli wikipedia trending` | Trending Wikipedia articles |
|
|
11
13
|
|
|
12
14
|
## Usage Examples
|
|
13
15
|
|