@jackwener/opencli 1.0.6 → 1.1.1
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/.agents/skills/cross-project-adapter-migration/SKILL.md +2 -2
- package/.github/pull_request_template.md +7 -0
- package/.github/workflows/doc-check.yml +36 -0
- package/.github/workflows/docs.yml +7 -42
- package/CHANGELOG.md +23 -0
- package/CLI-EXPLORER.md +9 -8
- package/README.md +51 -10
- package/README.zh-CN.md +29 -11
- package/SKILL.md +102 -33
- package/dist/browser/cdp.js +6 -1
- package/dist/browser/page.d.ts +4 -1
- package/dist/browser/page.js +7 -1
- package/dist/build-manifest.js +23 -16
- package/dist/cli-manifest.json +951 -296
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +225 -148
- package/dist/clis/antigravity/serve.js +296 -47
- package/dist/clis/apple-podcasts/commands.test.d.ts +2 -0
- package/dist/clis/apple-podcasts/commands.test.js +76 -0
- package/dist/clis/apple-podcasts/search.js +2 -2
- package/dist/clis/apple-podcasts/top.js +9 -2
- package/dist/clis/arxiv/paper.js +21 -0
- package/dist/clis/arxiv/search.js +24 -0
- package/dist/clis/arxiv/utils.d.ts +18 -0
- package/dist/clis/arxiv/utils.js +49 -0
- package/dist/clis/bilibili/dynamic.js +1 -1
- package/dist/clis/bilibili/favorite.js +1 -1
- package/dist/clis/bilibili/feed.js +1 -1
- package/dist/clis/bilibili/following.js +1 -1
- package/dist/clis/bilibili/history.js +1 -1
- package/dist/clis/bilibili/me.js +1 -1
- package/dist/clis/bilibili/ranking.js +1 -1
- package/dist/clis/bilibili/search.js +3 -3
- package/dist/clis/bilibili/subtitle.js +1 -1
- package/dist/clis/bilibili/user-videos.js +1 -1
- package/dist/{bilibili.d.ts → clis/bilibili/utils.d.ts} +1 -1
- package/dist/clis/bloomberg/businessweek.d.ts +1 -0
- package/dist/clis/bloomberg/businessweek.js +17 -0
- package/dist/clis/bloomberg/economics.d.ts +1 -0
- package/dist/clis/bloomberg/economics.js +17 -0
- package/dist/clis/bloomberg/feeds.d.ts +1 -0
- package/dist/clis/bloomberg/feeds.js +15 -0
- package/dist/clis/bloomberg/industries.d.ts +1 -0
- package/dist/clis/bloomberg/industries.js +17 -0
- package/dist/clis/bloomberg/main.d.ts +1 -0
- package/dist/clis/bloomberg/main.js +17 -0
- package/dist/clis/bloomberg/markets.d.ts +1 -0
- package/dist/clis/bloomberg/markets.js +17 -0
- package/dist/clis/bloomberg/news.d.ts +1 -0
- package/dist/clis/bloomberg/news.js +105 -0
- package/dist/clis/bloomberg/opinions.d.ts +1 -0
- package/dist/clis/bloomberg/opinions.js +17 -0
- package/dist/clis/bloomberg/politics.d.ts +1 -0
- package/dist/clis/bloomberg/politics.js +17 -0
- package/dist/clis/bloomberg/tech.d.ts +1 -0
- package/dist/clis/bloomberg/tech.js +17 -0
- package/dist/clis/bloomberg/utils.d.ts +34 -0
- package/dist/clis/bloomberg/utils.js +364 -0
- package/dist/clis/bloomberg/utils.test.d.ts +1 -0
- package/dist/clis/bloomberg/utils.test.js +129 -0
- package/dist/clis/boss/batchgreet.d.ts +1 -0
- package/dist/clis/boss/batchgreet.js +147 -0
- package/dist/clis/boss/chatlist.js +2 -2
- package/dist/clis/boss/detail.js +2 -2
- package/dist/clis/boss/exchange.d.ts +1 -0
- package/dist/clis/boss/exchange.js +111 -0
- package/dist/clis/boss/greet.d.ts +1 -0
- package/dist/clis/boss/greet.js +175 -0
- package/dist/clis/boss/invite.d.ts +1 -0
- package/dist/clis/boss/invite.js +158 -0
- package/dist/clis/boss/joblist.d.ts +1 -0
- package/dist/clis/boss/joblist.js +55 -0
- package/dist/clis/boss/mark.d.ts +1 -0
- package/dist/clis/boss/mark.js +141 -0
- package/dist/clis/boss/recommend.d.ts +1 -0
- package/dist/clis/boss/recommend.js +83 -0
- package/dist/clis/boss/search.js +1 -1
- package/dist/clis/boss/send.js +1 -1
- package/dist/clis/boss/stats.d.ts +1 -0
- package/dist/clis/boss/stats.js +116 -0
- package/dist/clis/chaoxing/assignments.js +1 -1
- package/dist/clis/chaoxing/exams.js +1 -1
- package/dist/{chaoxing.d.ts → clis/chaoxing/utils.d.ts} +1 -1
- package/dist/{chaoxing.js → clis/chaoxing/utils.js} +0 -2
- package/dist/clis/chaoxing/utils.test.d.ts +1 -0
- package/dist/{chaoxing.test.js → clis/chaoxing/utils.test.js} +1 -1
- package/dist/clis/chatgpt/read.js +1 -1
- package/dist/clis/chatwise/export.js +1 -1
- package/dist/clis/chatwise/model.js +2 -2
- package/dist/clis/chatwise/screenshot.js +1 -1
- package/dist/clis/codex/export.js +1 -1
- package/dist/clis/codex/model.js +2 -2
- package/dist/clis/codex/screenshot.js +1 -1
- package/dist/clis/coupang/add-to-cart.js +3 -4
- package/dist/clis/coupang/search.js +2 -4
- package/dist/clis/coupang/utils.test.d.ts +1 -0
- package/dist/{coupang.test.js → clis/coupang/utils.test.js} +1 -1
- package/dist/clis/ctrip/search.js +1 -1
- package/dist/clis/cursor/export.js +1 -1
- package/dist/clis/cursor/model.js +2 -2
- package/dist/clis/cursor/screenshot.js +1 -1
- package/dist/clis/jike/comment.js +2 -3
- package/dist/clis/jike/create.js +1 -2
- package/dist/clis/jike/feed.js +0 -1
- package/dist/clis/jike/like.js +1 -2
- package/dist/clis/jike/notifications.js +0 -1
- package/dist/clis/jike/post.yaml +1 -0
- package/dist/clis/jike/repost.js +1 -2
- package/dist/clis/jike/search.js +2 -3
- package/dist/clis/jike/topic.yaml +1 -0
- package/dist/clis/jike/user.yaml +1 -0
- package/dist/clis/jimeng/history.yaml +0 -1
- package/dist/clis/linkedin/search.js +7 -7
- package/dist/clis/linux-do/category.yaml +1 -0
- package/dist/clis/linux-do/search.yaml +4 -3
- package/dist/clis/linux-do/topic.yaml +1 -0
- package/dist/clis/notion/export.js +1 -1
- package/dist/clis/reddit/comment.js +3 -4
- package/dist/clis/reddit/read.js +4 -5
- package/dist/clis/reddit/save.js +2 -3
- package/dist/clis/reddit/saved.js +0 -1
- package/dist/clis/reddit/search.yaml +1 -0
- package/dist/clis/reddit/subscribe.js +0 -1
- package/dist/clis/reddit/upvote.js +2 -3
- package/dist/clis/reddit/upvoted.js +0 -1
- package/dist/clis/reddit/user-comments.yaml +1 -0
- package/dist/clis/reddit/user-posts.yaml +1 -0
- package/dist/clis/reddit/user.yaml +1 -0
- package/dist/clis/reuters/search.js +1 -1
- package/dist/clis/sinafinance/news.d.ts +7 -0
- package/dist/clis/sinafinance/news.js +61 -0
- package/dist/clis/smzdm/search.js +2 -3
- package/dist/clis/stackoverflow/search.yaml +1 -0
- package/dist/clis/steam/top-sellers.yaml +29 -0
- package/dist/clis/twitter/accept.js +2 -2
- package/dist/clis/twitter/article.js +2 -2
- package/dist/clis/twitter/block.d.ts +1 -0
- package/dist/clis/twitter/block.js +88 -0
- package/dist/clis/twitter/delete.js +1 -1
- package/dist/clis/twitter/hide-reply.d.ts +1 -0
- package/dist/clis/twitter/hide-reply.js +66 -0
- package/dist/clis/twitter/like.js +1 -1
- package/dist/clis/twitter/post.js +1 -1
- package/dist/clis/twitter/reply-dm.js +1 -1
- package/dist/clis/twitter/reply.js +2 -2
- package/dist/clis/twitter/search.js +1 -1
- package/dist/clis/twitter/thread.js +2 -2
- package/dist/clis/twitter/trending.d.ts +1 -0
- package/dist/clis/twitter/trending.js +91 -0
- package/dist/clis/twitter/unblock.d.ts +1 -0
- package/dist/clis/twitter/unblock.js +71 -0
- package/dist/clis/v2ex/topic.yaml +1 -0
- package/dist/clis/weibo/hot.js +0 -1
- package/dist/clis/weread/book.js +1 -1
- package/dist/clis/weread/highlights.js +1 -1
- package/dist/clis/weread/notes.js +1 -1
- package/dist/clis/weread/search.js +1 -1
- package/dist/clis/wikipedia/search.d.ts +1 -0
- package/dist/clis/wikipedia/search.js +30 -0
- package/dist/clis/wikipedia/summary.d.ts +1 -0
- package/dist/clis/wikipedia/summary.js +28 -0
- package/dist/clis/wikipedia/utils.d.ts +8 -0
- package/dist/clis/wikipedia/utils.js +18 -0
- package/dist/clis/xiaohongshu/creator-note-detail.d.ts +79 -5
- package/dist/clis/xiaohongshu/creator-note-detail.js +323 -70
- package/dist/clis/xiaohongshu/creator-note-detail.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +258 -0
- package/dist/clis/xiaohongshu/creator-notes-summary.d.ts +28 -0
- package/dist/clis/xiaohongshu/creator-notes-summary.js +92 -0
- package/dist/clis/xiaohongshu/creator-notes-summary.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/creator-notes-summary.test.js +49 -0
- package/dist/clis/xiaohongshu/creator-notes.d.ts +18 -5
- package/dist/clis/xiaohongshu/creator-notes.js +189 -71
- package/dist/clis/xiaohongshu/creator-notes.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/creator-notes.test.js +191 -0
- package/dist/clis/xiaohongshu/creator-profile.js +0 -1
- package/dist/clis/xiaohongshu/creator-stats.js +0 -1
- package/dist/clis/xiaohongshu/download.js +2 -3
- package/dist/clis/xiaohongshu/feed.yaml +0 -1
- package/dist/clis/xiaohongshu/notifications.yaml +0 -1
- package/dist/clis/xiaohongshu/search.js +2 -2
- package/dist/clis/xiaohongshu/user.js +1 -2
- package/dist/clis/yahoo-finance/quote.js +0 -1
- package/dist/clis/youtube/search.js +1 -1
- package/dist/clis/youtube/transcript.js +1 -1
- package/dist/clis/youtube/video.js +1 -1
- package/dist/clis/zhihu/download.js +1 -2
- package/dist/clis/zhihu/question.js +1 -1
- package/dist/clis/zhihu/search.yaml +4 -3
- package/dist/commanderAdapter.d.ts +21 -0
- package/dist/commanderAdapter.js +111 -0
- package/dist/{engine.d.ts → discovery.d.ts} +0 -6
- package/dist/{engine.js → discovery.js} +1 -98
- package/dist/download/index.d.ts +2 -6
- package/dist/download/index.js +19 -46
- package/dist/engine.test.d.ts +1 -1
- package/dist/engine.test.js +8 -7
- package/dist/execution.d.ts +22 -0
- package/dist/execution.js +129 -0
- package/dist/explore.js +121 -107
- package/dist/external-clis.yaml +48 -0
- package/dist/external.d.ts +25 -0
- package/dist/external.js +156 -0
- package/dist/main.js +1 -1
- package/dist/pipeline/steps/browser.js +8 -2
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +2 -0
- package/dist/runtime.d.ts +5 -0
- package/dist/runtime.js +8 -0
- package/dist/serialization.d.ts +34 -0
- package/dist/serialization.js +63 -0
- package/dist/types.d.ts +4 -1
- package/docs/.vitepress/config.mts +14 -3
- package/docs/adapters/browser/arxiv.md +27 -0
- package/docs/adapters/browser/barchart.md +32 -0
- package/docs/adapters/browser/bloomberg.md +70 -0
- package/docs/adapters/browser/chaoxing.md +39 -0
- package/docs/adapters/browser/grok.md +35 -0
- package/docs/adapters/browser/hf.md +42 -0
- package/docs/adapters/browser/jike.md +45 -0
- package/docs/adapters/browser/jimeng.md +39 -0
- package/docs/adapters/browser/linux-do.md +45 -0
- package/docs/adapters/browser/sinafinance.md +35 -0
- package/docs/adapters/browser/stackoverflow.md +35 -0
- package/docs/adapters/browser/steam.md +26 -0
- package/docs/adapters/browser/twitter.md +3 -0
- package/docs/adapters/browser/weread.md +48 -0
- package/docs/adapters/browser/wikipedia.md +30 -0
- package/docs/adapters/browser/xiaohongshu.md +5 -1
- package/docs/adapters/desktop/chatgpt.md +3 -3
- package/docs/adapters/index.md +13 -0
- package/docs/advanced/download.md +4 -4
- package/docs/developer/architecture.md +17 -4
- package/package.json +1 -1
- package/scripts/check-doc-coverage.sh +69 -0
- package/scripts/copy-yaml.cjs +7 -0
- package/src/browser/cdp.ts +9 -4
- package/src/browser/page.ts +7 -1
- package/src/build-manifest.ts +25 -19
- package/src/cli.ts +253 -119
- package/src/clis/antigravity/serve.ts +323 -50
- package/src/clis/apple-podcasts/commands.test.ts +95 -0
- package/src/clis/apple-podcasts/search.ts +2 -2
- package/src/clis/apple-podcasts/top.ts +12 -2
- package/src/clis/arxiv/paper.ts +21 -0
- package/src/clis/arxiv/search.ts +24 -0
- package/src/clis/arxiv/utils.ts +63 -0
- package/src/clis/bilibili/dynamic.ts +1 -1
- package/src/clis/bilibili/favorite.ts +1 -1
- package/src/clis/bilibili/feed.ts +1 -1
- package/src/clis/bilibili/following.ts +1 -1
- package/src/clis/bilibili/history.ts +1 -1
- package/src/clis/bilibili/me.ts +1 -1
- package/src/clis/bilibili/ranking.ts +1 -1
- package/src/clis/bilibili/search.ts +3 -3
- package/src/clis/bilibili/subtitle.ts +1 -1
- package/src/clis/bilibili/user-videos.ts +1 -1
- package/src/{bilibili.ts → clis/bilibili/utils.ts} +1 -1
- package/src/clis/bloomberg/businessweek.ts +18 -0
- package/src/clis/bloomberg/economics.ts +18 -0
- package/src/clis/bloomberg/feeds.ts +16 -0
- package/src/clis/bloomberg/industries.ts +18 -0
- package/src/clis/bloomberg/main.ts +18 -0
- package/src/clis/bloomberg/markets.ts +18 -0
- package/src/clis/bloomberg/news.ts +136 -0
- package/src/clis/bloomberg/opinions.ts +18 -0
- package/src/clis/bloomberg/politics.ts +18 -0
- package/src/clis/bloomberg/tech.ts +18 -0
- package/src/clis/bloomberg/utils.test.ts +135 -0
- package/src/clis/bloomberg/utils.ts +429 -0
- package/src/clis/boss/batchgreet.ts +167 -0
- package/src/clis/boss/chatlist.ts +2 -2
- package/src/clis/boss/detail.ts +2 -2
- package/src/clis/boss/exchange.ts +126 -0
- package/src/clis/boss/greet.ts +198 -0
- package/src/clis/boss/invite.ts +177 -0
- package/src/clis/boss/joblist.ts +63 -0
- package/src/clis/boss/mark.ts +155 -0
- package/src/clis/boss/recommend.ts +94 -0
- package/src/clis/boss/search.ts +1 -1
- package/src/clis/boss/send.ts +1 -1
- package/src/clis/boss/stats.ts +130 -0
- package/src/clis/chaoxing/assignments.ts +1 -1
- package/src/clis/chaoxing/exams.ts +1 -1
- package/src/{chaoxing.test.ts → clis/chaoxing/utils.test.ts} +1 -1
- package/src/{chaoxing.ts → clis/chaoxing/utils.ts} +1 -3
- package/src/clis/chatgpt/README.zh-CN.md +3 -3
- package/src/clis/chatgpt/read.ts +1 -1
- package/src/clis/chatwise/export.ts +1 -1
- package/src/clis/chatwise/model.ts +2 -2
- package/src/clis/chatwise/screenshot.ts +1 -1
- package/src/clis/codex/export.ts +1 -1
- package/src/clis/codex/model.ts +2 -2
- package/src/clis/codex/screenshot.ts +1 -1
- package/src/clis/coupang/add-to-cart.ts +3 -4
- package/src/clis/coupang/search.ts +2 -4
- package/src/{coupang.test.ts → clis/coupang/utils.test.ts} +1 -1
- package/src/clis/ctrip/search.ts +1 -1
- package/src/clis/cursor/export.ts +1 -1
- package/src/clis/cursor/model.ts +2 -2
- package/src/clis/cursor/screenshot.ts +1 -1
- package/src/clis/jike/comment.ts +2 -3
- package/src/clis/jike/create.ts +1 -2
- package/src/clis/jike/feed.ts +0 -1
- package/src/clis/jike/like.ts +1 -2
- package/src/clis/jike/notifications.ts +0 -1
- package/src/clis/jike/post.yaml +1 -0
- package/src/clis/jike/repost.ts +1 -2
- package/src/clis/jike/search.ts +2 -3
- package/src/clis/jike/topic.yaml +1 -0
- package/src/clis/jike/user.yaml +1 -0
- package/src/clis/jimeng/history.yaml +0 -1
- package/src/clis/linkedin/search.ts +7 -7
- package/src/clis/linux-do/category.yaml +1 -0
- package/src/clis/linux-do/search.yaml +4 -3
- package/src/clis/linux-do/topic.yaml +1 -0
- package/src/clis/notion/export.ts +1 -1
- package/src/clis/reddit/comment.ts +3 -4
- package/src/clis/reddit/read.ts +4 -5
- package/src/clis/reddit/save.ts +2 -3
- package/src/clis/reddit/saved.ts +0 -1
- package/src/clis/reddit/search.yaml +1 -0
- package/src/clis/reddit/subscribe.ts +0 -1
- package/src/clis/reddit/upvote.ts +2 -3
- package/src/clis/reddit/upvoted.ts +0 -1
- package/src/clis/reddit/user-comments.yaml +1 -0
- package/src/clis/reddit/user-posts.yaml +1 -0
- package/src/clis/reddit/user.yaml +1 -0
- package/src/clis/reuters/search.ts +1 -1
- package/src/clis/sinafinance/news.ts +76 -0
- package/src/clis/smzdm/search.ts +2 -3
- package/src/clis/stackoverflow/search.yaml +1 -0
- package/src/clis/steam/top-sellers.yaml +29 -0
- package/src/clis/twitter/accept.ts +2 -2
- package/src/clis/twitter/article.ts +2 -2
- package/src/clis/twitter/block.ts +92 -0
- package/src/clis/twitter/delete.ts +1 -1
- package/src/clis/twitter/hide-reply.ts +70 -0
- package/src/clis/twitter/like.ts +1 -1
- package/src/clis/twitter/post.ts +1 -1
- package/src/clis/twitter/reply-dm.ts +1 -1
- package/src/clis/twitter/reply.ts +2 -2
- package/src/clis/twitter/search.ts +1 -1
- package/src/clis/twitter/thread.ts +2 -2
- package/src/clis/twitter/trending.ts +113 -0
- package/src/clis/twitter/unblock.ts +75 -0
- package/src/clis/v2ex/topic.yaml +1 -0
- package/src/clis/weibo/hot.ts +0 -1
- package/src/clis/weread/book.ts +1 -1
- package/src/clis/weread/highlights.ts +1 -1
- package/src/clis/weread/notes.ts +1 -1
- package/src/clis/weread/search.ts +1 -1
- package/src/clis/wikipedia/search.ts +32 -0
- package/src/clis/wikipedia/summary.ts +28 -0
- package/src/clis/wikipedia/utils.ts +20 -0
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +272 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +425 -73
- package/src/clis/xiaohongshu/creator-notes-summary.test.ts +54 -0
- package/src/clis/xiaohongshu/creator-notes-summary.ts +120 -0
- package/src/clis/xiaohongshu/creator-notes.test.ts +211 -0
- package/src/clis/xiaohongshu/creator-notes.ts +254 -75
- package/src/clis/xiaohongshu/creator-profile.ts +0 -1
- package/src/clis/xiaohongshu/creator-stats.ts +0 -1
- package/src/clis/xiaohongshu/download.ts +2 -3
- package/src/clis/xiaohongshu/feed.yaml +0 -1
- package/src/clis/xiaohongshu/notifications.yaml +0 -1
- package/src/clis/xiaohongshu/search.ts +2 -2
- package/src/clis/xiaohongshu/user.ts +1 -2
- package/src/clis/yahoo-finance/quote.ts +0 -1
- package/src/clis/youtube/search.ts +1 -1
- package/src/clis/youtube/transcript.ts +1 -1
- package/src/clis/youtube/video.ts +1 -1
- package/src/clis/zhihu/download.ts +1 -2
- package/src/clis/zhihu/question.ts +1 -1
- package/src/clis/zhihu/search.yaml +4 -3
- package/src/commanderAdapter.ts +113 -0
- package/src/daemon.ts +3 -3
- package/src/{engine.ts → discovery.ts} +1 -108
- package/src/download/index.ts +21 -54
- package/src/engine.test.ts +8 -7
- package/src/execution.ts +138 -0
- package/src/explore.ts +135 -109
- package/src/external-clis.yaml +48 -0
- package/src/external.ts +185 -0
- package/src/main.ts +1 -1
- package/src/pipeline/steps/browser.ts +7 -2
- package/src/registry.ts +5 -0
- package/src/runtime.ts +9 -0
- package/src/serialization.ts +79 -0
- package/src/types.ts +1 -1
- package/tests/e2e/browser-public.test.ts +25 -0
- package/tests/e2e/public-commands.test.ts +55 -1
- package/dist/clis/twitter/trending.yaml +0 -46
- package/src/clis/twitter/trending.yaml +0 -46
- /package/dist/{chaoxing.test.d.ts → clis/arxiv/paper.d.ts} +0 -0
- /package/dist/{coupang.test.d.ts → clis/arxiv/search.d.ts} +0 -0
- /package/dist/{bilibili.js → clis/bilibili/utils.js} +0 -0
- /package/dist/{coupang.d.ts → clis/coupang/utils.d.ts} +0 -0
- /package/dist/{coupang.js → clis/coupang/utils.js} +0 -0
- /package/src/{coupang.ts → clis/coupang/utils.ts} +0 -0
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point: registers built-in commands and wires up Commander.
|
|
3
|
+
*
|
|
4
|
+
* Built-in commands are registered inline here (list, validate, explore, etc.).
|
|
5
|
+
* Dynamic adapter commands are registered via commanderAdapter.ts.
|
|
6
|
+
*/
|
|
1
7
|
export declare function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void;
|
package/dist/cli.js
CHANGED
|
@@ -1,41 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point: registers built-in commands and wires up Commander.
|
|
3
|
+
*
|
|
4
|
+
* Built-in commands are registered inline here (list, validate, explore, etc.).
|
|
5
|
+
* Dynamic adapter commands are registered via commanderAdapter.ts.
|
|
6
|
+
*/
|
|
1
7
|
import { Command } from 'commander';
|
|
2
8
|
import chalk from 'chalk';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
9
|
+
import { fullName, getRegistry, strategyLabel } from './registry.js';
|
|
10
|
+
import { serializeCommand, formatArgSummary } from './serialization.js';
|
|
5
11
|
import { render as renderOutput } from './output.js';
|
|
6
|
-
import {
|
|
7
|
-
import { browserSession, DEFAULT_BROWSER_COMMAND_TIMEOUT, runWithTimeout } from './runtime.js';
|
|
12
|
+
import { getBrowserFactory, browserSession } from './runtime.js';
|
|
8
13
|
import { PKG_VERSION } from './version.js';
|
|
9
14
|
import { printCompletionScript } from './completion.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
15
|
+
import { loadExternalClis, executeExternalCli, installExternalCli, registerExternalCli, isBinaryInstalled } from './external.js';
|
|
16
|
+
import { registerAllCommands } from './commanderAdapter.js';
|
|
12
17
|
export function runCli(BUILTIN_CLIS, USER_CLIS) {
|
|
13
18
|
const program = new Command();
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
program
|
|
19
|
+
// enablePositionalOptions: prevents parent from consuming flags meant for subcommands;
|
|
20
|
+
// prerequisite for passThroughOptions to forward --help/--version to external binaries
|
|
21
|
+
program
|
|
22
|
+
.name('opencli')
|
|
23
|
+
.description('Make any website your CLI. Zero setup. AI-powered.')
|
|
24
|
+
.version(PKG_VERSION)
|
|
25
|
+
.enablePositionalOptions();
|
|
26
|
+
// ── Built-in: list ────────────────────────────────────────────────────────
|
|
27
|
+
program
|
|
28
|
+
.command('list')
|
|
29
|
+
.description('List all available CLI commands')
|
|
30
|
+
.option('-f, --format <fmt>', 'Output format: table, json, yaml, md, csv', 'table')
|
|
31
|
+
.option('--json', 'JSON output (deprecated)')
|
|
17
32
|
.action((opts) => {
|
|
18
33
|
const registry = getRegistry();
|
|
19
34
|
const commands = [...registry.values()].sort((a, b) => fullName(a).localeCompare(fullName(b)));
|
|
20
|
-
const rows = commands.map(c => ({
|
|
21
|
-
command: fullName(c),
|
|
22
|
-
site: c.site,
|
|
23
|
-
name: c.name,
|
|
24
|
-
description: c.description,
|
|
25
|
-
strategy: strategyLabel(c),
|
|
26
|
-
browser: c.browser,
|
|
27
|
-
args: c.args.map(a => a.name).join(', '),
|
|
28
|
-
}));
|
|
29
35
|
const fmt = opts.json && opts.format === 'table' ? 'json' : opts.format;
|
|
36
|
+
const isStructured = fmt === 'json' || fmt === 'yaml';
|
|
30
37
|
if (fmt !== 'table') {
|
|
38
|
+
const rows = isStructured
|
|
39
|
+
? commands.map(serializeCommand)
|
|
40
|
+
: commands.map(c => ({
|
|
41
|
+
command: fullName(c),
|
|
42
|
+
site: c.site,
|
|
43
|
+
name: c.name,
|
|
44
|
+
description: c.description,
|
|
45
|
+
strategy: strategyLabel(c),
|
|
46
|
+
browser: !!c.browser,
|
|
47
|
+
args: formatArgSummary(c.args),
|
|
48
|
+
}));
|
|
31
49
|
renderOutput(rows, {
|
|
32
50
|
fmt,
|
|
33
|
-
columns: ['command', 'site', 'name', 'description', 'strategy', 'browser', 'args'
|
|
51
|
+
columns: ['command', 'site', 'name', 'description', 'strategy', 'browser', 'args',
|
|
52
|
+
...(isStructured ? ['columns', 'domain'] : [])],
|
|
34
53
|
title: 'opencli/list',
|
|
35
54
|
source: 'opencli list',
|
|
36
55
|
});
|
|
37
56
|
return;
|
|
38
57
|
}
|
|
58
|
+
// Table (default) — grouped by site
|
|
39
59
|
const sites = new Map();
|
|
40
60
|
for (const cmd of commands) {
|
|
41
61
|
const g = sites.get(cmd.site) ?? [];
|
|
@@ -48,48 +68,113 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
|
|
|
48
68
|
for (const [site, cmds] of sites) {
|
|
49
69
|
console.log(chalk.bold.cyan(` ${site}`));
|
|
50
70
|
for (const cmd of cmds) {
|
|
51
|
-
const tag = strategyLabel(cmd) === 'public'
|
|
71
|
+
const tag = strategyLabel(cmd) === 'public'
|
|
72
|
+
? chalk.green('[public]')
|
|
73
|
+
: chalk.yellow(`[${strategyLabel(cmd)}]`);
|
|
52
74
|
console.log(` ${cmd.name} ${tag}${cmd.description ? chalk.dim(` — ${cmd.description}`) : ''}`);
|
|
53
75
|
}
|
|
54
76
|
console.log();
|
|
55
77
|
}
|
|
56
|
-
|
|
78
|
+
const externalClis = loadExternalClis();
|
|
79
|
+
if (externalClis.length > 0) {
|
|
80
|
+
console.log(chalk.bold.cyan(' external CLIs'));
|
|
81
|
+
for (const ext of externalClis) {
|
|
82
|
+
const isInstalled = isBinaryInstalled(ext.binary);
|
|
83
|
+
const tag = isInstalled ? chalk.green('[installed]') : chalk.yellow('[auto-install]');
|
|
84
|
+
console.log(` ${ext.name} ${tag}${ext.description ? chalk.dim(` — ${ext.description}`) : ''}`);
|
|
85
|
+
}
|
|
86
|
+
console.log();
|
|
87
|
+
}
|
|
88
|
+
console.log(chalk.dim(` ${commands.length} built-in commands across ${sites.size} sites, ${externalClis.length} external CLIs`));
|
|
57
89
|
console.log();
|
|
58
90
|
});
|
|
59
|
-
|
|
91
|
+
// ── Built-in: validate / verify ───────────────────────────────────────────
|
|
92
|
+
program
|
|
93
|
+
.command('validate')
|
|
94
|
+
.description('Validate CLI definitions')
|
|
95
|
+
.argument('[target]', 'site or site/name')
|
|
60
96
|
.action(async (target) => {
|
|
61
97
|
const { validateClisWithTarget, renderValidationReport } = await import('./validate.js');
|
|
62
98
|
console.log(renderValidationReport(validateClisWithTarget([BUILTIN_CLIS, USER_CLIS], target)));
|
|
63
99
|
});
|
|
64
|
-
program
|
|
100
|
+
program
|
|
101
|
+
.command('verify')
|
|
102
|
+
.description('Validate + smoke test')
|
|
103
|
+
.argument('[target]')
|
|
104
|
+
.option('--smoke', 'Run smoke tests', false)
|
|
65
105
|
.action(async (target, opts) => {
|
|
66
106
|
const { verifyClis, renderVerifyReport } = await import('./verify.js');
|
|
67
107
|
const r = await verifyClis({ builtinClis: BUILTIN_CLIS, userClis: USER_CLIS, target, smoke: opts.smoke });
|
|
68
108
|
console.log(renderVerifyReport(r));
|
|
69
109
|
process.exitCode = r.ok ? 0 : 1;
|
|
70
110
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
111
|
+
// ── Built-in: explore / synthesize / generate / cascade ───────────────────
|
|
112
|
+
program
|
|
113
|
+
.command('explore')
|
|
114
|
+
.alias('probe')
|
|
115
|
+
.description('Explore a website: discover APIs, stores, and recommend strategies')
|
|
116
|
+
.argument('<url>')
|
|
117
|
+
.option('--site <name>')
|
|
118
|
+
.option('--goal <text>')
|
|
119
|
+
.option('--wait <s>', '', '3')
|
|
120
|
+
.option('--auto', 'Enable interactive fuzzing')
|
|
121
|
+
.option('--click <labels>', 'Comma-separated labels to click before fuzzing')
|
|
122
|
+
.action(async (url, opts) => {
|
|
123
|
+
const { exploreUrl, renderExploreSummary } = await import('./explore.js');
|
|
124
|
+
const clickLabels = opts.click
|
|
125
|
+
? opts.click.split(',').map((s) => s.trim())
|
|
126
|
+
: undefined;
|
|
127
|
+
const workspace = `explore:${inferHost(url, opts.site)}`;
|
|
128
|
+
const result = await exploreUrl(url, {
|
|
129
|
+
BrowserFactory: getBrowserFactory(),
|
|
130
|
+
site: opts.site,
|
|
131
|
+
goal: opts.goal,
|
|
132
|
+
waitSeconds: parseFloat(opts.wait),
|
|
133
|
+
auto: opts.auto,
|
|
134
|
+
clickLabels,
|
|
135
|
+
workspace,
|
|
136
|
+
});
|
|
137
|
+
console.log(renderExploreSummary(result));
|
|
138
|
+
});
|
|
139
|
+
program
|
|
140
|
+
.command('synthesize')
|
|
141
|
+
.description('Synthesize CLIs from explore')
|
|
142
|
+
.argument('<target>')
|
|
143
|
+
.option('--top <n>', '', '3')
|
|
144
|
+
.action(async (target, opts) => {
|
|
145
|
+
const { synthesizeFromExplore, renderSynthesizeSummary } = await import('./synthesize.js');
|
|
146
|
+
console.log(renderSynthesizeSummary(synthesizeFromExplore(target, { top: parseInt(opts.top) })));
|
|
147
|
+
});
|
|
148
|
+
program
|
|
149
|
+
.command('generate')
|
|
150
|
+
.description('One-shot: explore → synthesize → register')
|
|
151
|
+
.argument('<url>')
|
|
152
|
+
.option('--goal <text>')
|
|
153
|
+
.option('--site <name>')
|
|
154
|
+
.action(async (url, opts) => {
|
|
155
|
+
const { generateCliFromUrl, renderGenerateSummary } = await import('./generate.js');
|
|
156
|
+
const workspace = `generate:${inferHost(url, opts.site)}`;
|
|
157
|
+
const r = await generateCliFromUrl({
|
|
158
|
+
url,
|
|
159
|
+
BrowserFactory: getBrowserFactory(),
|
|
160
|
+
builtinClis: BUILTIN_CLIS,
|
|
161
|
+
userClis: USER_CLIS,
|
|
162
|
+
goal: opts.goal,
|
|
163
|
+
site: opts.site,
|
|
164
|
+
workspace,
|
|
165
|
+
});
|
|
166
|
+
console.log(renderGenerateSummary(r));
|
|
167
|
+
process.exitCode = r.ok ? 0 : 1;
|
|
168
|
+
});
|
|
169
|
+
program
|
|
170
|
+
.command('cascade')
|
|
171
|
+
.description('Strategy cascade: find simplest working strategy')
|
|
172
|
+
.argument('<url>')
|
|
173
|
+
.option('--site <name>')
|
|
88
174
|
.action(async (url, opts) => {
|
|
89
175
|
const { cascadeProbe, renderCascadeResult } = await import('./cascade.js');
|
|
90
|
-
const
|
|
91
|
-
const result = await browserSession(
|
|
92
|
-
// Navigate to the site first for cookie context
|
|
176
|
+
const workspace = `cascade:${inferHost(url, opts.site)}`;
|
|
177
|
+
const result = await browserSession(getBrowserFactory(), async (page) => {
|
|
93
178
|
try {
|
|
94
179
|
const siteUrl = new URL(url);
|
|
95
180
|
await page.goto(`${siteUrl.protocol}//${siteUrl.host}`);
|
|
@@ -97,15 +182,12 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
|
|
|
97
182
|
}
|
|
98
183
|
catch { }
|
|
99
184
|
return cascadeProbe(page, url);
|
|
100
|
-
}, { workspace
|
|
101
|
-
return new URL(url).host;
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return 'default';
|
|
105
|
-
} })()}` });
|
|
185
|
+
}, { workspace });
|
|
106
186
|
console.log(renderCascadeResult(result));
|
|
107
187
|
});
|
|
108
|
-
|
|
188
|
+
// ── Built-in: doctor / setup / completion ─────────────────────────────────
|
|
189
|
+
program
|
|
190
|
+
.command('doctor')
|
|
109
191
|
.description('Diagnose opencli browser bridge connectivity')
|
|
110
192
|
.option('--live', 'Test browser connectivity (requires Chrome running)', false)
|
|
111
193
|
.option('--sessions', 'Show active automation sessions', false)
|
|
@@ -114,124 +196,119 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
|
|
|
114
196
|
const report = await runBrowserDoctor({ live: opts.live, sessions: opts.sessions, cliVersion: PKG_VERSION });
|
|
115
197
|
console.log(renderBrowserDoctorReport(report));
|
|
116
198
|
});
|
|
117
|
-
program
|
|
199
|
+
program
|
|
200
|
+
.command('setup')
|
|
118
201
|
.description('Interactive setup: verify browser bridge connectivity')
|
|
119
202
|
.action(async () => {
|
|
120
203
|
const { runSetup } = await import('./setup.js');
|
|
121
204
|
await runSetup({ cliVersion: PKG_VERSION });
|
|
122
205
|
});
|
|
123
|
-
program
|
|
206
|
+
program
|
|
207
|
+
.command('completion')
|
|
124
208
|
.description('Output shell completion script')
|
|
125
209
|
.argument('<shell>', 'Shell type: bash, zsh, or fish')
|
|
126
210
|
.action((shell) => {
|
|
127
211
|
printCompletionScript(shell);
|
|
128
212
|
});
|
|
129
|
-
// ──
|
|
213
|
+
// ── External CLIs ─────────────────────────────────────────────────────────
|
|
214
|
+
const externalClis = loadExternalClis();
|
|
215
|
+
program
|
|
216
|
+
.command('install')
|
|
217
|
+
.description('Install an external CLI')
|
|
218
|
+
.argument('<name>', 'Name of the external CLI')
|
|
219
|
+
.action((name) => {
|
|
220
|
+
const ext = externalClis.find(e => e.name === name);
|
|
221
|
+
if (!ext) {
|
|
222
|
+
console.error(chalk.red(`External CLI '${name}' not found in registry.`));
|
|
223
|
+
process.exitCode = 1;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
installExternalCli(ext);
|
|
227
|
+
});
|
|
228
|
+
program
|
|
229
|
+
.command('register')
|
|
230
|
+
.description('Register an external CLI')
|
|
231
|
+
.argument('<name>', 'Name of the CLI')
|
|
232
|
+
.option('--binary <bin>', 'Binary name if different from name')
|
|
233
|
+
.option('--install <cmd>', 'Auto-install command')
|
|
234
|
+
.option('--desc <text>', 'Description')
|
|
235
|
+
.action((name, opts) => {
|
|
236
|
+
registerExternalCli(name, { binary: opts.binary, install: opts.install, description: opts.desc });
|
|
237
|
+
});
|
|
238
|
+
function passthroughExternal(name, parsedArgs) {
|
|
239
|
+
const args = parsedArgs ?? (() => {
|
|
240
|
+
const idx = process.argv.indexOf(name);
|
|
241
|
+
return process.argv.slice(idx + 1);
|
|
242
|
+
})();
|
|
243
|
+
try {
|
|
244
|
+
executeExternalCli(name, args, externalClis);
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
248
|
+
process.exitCode = 1;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const ext of externalClis) {
|
|
252
|
+
if (program.commands.some(c => c.name() === ext.name))
|
|
253
|
+
continue;
|
|
254
|
+
program
|
|
255
|
+
.command(ext.name)
|
|
256
|
+
.description(`(External) ${ext.description || ext.name}`)
|
|
257
|
+
.argument('[args...]')
|
|
258
|
+
.allowUnknownOption()
|
|
259
|
+
.passThroughOptions()
|
|
260
|
+
.helpOption(false)
|
|
261
|
+
.action((args) => passthroughExternal(ext.name, args));
|
|
262
|
+
}
|
|
263
|
+
// ── Antigravity serve (long-running, special case) ────────────────────────
|
|
130
264
|
const antigravityCmd = program.command('antigravity').description('antigravity commands');
|
|
131
|
-
antigravityCmd
|
|
265
|
+
antigravityCmd
|
|
266
|
+
.command('serve')
|
|
132
267
|
.description('Start Anthropic-compatible API proxy for Antigravity')
|
|
133
268
|
.option('--port <port>', 'Server port (default: 8082)', '8082')
|
|
134
269
|
.action(async (opts) => {
|
|
135
270
|
const { startServe } = await import('./clis/antigravity/serve.js');
|
|
136
271
|
await startServe({ port: parseInt(opts.port) });
|
|
137
272
|
});
|
|
138
|
-
// ── Dynamic
|
|
139
|
-
const registry = getRegistry();
|
|
273
|
+
// ── Dynamic adapter commands ──────────────────────────────────────────────
|
|
140
274
|
const siteGroups = new Map();
|
|
141
|
-
// Pre-seed with the antigravity command registered above to avoid duplicates
|
|
142
275
|
siteGroups.set('antigravity', antigravityCmd);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
276
|
+
registerAllCommands(program, siteGroups);
|
|
277
|
+
// ── Unknown command fallback ──────────────────────────────────────────────
|
|
278
|
+
const DENY_LIST = new Set([
|
|
279
|
+
'rm', 'sudo', 'dd', 'mkfs', 'fdisk', 'shutdown', 'reboot',
|
|
280
|
+
'kill', 'killall', 'chmod', 'chown', 'passwd', 'su', 'mount',
|
|
281
|
+
'umount', 'format', 'diskutil',
|
|
282
|
+
]);
|
|
283
|
+
program.on('command:*', (operands) => {
|
|
284
|
+
const binary = operands[0];
|
|
285
|
+
if (DENY_LIST.has(binary)) {
|
|
286
|
+
console.error(chalk.red(`Refusing to register system command '${binary}'.`));
|
|
287
|
+
process.exitCode = 1;
|
|
288
|
+
return;
|
|
148
289
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// Register positional args first, then named options
|
|
154
|
-
const positionalArgs = [];
|
|
155
|
-
for (const arg of cmd.args) {
|
|
156
|
-
if (arg.positional) {
|
|
157
|
-
const bracket = arg.required ? `<${arg.name}>` : `[${arg.name}]`;
|
|
158
|
-
subCmd.argument(bracket, arg.help ?? '');
|
|
159
|
-
positionalArgs.push(arg);
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
const flag = arg.required ? `--${arg.name} <value>` : `--${arg.name} [value]`;
|
|
163
|
-
if (arg.required)
|
|
164
|
-
subCmd.requiredOption(flag, arg.help ?? '');
|
|
165
|
-
else if (arg.default != null)
|
|
166
|
-
subCmd.option(flag, arg.help ?? '', String(arg.default));
|
|
167
|
-
else
|
|
168
|
-
subCmd.option(flag, arg.help ?? '');
|
|
169
|
-
}
|
|
290
|
+
if (isBinaryInstalled(binary)) {
|
|
291
|
+
console.log(chalk.cyan(`🔹 Auto-discovered local CLI '${binary}'. Registering...`));
|
|
292
|
+
registerExternalCli(binary);
|
|
293
|
+
passthroughExternal(binary);
|
|
170
294
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// Collect positional args
|
|
178
|
-
for (let i = 0; i < positionalArgs.length; i++) {
|
|
179
|
-
const arg = positionalArgs[i];
|
|
180
|
-
const v = actionArgs[i];
|
|
181
|
-
if (v !== undefined)
|
|
182
|
-
kwargs[arg.name] = v;
|
|
183
|
-
}
|
|
184
|
-
// Collect named options
|
|
185
|
-
for (const arg of cmd.args) {
|
|
186
|
-
if (arg.positional)
|
|
187
|
-
continue;
|
|
188
|
-
const camelName = arg.name.replace(/-([a-z])/g, (_m, ch) => ch.toUpperCase());
|
|
189
|
-
const v = actionOpts[arg.name] ?? actionOpts[camelName];
|
|
190
|
-
if (v !== undefined)
|
|
191
|
-
kwargs[arg.name] = v;
|
|
192
|
-
}
|
|
193
|
-
try {
|
|
194
|
-
if (actionOpts.verbose)
|
|
195
|
-
process.env.OPENCLI_VERBOSE = '1';
|
|
196
|
-
let result;
|
|
197
|
-
if (shouldUseBrowserSession(cmd)) {
|
|
198
|
-
const BrowserFactory = process.env.OPENCLI_CDP_ENDPOINT ? CDPBridge : BrowserBridge;
|
|
199
|
-
result = await browserSession(BrowserFactory, async (page) => {
|
|
200
|
-
// Cookie/header strategies require same-origin context for credentialed fetch.
|
|
201
|
-
if ((cmd.strategy === Strategy.COOKIE || cmd.strategy === Strategy.HEADER) && cmd.domain) {
|
|
202
|
-
try {
|
|
203
|
-
await page.goto(`https://${cmd.domain}`);
|
|
204
|
-
await page.wait(2);
|
|
205
|
-
}
|
|
206
|
-
catch { }
|
|
207
|
-
}
|
|
208
|
-
return runWithTimeout(executeCommand(cmd, page, kwargs, actionOpts.verbose), { timeout: cmd.timeoutSeconds ?? DEFAULT_BROWSER_COMMAND_TIMEOUT, label: fullName(cmd) });
|
|
209
|
-
}, { workspace: `site:${cmd.site}` });
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
result = await executeCommand(cmd, null, kwargs, actionOpts.verbose);
|
|
213
|
-
}
|
|
214
|
-
if (actionOpts.verbose && (!result || (Array.isArray(result) && result.length === 0))) {
|
|
215
|
-
console.error(chalk.yellow(`[Verbose] Warning: Command returned an empty result. If the website structural API changed or requires authentication, check the network or update the adapter.`));
|
|
216
|
-
}
|
|
217
|
-
const resolved = getRegistry().get(fullName(cmd)) ?? cmd;
|
|
218
|
-
renderOutput(result, { fmt: actionOpts.format, columns: resolved.columns, title: `${resolved.site}/${resolved.name}`, elapsed: (Date.now() - startTime) / 1000, source: fullName(resolved), footerExtra: resolved.footerExtra?.(kwargs) });
|
|
219
|
-
}
|
|
220
|
-
catch (err) {
|
|
221
|
-
if (err instanceof CliError) {
|
|
222
|
-
console.error(chalk.red(`Error [${err.code}]: ${err.message}`));
|
|
223
|
-
if (err.hint)
|
|
224
|
-
console.error(chalk.yellow(`Hint: ${err.hint}`));
|
|
225
|
-
}
|
|
226
|
-
else if (actionOpts.verbose && err.stack) {
|
|
227
|
-
console.error(chalk.red(err.stack));
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
console.error(chalk.red(`Error: ${err.message ?? err}`));
|
|
231
|
-
}
|
|
232
|
-
process.exitCode = 1;
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
}
|
|
295
|
+
else {
|
|
296
|
+
console.error(chalk.red(`error: unknown command '${binary}'`));
|
|
297
|
+
program.outputHelp();
|
|
298
|
+
process.exitCode = 1;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
236
301
|
program.parse();
|
|
237
302
|
}
|
|
303
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
304
|
+
/** Infer a workspace-friendly hostname from a URL, with site override. */
|
|
305
|
+
function inferHost(url, site) {
|
|
306
|
+
if (site)
|
|
307
|
+
return site;
|
|
308
|
+
try {
|
|
309
|
+
return new URL(url).host;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return 'default';
|
|
313
|
+
}
|
|
314
|
+
}
|