Commit Graph

264 Commits

Author SHA1 Message Date
jakevin ba2dcc0dcc fix(browser): enforce fixed daemon bridge port (#2031) 2026-06-27 21:51:54 +08:00
jakevin 22bedf21eb docs(readme): recommend OpenCLIApp install path 2026-06-22 03:01:19 +08:00
AstroHan c027944380 feat(xiaohongshu): add ask adapter with citations
feat(xiaohongshu): add ask adapter with citations

Co-authored-by: codex-mini1 <codex-mini1@users.noreply.github.com>
Co-authored-by: First-principles-1 <first-principles-1@users.noreply.github.com>
2026-06-14 04:13:56 +08:00
sundyli ac0a8ba725 feat(huodongxing): add events adapter
feat(huodongxing): add events adapter

Co-authored-by: codex-mini0 <codex-mini0@users.noreply.github.com>
Co-authored-by: First-principles-0 <first-principles-0@users.noreply.github.com>
2026-06-14 04:12:38 +08:00
Jacky 7382a3541f feat(slock): add collaboration adapter
feat(slock): add collaboration adapter

Co-authored-by: codex-mini1 <codex-mini1@users.noreply.github.com>
Co-authored-by: First-principles-1 <first-principles-1@users.noreply.github.com>
2026-06-13 02:52:05 +08:00
Ocean aa468589c5 feat(bilibili,xiaohongshu): add follow and unfollow commands
feat(bilibili,xiaohongshu): add follow and unfollow commands

Co-authored-by: codex-mini0 <codex-mini0@users.noreply.github.com>
Co-authored-by: First-principles-0 <first-principles-0@users.noreply.github.com>
2026-06-12 02:13:10 +08:00
jakevin d8fc0a9e2b docs: hide single-command WeChat Channels from site lists (#1865) 2026-06-06 00:51:14 +08:00
jakevin cc760810a2 feat(browser): surface sitemap context (#1820) 2026-06-02 01:26:30 +08:00
jasonyang365 6d99979c4d feat(trae-cn): add desktop adapter
Reviewed-by: codex-mini1
Reviewed-by: First-principles-1
No-check override: WAWQAQ 2026-06-01
2026-06-01 01:15:28 +08:00
Zhongyue Lin 1aec5c59dc feat(trae-solo): add desktop adapter
Reviewed-by: codex-mini0
Reviewed-by: First-principles-0
No-check override: WAWQAQ 2026-06-01
2026-06-01 00:55:46 +08:00
RavenLiao cbf1ac1558 feat(wechat-channels): add publish adapter
Reviewed-by: codex-mini0
Reviewed-by: First-principles-0
No-check override: WAWQAQ 2026-06-01
2026-06-01 00:22:06 +08:00
Zhongyue Lin 6126413d60 feat(qoder): add Qoder IDE adapter
Reviewed-by: codex-mini0
Reviewed-by: First-principles-0
No-check override: WAWQAQ 2026-06-01
2026-06-01 00:07:49 +08:00
Zhongyue Lin 5b11251692 feat(kimi): add kimi.com adapter
Reviewed-by: codex-mini1
Reviewed-by: First-principles-1
No-check override: WAWQAQ 2026-06-01
2026-06-01 00:05:48 +08:00
Gaurav Saxena 3307640a05 feat(twitter): add batch follow and list lifecycle commands
Reviewed-by: codex-mini0
Reviewed-by: First-principles-0
2026-05-31 20:23:54 +08:00
jakevin c3d2fc1f9f docs(readme): prefix Let AI Agents bullet with "Browser User &" (#1796) 2026-05-31 04:56:56 +08:00
jakevin 4e8bad41fb Revert "docs(readme): add Trendshift "trending repo" badge to top of README (#1773)" (#1774)
This reverts commit 29e8fe9a16.
2026-05-28 17:40:50 +08:00
jakevin 29e8fe9a16 docs(readme): add Trendshift "trending repo" badge to top of README (#1773)
Per WAWQAQ DM. OpenCLI is featured on Trendshift
(https://trendshift.io/repositories/23541) — surfacing the badge at
the top of README gives social proof to new visitors and links back
to the Trendshift listing.

Placement: above the `# OpenCLI` heading so it renders as a banner
before the title (standard Trendshift placement pattern). 250×55 inline
SVG. Both EN and ZH READMEs updated.
2026-05-28 17:38:59 +08:00
Gaurav Saxena 7ed42a67b8 feat(linkedin): read profile experience
Add a LinkedIn profile-experience reader with visible-DOM extraction, typed empty/auth/parser boundaries, safe http(s) URL output, and documentation.
2026-05-27 02:27:13 +08:00
jakevin b6965a5973 feat(linkedin): consolidate read commands
Consolidates PRs #1722, #1723, #1724, #1725, #1726, and #1727 after B-group lead+aux review.\n\nReviewed-by: codex-mini1\nReviewed-by: First-principles-1
2026-05-23 17:01:56 +08:00
lamb liu 6804324066 feat(geogebra): add GeoGebra browser adapter suite
Merged by pr-manager after lead+aux content green; maintainer explicitly allowed no-check gate override.
2026-05-22 11:30:05 +08:00
NSOiO 6ed93fdbe5 feat(upwork): add search, feed, and detail commands
Merged by pr-manager after lead+aux content green; maintainer explicitly allowed no-check gate override.
2026-05-22 11:28:53 +08:00
jakevin cd2c3ebf81 docs(readme): correct Node floor (>=20 not 21) + drop Prerequisites section (#1705)
Per WAWQAQ DMs:

1. The README stated "Node.js >= 21" in 6 places, but the actual
   runtime floor is 20 (`MIN_SUPPORTED_NODE_MAJOR = 20` in
   src/runtime-detect.ts, `engines.node: ">=20.0.0"` in package.json,
   undici pinned to 6.x in 1.8.0 to keep Node 20 compatibility).
   Stale carryover from before PR #1518/#1524 lowered the floor.
   All 6 mentions (3 EN, 3 ZH) corrected to 20.

2. Prerequisites section was redundant with Quick Start (Node version
   is in step 1 "Install OpenCLI"; Chrome/login state is in step 2
   "Install Browser Bridge Extension" + step 3 "Verify"). Removed in
   both EN and ZH.
2026-05-21 16:15:57 +08:00
Benjamin Liu 299c020eb3 feat(chess): add Chess.com adapter
Adds Chess.com stats/games/game/analyze commands using the public Chess.com API/callback endpoints with typed error boundaries and docs/tests.
2026-05-20 18:01:15 +08:00
jakevin 7d0f46d009 docs(readme): CLI Hub brand aliases + Exit Codes split to docs (#1685)
Per WAWQAQ DM:

1. **CLI Hub**: bare-name enumeration ("ntn", "discord") didn't tell
   readers what those binaries map to. Switched to the `opencli external
   list` brand-alias format: `ntn(notion)`, `discord(discord-cli)`,
   `dws(DingTalk Workspace)`, `wecom-cli(企业微信)`, `tg(tg-cli)`,
   `wx(wx-cli)`. Names that are already self-explanatory (gh / docker /
   vercel / wrangler / obsidian / longbridge / lark-cli) stay bare.

2. **Exit Codes**: the 9-row table + example block was disproportionate
   for a README. Compressed to one sentence with the 7 actionable codes
   inline, full table relocated to:
   - EN: `docs/guide/exit-codes.md` (new)
   - ZH: `docs/zh/guide/exit-codes.md` (new)
2026-05-20 03:58:27 +08:00
jakevin 5cb075d102 docs(readme): drop For Developers section (#1684)
Per WAWQAQ: from-source install instructions are infrastructure detail
that don't belong in a public-facing README. Contributors finding
themselves in this repo will already know `npm install / build / link`
patterns; users who reach the README from npm don't need them.

Removed in both EN and ZH.
2026-05-20 03:55:37 +08:00
jakevin 7a2ab47bf8 chore(skills): remove smart-search (#1683) 2026-05-20 03:23:32 +08:00
jakevin 2c8b50c4fd docs(readme): shrink CLI Hub + Core Concepts + merge Update into Install (#1681)
Per WAWQAQ:

1. **CLI Hub**: drop the 13-row 3-column table; enumerate just the
   names inline ("gh · docker · vercel · wrangler · ntn · obsidian · …")
   plus one-liner register / list commands. Removes "Manual install"
   ntn note (search lives in external-clis.yaml / ntn's own docs).
   Compresses the 7-row Desktop App Adapters table to a single inline
   line pointing at docs/adapters/desktop/.

2. **Core Concepts** section dissolved: its four subsections
   ("browser", "Built-in adapters", "Writing a new adapter",
   "CLI Hub and desktop adapters") duplicated the intro 3-bullet
   + later dedicated sections. Kept the substantive "Writing a new
   adapter" callout as its own top-level section. The "For AI Agents
   (Developer Guide)" tail block at the bottom was a third copy of
   the same recipe — removed.

3. **Update** merged with **Install skills**: install header now
   reads "Install skills (also refreshes existing installs)", and
   the standalone Update section collapses to a single command
   (`npm install -g @jackwener/opencli@latest && npx skills add ...`).

Net: EN 410 → 326 (-20%), ZH 455 → 366 (-20%). Same coverage; just
less repetition.
2026-05-20 03:12:36 +08:00
jakevin 4a3a55634a docs(readme): curate built-in commands to popular sites + add wrangler (#1679)
Per WAWQAQ:

1. Built-in Commands table cut from 30 EN rows / 86 ZH rows down to a
   curated 11-site list (xiaohongshu, bilibili, zhihu, hackernews,
   linkedin, reddit, twitter, claude, gemini, notebooklm, amazon).
   The README is meant to surface high-traffic / well-known sites;
   the long-tail (100+ adapters) is one click away via
   docs/adapters/index.md. linkedin (full) replaces linkedin-learning
   in the curated set per the spec.

2. Add Cloudflare Wrangler as a new external CLI passthrough:
   - src/external-clis.yaml entry (binary: wrangler, npm -g)
   - CLI Hub table row in EN + ZH READMEs
   - cli-manifest.json regen reflects the new entry (857 entries)
2026-05-19 23:17:15 +08:00
jakevin acc18be999 docs(readme): tighten skill attribution + remove redundant Highlights (#1666)
Per WAWQAQ T1 + T2 review:

T1 — skill attribution carries the same intent PR #1654 started but
hadn't fully cleaned up:
- Skill table row for `opencli-adapter-author` no longer claims it
  "operate[s] a site in real time" (SKILL.md explicitly says ad-hoc
  driving lives in `opencli-browser`). Browser-op example
  ("Help me check my Xiaohongshu notifications") moved to the
  `opencli-browser` row where it belongs.
- "How it works" section's 5 browser primitives (navigate / read /
  interact / extract / wait) now point to `opencli-browser` instead
  of `opencli-adapter-author`.
- Skill references list re-orders to surface `opencli-browser` first
  with a concrete description, and `opencli-adapter-author` no longer
  claims to cover "browser operation".

T2 — drop the Highlights section. Pre-Quick-Start had four parallel
summary blocks (3-line tagline / 3-bullet automation intro / CLI-hub
+ desktop line / 5-bullet Highlights) that all said the same thing.
Highlights was the most-recent and most-redundant of the four; the
remaining three carry the value props cleanly: tagline → three usage
modes → CLI-hub + desktop scope.

EN + ZH READMEs synced.
2026-05-19 13:28:44 +08:00
Benjamin Liu 67ed9e9c81 feat(linkedin-learning): add search / trending / course read commands (#1657)
* feat(linkedin-learning): add search / trending / course read commands (#1021)

Closes #1021. Adds a new linkedin-learning site adapter with three
read-only commands against LinkedIn Learning's public learning-api
REST surface. Shares cookie session with linkedin.com; Learning
queries are not subject to the people-search CUL.

Commands:
- linkedin-learning search <keywords>  searchV2?q=keywords
- linkedin-learning trending            feedRecommendationGroups?q=learner
- linkedin-learning course <slug>      courses?q=slug

Endpoints were discovered via browser network capture on
/learning/search and /learning/<slug> pages: searchV2 returns a flat
list of courses/videos/paths keyed by entityType, headline.title.text
holds the canonical title, length is a TimeSpan in seconds, and rating
is averaged from ratingSum/ratingCount when averageRating is missing.

trending walks the carousels array on each recommendation group, flattens
cards across them, dedups by slug, and respects --limit. Group is
labeled with the carousel title (e.g. "Top picks for you") or the
upstream annotation tag (TOP_PICKS).

course accepts either a bare slug or a full /learning/<slug> URL, then
hits /learning-api/courses?q=slug. The detail endpoint omits rating
fields even when search reports them; this is documented in the
adapter doc rather than fixed via a second /reviews fetch to keep the
PR scoped to one endpoint per command.

CUL caveat: Learning's API has no per-month limit, so dev iterations
can be much more aggressive than the people-search adapter (#1649).
Three commands were live-verified against a logged-in account with
60s sleeps between calls (conservative for first-pass safety).

Tests: 28 unit tests across search.test.js (12), trending.test.js (6),
course.test.js (10) cover URL construction, limit validation, author
join, duration / rating coercion, row mapping, carousel flattening
and dedup, slug parsing from URL forms, and the standard auth /
empty / fetch-failure error paths.

Live verified:
- search "AI agent" --limit 3: 3 rows with title/instructor/rating
- trending --limit 3: 3 personalized course picks
- course agentic-ai-build-your-first-agentic-ai-system: title, 3932s
  duration, 18 videos, release date 2026-03-27

* fix(linkedin-learning): harden read result boundaries

* fix(linkedin-learning): require course title evidence

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-19 13:17:33 +08:00
jakevin f0d9aa187c docs(readme): fix skill attribution for "operate any website" use case (#1654)
Per WAWQAQ feedback: the intro section's "Let AI Agents operate any
website" bullet mistakenly references `opencli-adapter-author`, which
is the skill for **writing** adapters (correctly referenced in the
adjacent "Write new adapters" bullet). The skill for ad-hoc browser
driving is `opencli-browser` — its own SKILL.md frontmatter explicitly
says "Not for writing adapters — see opencli-adapter-author for that",
and `opencli-adapter-author` says "For ad-hoc browser driving (no
adapter), see opencli-browser instead".

Two locations affected with the same error: the intro bullet and the
Core Concepts > `browser` section. Both EN and ZH READMEs updated.
2026-05-19 00:37:32 +08:00
Jun 24f643af16 feat(xianyu): add inbox, messages, and reply commands (#1639)
* fix: tighten internal callback types

* feat(xianyu): add private message commands

* fix(xianyu): harden IM command contracts

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-18 20:41:51 +08:00
jakevin 0c488bbf51 docs(readme): simplify Highlights from 9 to 5 bullets (#1605)
Per WAWQAQ feedback: the previous Highlights list was bloated with hollow
marketing phrases and overlapping bullets (e.g. "Browser Automation for AI
Agents" + "AI Agent ready" said the same thing twice, "Pipeable, scriptable,
CI-friendly" is generic CLI filler).

Cut "AI Agent ready", "Account-safe" (folded into Live Browser Automation),
"Deterministic"'s second sentence (folded into Zero LLM cost), and merged
"Website → CLI" with "CLI Hub" into "100+ adapters + CLI Hub". Result is 5
concrete capability bullets instead of 9, each tied to a real feature.

EN and ZH READMEs kept in sync.
2026-05-16 20:57:33 +08:00
asimov 663b3387ee feat(bilibili): add summary command for the official AI video summary (#1590)
* feat(bilibili): add summary command for the official AI video summary

Adds `opencli bilibili summary <bvid>` — fetches Bilibili's official
AI-generated video summary (the "AI总结" shown on the video page) via
/x/web-interface/view/conclusion/get.

Returns the overall summary followed by the timestamped section outline,
so you get a structured digest of a video without watching it.

- Resolves cid + up_mid from the view endpoint (both required by the
  conclusion API), then calls the WBI-signed conclusion endpoint.
- Throws a clear EmptyResultError when a video has no AI summary —
  Bilibili only generates them for some videos.

Covered by clis/bilibili/summary.test.js (5 cases): summary + outline,
summary without outline, no-summary, view-resolution failure, API error.

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

* fix(bilibili): harden summary command contract

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-16 16:50:48 +08:00
胡大头 baf1522420 feat: add Youdao Notes shared note reader adapter (#1547)
* feat: add Youdao Notes shared note reader adapter

Add a new adapter for reading publicly shared Youdao Notes (有道云笔记).

- youdao note <url>: Fetches a public shared note by its share URL
  using browser-based DOM extraction. Extracts title, content, and
  keyword tags from the React-rendered page.
- Supports note.youdao.com and note.youdao.cn share URLs.
- Includes test coverage (3 tests) and documentation.

Closes #1418

* fix: extract full note content from React Redux store

Previously the adapter only extracted the AI summary section from the
DOM. Now it accesses the React fiber tree to read the full note content
from the Redux store (store.content.data.content), which contains the
complete note body in Youdao's structured format.

The extractor recursively walks Youdao's proprietary node format (key '8'
for text content) to reconstruct the full note as plain text.

* fix(youdao): harden shared note reader contract

---------

Co-authored-by: huzekang <huzekang@opencode.ai>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-16 14:16:25 +08:00
jakevin e3995df25c docs(readme): tighten tagline + add form-filling example (#1596)
- Replace 2-line tagline (websites/browser/electron/local + reuse logged-in browser) with a single line emphasizing the two core capabilities side by side: 把任意网站变成 CLI & 让 AI Agent 操控登录态浏览器
- Add "Help me fill out this form" as the leading opencli-browser skill example so the table surfaces browser-side capabilities, not just scraping
2026-05-16 13:15:37 +08:00
jakevin b6f352b318 feat(external): add longbridge cli (#1584) 2026-05-15 16:27:08 +08:00
jakevin 9c4f4a3d30 fix(cli): show external CLI package aliases (#1560) 2026-05-14 16:28:18 +08:00
jakevin 29c135b656 refactor(notion): replace built-in CDP adapter with external ntn CLI (#1559)
* refactor(notion): replace built-in CDP adapter with external ntn CLI

Notion has shipped an official CLI at https://ntn.dev. It uses the
public Notion API (blocks / databases / properties / comments) instead
of reverse-engineering the Desktop UI, so it survives Notion app
updates and exposes a wider command surface than the in-tree adapter
could.

Changes:
  - `src/external-clis.yaml` — register `ntn` as first-class external CLI
    (binary `ntn`, homepage ntn.dev, install via the shell-pipe script
    on mac/linux)
  - `clis/notion/` — entire directory removed (8 commands: status /
    search / read / new / write / sidebar / favorites / export)
  - `docs/adapters/desktop/notion.md` — removed
  - `docs/.vitepress/config.mts` — drop nav entry
  - `docs/adapters/index.md` — drop adapter row
  - `README.md` / `README.zh-CN.md` — drop notion from feature lines,
    drop adapter table row, add `ntn` to CLI hub examples
  - `docs/index.md` / `docs/zh/index.md` / `docs/guide/getting-started.md`
    — drop notion from electron-control feature copy
  - `skills/opencli-usage/SKILL.md` — drop notion from electron list
  - `cli-manifest.json` — rebuilt with --allow-removals=8

Migration for users:
  `curl -fsSL https://ntn.dev | bash`  (or `opencli external install ntn`)
  Then use `opencli ntn <command>` in place of `opencli notion <command>`.

Rationale: the in-tree adapter was reverse-engineered against Notion
Desktop CDP and shipped only 8 commands. The official CLI gives users
the full Notion API surface and reduces our maintenance burden to zero.
Same pattern as gh / obsidian / lark-cli / tg-cli / discord-cli / wx-cli.

Verification:
  - `npx tsc --noEmit` clean
  - `npx vitest run --project unit` → 1091/1 skipped
  - `npm run build` (with --allow-removals=8) — manifest 809 entries
  - grep notion in user-facing docs (README / docs / skills) — only
    descriptive mentions remain in non-blocking places (comparison /
    site-recon / electron how-to / design doc), no broken adapter
    references

* fix(notion): align ntn external migration

* docs(notion): clarify ntn manual install
2026-05-14 16:12:17 +08:00
jakevin 40b2f75098 feat(external)!: drop -cli suffix from tg/discord/wx subcommand names (#1544)
The opencli external-CLI name is the user-typed subcommand; the binary is
what gets executed. The convention everywhere else (`gh`, `docker`,
`obsidian`, `vercel`, `dws`) is `name == binary`. Three entries violated
the convention: `tg-cli` / `discord-cli` / `wx-cli` registered an
opencli name with a `-cli` suffix that does NOT exist on the binary,
forcing the awkward double-prefix `opencli discord-cli dc` instead of
`opencli discord dc`.

The README's example column already showed the desired form
(`opencli tg search`, `opencli discord recent`, `opencli wx search`) —
only the yaml registration was out of sync.

Renames in `src/external-clis.yaml`:

* `name: tg-cli`     → `name: tg`       (binary: `tg`)
* `name: discord-cli`→ `name: discord`  (binary: `discord`)
* `name: wx-cli`     → `name: wx`       (binary: `wx`)

The `binary`, `homepage`, and `install` fields are unchanged — the
underlying packages (`kabi-tg-cli`, `kabi-discord-cli`, `@jackwener/wx-cli`)
keep their published names.

Other entries left as-is: `lark-cli`, `wecom-cli`, and `dws` already have
`name == binary` (their actual binaries are `lark-cli`, `wecom-cli`, `dws`).

BREAKING CHANGE: `opencli tg-cli ...`, `opencli discord-cli ...`,
`opencli wx-cli ...` no longer resolve. Use `opencli tg ...`,
`opencli discord ...`, `opencli wx ...` instead. The feature is recent
(shipped 2026-05) so impact is expected to be minimal.
2026-05-14 04:13:39 +08:00
jakevin 587750cad3 refactor(env): remove OPENCLI_KEEP_TAB (#1509)
`OPENCLI_KEEP_TAB` was a debugging shortcut, not a config dimension. It
let users override `--keep-tab` globally via the shell environment,
which contradicts the per-command lifecycle model: `siteSession:'persistent'`
already pins persistent site tabs as a hard adapter-metadata constraint,
and `--keep-tab true|false` covers the ad-hoc override case. The env
just leaked process state across every browser command in the shell.

Changes:
  - src/execution.ts: `resolveKeepTab()` drops the
    `normalizeBooleanOption('OPENCLI_KEEP_TAB', process.env.OPENCLI_KEEP_TAB)`
    fallback. `--keep-tab` is now the single user override.
  - src/execution.test.ts: two regression tests rewritten to use the
    `executeCommand(cmd, {}, false, { keepTab: 'true' })` signature
    instead of the env. Logic and assertions unchanged.
  - README.md / README.zh-CN.md / skills/opencli-usage/SKILL.md:
    drop the env table row. `--keep-tab` documentation stays.
  - CHANGELOG.md: BREAKING entry under Unreleased.

Note: the 1.7.15 CHANGELOG entry still references the env historically;
that's intentional, historical entries are not retroactively edited.

Verification:
  - npx tsc --noEmit pass
  - npx vitest run --project unit --project extension → 1144/1145 pass
    (1 unrelated skip)
  - typed-error-lint baseline 189
  - silent-column-drop baseline 103
2026-05-12 22:02:17 +08:00
jakevin 0e168d570e refactor(browser): replace --session flag with <sessionname> positional (#1505)
* refactor(browser): replace --session flag with <sessionname> positional

The `--session <name>` flag was semantically required but syntactically
optional, which is an anti-pattern. Required + flag is a contradiction:
flag form implies "optional", required is a runtime patch on top. Session
is OpenCLI's "operation target" identifier — the natural form for that is
a positional argument, like `docker exec <container> <cmd>` or
`git checkout <branch>`.

New surface:

  opencli browser <sessionname> open https://x.com
  opencli browser <sessionname> click 12
  opencli browser <sessionname> bind
  opencli browser <sessionname> unbind

Commander 14 cannot natively combine a parent positional with subcommand
dispatch — the parent's positional is shadowed by subcommand matching. To
bridge that, main.ts now pre-processes argv: when the token after `browser`
is non-flag and not a known subcommand name, it is treated as the
sessionname and rewritten to the internal `--session <name>` flag form
before commander parses it. Help text on the `browser` command is
overridden via `.usage('<sessionname> <command> [options]')` so users see
the positional form.

Reserved subcommand names (33) are listed in cli-argv-preprocess.ts and
tested for parity with cli.ts subcommand registrations. If a future
subcommand is added, the test fails loudly.

Synced surfaces:
  - README.md / README.zh-CN.md — all examples
  - docs/guide/browser-bridge.md (+ zh)
  - skills/opencli-browser/SKILL.md (bind/unbind, examples, table)
  - skills/opencli-usage/SKILL.md
  - tests/e2e/browser-tabs.test.ts
  - CHANGELOG.md (Unreleased BREAKING)

The internal `--session` flag and the unit tests calling
`program.parseAsync(['...', 'browser', '--session', 'foo', ...])` are
preserved as a stable internal API: tests bypass main.ts pre-processing
and exercise commander directly. The pre-processor has its own targeted
test file (cli-argv-preprocess.test.ts, 10 tests, all green).

Verification:
  - npx tsc --noEmit — pass
  - npx vitest run --project unit — 1073/1074 pass (1 unrelated skip)
  - npx vitest run --project extension — 61/61 pass
  - npm run check:typed-error-lint — baseline 189
  - npm run check:silent-column-drop — baseline 103

* fix(cli-argv): only rewrite when `browser` is the root command

The preprocessor was looping through every argv slot and would mis-rewrite
occurrences of the literal word `browser` deeper in argv (e.g. `opencli
adapter init browser/x` or arg values containing `browser`).

Now the preprocessor walks past leading root flags + their values to
identify the root command token, and only acts when that token is
`browser`. The full set of root value-consuming flags
(`ROOT_VALUE_FLAGS`) is documented inline and kept in sync with the
`program.option()` calls in cli.ts.

Adds regression tests:
  - `opencli adapter init browser x` not rewritten
  - URL/path values containing `browser` not rewritten
  - `list browser state` (different root command) not rewritten
  - `--profile work browser foo state` correctly identifies `foo` as
    sessionname (not as --profile's value)
  - `--profile=work` long-form-with-equals consumes one slot only
  - boolean flags (`-v`) don't consume the next value

12/12 preprocessor tests pass.

* fix(cli-argv): hide --session flag, fail-fast on retired form, rename to <session>

Three blockers in #1505 review:

1. `--session` flag was still visible in `opencli browser --help` and could
   be used as a public entrance, contradicting "positional only" UX.
   Fix: switch from `.requiredOption()` to `.addOption(new Option(...).hideHelp())`.
   The flag is preserved as an internal API for the daemon protocol and direct
   `program.parseAsync` callers (tests), but is no longer documented or
   surfaced in structured help.

2. `opencli browser --session foo state` still succeeded. Now the argv
   preprocessor throws `BrowserSessionArgvError` when root `browser` is
   followed by `--session`, and main.ts catches it and exits with a
   user-facing usage error pointing to the positional form.

3. Missing-session error message exposed the internal flag:
   `required option '--session <name>' not specified`. Now `getBrowserSession()`
   in the action body throws `<session> is a required positional argument:
   opencli browser <session> <command>`, and commander no longer guards the
   hidden option.

Also (per @WAWQAQ) rename placeholder `<sessionname>` -> `<session>` everywhere
user-facing — shorter, matches CLI convention. The help text "<session> is a
required positional: pass the name of the browser session..." carries the
"name" semantics in description, not in the placeholder itself.

Sync surfaces:
  - src/cli.ts — usage line, addOption with hideHelp, descriptions
  - src/cli-argv-preprocess.ts — throw on --session form
  - src/cli-argv-preprocess.test.ts — refusal test for old form
  - src/cli.test.ts — assertions updated for hidden option + new error path
  - src/help.ts — read `_usage` private field to respect `.usage()` override
    (commander's `.usage()` getter returns auto-generated form if not set,
    which would otherwise pollute every namespace's usage string)
  - src/main.ts — catch BrowserSessionArgvError, stderr + exit
  - README.md / README.zh-CN.md
  - docs/guide/browser-bridge.md / docs/zh/guide/browser-bridge.md
  - skills/opencli-browser/SKILL.md / skills/opencli-usage/SKILL.md
  - CHANGELOG.md

Manual smoke tests (against built dist):
  - `opencli browser --help` shows `Usage: opencli browser <session> <command> [options]`
  - `opencli browser --help` Options block does NOT show `--session`
  - `opencli browser --session foo state` → friendly error, no commander stacktrace
  - `opencli browser state` → `<session> is a required positional argument: opencli browser <session> <command>`
  - `opencli browser foo state` → parses correctly

* fix: inject <session> into subcommand help paths and drop stale sessions ref

Two follow-up blockers from #1505 review:

1. Subcommand help and structured help still rendered the command path
   without the parent's positional. `opencli browser foo state --help`
   showed `Usage: opencli browser state [options]`, which would lead
   users (and agents reading structured help) to think
   `opencli browser state` was a valid invocation. Now:

   - `commanderPath()` injects an ancestor's leading-positional placeholder
     (extracted from its `.usage()` override) between the ancestor's name
     and the next path segment when building paths upward.
   - `commandPathFromRoot()` strips placeholder segments (e.g. `<session>`)
     from the relative `name` field so agents can still address subcommands
     by their leaf name; placeholders remain in the `command` / `usage`
     display paths.
   - `program.configureHelp({ commandUsage: ... })` is applied recursively
     to every descendant of `browser`, because commander does NOT inherit
     `configureHelp` into subcommands.

   Result:
     opencli browser <session> click --help
     -> Usage: opencli browser <session> click [target] [options]

   Daemon, plugin, adapter, profile namespaces (no `.usage()` override)
   are unaffected.

2. `skills/opencli-browser/SKILL.md` still referenced
   `opencli browser sessions`, which was removed in #1470. Replaced the
   sentence with the underlying invariant ("Bound sessions have no
   OpenCLI idle-close timer; the binding lasts until `unbind`, tab close,
   window close, or daemon restart") without mentioning the deleted
   command.

Tests:
  - cli.test.ts: structured help expectations updated to include
    `<session>` in command/usage paths (3 tests)
  - cli-argv-preprocess.test.ts: 12 tests still green
  - 1136/1137 unit+extension green (1 unrelated skip)
  - typed-error-lint baseline 189
  - silent-column-drop baseline 103
2026-05-12 20:44:29 +08:00
Benjamin Liu 64ac362a40 feat(rednote): add rednote.com adapter mirroring xiaohongshu read commands (#1136) (#1475)
* feat(rednote): add rednote.com adapter mirroring xiaohongshu read commands (#1136)

Implements rednote.com support as discussed in issue #1136. The mainland
xiaohongshu adapter stays in place; international users redirected to
www.rednote.com now have a CLI without a copy-pasted adapter.

Issue #1136 documents that xiaohongshu and rednote share DOM selectors,
URL paths, API paths, response schema, cookies, and the xsec_token auth
mechanism. The only material differences:

  Layer            xiaohongshu                rednote
  Web host         www.xiaohongshu.com        www.rednote.com
  API host         edith.xiaohongshu.com      webapi.rednote.com
  Security host    fe-static.xhscdn.com       as.rednote.com
  Cookie root      .xiaohongshu.com           .rednote.com
  Search gate      Inline text                Full-screen modal + text

## Architecture (minimal)

`clis/xiaohongshu/*` keep all selector / regex / extraction logic. Each
command file is touched minimally to export the IIFE or pipeline so the
sibling adapter can reuse it:

  search.js          + export const buildSearchExtractJs(webHost)
                     + export const command = cli({...})
  note.js            + export const NOTE_EXTRACT_JS
                     + export const command = cli({...})
  comments.js        + export function buildCommentsExtractJs(withReplies)
                     + export parseCommentLimit
                     + export const command = cli({...})
  download.js        + export function buildDownloadExtractJs(noteId)
                       (CDN allowlist now includes rednote alongside xhscdn)
                     + export const command = cli({...})
  user.js            + export const USER_SNAPSHOT_JS
                     + export const command = cli({...})
  feed.js            + export function buildFeedPipeline(webHost)
                     + export const command = cli({...})
  notifications.js   + export function buildNotificationsPipeline(webHost)
                     + export const command = cli({...})
  note-helpers.js    buildNoteUrl now accepts `cookieRoot` + `signedUrlHint`
                     options (defaults preserved so xhs callers and tests
                     are unchanged)
  user-helpers.js    buildXhsNoteUrl / extractXhsUserNotes accept an
                     optional `webHost` argument (default xhs)

The `export const command = cli({...})` pattern matches twitter/lists.js
and clis/discord-app/*; without it the build-manifest scanner attributes
xhs's command to whichever rednote sibling triggered the transitive
import first.

## clis/rednote/ — thin shims

Each rednote command file imports the relevant builder / constant from
its xiaohongshu sibling and calls `cli()` with the rednote host triple.
No selectors, regexes, or extraction logic are duplicated.

  search.js          imports buildSearchExtractJs + noteIdToDate
                     declares its own WAIT_FOR_CONTENT_JS (modal + text
                     login-gate variants — the one xhs behaviour that
                     genuinely differs)
  note.js            imports NOTE_EXTRACT_JS + buildNoteUrl + parseNoteId
  comments.js        imports buildCommentsExtractJs + parseCommentLimit
                     + buildNoteUrl + parseNoteId
  download.js        imports buildDownloadExtractJs + buildNoteUrl + parseNoteId
  user.js            imports USER_SNAPSHOT_JS + extractXhsUserNotes
                     + normalizeXhsUserId

## Scope (initial)

Ships the five commands verified live against the user's logged-in
rednote.com session: search / note / comments / user / download.

`feed` and `notifications` are intentionally left out. Both rely on
intercepting the xiaohongshu Pinia store at the `homefeed` / `you`
capture pattern; live verification on rednote returns `tap → dict
(error)` for the feed step, so shipping them would surface a broken
contract. The mainland xiaohongshu commands continue to work. Adding
the rednote-side feed / notifications is straightforward follow-up
work once someone with rednote access maps the network surface.

Creator-center commands (publish, creator-*) have no rednote
counterpart and stay xiaohongshu-only, per the reporter's note in #1136.

## Verification

  - clis/xiaohongshu/ + clis/rednote/: 103/103 tests green
  - npx tsc --noEmit: clean
  - npm run build: 807 manifest entries (xhs 13 + rednote 5 + everything
    else preserved)
  - silent-column-drop / typed-error-lint: 103 / 189 baseline entries,
    no new violations
  - Live verify against the user's rednote.com session:
      rednote search "travel" --limit 1 → real note row
      rednote note <signed-url>         → 7 field/value rows
      rednote comments <signed-url> --limit 3 → 3 top-level rows
      rednote user 5b21f6564eacab3b38f05c39 --limit 2 → 2 profile notes
    Spaced 15–30s between runs per the xhs/rednote rate-limit guidance;
    no write commands invoked. Regression check: xiaohongshu/feed on
    the existing mainland session still returns the standard 6-field
    rows after the refactor.

Closes #1136

* fix(rednote): tighten adapter failure boundaries

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-12 02:32:25 +08:00
jakevin 467fdd0b62 refactor(adapter): rename site browser reuse to persistent sessions (#1462) 2026-05-11 04:56:34 +08:00
jakevin 9c06e84c89 refactor(browser): replace workspaces with sessions (#1461) 2026-05-11 04:26:51 +08:00
jakevin 864af48b0b docs(readme): list tg-cli, discord-cli, wx-cli in External CLI sections (#1459)
Follow-up to feat #1458 (registering tg-cli/discord-cli/wx-cli in
src/external-clis.yaml) — README and README.zh-CN had not been updated
to reflect the new entries.

Updates four spots in each README:
- intro paragraph that names example external CLIs
- "CLI Hub" highlight bullet
- "OpenCLI is not only for websites" bullet list
- the External CLI table itself
2026-05-11 03:19:53 +08:00
jakevin a92f382c2d refactor(browser): split interactive and automation windows 2026-05-11 01:48:18 +08:00
jakevin da833d3efe chore(release): clean stale metadata surfaces (#1395)
chore(release): clean stale metadata surfaces
2026-05-07 22:00:51 +08:00
jakevin fa7851bb9a feat(browser): add adapter session reuse (#1383) 2026-05-07 15:24:54 +08:00
hanzi 2a85152875 feat(browser): add verified fill command (#1222)
* feat(browser): add verified fill command

* feat(browser): implement exact fill primitive

* docs(browser): document fill pipeline submit

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-05-06 02:22:50 +08:00