Commit Graph

1131 Commits

Author SHA1 Message Date
jakevin 1ecbf7a17c Revert "feat(output): optimize table formatting with width capping and key/value layout (#1081)" (#1085)
This reverts commit 3bbea014e5.
2026-04-19 21:47:35 +08:00
Benjamin Liu 3bbea014e5 feat(output): optimize table formatting with width capping and key/value layout (#1081)
* feat(output): optimize table formatting with column width capping and key/value layout

Closes #1017

* test(output): cover key-value and width-capped tables

* fix(output): truncate capped table cells

* test(output): make table assertions color-safe

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-19 21:39:29 +08:00
Eagle 6b2f4cdc31 feat(browser): add cross-origin iframe support via CDP execution contexts (#1084)
* feat(browser): add cross-origin iframe support via CDP execution contexts

Enable interaction with cross-origin iframes through CDP's execution
context mechanism, without requiring content scripts or all_frames.

- Track frame execution contexts via Runtime.executionContextCreated events
- Add 'frames' action to list all child frames (including cross-origin)
- Support frameIndex in 'exec' action to evaluate JS in specific frames
- Add Page.frames() and Page.evaluateInFrame() APIs for CLI consumers
- Tag cross-origin iframes with [F0]/[F1] indices in DOM snapshots
- Add Page.getFrameTree to CDP allowlist

Closes #1077

Change-Id: Id03361ddb616912dff3bfa8e59e8b68716de590b

* fix(browser): align cross-origin iframe routing contract

* fix(browser): unify iframe frame-index routing

---------

Co-authored-by: xuezhangying <xuezhangying@bytedance.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-19 20:41:59 +08:00
zhengyu fbdb1b24dc fix(browser): harden multi-tab routing and target isolation (#1072)
* fix(browser): harden multi-tab routing and target isolation

- make daemon command ids collision-resistant and retry duplicate pending ids\n- add validated tab list/new/select/close flows with persisted default targets\n- keep untargeted browser commands on the default tab unless tab select changes it\n- document tab targeting and add unit, extension, and e2e coverage for concurrent multi-tab execution

* fix(browser): keep default tab stable after tab new

* fix(browser): close remaining tab routing gates

* docs(browser): align target id wording

* docs(browser): refine target id examples

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-19 18:48:45 +08:00
jakevin fe59ee990c docs: rewrite browser sections — browser is for AI Agents, not manual use (#1080)
From first principles, `opencli browser` commands exist for AI Agents to
operate websites through the browser skill. Reframe both READMEs to reflect
this: show users how to install the skill into their AI agent and describe
tasks in natural language, rather than listing raw CLI commands.
2026-04-19 02:19:10 +08:00
Ocean bb21e7e831 feat(twitter): GraphQL-based lists + list-tweets + list-add/remove (#1076)
* feat(twitter): rewrite lists via GraphQL + add list-tweets

The DOM-scraping / detail-click approach in PR #1053 remained fragile
against X's frequent overview-page rendering changes and slow (N+1 page
loads per list). Rewrite `twitter lists` to call
`ListsManagementPageTimeline` GraphQL directly — one request returns all
owned + subscribed lists with id/name/member_count/subscriber_count/mode.

Also add `twitter list-tweets <listId>` for pulling the tweet stream from
a list, completing the read-side chain (lists → pick an id → list-tweets).

- lists: drop positional `user` arg (GraphQL returns only logged-in
  user's lists), add `id` column, change followers to exact integer from
  subscriber_count.
- list-tweets: same GraphQL pattern as bookmarks/likes (BEARER + ct0 +
  dynamic queryId with static fallback + cursor pagination).
- Delete obsolete lists-parser.js and lists.d.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(twitter): add list-add / list-remove with Save-button commit

Two new commands to toggle list membership. X's list dialog uses a
"click-to-stage, Save-to-commit" pattern — clicking a row only updates
optimistic UI; the actual POST fires when the user clicks the top-right
"Save" button. Pressing ESC or the close-X silently cancels the change.

Implementation:
- Resolve listId → name via ListsManagementPageTimeline GraphQL, so we
  match the dialog row by name (dialog rows have no data-testid listId).
- Open profile page → DOM click "…" menu → "Add/remove from Lists".
- Scroll dialog to locate target row (virtualized list).
- page.nativeClick on row — trusted CDP Input.dispatchMouseEvent fires
  React's onclick, flips aria-checked (.click() alone does not suffice;
  X ignores non-trusted events for list mutations).
- page.nativeClick on the Save button — commits to server.
- Verify by re-fetching ListsManagementPageTimeline and diffing
  member_count: success only if N→N±1. No silent successes.

This fixes the pattern where batch `list-add` calls returned success for
every user but committed zero to the server (optimistic UI lied).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: stabilize twitter list manifest and query ids

* docs: add twitter list command discoverability

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-19 01:42:42 +08:00
Pandas886 b65df6b1e2 fix(zsxq): separate content field from title, remove title truncation (#1079)
* fix(zsxq): separate content field from title, remove title truncation

- Split getTopicText to return only title, add getTopicContent for body text
- Remove .slice(0, 120) that was truncating titles
- content field now contains full body text instead of duplicating title

* fix(zsxq): preserve title fallback for body-only topics

---------

Co-authored-by: huzekang <huzekang@opencode.ai>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-19 01:42:31 +08:00
Mu 0cd63562f2 feat: migrate academic and policy adapters (#243)
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-17 15:46:32 +08:00
jakevin 02d637f3d2 fix(e2e): accept CONFIG_ERROR (exit 78) in xiaoyuzhou E2E guard (#1066)
PR #1059 migrated xiaoyuzhou from SSR scraping to authenticated API.
The E2E tests run without credentials, producing exit code 78
(CONFIG_ERROR). The existing `isExpectedChineseSiteRestriction` guard
only caught FETCH_ERROR, PARSE_ERROR, and NOT_FOUND — not config
errors from missing auth credentials.
2026-04-17 12:02:49 +08:00
jakevin 44d87879d8 refactor: clean up design debt — deprecated APIs, duplicated validation, dead plugin wrappers (#1065)
Three improvements from the design debt audit:

1. Remove deprecated `tabId` field and `getActiveTabId()` method
   - Delete `tabId` from DaemonCommand (daemon-client.ts) and Command (protocol.ts)
   - Delete `getActiveTabId()` from IPage interface (types.ts) and Page class (page.ts)
   - Update extension resolveCommandTabId() to remove legacy fallback
   - Update handleTabs select case to remove tabId check
   - The tab→page migration is now complete

2. Unify argument validation into single code path
   - Remove `normalizeArgValue()` from commanderAdapter.ts
   - Commander adapter now passes raw values to prepareCommandArgs()
   - All coercion (bool, int, number) and validation (required, choices)
     happens once in coerceAndValidateArgs() in execution.ts
   - Eliminates duplicated boolean normalization

3. Remove dead plugin filesystem wrappers
   - Delete `promoteDir()` — never called in production code
   - Delete `replaceDir()` — thin wrapper over beginReplaceDir, never called
   - Remove corresponding test-only exports and tests
   - Rename PromoteDirFsOps → ReplaceDirFsOps to match remaining usage
   - Transaction infrastructure (runTransaction, beginReplaceDir,
     beginReplaceSymlink) retained — used by publishStandalonePlugin
     and publishMonorepoPlugins for atomic multi-step operations
2026-04-17 10:52:57 +08:00
jakevin cb9521d52d fix(extension): per-workspace idle timeout for browser sessions (#1064)
* fix(extension): per-workspace idle timeout for browser sessions (#1058)

The global 30s WINDOW_IDLE_TIMEOUT was too aggressive for interactive
`opencli browser` commands where users type manually between invocations.

- browser:*/operate:* workspaces now default to 10 min idle timeout
- Adapter workspaces keep the existing 30s timeout
- Support custom timeout via OPENCLI_BROWSER_TIMEOUT env var (seconds)
  or command-level idleTimeout parameter
- Surface sessionExpired warning when a new window is created after
  the previous session timed out
- Fix stale comment (said 120s, actual was 30s)

Closes #1058

* fix: resolve sessionExpired double-delete race and timeout override lifecycle

Addresses @codex-coder review blockers:

1. sessionExpired flag was never set because getAutomationWindow()
   consumed expiredWorkspaces before handleCommand() could check it.
   Fix: use .has() in getAutomationWindow, only .delete() in handleCommand.

2. workspaceTimeoutOverrides was never cleaned up — once set, it
   persisted until extension restart. Fix: clear override on idle
   timeout expiry, explicit close-window, and borrowed-session detach.

Adds 5 tests covering:
- browser:* uses 10min timeout (not 30s)
- sessionExpired flag is set and consumed correctly
- workspaceTimeoutOverrides cleared on idle expiry
- workspaceTimeoutOverrides cleared on explicit close
- idleTimeout from command applies to workspace override

* refactor: remove sessionExpired warning per product decision

@WAWQAQ decided session-expired warning is not needed.
Remove expiredWorkspaces tracking, sessionExpired flag from protocol,
and related CLI-side warning code. Keep per-workspace timeout and
override lifecycle cleanup.

* fix: clean up workspaceTimeoutOverrides on user-initiated window close

The windows.onRemoved listener was missing workspaceTimeoutOverrides
cleanup, causing stale overrides to persist across sessions when users
manually close the automation window.
2026-04-17 10:51:39 +08:00
jakevin 025df31ce5 refactor(antigravity): keep timeout parsing local (#1063) 2026-04-17 10:11:46 +08:00
deepziyu 8a8f4a1778 fix(antigravity): implement configurable timeout and auto-reconnect for serve (#859)
* fix(antigravity): implement configurable timeout and auto-reconnect for serve

* fix(antigravity): avoid private runtime import

* docs(antigravity): document serve timeout options

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-17 10:04:08 +08:00
Kagura ab44d9f542 fix(xiaoyuzhou): migrate from broken SSR scraping to authenticated API (fixes #1023) (#1059)
* fix(xiaoyuzhou): migrate from broken SSR scraping to authenticated API (fixes #1023)

Xiaoyuzhou removed SSR rendering — /podcast/<id> and /episode/<id> pages
now return 404, breaking fetchPageProps() which scraped __NEXT_DATA__.

Migrate podcast, podcast-episodes, episode, and download commands to use
the existing authenticated API client (requestXiaoyuzhouJson) that
transcript.js already uses successfully.

Changes:
- podcast.js: use /v1/podcast/get API endpoint
- podcast-episodes.js: use /v1/podcast/listEpisode API endpoint
- episode.js: use /v1/episode/get API endpoint
- download.js: use /v1/episode/get API endpoint
- utils.js: remove unused fetchPageProps, keep format helpers
- Update all affected tests (download.test.js, utils.test.js)
- Change strategy from PUBLIC to LOCAL (requires credentials)

* fix(xiaoyuzhou): align local strategy contract

* fix(xiaoyuzhou): align local api metadata

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-16 23:15:40 +08:00
jakevin 4ebada6b99 docs: add adapter docs for eastmoney, tdx, ths (#1061)
#1025 merged hot-rank adapters for eastmoney/tdx/ths but the
accompanying docs were missing. This breaks the Doc Check CI
workflow on every PR ('--strict' mode, exits non-zero when
`scripts/check-doc-coverage.sh` finds adapters without docs),
blocking merges across the board.

Adds a doc page per adapter, registers them in the adapters
index table, and adds sidebar entries in the VitePress config.
2026-04-16 22:57:03 +08:00
AstroHan bc06d99c83 fix(xiaohongshu): detect current draft save success (#1060) 2026-04-16 22:55:29 +08:00
AstroHan 3738cd2595 fix(twitter): repair lists scraping from detail pages (#1053) 2026-04-16 14:33:18 +08:00
AstroHan 240dccd754 fix(xiaohongshu): verify title input sticks on publish (#1050) 2026-04-16 14:30:37 +08:00
Cosmostima 44b4107f36 feat(nowcoder): add 牛客网 adapter with 16 commands (#1036)
* feat(nowcoder): add 牛客网 adapter with 16 commands

Add adapters for Nowcoder (牛客网), China's leading tech job-seeking
and interview preparation community.

- 7 Public commands: hot, trending, topics, recommend, creators, companies, jobs
- 9 Cookie commands: search, suggest, experience, referral, salary, papers, practice, notifications, detail
- All post-list commands include id field for drill-down to detail
- Documentation: adapter page, index table, sidebar entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(nowcoder): register adapter and document usage

---------

Co-authored-by: tima <tima@cosmos-macmini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-15 22:51:55 +08:00
jakevin 3076c12d6c chore: bump version to 1.7.4 (#1045) v1.7.4 2026-04-15 15:50:30 +08:00
Howard 44147e54c1 feat(youtube): add feed, history, watch-later, subscriptions, playlist, like, unlike, subscribe, unsubscribe (#1029)
* feat(youtube): add feed, history, watch-later, subscriptions, playlist, like, unlike, subscribe, unsubscribe

* fix(youtube): normalize subscriptions channel fields

* docs(skills): add youtube command coverage

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-15 12:43:27 +08:00
槑囿脑袋 677e37b7a4 feat(xiaoyuzhou): add episode download and transcript support (#1031)
* feat(xiaoyuzhou): add episode audio download

* feat(xiaoyuzhou): add transcript download support

* docs(xiaoyuzhou): clarify credential file requirement

* fix(xiaoyuzhou): remove env credential fallback
2026-04-15 12:35:27 +08:00
Harvey Yue d48c71b993 feat(binance): depth shows both bids and asks (#1019)
* feat(binance): depth shows both bids and asks

* test(pipeline): cover root data access after inline select

* fix(binance): preserve map select context and register manifest entries

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-15 12:30:31 +08:00
DavidDuang 6fbeda951e feat: add hot stock ranking adapters for eastmoney, tdx, ths (#1025)
* feat: add hot stock ranking adapters for eastmoney, tdx, ths

Add three new site adapters for Chinese stock hot rankings:
- eastmoney/hot-rank: 东方财富热股榜
- tdx/hot-rank: 通达信热搜榜
- ths/hot-rank: 同花顺热股榜

All use Strategy.COOKIE browser mode with page.evaluate() DOM scraping.
Each includes co-located tests (13 tests total, all passing).

* fix(tdx,ths): add symbol validation and deduplication in evaluate()

Add seen Set for deduplication and skip entries with empty symbol/name,
matching the pattern already used in eastmoney/hot-rank.js.

* fix: refine hot-rank selectors based on browser inspection

- eastmoney: use table.rank_table tbody tr with td index-based extraction,
  fix name from a[title] to avoid post content contamination
- tdx: use div.top-cell[data-code] data attributes for reliable extraction,
  add tags column from div.tips-item.gnbk
- ths: use card-based layout selectors, remove price column (not in UI),
  extract tags from div.tag.PFSC-R

* fix(hot-rank): align tdx and ths columns with actual output

* fix: register hot stock ranking adapters

---------

Co-authored-by: dengjingren <dengjingren@cn.wilmar-intl.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-15 12:24:41 +08:00
jakevin 9bcdaaa0be fix(external): use safe npm install for dws (#1033) 2026-04-15 12:12:13 +08:00
zhengyu db70a3aaf3 fix(deamon&extension): preserve network capture and surface extension mismatch diagnostics (#1030)
* fix: preserve network capture and surface extension mismatch diagnostics

Older Browser Bridge installs can still connect to the daemon while
missing two capabilities we now rely on: the network-capture actions
and the extension version handshake. That created three user-facing
failure modes with real impact:

1. `opencli explore ...` crashed with `Unknown action: network-capture-start`
   against an old extension, so exploration stopped before any site
   analysis finished.
2. `opencli doctor` and `opencli daemon status` could show a healthy
   connection even when the extension never reported a version, which
   hid the compatibility problem and sent users toward the wrong fix.
3. After reloading a new extension, `explore` could still report
   `Endpoints: 0 total, 0 API` because `handleNavigate()` detached the
   debugger before top-level navigation and cleared the active network
   capture state right before the page load we needed to observe.

Fix this in two layers:

- Teach `Page` to treat unsupported `network-capture-*` actions as an
  old-extension compatibility case. It now warns once, memoizes the
  unsupported state, and returns empty capture data instead of throwing.
- Teach `doctor` and `daemon status` to treat "connected but version
  unknown" as a warning instead of a healthy state, so version-handshake
  failures are visible immediately.
- Preserve the debugger attachment while network capture is armed, so
  the initial navigation keeps the capture state alive and the extension
  can record requests from the first page load.

Before:

- `opencli explore ...` -> `Error: Unknown action: network-capture-start`
- `opencli doctor` -> `[OK] Extension: connected` / `Everything looks good!`
- `opencli daemon status` -> `Extension: connected` even when the
  extension version was missing
- `opencli explore ...` after reloading the extension -> `Endpoints: 0 total, 0 API`

After:

- `opencli explore ...` on an old extension -> warns once and continues
- `opencli doctor` -> `[WARN] Extension: connected (version unknown)`
- `opencli daemon status` -> `Extension: connected (version unknown)`
- `opencli explore ...` on the reloaded extension keeps network capture
  armed across navigation instead of clearing it before the page load

* fix: reset network capture flags on closeWindow()

Prevents stale _networkCaptureUnsupported flag from persisting across
sessions when the user reinstalls or reloads the extension mid-session.

* fix: startNetworkCapture returns boolean to prevent false-positive on old extensions

When the extension doesn't support network-capture-*, startNetworkCapture()
now returns false instead of silently resolving. This ensures browser open/
network correctly falls back to the JS interceptor on old extensions.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-15 12:07:31 +08:00
jakevin 0040081f2b fix: auto-restart stale daemon and improve connection error messages (#1028)
* fix: auto-restart stale daemon and improve connection error messages

When daemon is running but extension never connected (stale daemon started
before extension was installed), the CLI now auto-restarts the daemon to
give the extension a fresh WebSocket endpoint, instead of just waiting
and then telling the user to install the extension.

Also improves error messages across cli.ts, bridge.ts, and doctor.ts to
suggest "opencli daemon stop && opencli doctor" as the quick fix, since
that's what actually resolves the issue.

* fix: version-aware stale daemon detection and improved error messages

- Daemon /status now includes `daemonVersion` field
- bridge.ts: when daemon is running but extension not connected, checks
  daemonVersion vs CLI version. Only auto-restarts if version mismatch
  (stale daemon from older CLI). Same-version daemon shows improved error
  message with "opencli daemon stop && opencli doctor" hint.
- doctor.ts: explicitly identifies stale daemon (version mismatch) in
  diagnostics report, shows daemon version in status line
- cli.ts: error message changed to suggest "opencli daemon stop && opencli doctor"

* fix: treat missing daemonVersion as stale, verify shutdown before respawn

- Missing daemonVersion (pre-version daemon) is now treated as stale,
  covering the most common user scenario (old daemon without version field)
- After requestDaemonShutdown(), poll until daemon actually stops (port
  released) before spawning new one, with 3s timeout
- If shutdown request fails, log warning instead of silently proceeding
- doctor.ts also treats missing daemonVersion as stale with clear message

* fix: fail explicitly when stale daemon replacement fails

- If shutdown request fails or port isn't released within 3s, throw
  'Stale daemon could not be replaced' instead of blindly spawning on
  an occupied port
- Add tests for all three stale-daemon branches: same-version (no
  restart), missing daemonVersion (stale), mismatched version (stale)

* fix: use type-based error dispatch in browserAction instead of string matching

browserAction() now checks `instanceof BrowserConnectError` first and
renders both message and hint, instead of string-matching on message
content. This ensures stale daemon errors ("Stale daemon could not be
replaced") surface the actionable hint to the user.
2026-04-15 11:33:26 +08:00
AstroHan 16d597cfce fix(doubao): harden ask response parsing (#933)
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-14 20:43:12 +08:00
flizzywine ba3a674d7b feat(grok): add image command for grok.com image generation (#906)
* feat(grok): add image command for grok.com image generation

Add `opencli grok image <prompt>` which submits a prompt via the existing
grok.com browser session and returns the generated image URLs from the
latest assistant bubble.

Because assets.grok.com URLs are gated by Cloudflare and cannot be
downloaded with a plain HTTP client, the --out flag triggers an in-page
fetch(credentials: 'include') so the browser session's cookies and
referer are attached, then writes the decoded blob to disk.

Flags:
- --new       start a fresh chat before sending
- --timeout   max seconds to wait for the image (default 240)
- --count     minimum number of images to wait for before returning
- --out       directory to save downloaded images

Ships with unit tests for the helpers (isOnGrok, normalizeBooleanFlag,
dedupeBySrc, imagesSignature, extFromContentType, buildFilename).

* fix(grok): harden image composer and bubble detection

* fix(grok): harden image flow and docs

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-14 20:42:43 +08:00
warkcod 0e38fd8c37 Feat/douban book subject (#993)
* chore: ignore local worktrees

* feat(douban): support book subject details
2026-04-14 20:41:14 +08:00
AstroHan cd48917a39 fix(xiaohongshu): require signed note URLs (#996)
* fix(xiaohongshu): require signed note urls

* chore: drop generated manifest from pr
2026-04-14 20:40:58 +08:00
CissiBot 45d6f5b09f feat(uiverse): add Uiverse code and preview adapters (#1000)
* feat(uiverse): add code and preview adapters

* fix(manifest): register uiverse commands

* docs(uiverse): add usage examples

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-14 20:38:38 +08:00
XavierCai 3ebc46f978 feat(bilibili): favorite command supports specifying fid (#1013)
* feat(bilibili): favorite command supports specifying fid

* fix(bilibili): sync favorite help and docs contract

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-14 20:37:54 +08:00
Benjamin Liu 6e29845dc3 fix(plugin): install monorepo sub-plugin dependencies when not hoisted (#1007)
Closes #722
2026-04-14 17:25:50 +08:00
mademing68092354-glitch 88bce1becf fix(chatgpt): support Chinese UI for model selector (#1006)
When ChatGPT macOS app is set to Chinese language, the "Options"
button label becomes "选项". This change checks for both English
and Chinese labels to find the button.

Co-authored-by: mad <mademing@maddeMac-mini.local>
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-14 17:21:54 +08:00
jakevin ca68f3999b feat: Ref-Backed Locator for browser actions (#1016)
* feat: implement Ref-Backed Locator for browser actions

Introduces a unified target resolution system with fingerprint
verification and structured error diagnostics.

Snapshot phase:
- Each interactive element now gets a fingerprint (tag, role, text,
  ariaLabel, id, testId) stored in window.__opencli_ref_identity
- Zero overhead: metadata is already available during DOM walk

Resolution phase (new target-resolver.ts):
- Numeric input → ref path with fingerprint verification
- CSS-like input → querySelectorAll with uniqueness check
- No more silent first-match: ambiguous selectors are rejected

Error model (new target-errors.ts):
- stale_ref: element identity changed since snapshot
- ambiguous: CSS selector matched multiple elements (with candidates)
- not_found: element not in DOM or invalid input
- All errors include actionable hints for AI agents

base-page.ts:
- click() and typeText() now use two-phase resolve-then-act
- Existing CDP fallback for click preserved

* feat: migrate scrollTo to unified resolver pipeline

scrollTo now uses the same two-phase resolve-then-act pattern as
click and typeText, getting fingerprint verification and structured
error diagnostics (stale_ref/ambiguous/not_found) for free.

* fix: address review — stronger fingerprint verification & surface TargetError in CLI

1. Fingerprint verification now uses the full identity vector (tag, id,
   testId, ariaLabel, role, text) instead of just tag/role/text. Strong
   identifiers (id, testId) are decisive; remaining signals use majority
   voting. Fixes false negatives where same-tag elements swapped.

2. browserAction() now renders TargetError with code, hint, and
   candidates list instead of just the message string.

* fix: migrate get/select/type-autocomplete to unified resolver

- browser get text/value/attributes now resolve via resolveTargetJs
  instead of raw querySelector, getting fingerprint verification and
  structured errors for free
- browser select uses selectResolvedJs on __resolved element
- type command's autocomplete detection uses isAutocompleteResolvedJs
  on the already-resolved element
- Fix empty-string text prefix match: fp.text="Login" + text="" no
  longer falsely passes fingerprint check
2026-04-14 16:57:05 +08:00
jakevin 847c8317b6 fix(twitter): register lists command in manifest (#1011) 2026-04-14 10:37:34 +08:00
forvendettaw 741bcf9b6e Add bookmark_count field to bookmarks command (#1010)
* Add bookmark_count field to bookmarks command

Extract bookmark_count from legacy object in Twitter GraphQL
Bookmarks response. Add to returned tweet object and table columns.

* fix(manifest): sync twitter bookmarks columns

---------

Co-authored-by: Hermes Agent <hermes@lei.zong>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-14 10:27:20 +08:00
dependabot[bot] 44388d21fc chore(ci): bump softprops/action-gh-release from 2.6.1 to 3.0.0 (#1002)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.1 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2.6.1...v3.0.0)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-14 10:18:45 +08:00
dependabot[bot] 745ce459d1 chore(deps): bump undici from 8.0.2 to 8.1.0 (#1003)
Bumps [undici](https://github.com/nodejs/undici) from 8.0.2 to 8.1.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v8.0.2...v8.1.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-14 10:18:32 +08:00
dependabot[bot] a5cd0dc307 chore(deps): bump @types/node from 25.5.2 to 25.6.0 (#1004)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-14 10:18:24 +08:00
dependabot[bot] beabed4bad chore(deps): bump vitest from 4.1.2 to 4.1.4 (#1005)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.2 to 4.1.4.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-14 10:18:15 +08:00
jakevin fa208ec761 docs: sync Highlights cleanup across all doc surfaces (#1009)
- docs/index.md: update feature cards to match README Highlights
- docs/zh/index.md: sync Chinese feature cards
- docs/guide/getting-started.md: align Highlights section
- README.zh-CN.md: rename "为什么是 OpenCLI" to "亮点", align with EN
2026-04-14 09:24:33 +08:00
jakevin 56a727cc04 docs: remove empty Why OpenCLI section and clean up Highlights (#1008)
- Remove the empty "Why OpenCLI" heading
- Rename "CLI All Electron" to "Desktop App Control" for clarity
- Remove "Anti-detection built-in" (exposes implementation details)
- Remove "Broad coverage" (duplicates intro and Built-in Commands table)
- Merge "Self-healing setup" and "Dynamic Loader" out (minor features)
- Rename "External CLI Hub" to "CLI Hub" for brevity
2026-04-14 09:19:08 +08:00
jakevin feedaf93b4 fix: remove duplicate extension zip from releases (#1001)
* fix: remove duplicate extension zip from releases

The release and build-extension workflows were creating both
opencli-extension.zip and opencli-extension-v{version}.zip (identical
content), causing both to be uploaded. Keep only the versioned filename.

* docs: update extension zip filename to versioned format

Update all references from opencli-extension.zip to
opencli-extension-v{version}.zip to match the workflow change.
2026-04-13 23:47:58 +08:00
jakevin 9ebb921c89 chore: prune legacy config switches (#998) 2026-04-13 23:28:30 +08:00
jakevin 9ac2e1d8ef chore: bump version to 1.7.3 (#997) v1.7.3 2026-04-13 23:12:50 +08:00
SherlockSalvatore 2aee4caa10 feat(mubu): add Mubu adapter with 5 commands (#964)
* feat(mubu): add mubu (mubu.com) adapter with 5 commands

Commands: doc, docs, notes, recent, search.

- Uses COOKIE strategy; API calls via in-page XHR with Jwt-Token
  from localStorage (matches the web app's own mechanism).
- Renders node trees to Markdown (default) or plain text;
  supports tables, tasks, images, emoji, mentions, strikethrough,
  underline, and nested structures.
- notes supports flexible time ranges: single day, month, year,
  or custom --from/--to spans, plus a --list overview mode.
- search returns full-text matches with hit count and snippets
  for both folders and documents.

* fix(manifest): register mubu commands in runtime manifest

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-13 16:50:32 +08:00
jakevin 323fe8857c refactor: unify OPENCLI_VERBOSE and DEBUG=opencli (#991)
* refactor: unify OPENCLI_VERBOSE and DEBUG=opencli into one mechanism

Three debug output levels (verbose/debug/diagnostic) was redundant.
Merge DEBUG=opencli into OPENCLI_VERBOSE so `-v` flag controls all
verbose/debug output through a single mechanism.

- log.verbose() now checks both OPENCLI_VERBOSE and DEBUG=opencli
- log.debug() becomes an alias for log.verbose() (backward compat)
- boss/utils.js verbose helper simplified to check OPENCLI_VERBOSE only
- DEBUG=opencli still works as fallback (no breaking change)

* fix(boss): preserve debug fallback for verbose logs
2026-04-13 16:48:06 +08:00
jakevin ff6563d12a Fix automation window not closing on command failure (#992)
The error path in executeCommand did not call page.closeWindow(),
leaving the automation window open until the extension's idle timer
fires. On Windows, MV3 service worker suspension makes this timer
unreliable, causing windows to linger indefinitely.

Now closeWindow is called after diagnostic collection but before
rethrowing, ensuring the window is closed on both success and failure.
2026-04-13 16:47:47 +08:00