mirror of
https://github.com/jackwener/OpenCLI.git
synced 2026-09-14 18:25:42 +08:00
codex/refactor-external-cli-surface
11 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
61b247f90c |
feat(quark): add Quark Drive adapter (#858)
* feat(quark): add Quark Drive adapter (ls, mkdir, mv, rename, rm, save, share-tree) Browser-based adapter for Quark Cloud Drive (pan.quark.cn) using cookie strategy. Supports file browsing, folder management, and saving shared files with task polling for async operations. * fix(quark): address review feedback on adapter correctness and docs - ls: fix depth off-by-one (default 0 now lists target folder only) - save/mv: report success only after pollTask confirms completion; throw on timeout - save/mv: reject combining --to and --to-fid instead of silently preferring --to-fid - utils: check content-type before calling r.json() to handle non-JSON responses gracefully - tests: add quark graceful auth-failure E2E cases for all 7 commands - docs: add Browser Bridge extension to prerequisites; fix mkdir --parent example; expand command table with positional args; add Notes section explaining stoken flow * fix(quark): map auth failures and cover utils * fix(quark): reuse auth mapping for share-tree --------- Co-authored-by: xzy <xzy@mbp-m5.local> Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
5553300597 |
feat(linux-do): split topic content into a dedicated command (#821)
* feat(linux-do): split topic content into a dedicated command Move the old main-post path out of linux-do topic so topic stays a summarized first-page reader while topic-content becomes the Markdown-focused entrypoint for full post bodies. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat(linux-do): update topic content handling to include YAML front matter * fix(linux-do): update default output format to plain for topic-content rendering * fix(linux-do): replace js-yaml with inline YAML serialization for topic-content Adapters must only import node builtins, relative modules, or opencli public APIs. Hand-roll the simple front matter serialization to remove the third-party js-yaml dependency. * fix(linux-do): refine YAML quoting to only escape colons followed by space Colons in URLs (e.g. https://) are valid unquoted YAML values. Only quote when a colon is followed by a space or appears at end of line. --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
f377ec000c |
feat(元宝): add browser adapter and docs (#693)
* feat(yuanbao): add browser adapter and docs * refactor(yuanbao): normalize adapter failures to CliError * refactor: extract shared yuanbao helpers to reduce duplication Move isOnYuanbao, ensureYuanbaoPage, hasLoginGate, authRequired, and IS_VISIBLE_JS to shared.ts. This eliminates identical copies across ask.ts and new.ts, reducing correctness risk when modifying shared logic. --------- Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
cf79ec5c23 |
feat(xueqiu): add comments command (#587)
* feat: add xueqiu comments command * docs(xueqiu): add comments command docs --------- Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
440c001a20 |
feat(band): add Band.us adapter — bands, posts, mentions, post commands (#532)
* feat(band): add bands, posts, and mentions commands for band.us
- bands: lists all Bands via get_band_list_with_filter intercept
- posts: lists posts from a Band via get_posts_and_announcements intercept
- mentions: shows @mention notifications via get_news intercept
All use Strategy.INTERCEPT since band.us API requires an HMAC md header
generated by its own JS. SPA navigation to /band/{no}/post triggers the
band list and posts APIs; bell + @メンション tab click triggers mentions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(band): clean up all three band adapters
- Fix doc comments: Band uses XHR not fetch; clarify INTERCEPT rationale
- bands: replace for-loop with flatMap; explain why band page nav is needed
- posts: remove item.post ?? item fallback (API always wraps in post); rename
finalRequests → requests for consistency; extract stripBandTags helper
- mentions: remove redundant ?? defaults (args have defaults defined); fix
unreadOnly bug (was not applied to post/comment modes); consolidate Band tag
stripping to single regex; cast kwargs types directly instead of converting;
add comments explaining last-response strategy and 'referred' filter flag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band/posts): handle mixed post/announcement items from API
get_posts_and_announcements returns both regular posts and announcements
that have different shapes — some lack post_no and wrap differently.
Restore item.post ?? item fallback and filter out items with no resolvable
identifier to prevent undefined in URLs and empty rows in output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(band): add post command — full post export with comments and photo download
Exports the complete content of a single Band post:
- Post body (with Band markup tags stripped)
- All comments in chronological order
- Photo URLs shown inline, or downloaded with --output <dir>
Uses Strategy.INTERCEPT with a broad 'band.us' pattern to capture both the
batch request (embedding get_post) and get_comments in one SPA navigation.
Responses are identified client-side by shape: batch_result array vs items
array with comment_id fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(band): replace XHR interception with direct DOM extraction
- bands, posts, post: navigate directly to target URL instead of home→SPA detour
- All three switch from Strategy.INTERCEPT to Strategy.COOKIE with navigateBefore: false
(bands uses framework pre-nav to home; posts/post disable it and goto target directly)
- DOM extraction polls for specific content elements rather than fixed waits
- post: confirm selectors via browser inspection (a.text, time.time, .sCommentList,
.sReplyList for nested replies); add --comments flag to skip comment fetch
- posts: extract from rendered post list DOM; correct comment item selector (div.cComment)
- Fix: post empty-result guard changed from && to handle null data safely
- Fix: photo download now checks HTTP status code before piping to avoid writing
redirect HTML into image files
- Fix: mentions unread client-side filter skipped for 'mentioned' mode since
server already filtered via 未確認のみ button click
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address code review feedback
- post: replace manual http/https download with shared downloadMedia utility
(handles redirects, timeouts, stream errors correctly)
- post: fix photo URL resolution to use location.href as base, handling
protocol-relative and relative URLs without throwing
- post: switch to node:-prefixed imports per repo convention
- post/posts: remove redundant ArgumentError guards — framework already
validates required args before func() is called
- mentions: INTERCEPT strategy is intentional (Band HMAC prevents DOM-only
approach for notifications; update PR description to clarify)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address second round of code review feedback
- bands: tighten href selector to /band/{id}(?:/post)?$ so feed/post-detail
links are excluded; only sidebar navigation links match
- mentions: replace fixed page.wait(2) sleeps with polling on
getInterceptedRequests() — waits up to 8 s per action, exits as soon
as the expected number of captures arrives (avoids flakiness on slow XHR)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): fix selector bugs found during testing
- bands: use a.bandCover._link + p.uriText + span.member em selectors
(previous a[href*="/band/"] + .bandName combo leaked "メンバー" text)
- posts: use article.cContentsCard._postMainWrap + span.count selectors
(previous li._postListItem selector matched nothing; DOM changed)
- mentions: fix page.wait(500) → page.wait(0.5) (was waiting 500s not ms);
use timestamp-suffixed URL to force fresh page load each run so the
notification panel is closed; fix get_news vs get_news_count capture
ambiguity with result_data.news check; replace cumulative waitForCaptures
with waitForOneCapture (getInterceptedRequests clears array on each call)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band/mentions): use CSS class selector for bell button instead of locale-dependent text match
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address third round of code review feedback
- post: pass browser cookies to downloadMedia so Band's login-protected
photo URLs don't fail with 401/403
- post: include photos.length in empty-result guard so photo-only posts
are not falsely reported as not found
- mentions: accumulate captures across poll iterations so get_news_count
responses don't cause early exit before the real get_news arrives
- mentions: update docstring to match actual implementation (client-side
filtering, no tab-click)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address fourth round of code review feedback
- mentions: fail fast with a clear error when bell button is not found,
instead of silently no-op and waiting 8s before EmptyResultError
- post: use shared formatCookieHeader() instead of manual cookie string
construction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address fifth round of code review feedback
- mentions: replace fixed page.wait(2) with polling for bell button
readiness (up to 10s), eliminating the fixed sleep and fail-fast
when the selector is missing
- mentions: add explicit !newsReq guard with a clear error message when
get_news capture times out, instead of falling through to a misleading
"No notifications found"
- posts: skip posts with no permalink href instead of emitting a bogus
'https://www.band.us' URL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address sixth round of code review feedback
- post: only send Band cookies to *.band.us photo URLs; third-party CDN
URLs are downloaded without cookies to avoid cross-domain cookie leakage
- bands: strip non-digit chars before parseInt so member counts like
"1,234" parse correctly
- posts: same fix for comment counts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address seventh round of code review feedback
- posts: check limit before push so --limit 0 returns empty result
- post: indent replies proportionally by depth (' '.repeat(depth))
so multi-level threads remain readable in table output
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band/bands): anchor href regex to prevent matching post-detail URLs
Pattern now requires /band/{id} or /band/{id}/post (with optional trailing
slash) so deeper paths like /band/{id}/post/{postNo} are excluded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address ninth round of code review feedback
- mentions: guard bell click with a boolean return so a disappearing
element throws a clear EmptyResultError instead of a raw TypeError
- post: wait for comment list container instead of first .cComment so
posts with zero comments don't incur a fixed 6s delay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): use page.getCookies() for login detection across all commands
Replaces document.cookie.includes('band_session') with
page.getCookies({ domain: 'band.us' }) so login detection works even
if Band.us marks the session cookie as HttpOnly in the future.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address eleventh round of code review feedback
- mentions: replace EmptyResultError with SelectorError for missing/
disappeared bell button — produces a clearer SELECTOR error code
- post: assign per-photo filenames using a global index across both
download batches so band-hosted and CDN photos don't overwrite each other
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band): address twelfth round of code review feedback
- post: derive file extension from URL path and include in filename
(e.g. photo_1.jpg) so downloaded photos have correct extensions
- posts: remove dead code guard (!url && !content) — url is always
non-empty here since href-empty posts are already skipped above
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(band/post): use url-scoped getCookies for photo download auth
Domain-scoped getCookies may omit host-only cookies scoped to www.band.us;
using url: 'https://www.band.us' ensures all relevant cookies are included
in the auth header for Band-hosted photo downloads.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(band): add adapter documentation and sidebar entry
Required by CI doc-check --strict: every adapter in src/clis/ must have
a corresponding docs/adapters/browser/*.md file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(e2e): wire band auth coverage into default matrix
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
|
||
|
|
e64046219d |
feat(linux-do): refactor adapters with unified feed, tags, user commands (#434)
* feat(linux-do): refactor adapters with unified feed, tags, user commands - Replace hot/latest/category with unified `feed` command (tag/category/view routing) - Add `tags`, `user-topics`, `user-posts` commands - Add static data files for categories and tags lookup - Fix error handling: use CliError subclasses instead of raw Error - Fix Discourse API field mapping in search (tags, created) - Add strategy: cookie to all YAML adapters - Update docs and README command listings - Update E2E tests for new command signatures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * review: resolve linux-do feed from live metadata * fix: restore linux-do CI * fix: harden linux-do compatibility * refactor: stabilize linux-do command migration --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
d36a43e805 |
feat(pixiv): add Pixiv adapter (#403)
* feat(pixiv): add Pixiv adapter with 6 commands Add support for Pixiv (pixiv.net) with the following commands: - ranking: daily/weekly/monthly illustration rankings - search: search illustrations by keyword/tag - user: view artist profile info - illusts: list illustrations by artist - detail: view illustration details (tags, stats) - download: download original-quality images All commands use COOKIE strategy to reuse Chrome's logged-in session. YAML adapters for simple API fetches (ranking, detail, user), TypeScript for complex logic (search, illusts, download with Referer header). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(pixiv): add unit tests and E2E auth failure tests - search.test.ts: auth error, result parsing, limit, empty results (4 tests) - illusts.test.ts: auth error, empty user, two-step fetch, limit (4 tests) - download.test.ts: auth error, no images, Referer header, partial failure (4 tests) - Add pixiv to vitest adapter project include list - Add 5 pixiv commands to E2E browser-auth graceful failure tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pixiv): correct ranking API path and YAML arg naming - ranking: use /ranking.php?format=json (not /ajax/ranking which 404s) - ranking: fix JSON path from data.body.contents to data.contents - user/detail: rename hyphenated args (user-id → uid, illust-id → id) to fix YAML template evaluation (dot access doesn't support hyphens) All 6 commands verified working against live Pixiv API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pixiv): use JSON.stringify to prevent code injection in page.evaluate Address CodeRabbit review: all user inputs (query, userId, illustId, idsParam) passed to page.evaluate are now serialized via JSON.stringify instead of direct string interpolation, preventing code injection in browser context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(pixiv): address code review feedback - ranking.yaml: add | json filter to page/limit args for defense-in-depth - user.yaml: guard illusts/manga/novels with typeof check for robustness - Extract shared createPageMock to test-utils.ts, deduplicate across 3 test files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(pixiv): use minimal page mock and add download E2E test - test-utils.ts: slim down to minimal mock (goto, evaluate, getCookies) with overrides support, matching upstream's pragmatic mock style - Add missing download command to E2E browser-auth graceful failure tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pixiv): address all remaining CodeRabbit review comments - detail.yaml: add url to columns to match description mentioning "URLs" - All adapters: differentiate HTTP errors — 401/403 → AuthRequiredError, 404 → "not found", others → generic "request failed (HTTP N)" - Tests: use beforeAll to cache registry lookup, avoiding repeated reads from global singleton - Tests: assert error type (AuthRequiredError) not just message content - Tests: add dedicated test cases for non-auth errors (500) and 404 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(pixiv): add adapter docs and indexes - Add pixiv.md documentation page under docs/adapters/browser/ - Update docs/adapters/index.md with pixiv entry - Add Pixiv to sidebar in docs/.vitepress/config.mts - Update README.md and README.zh-CN.md adapter tables - Add pixiv to download support tables in both READMEs Completes the documentation checklist for the pixiv adapter PR. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pixiv): address code review findings - Use CommandExecutionError instead of raw Error for HTTP failures - Add page.goto() before page.evaluate() to establish browser context - Fix search keyword double-encoding in URL construction - Fix ranking.yaml using rating_count instead of illust_bookmark_count - Throw on batch detail fetch failure instead of silent empty return - Add beforeEach mock reset in download tests - Add novels column to user.yaml output Ensures pixiv adapter follows upstream CliError conventions and handles edge cases correctly before submitting to upstream. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(pixiv): improve download description in READMEs - Replace technical Referer header detail with user-facing description - Describe what users care about: original quality and multi-page support Technical details belong in code comments, not user-facing docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(pixiv): expand usage examples with all options - Add ranking mode examples including R18 variants - Add search filter examples (mode, order, pagination) - Organize examples by command category for readability Users need to know available options without reading source code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pixiv): address second round of CodeRabbit review comments - Validate illust-id is numeric to prevent path traversal - Move URL parsing inside per-item try block for graceful error handling - Add auth error handling for batch detail request (consistent with step 1) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(pixiv): extract shared pixivFetch helper, add input validation & batch support - Create utils.ts with pixivFetch() for unified navigate + fetch + error handling - Refactor search.ts, illusts.ts, download.ts to use pixivFetch (DRY) - Add user-id/illust-id numeric validation in TS adapters - Add batch pagination in illusts.ts for limit > 48 (Pixiv server limit) - Add comment explaining Pixiv search API dual keyword requirement - Update tests: new invalid-ID test cases, aligned mock format with pixivFetch --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
ea8324257d |
feat(yollomi): add new commands and update documentation in README files (#235)
* feat(yollomi): add new commands and update documentation in README files - Added yollomi commands for generating images, videos, and editing capabilities. - Updated README.md and README.zh-CN.md to include yollomi in the command list. - Enhanced SKILL.md with yollomi-related tags and usage examples. * feat(yollomi): add yollomi adapter to documentation - Included yollomi in the VitePress configuration for browser adapters. - Updated adapters index documentation to reflect yollomi's capabilities and commands. * fix(yollomi): bug fixes, tests & improvements - models.ts: add browser: false (no browser connection needed for hardcoded data) - edit.ts: remove unused resolveImageInput import - upload.ts: lower video upload limit from 100MB to 20MB (base64 OOM risk) - generate.ts: improve file extension detection using URL.pathname - upscale.ts: use choices for scale arg, improve extension detection - object-remover.ts: make image/mask args positional - Add yollomi models tests to public-commands.test.ts - Add yollomi generate/video graceful-failure tests to browser-auth.test.ts --------- Co-authored-by: anichikage <hanzhishuai@bytedance.com> Co-authored-by: jackwener <jakevingoo@gmail.com> |
||
|
|
4343ec07e0 |
fix(tests): use positional arg syntax in browser search tests (#302)
Replace redundant --keyword/--query named flags with positional arg syntax for all search commands that declare positional: true. Also fix --query usage in tiktok.md docs example. Affected: - bilibili, weibo, zhihu, reuters, youtube, smzdm, boss, coupang, xiaohongshu search (browser-public.test.ts) - linux-do search (browser-auth.test.ts) - tiktok search (docs/adapters/browser/tiktok.md) |
||
|
|
e1d4a6e5e6 |
feat(linux-do): add linux.do adapter with 6 commands (#43) (#56)
Add linux.do (Discourse-based forum) support with 6 YAML pipeline commands: - hot: trending topics with period filter (all/daily/weekly/monthly/yearly) - latest: newest topics - categories: list all categories with slug/id for further queries - category: browse topics within a specific category - topic: post details with replies (first page) - search: search topics by keyword All commands use navigate+evaluate pattern with cookie auth (linux.do enforces login_required on all endpoints). Security: user inputs sanitized via | json filter + encodeURIComponent. HTML content stripped with block-tag spacing and full entity decoding. |
||
|
|
788b069c02 |
feat: add E2E testing infrastructure with real Chrome in CI
## Changes ### E2E Test Suite (~52 test cases) - public-commands.test.ts — Public API commands (hackernews, v2ex) - browser-public.test.ts — Browser commands for public data across all sites - browser-auth.test.ts — Graceful failure verification for login-required commands - management.test.ts — Full coverage of management commands - output-formats.test.ts — Output format validation (json/yaml/csv/md) - smoke/api-health.test.ts — Scheduled API health checks ### Auto-detect Browser Mode - buildMcpArgs uses CI env var to select mode: - Local (no CI) → --extension (connect to user's Chrome) - CI → standalone (launches its own browser) ### CI Pipeline - e2e-headed.yml — Real Chrome via setup-chrome + xvfb in headed mode - ci.yml — build + unit-test (2 shards) + smoke-test (scheduled/manual) - Composite action for shared Chrome + xvfb setup ### Documentation - New TESTING.md — Architecture, coverage, local setup, how to add tests Co-authored-by: AlexYue <yj976240184@qq.com> |