@jackwener/opencli 1.1.0 → 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 +25 -10
- package/README.zh-CN.md +26 -11
- package/SKILL.md +95 -31
- 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 +431 -276
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +189 -162
- 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/search.js +1 -1
- 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.js +17 -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.js +2 -2
- package/dist/clis/boss/chatlist.js +2 -2
- package/dist/clis/boss/detail.js +2 -2
- package/dist/clis/boss/greet.js +4 -4
- package/dist/clis/boss/search.js +1 -1
- package/dist/clis/boss/send.js +1 -1
- package/dist/clis/boss/stats.js +2 -2
- 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/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.js +1 -1
- package/dist/clis/xiaohongshu/creator-note-detail.d.ts +15 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +69 -5
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +80 -33
- package/dist/clis/xiaohongshu/creator-notes.js +35 -5
- package/dist/clis/xiaohongshu/creator-notes.test.js +35 -6
- 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 +7 -2
- package/dist/external.js +11 -14
- 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 +6 -1
- package/src/browser/page.ts +7 -1
- package/src/build-manifest.ts +25 -19
- package/src/cli.ts +218 -139
- 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/search.ts +1 -1
- 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 +2 -2
- package/src/clis/boss/chatlist.ts +2 -2
- package/src/clis/boss/detail.ts +2 -2
- package/src/clis/boss/greet.ts +4 -4
- package/src/clis/boss/search.ts +1 -1
- package/src/clis/boss/send.ts +1 -1
- package/src/clis/boss/stats.ts +2 -2
- 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/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 +1 -1
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +82 -33
- package/src/clis/xiaohongshu/creator-note-detail.ts +89 -5
- package/src/clis/xiaohongshu/creator-notes.test.ts +39 -6
- package/src/clis/xiaohongshu/creator-notes.ts +44 -5
- 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/{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 +9 -0
- package/src/external.ts +15 -12
- 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/docs/public/CNAME +0 -1
- package/src/clis/twitter/trending.yaml +0 -46
- /package/dist/{bilibili.js → clis/bilibili/utils.js} +0 -0
- /package/dist/{chaoxing.test.d.ts → clis/bloomberg/businessweek.d.ts} +0 -0
- /package/dist/{coupang.test.d.ts → clis/bloomberg/economics.d.ts} +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/explore.js
CHANGED
|
@@ -210,6 +210,120 @@ const FRAMEWORK_DETECT_JS = detectFramework.toString();
|
|
|
210
210
|
const STORE_DISCOVER_JS = discoverStores.toString();
|
|
211
211
|
// ── Auto-Interaction (Fuzzing) ─────────────────────────────────────────────
|
|
212
212
|
const INTERACT_FUZZ_JS = interactFuzz.toString();
|
|
213
|
+
// ── Analysis helpers (extracted from exploreUrl) ───────────────────────────
|
|
214
|
+
/** Filter, deduplicate, and score network endpoints. */
|
|
215
|
+
function analyzeEndpoints(networkEntries) {
|
|
216
|
+
const seen = new Map();
|
|
217
|
+
for (const entry of networkEntries) {
|
|
218
|
+
if (!entry.url)
|
|
219
|
+
continue;
|
|
220
|
+
const ct = entry.contentType.toLowerCase();
|
|
221
|
+
if (ct.includes('image/') || ct.includes('font/') || ct.includes('css') || ct.includes('javascript') || ct.includes('wasm'))
|
|
222
|
+
continue;
|
|
223
|
+
if (entry.status && entry.status >= 400)
|
|
224
|
+
continue;
|
|
225
|
+
const pattern = urlToPattern(entry.url);
|
|
226
|
+
const key = `${entry.method}:${pattern}`;
|
|
227
|
+
if (seen.has(key))
|
|
228
|
+
continue;
|
|
229
|
+
const qp = [];
|
|
230
|
+
try {
|
|
231
|
+
new URL(entry.url).searchParams.forEach((_v, k) => { if (!VOLATILE_PARAMS.has(k))
|
|
232
|
+
qp.push(k); });
|
|
233
|
+
}
|
|
234
|
+
catch { }
|
|
235
|
+
const ep = {
|
|
236
|
+
pattern, method: entry.method, url: entry.url, status: entry.status, contentType: ct,
|
|
237
|
+
queryParams: qp, hasSearchParam: qp.some(p => SEARCH_PARAMS.has(p)),
|
|
238
|
+
hasPaginationParam: qp.some(p => PAGINATION_PARAMS.has(p)),
|
|
239
|
+
hasLimitParam: qp.some(p => LIMIT_PARAMS.has(p)),
|
|
240
|
+
authIndicators: detectAuthIndicators(entry.requestHeaders),
|
|
241
|
+
responseAnalysis: entry.responseBody ? analyzeResponseBody(entry.responseBody) : null,
|
|
242
|
+
score: 0,
|
|
243
|
+
};
|
|
244
|
+
ep.score = scoreEndpoint(ep);
|
|
245
|
+
seen.set(key, ep);
|
|
246
|
+
}
|
|
247
|
+
const analyzed = [...seen.values()].filter(ep => ep.score >= 5).sort((a, b) => b.score - a.score);
|
|
248
|
+
return { analyzed, totalCount: seen.size };
|
|
249
|
+
}
|
|
250
|
+
/** Infer CLI capabilities from analyzed endpoints. */
|
|
251
|
+
function inferCapabilitiesFromEndpoints(endpoints, stores, opts) {
|
|
252
|
+
const capabilities = [];
|
|
253
|
+
const usedNames = new Set();
|
|
254
|
+
for (const ep of endpoints.slice(0, 8)) {
|
|
255
|
+
let capName = inferCapabilityName(ep.url, opts.goal);
|
|
256
|
+
if (usedNames.has(capName)) {
|
|
257
|
+
const suffix = ep.pattern.split('/').filter(s => s && !s.startsWith('{') && !s.includes('.')).pop();
|
|
258
|
+
capName = suffix ? `${capName}_${suffix}` : `${capName}_${usedNames.size}`;
|
|
259
|
+
}
|
|
260
|
+
usedNames.add(capName);
|
|
261
|
+
const cols = [];
|
|
262
|
+
if (ep.responseAnalysis) {
|
|
263
|
+
for (const role of ['title', 'url', 'author', 'score', 'time']) {
|
|
264
|
+
if (ep.responseAnalysis.detectedFields[role])
|
|
265
|
+
cols.push(role);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const args = [];
|
|
269
|
+
if (ep.hasSearchParam)
|
|
270
|
+
args.push({ name: 'keyword', type: 'str', required: true });
|
|
271
|
+
args.push({ name: 'limit', type: 'int', required: false, default: 20 });
|
|
272
|
+
if (ep.hasPaginationParam)
|
|
273
|
+
args.push({ name: 'page', type: 'int', required: false, default: 1 });
|
|
274
|
+
const epStrategy = inferStrategy(ep.authIndicators);
|
|
275
|
+
let storeHint;
|
|
276
|
+
if ((epStrategy === 'intercept' || ep.authIndicators.includes('signature')) && stores.length > 0) {
|
|
277
|
+
for (const s of stores) {
|
|
278
|
+
const matchingAction = s.actions.find(a => capName.split('_').some(part => a.toLowerCase().includes(part)) ||
|
|
279
|
+
a.toLowerCase().includes('fetch') || a.toLowerCase().includes('get'));
|
|
280
|
+
if (matchingAction) {
|
|
281
|
+
storeHint = { store: s.id, action: matchingAction };
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
capabilities.push({
|
|
287
|
+
name: capName, description: `${opts.site ?? detectSiteName(opts.url)} ${capName}`,
|
|
288
|
+
strategy: storeHint ? 'store-action' : epStrategy,
|
|
289
|
+
confidence: Math.min(ep.score / 20, 1.0), endpoint: ep.pattern,
|
|
290
|
+
itemPath: ep.responseAnalysis?.itemPath ?? null,
|
|
291
|
+
recommendedColumns: cols.length ? cols : ['title', 'url'],
|
|
292
|
+
recommendedArgs: args,
|
|
293
|
+
...(storeHint ? { storeHint } : {}),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
const allAuth = new Set(endpoints.flatMap(ep => ep.authIndicators));
|
|
297
|
+
const topStrategy = allAuth.has('signature') ? 'intercept'
|
|
298
|
+
: allAuth.has('bearer') || allAuth.has('csrf') ? 'header'
|
|
299
|
+
: allAuth.size === 0 ? 'public' : 'cookie';
|
|
300
|
+
return { capabilities, topStrategy, authIndicators: [...allAuth] };
|
|
301
|
+
}
|
|
302
|
+
/** Write explore artifacts (manifest, endpoints, capabilities, auth, stores) to disk. */
|
|
303
|
+
async function writeExploreArtifacts(targetDir, result, analyzedEndpoints, stores) {
|
|
304
|
+
await fs.promises.mkdir(targetDir, { recursive: true });
|
|
305
|
+
const tasks = [
|
|
306
|
+
fs.promises.writeFile(path.join(targetDir, 'manifest.json'), JSON.stringify({
|
|
307
|
+
site: result.site, target_url: result.target_url, final_url: result.final_url, title: result.title,
|
|
308
|
+
framework: result.framework, stores: stores.map(s => ({ type: s.type, id: s.id, actions: s.actions })),
|
|
309
|
+
top_strategy: result.top_strategy, explored_at: new Date().toISOString(),
|
|
310
|
+
}, null, 2)),
|
|
311
|
+
fs.promises.writeFile(path.join(targetDir, 'endpoints.json'), JSON.stringify(analyzedEndpoints.map(ep => ({
|
|
312
|
+
pattern: ep.pattern, method: ep.method, url: ep.url, status: ep.status,
|
|
313
|
+
contentType: ep.contentType, score: ep.score, queryParams: ep.queryParams,
|
|
314
|
+
itemPath: ep.responseAnalysis?.itemPath ?? null, itemCount: ep.responseAnalysis?.itemCount ?? 0,
|
|
315
|
+
detectedFields: ep.responseAnalysis?.detectedFields ?? {}, authIndicators: ep.authIndicators,
|
|
316
|
+
})), null, 2)),
|
|
317
|
+
fs.promises.writeFile(path.join(targetDir, 'capabilities.json'), JSON.stringify(result.capabilities, null, 2)),
|
|
318
|
+
fs.promises.writeFile(path.join(targetDir, 'auth.json'), JSON.stringify({
|
|
319
|
+
top_strategy: result.top_strategy, indicators: result.auth_indicators, framework: result.framework,
|
|
320
|
+
}, null, 2)),
|
|
321
|
+
];
|
|
322
|
+
if (stores.length > 0) {
|
|
323
|
+
tasks.push(fs.promises.writeFile(path.join(targetDir, 'stores.json'), JSON.stringify(stores, null, 2)));
|
|
324
|
+
}
|
|
325
|
+
await Promise.all(tasks);
|
|
326
|
+
}
|
|
213
327
|
// ── Main explore function ──────────────────────────────────────────────────
|
|
214
328
|
export async function exploreUrl(url, opts) {
|
|
215
329
|
const waitSeconds = opts.waitSeconds ?? 3.0;
|
|
@@ -301,120 +415,20 @@ export async function exploreUrl(url, opts) {
|
|
|
301
415
|
}
|
|
302
416
|
catch { }
|
|
303
417
|
}
|
|
304
|
-
// Step 7: Analyze endpoints
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
continue;
|
|
309
|
-
const ct = entry.contentType.toLowerCase();
|
|
310
|
-
if (ct.includes('image/') || ct.includes('font/') || ct.includes('css') || ct.includes('javascript') || ct.includes('wasm'))
|
|
311
|
-
continue;
|
|
312
|
-
if (entry.status && entry.status >= 400)
|
|
313
|
-
continue;
|
|
314
|
-
const pattern = urlToPattern(entry.url);
|
|
315
|
-
const key = `${entry.method}:${pattern}`;
|
|
316
|
-
if (seen.has(key))
|
|
317
|
-
continue;
|
|
318
|
-
const qp = [];
|
|
319
|
-
try {
|
|
320
|
-
new URL(entry.url).searchParams.forEach((_v, k) => { if (!VOLATILE_PARAMS.has(k))
|
|
321
|
-
qp.push(k); });
|
|
322
|
-
}
|
|
323
|
-
catch { }
|
|
324
|
-
const ep = {
|
|
325
|
-
pattern, method: entry.method, url: entry.url, status: entry.status, contentType: ct,
|
|
326
|
-
queryParams: qp, hasSearchParam: qp.some(p => SEARCH_PARAMS.has(p)),
|
|
327
|
-
hasPaginationParam: qp.some(p => PAGINATION_PARAMS.has(p)),
|
|
328
|
-
hasLimitParam: qp.some(p => LIMIT_PARAMS.has(p)),
|
|
329
|
-
authIndicators: detectAuthIndicators(entry.requestHeaders),
|
|
330
|
-
responseAnalysis: entry.responseBody ? analyzeResponseBody(entry.responseBody) : null,
|
|
331
|
-
score: 0,
|
|
332
|
-
};
|
|
333
|
-
ep.score = scoreEndpoint(ep);
|
|
334
|
-
seen.set(key, ep);
|
|
335
|
-
}
|
|
336
|
-
const analyzedEndpoints = [...seen.values()].filter(ep => ep.score >= 5).sort((a, b) => b.score - a.score);
|
|
337
|
-
// Step 8: Infer capabilities
|
|
338
|
-
const capabilities = [];
|
|
339
|
-
const usedNames = new Set();
|
|
340
|
-
for (const ep of analyzedEndpoints.slice(0, 8)) {
|
|
341
|
-
let capName = inferCapabilityName(ep.url, opts.goal);
|
|
342
|
-
if (usedNames.has(capName)) {
|
|
343
|
-
const suffix = ep.pattern.split('/').filter(s => s && !s.startsWith('{') && !s.includes('.')).pop();
|
|
344
|
-
capName = suffix ? `${capName}_${suffix}` : `${capName}_${usedNames.size}`;
|
|
345
|
-
}
|
|
346
|
-
usedNames.add(capName);
|
|
347
|
-
const cols = [];
|
|
348
|
-
if (ep.responseAnalysis) {
|
|
349
|
-
for (const role of ['title', 'url', 'author', 'score', 'time']) {
|
|
350
|
-
if (ep.responseAnalysis.detectedFields[role])
|
|
351
|
-
cols.push(role);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
const args = [];
|
|
355
|
-
if (ep.hasSearchParam)
|
|
356
|
-
args.push({ name: 'keyword', type: 'str', required: true });
|
|
357
|
-
args.push({ name: 'limit', type: 'int', required: false, default: 20 });
|
|
358
|
-
if (ep.hasPaginationParam)
|
|
359
|
-
args.push({ name: 'page', type: 'int', required: false, default: 1 });
|
|
360
|
-
// Link store actions to capabilities when store-action strategy is recommended
|
|
361
|
-
const epStrategy = inferStrategy(ep.authIndicators);
|
|
362
|
-
let storeHint;
|
|
363
|
-
if ((epStrategy === 'intercept' || ep.authIndicators.includes('signature')) && stores.length > 0) {
|
|
364
|
-
// Try to find a store/action that matches this endpoint's purpose
|
|
365
|
-
for (const s of stores) {
|
|
366
|
-
const matchingAction = s.actions.find(a => capName.split('_').some(part => a.toLowerCase().includes(part)) ||
|
|
367
|
-
a.toLowerCase().includes('fetch') || a.toLowerCase().includes('get'));
|
|
368
|
-
if (matchingAction) {
|
|
369
|
-
storeHint = { store: s.id, action: matchingAction };
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
capabilities.push({
|
|
375
|
-
name: capName, description: `${opts.site ?? detectSiteName(url)} ${capName}`,
|
|
376
|
-
strategy: storeHint ? 'store-action' : epStrategy,
|
|
377
|
-
confidence: Math.min(ep.score / 20, 1.0), endpoint: ep.pattern,
|
|
378
|
-
itemPath: ep.responseAnalysis?.itemPath ?? null,
|
|
379
|
-
recommendedColumns: cols.length ? cols : ['title', 'url'],
|
|
380
|
-
recommendedArgs: args,
|
|
381
|
-
...(storeHint ? { storeHint } : {}),
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
// Step 9: Determine overall auth strategy
|
|
385
|
-
const allAuth = new Set(analyzedEndpoints.flatMap(ep => ep.authIndicators));
|
|
386
|
-
const topStrategy = allAuth.has('signature') ? 'intercept' : allAuth.has('bearer') || allAuth.has('csrf') ? 'header' : allAuth.size === 0 ? 'public' : 'cookie';
|
|
418
|
+
// Step 7+8: Analyze endpoints and infer capabilities
|
|
419
|
+
const { analyzed: analyzedEndpoints, totalCount } = analyzeEndpoints(networkEntries);
|
|
420
|
+
const { capabilities, topStrategy, authIndicators } = inferCapabilitiesFromEndpoints(analyzedEndpoints, stores, { site: opts.site, goal: opts.goal, url });
|
|
421
|
+
// Step 9: Assemble result and write artifacts
|
|
387
422
|
const siteName = opts.site ?? detectSiteName(metadata.url || url);
|
|
388
423
|
const targetDir = opts.outDir ?? path.join('.opencli', 'explore', siteName);
|
|
389
|
-
await fs.promises.mkdir(targetDir, { recursive: true });
|
|
390
424
|
const result = {
|
|
391
425
|
site: siteName, target_url: url, final_url: metadata.url, title: metadata.title,
|
|
392
426
|
framework, stores, top_strategy: topStrategy,
|
|
393
|
-
endpoint_count:
|
|
427
|
+
endpoint_count: totalCount,
|
|
394
428
|
api_endpoint_count: analyzedEndpoints.length,
|
|
395
|
-
capabilities, auth_indicators:
|
|
429
|
+
capabilities, auth_indicators: authIndicators,
|
|
396
430
|
};
|
|
397
|
-
|
|
398
|
-
const writeTasks = [];
|
|
399
|
-
writeTasks.push(fs.promises.writeFile(path.join(targetDir, 'manifest.json'), JSON.stringify({
|
|
400
|
-
site: siteName, target_url: url, final_url: metadata.url, title: metadata.title,
|
|
401
|
-
framework, stores: stores.map(s => ({ type: s.type, id: s.id, actions: s.actions })),
|
|
402
|
-
top_strategy: topStrategy, explored_at: new Date().toISOString(),
|
|
403
|
-
}, null, 2)));
|
|
404
|
-
writeTasks.push(fs.promises.writeFile(path.join(targetDir, 'endpoints.json'), JSON.stringify(analyzedEndpoints.map(ep => ({
|
|
405
|
-
pattern: ep.pattern, method: ep.method, url: ep.url, status: ep.status,
|
|
406
|
-
contentType: ep.contentType, score: ep.score, queryParams: ep.queryParams,
|
|
407
|
-
itemPath: ep.responseAnalysis?.itemPath ?? null, itemCount: ep.responseAnalysis?.itemCount ?? 0,
|
|
408
|
-
detectedFields: ep.responseAnalysis?.detectedFields ?? {}, authIndicators: ep.authIndicators,
|
|
409
|
-
})), null, 2)));
|
|
410
|
-
writeTasks.push(fs.promises.writeFile(path.join(targetDir, 'capabilities.json'), JSON.stringify(capabilities, null, 2)));
|
|
411
|
-
writeTasks.push(fs.promises.writeFile(path.join(targetDir, 'auth.json'), JSON.stringify({
|
|
412
|
-
top_strategy: topStrategy, indicators: [...allAuth], framework,
|
|
413
|
-
}, null, 2)));
|
|
414
|
-
if (stores.length > 0) {
|
|
415
|
-
writeTasks.push(fs.promises.writeFile(path.join(targetDir, 'stores.json'), JSON.stringify(stores, null, 2)));
|
|
416
|
-
}
|
|
417
|
-
await Promise.all(writeTasks);
|
|
431
|
+
await writeExploreArtifacts(targetDir, result, analyzedEndpoints, stores);
|
|
418
432
|
return { ...result, out_dir: targetDir };
|
|
419
433
|
})(), { timeout: exploreTimeout, label: `Explore ${url}` });
|
|
420
434
|
}, { workspace: opts.workspace });
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
- name: gh
|
|
2
|
+
binary: gh
|
|
3
|
+
description: "GitHub CLI — repos, PRs, issues, releases, gists"
|
|
4
|
+
homepage: "https://cli.github.com"
|
|
5
|
+
tags: [github, git, dev]
|
|
6
|
+
install:
|
|
7
|
+
mac: "brew install gh"
|
|
8
|
+
|
|
9
|
+
- name: obsidian
|
|
10
|
+
binary: obsidian
|
|
11
|
+
description: "Obsidian vault management — notes, search, tags, tasks, sync"
|
|
12
|
+
homepage: "https://obsidian.md/help/cli"
|
|
13
|
+
tags: [notes, knowledge, markdown]
|
|
14
|
+
install:
|
|
15
|
+
mac: "brew install --cask obsidian"
|
|
16
|
+
|
|
17
|
+
- name: readwise
|
|
18
|
+
binary: readwise
|
|
19
|
+
description: "Readwise & Reader CLI — highlights, annotations, reading list"
|
|
20
|
+
homepage: "https://github.com/readwiseio/readwise-cli"
|
|
21
|
+
tags: [reading, highlights]
|
|
22
|
+
install:
|
|
23
|
+
default: "npm install -g @readwiseio/readwise-cli"
|
|
24
|
+
|
|
25
|
+
- name: kubectl
|
|
26
|
+
binary: kubectl
|
|
27
|
+
description: "Kubernetes command-line tool"
|
|
28
|
+
homepage: "https://kubernetes.io/docs/reference/kubectl/"
|
|
29
|
+
tags: [kubernetes, k8s, devops]
|
|
30
|
+
install:
|
|
31
|
+
mac: "brew install kubectl"
|
|
32
|
+
|
|
33
|
+
- name: docker
|
|
34
|
+
binary: docker
|
|
35
|
+
description: "Docker command-line interface"
|
|
36
|
+
homepage: "https://docs.docker.com/engine/reference/commandline/cli/"
|
|
37
|
+
tags: [docker, containers, devops]
|
|
38
|
+
install:
|
|
39
|
+
mac: "brew install --cask docker"
|
|
40
|
+
|
|
41
|
+
- name: gws
|
|
42
|
+
binary: gws
|
|
43
|
+
description: "Google Workspace CLI — Docs, Sheets, Drive, Gmail, Calendar"
|
|
44
|
+
homepage: "https://github.com/nicholasgasior/gws"
|
|
45
|
+
tags: [google, docs, sheets, drive, workspace]
|
|
46
|
+
install:
|
|
47
|
+
mac: "brew install gws"
|
|
48
|
+
default: "npm install -g @nicholasgasior/gws"
|
package/dist/external.d.ts
CHANGED
|
@@ -16,5 +16,10 @@ export declare function loadExternalClis(): ExternalCliConfig[];
|
|
|
16
16
|
export declare function isBinaryInstalled(binary: string): boolean;
|
|
17
17
|
export declare function getInstallCmd(installConfig?: ExternalCliInstall): string | null;
|
|
18
18
|
export declare function installExternalCli(cli: ExternalCliConfig): boolean;
|
|
19
|
-
export declare function executeExternalCli(name: string, args: string[]):
|
|
20
|
-
export
|
|
19
|
+
export declare function executeExternalCli(name: string, args: string[], preloaded?: ExternalCliConfig[]): void;
|
|
20
|
+
export interface RegisterOptions {
|
|
21
|
+
binary?: string;
|
|
22
|
+
install?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function registerExternalCli(name: string, opts?: RegisterOptions): void;
|
package/dist/external.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import * as os from 'node:os';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { spawnSync, execSync } from 'node:child_process';
|
|
5
|
+
import { spawnSync, execSync, execFileSync } from 'node:child_process';
|
|
6
6
|
import yaml from 'js-yaml';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { log } from './logger.js';
|
|
@@ -45,8 +45,7 @@ export function loadExternalClis() {
|
|
|
45
45
|
export function isBinaryInstalled(binary) {
|
|
46
46
|
try {
|
|
47
47
|
const isWindows = os.platform() === 'win32';
|
|
48
|
-
|
|
49
|
-
execSync(`${cmd} ${binary}`, { stdio: 'ignore' });
|
|
48
|
+
execFileSync(isWindows ? 'where' : 'which', [binary], { stdio: 'ignore' });
|
|
50
49
|
return true;
|
|
51
50
|
}
|
|
52
51
|
catch {
|
|
@@ -92,8 +91,8 @@ export function installExternalCli(cli) {
|
|
|
92
91
|
return false;
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
|
-
export
|
|
96
|
-
const configs = loadExternalClis();
|
|
94
|
+
export function executeExternalCli(name, args, preloaded) {
|
|
95
|
+
const configs = preloaded ?? loadExternalClis();
|
|
97
96
|
const cli = configs.find((c) => c.name === name);
|
|
98
97
|
if (!cli) {
|
|
99
98
|
throw new Error(`External CLI '${name}' not found in registry.`);
|
|
@@ -107,8 +106,7 @@ export async function executeExternalCli(name, args) {
|
|
|
107
106
|
return;
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
|
-
// 3. Passthrough execution
|
|
111
|
-
// We use spawnSync to properly inherit stdio and block until completion
|
|
109
|
+
// 3. Passthrough execution with stdio inherited
|
|
112
110
|
const result = spawnSync(cli.binary, args, { stdio: 'inherit' });
|
|
113
111
|
if (result.error) {
|
|
114
112
|
console.error(chalk.red(`Failed to execute '${cli.binary}': ${result.error.message}`));
|
|
@@ -119,7 +117,7 @@ export async function executeExternalCli(name, args) {
|
|
|
119
117
|
process.exitCode = result.status;
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
|
-
export function registerExternalCli(name,
|
|
120
|
+
export function registerExternalCli(name, opts) {
|
|
123
121
|
const userPath = getUserRegistryPath();
|
|
124
122
|
const configDir = path.dirname(userPath);
|
|
125
123
|
if (!fs.existsSync(configDir)) {
|
|
@@ -138,14 +136,13 @@ export function registerExternalCli(name, binary, install, description) {
|
|
|
138
136
|
const existingIndex = items.findIndex((c) => c.name === name);
|
|
139
137
|
const newItem = {
|
|
140
138
|
name,
|
|
141
|
-
binary: binary || name,
|
|
139
|
+
binary: opts?.binary || name,
|
|
142
140
|
};
|
|
143
|
-
if (description)
|
|
144
|
-
newItem.description = description;
|
|
145
|
-
if (install)
|
|
146
|
-
newItem.install = { default: install };
|
|
141
|
+
if (opts?.description)
|
|
142
|
+
newItem.description = opts.description;
|
|
143
|
+
if (opts?.install)
|
|
144
|
+
newItem.install = { default: opts.install };
|
|
147
145
|
if (existingIndex >= 0) {
|
|
148
|
-
// Merge
|
|
149
146
|
items[existingIndex] = { ...items[existingIndex], ...newItem };
|
|
150
147
|
console.log(chalk.green(`Updated '${name}' in user registry.`));
|
|
151
148
|
}
|
package/dist/main.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as os from 'node:os';
|
|
6
6
|
import * as path from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { discoverClis } from './
|
|
8
|
+
import { discoverClis } from './discovery.js';
|
|
9
9
|
import { getCompletions } from './completion.js';
|
|
10
10
|
import { runCli } from './cli.js';
|
|
11
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -4,8 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { render } from '../template.js';
|
|
6
6
|
export async function stepNavigate(page, params, data, args) {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
if (typeof params === 'object' && params && 'url' in params) {
|
|
8
|
+
const url = String(render(params.url, { args, data }));
|
|
9
|
+
await page.goto(url, { waitUntil: params.waitUntil, settleMs: params.settleMs });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const url = render(params, { args, data });
|
|
13
|
+
await page.goto(String(url));
|
|
14
|
+
}
|
|
9
15
|
return data;
|
|
10
16
|
}
|
|
11
17
|
export async function stepClick(page, params, data, args) {
|
package/dist/registry.d.ts
CHANGED
|
@@ -49,3 +49,5 @@ export declare function getRegistry(): Map<string, CliCommand>;
|
|
|
49
49
|
export declare function fullName(cmd: CliCommand): string;
|
|
50
50
|
export declare function strategyLabel(cmd: CliCommand): string;
|
|
51
51
|
export declare function registerCommand(cmd: CliCommand): void;
|
|
52
|
+
export { serializeArg, serializeCommand, formatArgSummary, formatRegistryHelpText } from './serialization.js';
|
|
53
|
+
export type { SerializedArg } from './serialization.js';
|
package/dist/registry.js
CHANGED
|
@@ -43,3 +43,5 @@ export function strategyLabel(cmd) {
|
|
|
43
43
|
export function registerCommand(cmd) {
|
|
44
44
|
_registry.set(fullName(cmd), cmd);
|
|
45
45
|
}
|
|
46
|
+
// Re-export serialization helpers from their dedicated module
|
|
47
|
+
export { serializeArg, serializeCommand, formatArgSummary, formatRegistryHelpText } from './serialization.js';
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { IPage } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the appropriate browser factory based on environment config.
|
|
4
|
+
* Uses CDPBridge when OPENCLI_CDP_ENDPOINT is set, otherwise BrowserBridge.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getBrowserFactory(): new () => IBrowserFactory;
|
|
2
7
|
export declare const DEFAULT_BROWSER_CONNECT_TIMEOUT: number;
|
|
3
8
|
export declare const DEFAULT_BROWSER_COMMAND_TIMEOUT: number;
|
|
4
9
|
export declare const DEFAULT_BROWSER_EXPLORE_TIMEOUT: number;
|
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { BrowserBridge, CDPBridge } from './browser/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the appropriate browser factory based on environment config.
|
|
4
|
+
* Uses CDPBridge when OPENCLI_CDP_ENDPOINT is set, otherwise BrowserBridge.
|
|
5
|
+
*/
|
|
6
|
+
export function getBrowserFactory() {
|
|
7
|
+
return (process.env.OPENCLI_CDP_ENDPOINT ? CDPBridge : BrowserBridge);
|
|
8
|
+
}
|
|
1
9
|
export const DEFAULT_BROWSER_CONNECT_TIMEOUT = parseInt(process.env.OPENCLI_BROWSER_CONNECT_TIMEOUT ?? '30', 10);
|
|
2
10
|
export const DEFAULT_BROWSER_COMMAND_TIMEOUT = parseInt(process.env.OPENCLI_BROWSER_COMMAND_TIMEOUT ?? '60', 10);
|
|
3
11
|
export const DEFAULT_BROWSER_EXPLORE_TIMEOUT = parseInt(process.env.OPENCLI_BROWSER_EXPLORE_TIMEOUT ?? '120', 10);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization and formatting helpers for CLI commands and args.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `list` command, Commander --help, and build-manifest.
|
|
5
|
+
* Separated from registry.ts to keep the registry focused on types + registration.
|
|
6
|
+
*/
|
|
7
|
+
import type { Arg, CliCommand } from './registry.js';
|
|
8
|
+
export type SerializedArg = {
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
required: boolean;
|
|
12
|
+
positional: boolean;
|
|
13
|
+
choices: string[];
|
|
14
|
+
default: unknown;
|
|
15
|
+
help: string;
|
|
16
|
+
};
|
|
17
|
+
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
18
|
+
export declare function serializeArg(a: Arg): SerializedArg;
|
|
19
|
+
/** Full command metadata for structured output (json/yaml). */
|
|
20
|
+
export declare function serializeCommand(cmd: CliCommand): {
|
|
21
|
+
command: string;
|
|
22
|
+
site: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
strategy: string;
|
|
26
|
+
browser: boolean;
|
|
27
|
+
args: SerializedArg[];
|
|
28
|
+
columns: string[];
|
|
29
|
+
domain: string | null;
|
|
30
|
+
};
|
|
31
|
+
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
32
|
+
export declare function formatArgSummary(args: Arg[]): string;
|
|
33
|
+
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
34
|
+
export declare function formatRegistryHelpText(cmd: CliCommand): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization and formatting helpers for CLI commands and args.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `list` command, Commander --help, and build-manifest.
|
|
5
|
+
* Separated from registry.ts to keep the registry focused on types + registration.
|
|
6
|
+
*/
|
|
7
|
+
import { fullName, strategyLabel } from './registry.js';
|
|
8
|
+
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
9
|
+
export function serializeArg(a) {
|
|
10
|
+
return {
|
|
11
|
+
name: a.name,
|
|
12
|
+
type: a.type ?? 'string',
|
|
13
|
+
required: !!a.required,
|
|
14
|
+
positional: !!a.positional,
|
|
15
|
+
choices: a.choices ?? [],
|
|
16
|
+
default: a.default ?? null,
|
|
17
|
+
help: a.help ?? '',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Full command metadata for structured output (json/yaml). */
|
|
21
|
+
export function serializeCommand(cmd) {
|
|
22
|
+
return {
|
|
23
|
+
command: fullName(cmd),
|
|
24
|
+
site: cmd.site,
|
|
25
|
+
name: cmd.name,
|
|
26
|
+
description: cmd.description,
|
|
27
|
+
strategy: strategyLabel(cmd),
|
|
28
|
+
browser: !!cmd.browser,
|
|
29
|
+
args: cmd.args.map(serializeArg),
|
|
30
|
+
columns: cmd.columns ?? [],
|
|
31
|
+
domain: cmd.domain ?? null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// ── Formatting ──────────────────────────────────────────────────────────────
|
|
35
|
+
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
36
|
+
export function formatArgSummary(args) {
|
|
37
|
+
return args
|
|
38
|
+
.map(a => {
|
|
39
|
+
if (a.positional)
|
|
40
|
+
return a.required ? `<${a.name}>` : `[${a.name}]`;
|
|
41
|
+
return a.required ? `--${a.name}` : `[--${a.name}]`;
|
|
42
|
+
})
|
|
43
|
+
.join(' ');
|
|
44
|
+
}
|
|
45
|
+
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
46
|
+
export function formatRegistryHelpText(cmd) {
|
|
47
|
+
const lines = [];
|
|
48
|
+
const choicesArgs = cmd.args.filter(a => a.choices?.length);
|
|
49
|
+
for (const a of choicesArgs) {
|
|
50
|
+
const prefix = a.positional ? `<${a.name}>` : `--${a.name}`;
|
|
51
|
+
const def = a.default != null ? ` (default: ${a.default})` : '';
|
|
52
|
+
lines.push(` ${prefix}: ${a.choices.join(', ')}${def}`);
|
|
53
|
+
}
|
|
54
|
+
const meta = [];
|
|
55
|
+
meta.push(`Strategy: ${strategyLabel(cmd)}`);
|
|
56
|
+
meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
|
|
57
|
+
if (cmd.domain)
|
|
58
|
+
meta.push(`Domain: ${cmd.domain}`);
|
|
59
|
+
lines.push(meta.join(' | '));
|
|
60
|
+
if (cmd.columns?.length)
|
|
61
|
+
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
62
|
+
return '\n' + lines.join('\n') + '\n';
|
|
63
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* instead of `any` for browser interactions.
|
|
6
6
|
*/
|
|
7
7
|
export interface IPage {
|
|
8
|
-
goto(url: string
|
|
8
|
+
goto(url: string, options?: {
|
|
9
|
+
waitUntil?: 'load' | 'none';
|
|
10
|
+
settleMs?: number;
|
|
11
|
+
}): Promise<void>;
|
|
9
12
|
evaluate(js: string): Promise<any>;
|
|
10
13
|
getCookies(opts?: {
|
|
11
14
|
domain?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from 'vitepress'
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
|
-
base: '/',
|
|
4
|
+
base: '/docs/',
|
|
5
5
|
title: 'OpenCLI',
|
|
6
6
|
description: 'Make any website or Electron App your CLI — AI-powered, account-safe, self-healing.',
|
|
7
7
|
|
|
@@ -54,12 +54,19 @@ export default defineConfig({
|
|
|
54
54
|
{ text: 'YouTube', link: '/adapters/browser/youtube' },
|
|
55
55
|
{ text: 'Xueqiu', link: '/adapters/browser/xueqiu' },
|
|
56
56
|
{ text: 'V2EX', link: '/adapters/browser/v2ex' },
|
|
57
|
+
{ text: 'Bloomberg', link: '/adapters/browser/bloomberg' },
|
|
57
58
|
{ text: 'LinkedIn', link: '/adapters/browser/linkedin' },
|
|
58
59
|
{ text: 'Coupang', link: '/adapters/browser/coupang' },
|
|
59
60
|
{ text: 'BOSS Zhipin', link: '/adapters/browser/boss' },
|
|
60
61
|
{ text: 'Ctrip', link: '/adapters/browser/ctrip' },
|
|
61
62
|
{ text: 'Reuters', link: '/adapters/browser/reuters' },
|
|
62
63
|
{ text: 'SMZDM', link: '/adapters/browser/smzdm' },
|
|
64
|
+
{ text: 'Jike', link: '/adapters/browser/jike' },
|
|
65
|
+
{ text: 'Jimeng', link: '/adapters/browser/jimeng' },
|
|
66
|
+
{ text: 'LINUX DO', link: '/adapters/browser/linux-do' },
|
|
67
|
+
{ text: 'Chaoxing', link: '/adapters/browser/chaoxing' },
|
|
68
|
+
{ text: 'Grok', link: '/adapters/browser/grok' },
|
|
69
|
+
{ text: 'WeRead', link: '/adapters/browser/weread' },
|
|
63
70
|
],
|
|
64
71
|
},
|
|
65
72
|
{
|
|
@@ -72,6 +79,12 @@ export default defineConfig({
|
|
|
72
79
|
{ text: 'Apple Podcasts', link: '/adapters/browser/apple-podcasts' },
|
|
73
80
|
{ text: 'Xiaoyuzhou', link: '/adapters/browser/xiaoyuzhou' },
|
|
74
81
|
{ text: 'Yahoo Finance', link: '/adapters/browser/yahoo-finance' },
|
|
82
|
+
{ text: 'arXiv', link: '/adapters/browser/arxiv' },
|
|
83
|
+
{ text: 'Barchart', link: '/adapters/browser/barchart' },
|
|
84
|
+
{ text: 'Hugging Face', link: '/adapters/browser/hf' },
|
|
85
|
+
{ text: 'Sina Finance', link: '/adapters/browser/sinafinance' },
|
|
86
|
+
{ text: 'Stack Overflow', link: '/adapters/browser/stackoverflow' },
|
|
87
|
+
{ text: 'Wikipedia', link: '/adapters/browser/wikipedia' },
|
|
75
88
|
],
|
|
76
89
|
},
|
|
77
90
|
{
|
|
@@ -137,7 +150,6 @@ export default defineConfig({
|
|
|
137
150
|
{ text: '快速开始', link: '/zh/guide/getting-started' },
|
|
138
151
|
{ text: '安装', link: '/zh/guide/installation' },
|
|
139
152
|
{ text: 'Browser Bridge', link: '/zh/guide/browser-bridge' },
|
|
140
|
-
{ text: '问题排查', link: '/zh/guide/troubleshooting' },
|
|
141
153
|
],
|
|
142
154
|
},
|
|
143
155
|
],
|
|
@@ -154,7 +166,6 @@ export default defineConfig({
|
|
|
154
166
|
text: '开发者指南',
|
|
155
167
|
items: [
|
|
156
168
|
{ text: '贡献指南', link: '/zh/developer/contributing' },
|
|
157
|
-
{ text: '测试', link: '/zh/developer/testing' },
|
|
158
169
|
],
|
|
159
170
|
},
|
|
160
171
|
],
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# arXiv
|
|
2
|
+
|
|
3
|
+
**Mode**: 🌐 Public · **Domain**: `arxiv.org`
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| `opencli arxiv search` | Search arXiv papers |
|
|
10
|
+
| `opencli arxiv paper` | Get arXiv paper details by ID |
|
|
11
|
+
|
|
12
|
+
## Usage Examples
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Search for papers
|
|
16
|
+
opencli arxiv search "transformer attention" --limit 10
|
|
17
|
+
|
|
18
|
+
# Get paper details by arXiv ID
|
|
19
|
+
opencli arxiv paper 2301.00001
|
|
20
|
+
|
|
21
|
+
# JSON output
|
|
22
|
+
opencli arxiv search "LLM" -f json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
- No browser required — uses public arXiv API
|