Commit Graph

572 Commits

Author SHA1 Message Date
jakevin 7ebe8134cc docs: clean up READMEs - remove redundant sections (#261)
Removed from both EN/CN READMEs:
- Table of Contents (GitHub auto-generates TOC)
- Method 2: Load from npm Package (keep recommended + dev only)
- Bloomberg detailed note (too specific for README)
- Pipeline Step YAML example (developer-internal)
- Releasing New Versions (belongs in CONTRIBUTING.md)

EN README only:
- Simplified Testing section to one-liner + link to TESTING.md
2026-03-22 22:26:49 +08:00
jakevin c44bc62b60 chore: code cleanup + extension conflict troubleshooting (#260)
Cleanup:
- Remove redundant double-retry in resolveTabId (was retrying data: URI
  with the same data: URI)
- Fix stale comment (30s → 120s idle timeout)
- Remove verbose debug logging in resolveTabId
- Built extension is now smaller (16.66kB vs 17.18kB)

Extension conflict:
- Add hint to attach-failed error when chrome-extension:// URL is detected
- Add troubleshooting entry for extension conflicts (e.g. youmind, New Tab
  Override) to both README.md and README.zh-CN.md

Ref: #249
v1.2.6
2026-03-22 22:18:22 +08:00
jakevin 7f57e76485 fix: treat empty tab URL as debuggable (fixes first-run doctor --live failure) (#259)
When a new automation window is created, the initial tab URL may be
empty briefly while Chrome loads the data: URI. isDebuggableUrl('') was
returning false, causing ensureAttached to reject the tab.

Fix: only reject known non-debuggable URLs (chrome://, chrome-extension://).
Empty/undefined URLs are now treated as debuggable since they represent
tabs still loading.

Also adds 200ms delay after window creation to let Chrome populate the
tab URL.
v1.2.5
2026-03-22 22:10:30 +08:00
jakevin e9818c1b41 chore: remove CRX from release pipeline and docs (#258)
CRX files cannot be installed in modern Chrome without Chrome Web Store
publishing. Updated all docs to recommend 'Load unpacked' installation
method only. Added npm package loading method as alternative.

- Removed CRX build step from build-extension.yml workflow
- Removed CRX from artifact upload and release attachment
- Updated README.md, README.zh-CN.md, browser-bridge docs (en/zh)
- Added 'Load from npm package' as installation method
2026-03-22 22:07:33 +08:00
jakevin 3e91876d13 fix: replace all about:blank with data: URI to prevent New Tab Override interception (#257)
Root cause: getAutomationWindow and resolveTabId used about:blank which
New Tab Override extensions intercept immediately, replacing it with
chrome-extension:// URLs that cannot be debugged.

Changes:
- Window creation: about:blank → data:text/html
- reuseTab fallback: about:blank → data:text/html
- newTab handler: about:blank → data:text/html
- Added diagnostic logging to resolveTabId for debugging
- Synced extension version to 1.2.4

Ref: #249
v1.2.4
2026-03-22 22:04:25 +08:00
jakevin 7c02588105 chore: bump version to 1.2.3 (#256) v1.2.3 2026-03-22 21:48:17 +08:00
jakevin 112fdefa8d fix: harden resolveTabId against New Tab Override extension interception (#255)
resolveTabId's reuseTab path now verifies the URL is actually debuggable
after navigating to about:blank. If a New Tab Override extension intercepts
it (setting it back to chrome-extension://), falls back to a data: URI,
then creates a fresh tab as last resort.

This fixes the persistent 'attach failed: Cannot access chrome-extension://'
error for users with New Tab Override extensions installed.

Ref: #249
2026-03-22 21:47:44 +08:00
jakevin e077ad2336 chore: bump version to 1.2.2 (#254) v1.2.2 2026-03-22 21:27:03 +08:00
jakevin 81384ede00 chore: bump version to 1.2.1 (#252) v1.2.1 2026-03-22 21:24:42 +08:00
jakevin 71b2c3961b fix: harden browser automation pipeline (resolves #249) (#251)
- resolveTabId: validate URL even for explicit tabId, fall through to
  auto-resolve when tab is not debuggable or has been closed
- handleNavigate: wait for URL change before checking 'complete' status
  to avoid race condition with stale about:blank
- ensureAttached: pre-check tab URL, verify cached attach with probe,
  invalidate cache on URL change via onUpdated listener
- daemon-client: recognize transient extension errors (disconnected,
  attach failed) as retryable with 1500ms delay; fresh command ID per attempt
- pipeline executor: add per-step retry for browser steps (up to 2 retries
  on transient errors); cleanup automation window on pipeline failure
- page.ts: selectTab/newTab/closeTab properly update/invalidate _tabId
- daemon.ts: add WebSocket ping/pong heartbeat (15s interval, 2-miss disconnect)
- Increase automation window idle timeout from 30s to 120s
- Fix timeout param edge cases in BrowserBridge._ensureDaemon
- Remove unused chalk import; fix trailing import placement

Closes #249
2026-03-22 21:23:21 +08:00
jakevin b3b9892836 docs: add star history chart (#246) 2026-03-22 19:22:41 +08:00
jakevin 520622ac75 ci: update GitHub Actions runtime versions (#245) 2026-03-22 19:02:21 +08:00
jakevin 2d1b8c1e76 chore: prepare v1.2 release (#244) v1.2.0 2026-03-22 18:40:32 +08:00
ykfnxx 70651d3ba8 feat(douban): add movie adapter with search, top250, subject, marks, reviews commands (#239)
* feat(douban): add movie adapter with search, top250, subject, marks, reviews commands

- search: search movies by keyword
- top250: get top 250 movies
- subject: get movie details by id
- marks: export personal viewing marks
- reviews: export personal movie reviews

* review: resolve douban adapter blockers

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 17:57:34 +08:00
plat1ko 9696db9ed4 feat: make primary args positional across all CLIs (#242)
* feat: make primary args positional across all CLIs

Convert primary arguments from named options (--arg) to positional
arguments for a more natural CLI experience.

Affected sites: antigravity, bilibili, boss, chaoxing, coupang, grok,
hf, instagram, jike, jimeng, linkedin, linux-do, tiktok, twitter,
xiaohongshu, youtube

Also adds Arg Design Convention to CONTRIBUTING.md and earnings-date
to xueqiu command list in READMEs.

Usage examples:
  opencli xueqiu search '茅台'       (was: --query '茅台')
  opencli twitter followers elonmusk  (was: --user elonmusk)
  opencli bilibili download BV1xxx    (was: --bvid BV1xxx)

* review: keep config args named in positional cleanup

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 17:04:56 +08:00
jakevin c76f86c9cb refactor: fail fast on invalid pipeline steps (#237) 2026-03-22 14:53:57 +08:00
jakevin 4cd0409ded fix: harden twitter timeline review findings (#236) 2026-03-22 14:30:03 +08:00
VK ea113a6471 feat(devto): add devto adapter (#234)
* feat(devto): add devto adapter

* refactor(devto): improve adapters to match project conventions

- Make tag/username args positional for natural CLI usage:
  opencli devto tag javascript (instead of --tag javascript)
  opencli devto user ben (instead of --username ben)
- Add rank field (index + 1) matching hackernews/lobsters pattern
- Add tags field from tag_list for richer output
- Remove redundant author column from user command (already filtering by user)
- Use type: str (project convention) instead of type: string
- Increase default limit from 10 to 20 (matching other adapters)
- Update docs with positional arg examples

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 14:18:47 +08:00
AstroHan a439286398 docs(plugin): add juejin plugin to example plugins (#207) 2026-03-22 14:17:12 +08:00
AstroHan 1d56dd77a8 fix(wikipedia): fix search arg name + add random and trending commands (#231)
* fix(wikipedia): fix search arg name + add random and trending commands

- fix: search.ts referenced `args.keyword` but the argument is defined
  as `query`, causing the search term to always be undefined
- feat: add `random` command (random article summary via REST API)
- feat: add `trending` command (most-read articles, yesterday's data)

All commands are PUBLIC strategy, no browser required, reuse wikiFetch.

* refactor(wikipedia): extract shared types + add docs for random/trending

- Extract WikiSummary, WikiMostReadArticle types to utils.ts
- Extract EXTRACT_MAX_LEN/DESC_MAX_LEN constants
- Add formatSummaryRow() helper to eliminate duplicate mapping in
  summary.ts and random.ts
- Update docs with random and trending command examples

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 14:14:21 +08:00
AstroHan e98cf756e9 feat(twitter): add --type flag to timeline command (#83) (#232)
Support switching between For You (algorithmic) and Following
(chronological) timelines via `--type for-you|following`.

Both endpoints share the same response structure; only the GraphQL
endpoint name and queryId differ. QueryId is resolved dynamically
from fa0311/twitter-openapi with a hardcoded fallback, and validated
against /^[A-Za-z0-9_-]+$/ to prevent injection from upstream.
2026-03-22 12:11:21 +08:00
Zhang ShengYan 387aa0d6e5 fix: resolve inconsistent doctor --live report (fix #121) (#224)
* fix(doctor): refresh status after live check to resolve #121

* refactor: reorder live check before status read for natural consistency

Instead of calling checkDaemonStatus() twice (before and after the
connectivity check), reorder so that the live connectivity check runs
first, then read daemon status only once. This:
- Eliminates redundant checkDaemonStatus() call
- Naturally avoids the timing inconsistency (fixes #121)
- Also fixes the sessions query using stale status
- Simplifies test assertions to avoid over-coupling to exact wording

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 10:59:59 +08:00
jakevin 1ecac25df5 fix: correct SKILL.md github reference and add missing adapter docs (#230)
- SKILL.md: replace non-existent 'opencli github search' with correct
  'opencli gh' external CLI passthrough examples
- SKILL.md: remove 'github search' from public API commands list
- Add missing docs for douban, sinablog, substack adapters (fixes
  doc-check CI failure: 47/50 → 50/50)
- Add new adapter pages to VitePress sidebar config
2026-03-22 10:54:03 +08:00
jakevin 9921e5d696 remove broken desktop adapters (#221) 2026-03-22 04:14:07 +08:00
jakevin 4c8a447ead fix: align positional primary args and docs (#220) 2026-03-22 04:02:59 +08:00
plat1ko fb2a145e36 feat(xueqiu): make primary args positional (#213)
- search: query → positional
- stock: symbol → positional
- earnings-date: symbol → positional
- Fix build-manifest scanYaml to preserve positional field

Usage:
  opencli xueqiu search '茅台'
  opencli xueqiu stock SH600519
  opencli xueqiu earnings-date SH600519
2026-03-22 03:57:14 +08:00
jakevin bd274ce2d7 refactor: type discovery core (#219) 2026-03-22 03:46:24 +08:00
jakevin 28c393ec86 refactor: type browser core (#218) 2026-03-22 03:41:36 +08:00
jakevin 8a4ea411e1 refactor: type pipeline core (#217) 2026-03-22 03:33:59 +08:00
jakevin 45cee57ca0 refactor: reduce core any usage (#216) 2026-03-22 03:23:16 +08:00
AstroHan 4e3259976b feat(google): add search, suggest, news, and trends adapters (#184)
* feat(google): add search, suggest, news, and trends adapters

Four new commands under `google`:
- search: browser-based DOM extraction from google.com/search
- suggest: public JSON API (suggestqueries.google.com)
- news: public RSS feed (top stories + keyword search)
- trends: public RSS feed (daily trending searches by region)

Shared RSS parser in utils.ts with attribute/CDATA support.
Unit tests for parseRssItems, E2E tests with network skip guards.

* refactor(google): downgrade search strategy from COOKIE to PUBLIC

Google search results are public data, no login needed. Browser is
required for DOM rendering, not authentication. Standalone mode
confirmed working in testing.

* fix: update test comment to reflect PUBLIC strategy
2026-03-22 01:02:32 +08:00
Leo Yuan Tsao bdf5967abd feat: add douban, sinablog, substack adapters; upgrade medium to TS (#185)
New adapters:
- douban: book-hot, movie-hot, search (browser/cookie)
- sinablog: hot, search, article, user (search uses public API)
- substack: feed, publication, search (search uses public API)

Medium upgrade (YAML → TS):
- Replace tag.yaml/user.yaml/publication.yaml with TS adapters
- feed.ts (tag feed by topic), search.ts, user.ts with browser scraping
- Richer data: readTime, claps, description

Core pipeline improvements:
- template.ts: trim template before matching (supports multiline expressions)
- template.ts: evalJsExpr fallback for JS expressions in YAML templates
- template.ts: add urlencode/urldecode filters
- transform.ts: inline select inside map params
- build-manifest.ts: TS-over-YAML dedup with warning log
- build-manifest.ts: export scanTs/shouldReplaceManifestEntry for testing

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-22 01:01:21 +08:00
jakevin 7776db83d7 docs: consolidate adapter docs and discovery loading (#212) 2026-03-22 00:24:45 +08:00
plat1ko fae1dce027 feat(xueqiu): add earnings-date command (#211)
Add new YAML adapter to fetch upcoming earnings dates from xueqiu's
company events API (公司大事). Supports A-share and H-share stocks.

Features:
- Filter by subtype=2 (预计财报发布) from event timeline
- Show date, report name, and release status (⏳/✅)
- --next flag to return only the closest upcoming earnings date
- --limit to control result count

Co-authored-by: nekomoto911 <nekomoto911@gmail.com>
2026-03-22 00:22:30 +08:00
jakevin d831b04d48 feat(browser): advanced DOM snapshot engine with 13-layer pruning pipeline (#210)
Core Changes:
- New dom-snapshot.ts: 13-layer LLM-optimized DOM pruning engine
  - Tag filtering, SVG collapse, ad/noise detection
  - CSS visibility, viewport threshold, paint-order occlusion
  - Shadow DOM traversal, same-origin iframe extraction
  - BBox parent-child dedup, attribute whitelist + synthetic attrs
  - Table → markdown serialization
  - Incremental diff (mark new elements with *)
  - data-opencli-ref annotation for precise click/type targeting
  - Hidden interactive element hints (scroll-to-reveal)

New APIs:
- IPage.scrollTo(ref) — scroll to snapshot-identified elements
- IPage.getFormState() — extract all form fields as structured JSON
- scrollToRefJs(), getFormStateJs() — standalone JS generators

Integration:
- Page (daemon) + CDPPage (direct CDP): use new engine as primary
- dom-helpers click/type: 4-layer fallback (data-opencli-ref → data-ref → CSS → index)
- Exports from browser/index.ts barrel

Testing:
- 21 new tests for dom-snapshot engine
- All 283 tests pass (29 files, 1.07s)
- Split test scripts: npm test (unit only), npm run test:all (full)
2026-03-22 00:11:51 +08:00
jakevin a22875814b refactor: replace hardcoded skipPreNav with declarative navigateBefore field (#208)
Browser adapters using COOKIE/HEADER strategy need the page on the target
domain so credentialed fetch() carries cookies. Previously, execution.ts
hardcoded `cmd.site === 'boss'` to skip this pre-navigation for adapters
that handle their own goto().

Now each adapter self-declares via `navigateBefore: false` on CliCommand.
This is more extensible — new sites that manage their own navigation just
add the field instead of editing execution.ts.

Changes:
- Add `navigateBefore?: boolean | string` to CliCommand interface
- Add `resolvePreNav()` helper in execution.ts (replaces hardcoded check)
- All 14 boss adapters declare `navigateBefore: false`
- Wire through discovery.ts (YAML + manifest) and build-manifest.ts
2026-03-21 23:52:29 +08:00
云比云 ae30763e9b refactor(boss): extract common.ts utilities, fix missing login detection (#200)
* refactor(boss): extract common utilities, fix missing login detection

- Add src/clis/boss/common.ts with shared helpers:
  - bossFetch(): unified XHR template with auto cookie-expiry detection (code 7/37)
  - navigateToChat()/navigateTo(): page navigation helpers
  - checkAuth()/assertOk(): centralized login state validation
  - fetchFriendList()/fetchRecommendList()/findFriendByUid(): data queries
  - clickCandidateInList()/typeAndSendMessage(): UI automation helpers
  - verbose(): conditional debug logging

- Refactor all 14 boss adapters to use common.ts:
  - chatlist.ts: was missing cookie-expiry check (fixes #login-detect)
  - chatmsg.ts: was missing cookie-expiry check (fixes #login-detect)
  - Remaining 12 adapters: deduplicated XHR boilerplate and error handling

- Fix execution.ts: skip redundant pre-navigation for TS adapters
  - TS adapters handle their own goto(), pre-navigating caused double
    page loads and could trigger duplicate login prompts
  - Pre-navigation preserved for YAML pipeline commands that need it

Net reduction: ~730 lines of duplicated code across boss adapters.
All 244 unit tests pass.

* fix(review): fix execution.ts pre-nav regression, sanitize UID input, restore docs

- execution.ts: use site-specific skip (boss only) instead of isYamlPipeline.
  The original check skipped pre-navigation for ALL TS adapters, but weread,
  chaoxing, and others don't do their own goto() and depend on it.
- common.ts: sanitize numericUid to digits-only and use JSON.stringify for
  safe interpolation in page.evaluate() (prevents template literal injection).
- resume.ts: restore HTML structure doc comments (scraping selector guide).
- send.ts: restore MQTT architecture note (explains why UI automation is needed).

* fix: restore DEBUG env support in verbose(), improve skipPreNav comment

- verbose() now checks both OPENCLI_VERBOSE and DEBUG=opencli,
  matching the original behavior from search.ts and detail.ts
- Clarify skipPreNav comment with TODO for future adapter-level flag

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-21 23:37:13 +08:00
jakevin 3669a89323 fix: fix social adapter bugs, sync docs, refactor boss common utils (#204)
* refactor(boss): extract common utilities, fix missing login detection

- Add src/clis/boss/common.ts with shared helpers:
  - bossFetch(): unified XHR template with auto cookie-expiry detection (code 7/37)
  - navigateToChat()/navigateTo(): page navigation helpers
  - checkAuth()/assertOk(): centralized login state validation
  - fetchFriendList()/fetchRecommendList()/findFriendByUid(): data queries
  - clickCandidateInList()/typeAndSendMessage(): UI automation helpers
  - verbose(): conditional debug logging

- Refactor all 14 boss adapters to use common.ts:
  - chatlist.ts: was missing cookie-expiry check (fixes #login-detect)
  - chatmsg.ts: was missing cookie-expiry check (fixes #login-detect)
  - Remaining 12 adapters: deduplicated XHR boilerplate and error handling

- Fix execution.ts: skip redundant pre-navigation for TS adapters
  - TS adapters handle their own goto(), pre-navigating caused double
    page loads and could trigger duplicate login prompts
  - Pre-navigation preserved for YAML pipeline commands that need it

Net reduction: ~730 lines of duplicated code across boss adapters.
All 244 unit tests pass.

* fix: fix social adapter bugs and sync docs with implementation

Instagram:
- Remove 6 non-existent commands from docs (like/unlike/comment/save/unsave/follow/unfollow)
- Fix usage examples to use positional args

Facebook:
- Remove 6 non-existent commands from docs (friends/groups/memories/events/add-friend/join-group)
- Fix search.yaml: URL encode query param, add missing url column
- Fix feed.yaml: add English locale support for engagement regex patterns

TikTok:
- Fix save/unsave: replace broken data-e2e="undefined-icon" with bookmark-icon/collect-icon
- Fix like/unlike: add state detection to prevent toggling (checks aria-label + computed color)
- Fix notifications: rewrite nested setTimeout to async/await
- Fix comment: add post-comment verification, throw on missing post button

---------

Co-authored-by: Wing Huang <huangsen365@gmail.com>
2026-03-21 23:11:24 +08:00
sline eb0ccaf549 feat(instagram,facebook): add write actions and extended commands (#201)
* feat(instagram,facebook): add write actions and extended commands

Instagram write actions (7 commands, internal REST API + CSRF token):
- like/unlike: like or unlike a user's post by username + index
- comment: comment on a user's post
- save/unsave: bookmark or remove bookmark on a post
- follow/unfollow: follow or unfollow a user

Facebook extended commands (6 commands, DOM scraping):
- friends: friend suggestions list
- groups: list your joined groups with last post time
- memories: On This Day memories
- events: browse event categories
- add-friend: send friend request by username
- join-group: join a group by ID

All commands tested with live data. 258 existing tests pass.

* docs: add adapter documentation for instagram, facebook, lobsters

* docs: add missing medium adapter documentation
2026-03-21 23:09:39 +08:00
AstroHan fbf051d539 fix(extension): skip chrome-extension:// tabs in resolveTabId fallback (#198)
* fix(extension): skip chrome-extension:// tabs in resolveTabId fallback

Remove the unsafe fallback that returned `tabs[0]` regardless of URL
type. When no web-accessible tab exists in the automation window (e.g.
a New Tab Override extension replaced about:blank with its own
chrome-extension:// page), we now always create a fresh about:blank
tab instead. This prevents chrome.debugger.attach from failing with
"Cannot access a chrome-extension:// URL of different extension".

Fixes #195, fixes #197

* refactor(extension): rename isWebUrl → isDebuggableUrl & reuse tabs in resolveTabId

Improvements over the original fix:

1. Rename isWebUrl() → isDebuggableUrl(): better reflects the intent —
   the function determines whether a URL can be attached via CDP, not
   just whether it's a "web" URL (about:blank is debuggable but not
   really a web URL).

2. Reuse existing non-debuggable tabs: when a New Tab Override extension
   replaces about:blank with chrome-extension://, use chrome.tabs.update()
   to navigate the existing tab to about:blank instead of creating a new
   one. This prevents orphan tab accumulation since chrome.tabs.create()
   may also get intercepted by the same extension.

3. Only fall back to chrome.tabs.create() when the window has zero tabs,
   which is the truly empty-window edge case.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-21 23:05:06 +08:00
Kasumi fcff2e40be feat(grok): add opt-in --web flow for grok ask (#193) 2026-03-21 23:00:10 +08:00
sline 4391ccfcb8 feat(tiktok): add TikTok adapter with 15 commands (#202)
* feat(tiktok): add TikTok adapter with 15 commands

TikTok (15 commands, browser mode):

Read commands:
- profile: user profile info via rehydration script parsing
- search: search videos via internal search API
- explore: trending videos from explore page (DOM scraping)
- user: recent videos from a user page (DOM scraping)
- following: list accounts you follow
- friends: friend suggestions
- live: browse live streams with viewer counts
- notifications: activity notifications

Write commands (verified with real interactions):
- like/unlike: like or unlike a video by URL
- save/unsave: add or remove video from Favorites
- follow/unfollow: follow or unfollow a user
- comment: comment on a video

All write operations verified with live TikTok interactions.

* docs: add missing adapter documentation for doc-coverage CI
2026-03-21 22:57:56 +08:00
sline ce484c2a63 feat: add Lobste.rs, Instagram, and Facebook adapters (#199)
* feat(lobsters): add Lobste.rs adapter with hot, newest, active, tag commands

Add public API adapter for Lobste.rs (lobste.rs), a developer-focused
link aggregation community. All commands use the public JSON API and
require no authentication or browser.

Commands:
- hot: hottest stories
- newest: latest stories
- active: most active discussions
- tag: filter stories by tag (e.g. rust, security, programming)

* feat(instagram,facebook): add Instagram and Facebook adapters

Instagram (7 commands, browser mode - internal REST API):
- profile: user profile info (followers, following, posts, bio)
- search: search users
- user: recent posts from a user
- followers: list user's followers
- following: list user's following
- saved: saved posts
- explore: discover trending posts

Facebook (4 commands, browser mode - DOM scraping):
- profile: user/page profile info
- notifications: recent notifications
- feed: news feed posts
- search: search people, pages, posts

All commands require Chrome to be logged in to the respective site.
Instagram uses stable internal API endpoints with cookie auth.
Facebook uses DOM scraping via role attributes and semantic selectors.
2026-03-21 20:43:32 +08:00
VK 06c902aeed feat(medium): add medium adapter (#190) 2026-03-21 20:42:45 +08:00
AlexYue 1d39295f4b feat: plugin system (Stage 0-2)
* feat: plugin system (Stage 0-2)

- Stage 0: discoverPlugins() scans ~/.opencli/plugins/ at startup
- Stage 1: demo plugin repos (github-trending, hot-digest)
- Stage 2: opencli plugin install/uninstall/list commands
- package.json exports ./registry for TS plugin peerDep support
- 17 new/updated tests, tsc --noEmit clean

* fix: CDPBridge connect timeout unit mismatch (seconds vs ms)

opts.timeout is passed in seconds from runtime.ts but CDPBridge
was using it as milliseconds, causing instant timeout (30ms).

* feat: add registry-api public entry point for TS plugin peerDep support

- Add src/registry-api.ts: re-exports core registration API (cli, Strategy,
  getRegistry) without transitive side-effects, safe for plugin imports
- Update package.json exports: './registry' -> './dist/registry-api.js'
- Update src/registry.ts: use globalThis shared registry to ensure single
  instance across npm-linked plugin modules
- Update .gitignore for plugin-related artifacts

* fix: symlink host opencli into plugin node_modules on install

After npm install, replace the npm-installed @jackwener/opencli
with a symlink to the running host's package root. This ensures
TS plugins always resolve '@jackwener/opencli/registry' against
the host installation, avoiding version mismatches when the
published npm package lags behind.

* fix: transpile TS plugins to JS on install, deduplicate .ts/.js discovery

- installPlugin: after symlinking host opencli, transpile any .ts files
  to .js using esbuild from the host's node_modules/.bin/
- discoverPluginDir: skip .ts files when a .js sibling exists (production
  node cannot load .ts directly)
- scanPluginCommands: deduplicate basenames via Set to avoid showing
  'aggregate, aggregate' when both .ts and .js exist

* docs: add plugin system user guide

- New docs/guide/plugins.md covering:
  - Installation/uninstallation commands
  - Creating YAML plugins (zero-dep)
  - Creating TS plugins (with peerDep)
  - TS plugin install lifecycle (clone → deps → symlink → transpile)
  - Example plugins and troubleshooting
- Add Plugins to VitePress sidebar (EN + ZH)
- Link from getting-started.md Next Steps

* fix: address review issues in plugin system

- Security: replace execSync with execFileSync to prevent shell injection
- Replace deprecated npm --production with --omit=dev
- Tighten parseSource regex to [\w.-]+ to reject special chars
- Fix ZH sidebar plugin link (/guide/plugins → /zh/guide/plugins)
- Return plugin name from installPlugin() to avoid duplicated logic
- Use execFileSync for esbuild transpilation
- Fix misleading comment in linkHostOpencli

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-21 19:41:15 +08:00
jakevin 50ec7c6868 fix(docs): remove dead link to deleted github adapter (#194) 2026-03-21 13:48:49 +08:00
jackwener 644b8bcbd4 chore: remove github adapter (covered by gh CLI hub) 2026-03-21 10:55:03 +08:00
jackwener 4e274a92b7 v1.1.1 v1.1.1 2026-03-21 10:49:39 +08:00
jakevin d1ade61e8c fix(twitter): rewrite trending from YAML to TS with DOM scraping fallback (#189)
* fix(twitter): rewrite trending from YAML to TS with DOM scraping fallback

The old REST API /i/api/2/guide.json returns 503. Replace with a TS
adapter that:
- Tries legacy guide.json API first (with proper auth headers)
- Falls back to DOM scraping via [data-testid='trend'] elements
- Filters out promoted content
- Follows the same Strategy.COOKIE pattern as timeline.ts

* fix: use 'help' instead of 'description' in Arg (matches Arg interface)

* docs(steam): add adapter documentation, update READMEs

- Create docs/adapters/browser/steam.md
- Add steam entry to README.md and README.zh-CN.md
- Fixes doc-coverage CI check (44/44)
2026-03-21 10:44:32 +08:00
jakevin 5d84c6f63e Merge pull request #187 from yanCode/codex/fix-apple-podcasts
Fix Apple Podcasts search query handling and top chart failures
2026-03-21 10:32:03 +08:00