Commit Graph

788 Commits

Author SHA1 Message Date
jakevin ba67a3e086 docs: add individual skill install examples to README (#702)
Root SKILL.md was already removed in #703. Add per-skill install
commands to both EN and CN READMEs (without --full-depth since
root SKILL.md no longer blocks sub-skill discovery).
v1.6.1
2026-04-03 00:23:56 +08:00
jakevin ed1a61a445 chore: remove root SKILL.md, simplify README skill install (#703)
Root SKILL.md is redundant — skills/ directory (opencli-operate,
opencli-explorer, opencli-oneshot, opencli-usage) handles discovery.
Simplified README to single install command.
2026-04-03 00:12:31 +08:00
jakevin fe82b3882f docs: update outdated adapter counts, operate commands, and skill references (#701)
- Update adapter count from 50+/60+/66+ to 70+ across all docs (actual: 74 sites)
- Add missing operate commands (eval, network, init, verify) to README
- Add opencli-operate skill to Install AI Skills section in both READMEs
- Replace outdated "Playwright MCP Bridge" with "Browser Bridge" in doubao docs
2026-04-02 23:32:36 +08:00
jakevin 4d036a5364 chore: release v1.6.1 (#700) 2026-04-02 22:45:41 +08:00
jakevin a23de8fe7d fix: sync package-lock.json version to 1.6.0 (#698)
The v1.6.0 release commit bumped package.json but not package-lock.json,
causing bun/npm install failures due to version mismatch.
2026-04-02 22:39:09 +08:00
sline b8f1abc3a1 fix(twitter): use search input for SPA navigation instead of pushState (#695)
* fix(twitter): add search input fallback for intermittent SPA navigation failures

The pushState + popstate approach works in most environments but fails
intermittently for some users (see #690), likely due to Twitter A/B
tests or timing race conditions where the pathname hasn't updated when
checked.

This commit adds a fallback strategy: when pushState fails after 2
retries, we type the query into the search input on /explore and press
Enter. This triggers Twitter's own form handler, performing SPA
navigation without a full page reload (keeping the fetch interceptor
alive).

Both strategies use selector-based waiting ([data-testid="primaryColumn"])
rather than fixed delays, with graceful fallthrough on timeout.

Fixes #690

* test(twitter): update search test for fallback evaluate call

The search input fallback adds one extra evaluate() call when pushState
fails. Update the mock chain and assertion count accordingly.

* fix(twitter): guard nativeSetter and add fallback success test

- Add optional chaining on getOwnPropertyDescriptor().set to handle
  edge cases where Twitter's sandbox overrides the HTMLInputElement
  prototype.
- Add test case covering the full fallback path: pushState fails twice,
  search input fallback succeeds, results are returned correctly.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-02 22:27:48 +08:00
jakevin aa3edfefc0 chore: release v1.6.0 (#697) v1.6.0 2026-04-02 22:14:23 +08:00
jakevin b657c946a2 fix(skills): add YAML frontmatter for discovery and improve descriptions (#694)
* fix(skills): add YAML frontmatter for discovery and improve descriptions

- opencli-explorer: add missing frontmatter with name, description, tags
- opencli-oneshot: add missing frontmatter with name, description, tags
- opencli-usage: rewrite description to start with "Use when..." and
  include specific platform names for better keyword matching

Root cause of low trigger rate: explorer and oneshot had no frontmatter
at all, making them invisible to AI agent skill discovery. Usage had a
generic description without triggering conditions.

* fix(skills): add capability index, cross-skill links, and plugins entry

- Add "Quick Lookup by Capability" table so agents can find platforms
  by what they need (search, trending, feed, AI chat, finance, etc.)
- Add plugins.md entry to main index (was completely hidden)
- Add "Related Skills" section linking to opencli-explorer and
  opencli-oneshot for adapter development
- Compress platform listings for scannability

* fix(skills): inline compact command quick-reference table in SKILL.md

Add a self-contained command reference table directly in SKILL.md so
agents that can only read the main skill file still have full command
visibility. Each platform gets one row with all available commands.
Organized into Browser/Desktop/Public API/Management sections.
2026-04-02 22:03:39 +08:00
jakevin bb137ce901 feat: add opencli operate — browser control commands for Claude Code skill (#614)
Add `opencli operate` subcommand group with 15+ commands for
step-by-step browser control, designed as a Claude Code skill.
No LLM API key needed — Claude Code IS the LLM.

Commands:
  Navigation: open, back, scroll
  Inspect: state, screenshot, get (title/url/text/value/html/attributes)
  Interact: click, type, select, keys
  Wait: wait selector/text/time
  Extract: eval (execute JS in page context)
  API Discovery: network (auto-captured since last open, --detail N)
  Sedimentation: init (generate adapter scaffold), verify (test adapter)
  Session: close

Infrastructure:
  - CDP passthrough with 22-method allowlist
  - Two-layer retry for extension interference (aggressive for operate:*)
  - Network interceptor auto-injected on operate open
  - node_modules symlink for user TS adapter imports

Skill: skills/opencli-operate/SKILL.md
  - Complete command reference
  - Sedimentation workflow guide (explore → network → init → verify)
  - Adapter strategy guide (PUBLIC/COOKIE/UI)
  - Dual quickstart (AI Agent 1 step / Human 3 steps)
2026-04-02 19:30:35 +08:00
gucasbrg 7d7203891f fix(twitter): resolve article ID to tweet ID before GraphQL query (#688)
* fix(twitter): resolve article ID to tweet ID before GraphQL query

Article URLs (x.com/i/article/{articleId}) use a different ID than
tweet status URLs. The GraphQL TweetResultByRestId endpoint requires
the parent tweet ID, not the article ID.

Fix: navigate to the article page first, extract the associated tweet
ID from DOM links, then use that for the GraphQL query.

Fixes article fetching returning "Article not found" for all article URLs.

* fix: distinguish article URLs from status URLs, add explicit error handling

The previous commit routed all inputs through the article page, breaking
status URL and bare ID flows. Now only article URLs trigger the
article→tweet ID resolution. Status URLs and bare IDs keep the original
behavior. Also throws an explicit error if resolution fails instead of
silently falling back to the article ID.

---------

Co-authored-by: buruguo <buruguo@lambdafintech.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-02 18:33:51 +08:00
AstroHan 081efe37f7 fix(xiaohongshu): clarify empty note shell hint (#686)
* fix(xiaohongshu): clarify empty note shell hint

* fix(xiaohongshu): simplify empty shell detection to title+author check

The 7-field conjunction was overly strict — a note that rendered only
placeholder metrics but no title/author was still a valid empty shell.
Since title and author are always present on real notes, checking just
those two fields is a more reliable and simpler signal.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-02 18:33:36 +08:00
jakevin 777b882040 refactor: centralize daemon transport client (#692) 2026-04-02 18:28:50 +08:00
luo jiyin eead9e0aa5 docs: add tab completion to getting started guides (#658)
* docs: add tab completion to getting started guide

* docs: add tab completion to zh getting started guide
2026-04-02 16:11:54 +08:00
jakevin a21cc5e9f0 chore: release v1.5.9 (#678) v1.5.9 2026-04-02 13:49:10 +08:00
fii6 abd46bccba feat(gemini): add Gemini web adapter with minimal output (#619)
* feat(gemini): add web adapter with minimal output

* fix(gemini): use defaultFormat for minimal output

* fix(gemini): preserve full transcript responses

* docs(gemini): add browser adapter guide

* review: wire gemini into adapter indexes

---------

Co-authored-by: fii6 <246637913+fii6@users.noreply.github.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-02 13:39:35 +08:00
jakevin 098c7f4f92 feat: create skills/ directory structure (#670)
* feat: create skills/ directory structure per issue #605

- Create skills/opencli-usage/ with index and categorized command references
  - SKILL.md: main index with installation and prerequisites
  - browser.md: all browser-based commands (Bilibili, Twitter, Reddit, etc.)
  - desktop.md: desktop adapter commands (Cursor, Codex, Notion, etc.)
  - public-api.md: public API commands (HackerNews, V2EX, arXiv, etc.)
  - plugins.md: management commands, AI workflow, output formats
- Create skills/opencli-explorer/ from CLI-EXPLORER.md
- Create skills/opencli-oneshot/ from CLI-ONESHOT.md

Addresses #605 - enables skill-based discovery and selective installation

* fix: complete browser.md with all missing adapters and fix incorrect entries

- Added 15 missing browser adapters: Reuters, SMZDM, Ctrip, Barchart,
  Jike, Linux.do, WeRead, Jimeng, Pixiv, Web, Weixin, JD, LinkedIn,
  Sina Finance, Bloomberg (browser)
- Fixed incomplete entries: Facebook (added 5 missing commands),
  Coupang (corrected to match actual CLI), Yollomi (restored all 12
  commands), Doubao Web (restored send/read commands), Grok (fixed format)
- Added missing public APIs: StackOverflow, Xiaoyuzhou, Wikipedia
- Updated SKILL.md index to list all supported platforms across all
  categories including desktop adapters

* refactor: remove root SKILL.md, migrate Record Workflow to opencli-explorer

- Moved Record Workflow documentation (工作原理, 使用步骤, 页面类型表,
  候选 YAML→TS 转换, 故障排查) into skills/opencli-explorer/SKILL.md
- Deleted root SKILL.md — all content now lives under skills/

* docs: add AI skills installation guide to README

Add npx skills add instructions for all 3 skills (opencli-usage,
opencli-explorer, opencli-oneshot) to both README.md and README.zh-CN.md.
2026-04-02 13:38:27 +08:00
GanFanNewOrder d721eb6c6c feat(amazon): add browser adapter and docs (#659)
* feat(amazon): add browser adapter and docs

* review: wire amazon into discovery docs

---------

Co-authored-by: 泽加武 <zejiawu@zejiawudeMac-mini.local>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-02 13:32:23 +08:00
ajia1206 341bb87e09 test(xiaohongshu): redact creator fixture data (#647) 2026-04-02 01:21:53 +08:00
AstroHan 127dc3edea feat: add minimal record write candidates (#665) 2026-04-02 01:21:11 +08:00
jakevin f88e7569e9 refactor: src cleanup — deduplicate errors, cache VM, extract BasePage, remove Playwright MCP legacy (#667)
* refactor: deduplicate transient error checks, cache VM contexts, expose tab ID

- Extract shared isTransientBrowserError() into browser/errors.ts, replacing
  duplicated string-matching lists in daemon-client.ts and pipeline/executor.ts
- Cache compiled vm.Script objects in template.ts with LRU eviction (max 256),
  avoiding per-invocation VM context creation in pipeline loops
- Add getActiveTabId() to IPage interface and Page class for tab state inspection

* refactor: extract BasePage to deduplicate DOM helpers across Page and CDPPage

Both Page (daemon-backed) and CDPPage (direct CDP) had ~200 lines of
identical DOM helper implementations (click, type, scroll, wait, snapshot,
interceptor, etc). Extract shared logic into abstract BasePage class.
Subclasses now only implement transport-specific methods.

* refactor: rename mcp.ts to bridge.ts and clean up Playwright MCP references

The file browser/mcp.ts contained BrowserBridge (daemon session manager),
not MCP functionality. Renamed to bridge.ts for clarity. Also removed all
stale "Playwright MCP" references from comments and variable names across
the codebase — Playwright was removed long ago.
2026-04-02 00:51:15 +08:00
jakevin 9c2a777d11 chore: remove .agents directory (#668)
- Remove redundant .agents/skills and .agents/workflows
- Content already covered in CLI-EXPLORER.md and SKILL.md
2026-04-02 00:27:59 +08:00
jakevin 773178345d refactor: remove bind-current, restore owned-only browser automation model (#664)
* fix(notebooklm): remove bind-current workflow

* fix: relax notebook ID check in open.ts and clean up idle timeout test

- open.ts: only throw when page kind is not 'notebook'; log a warning
  instead of throwing when the notebook ID doesn't match exactly
- background.test.ts: remove unused tabs[1] setup in idle timeout test
  that was leftover from borrowed-session era

* build: rebuild extension dist after bind-current removal
2026-04-01 23:23:48 +08:00
jakevin 1ddca55b4a chore: release v1.5.8 (#663) v1.5.8 2026-04-01 22:12:39 +08:00
小左同学 4818871309 Handle foreign extension embeds before debugger attach (#662)
* Handle foreign extension embeds before debugger attach

* fix(extension): recover owned tabs without mutating borrowed tabs

* fix(extension): avoid adopting unrelated tabs

* Revert "fix(extension): avoid adopting unrelated tabs"

This reverts commit 2cba0c19da.

* Revert "fix(extension): recover owned tabs without mutating borrowed tabs"

This reverts commit 69dfadedae.

* fix(extension): avoid mutating tabs before attach

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-01 22:10:30 +08:00
jakevin c908d9cd47 chore: release v1.5.7 (#654) v1.5.7 2026-04-01 13:09:11 +08:00
jakevin 9b425c7550 feat: Electron auto-launcher — zero-config CDP connection (#653)
* docs: add dingtalk and wecom CLI to external CLI hub

Add dingtalk-workspace-cli and wecom-cli as external CLI integrations
alongside lark-cli, gh, docker, etc.

* feat: add confirmPrompt() to TUI module

* feat: add Electron app registry with builtin + user-defined apps

* feat: add Electron app launcher with auto-detect and restart

* fix: launcher uses processName for path discovery, platform-guard tests

* feat: integrate Electron auto-launcher into execution pipeline

- CDPBridge.connect() accepts cdpEndpoint parameter instead of requiring env var
- getBrowserFactory() selects CDPBridge for registered Electron apps by site name
- executeCommand() calls resolveElectronEndpoint() for Electron apps, skips daemon check
- Remove requiredEnv/OPENCLI_CDP_ENDPOINT from all chatwise commands
- Remove chatwise-opencli.ps1 wrapper script and chatwise/shared.ts
- Update antigravity/serve.ts to use launcher instead of manual env var
- Replace hardcoded app names in scoreCDPTarget with registry lookup
- Fix Discord bundleId typo (com.iscord.app → com.discord.app)

* fix: resolve review issues — port collision and registry completeness

- Change ChatGPT CDP port from 9224 to 9236 (was colliding with Antigravity)
- scoreCDPTarget now uses full registry (builtin + user-defined) via getAllElectronApps()
- Use displayName (falling back to processName) for target score boosting

* fix: assign unique CDP ports — antigravity 9234, chatgpt 9236

Both were sharing port 9224, which could cause silent mis-connection.
2026-04-01 12:49:52 +08:00
reabiter 12443f049e enhance(v2ex): add content, member, created, node fields to topic output (#648)
- Add content field to display topic body text
- Add member field to show topic author
- Add created field to show topic creation timestamp
- Add node field to show topic category
- Add id field for consistency with hot/latest commands

This makes v2ex topic command return meaningful details that are
not available in hot/latest listings.
2026-04-01 02:10:28 +08:00
Jack Lee ee0c2b65ea feat(youtube): add search filters — --type shorts/video/channel, --upload, --sort (#616)
* feat(youtube): add --type shorts/video/channel, --upload, --sort filters

Uses YouTube's native sp= filter params. Shorts = type 9 (sp=EgIQCQ).
Also parses reelItemRenderer for Shorts results.

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

* feat(youtube): add published time to search results

Shows when video was uploaded (e.g. "8h ago", "4d ago", "3mo ago").

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

* fix(youtube): prevent duplicate sp= params and remove redundant Shorts URL rewrite

- YouTube only supports one sp= parameter; using multiple causes
  unpredictable behavior. Pick the most specific filter with priority:
  type > upload > sort.
- Remove the post-processing Shorts URL rewrite — the reelItemRenderer
  branch already generates /shorts/ URLs directly.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-01 01:32:08 +08:00
warkcod 01057527f5 fix(bilibili): distinguish login-gated subtitles from empty results (#645)
* fix(bilibili): distinguish login-gated subtitles from empty results

* fix(test): use single toSatisfy assertion instead of double rejects.toThrow

Awaiting the same rejected promise twice is unreliable. Combine the
AuthRequiredError type check and message regex into one toSatisfy call.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-01 00:59:19 +08:00
reabiter 67fb022f16 fix(v2ex): add id field to hot and latest API responses (#646)
* fix(v2ex): add id field to hot and latest API responses

- Add id field to hot.yaml and latest.yaml pipeline output
- Enables downstream commands like 'v2ex topic <id>' to work seamlessly
- Fixes issue where v2ex hot/latest JSON output lacked topic IDs

* enhance(v2ex): add node and url fields to hot/latest output

In addition to the id field, include node name (板块) and topic URL
for richer output. All fields come from the existing API response.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-04-01 00:25:57 +08:00
jakevin 7ea3f6d3fb feat(stealth): harden CDP debugger detection countermeasures (#644)
Add 6 new anti-detection patches to stealth.ts and CDP-level debugger
statement neutralization to reduce risk of bot detection on platforms
like Xiaohongshu.

New patches:
- Shared toString disguise via WeakMap (undetectable by anti-bot scripts)
- Anti-debugger statement trap (Function/eval patching + CDP Debugger.setBreakpointsActive)
- Console method fingerprinting defense (re-wrap CDP-bound console methods)
- Window dimension detection defense (outerWidth/outerHeight normalization)
- Performance API entry filtering (remove debugger/devtools entries)
- document.$cdc_ property cleanup (backup for window-level cleanup)
- Iframe contentWindow.chrome consistency
2026-03-31 23:34:37 +08:00
ajia1206 818ae61889 fix(douyin): support current creator api response shapes (#618) 2026-03-31 23:01:13 +08:00
jakevin 811e4f5c3e fix(douyin): narrow getDraftCommand return type to fix TS2722 (#643) 2026-03-31 22:59:23 +08:00
AstroHan fea47abcec fix(douyin): repair creator draft flow (#640)
* fix(douyin): handle creator payload shapes

* refactor(douyin): drive draft via creator page

* fix(douyin): save resumable draft session

* fix(douyin): harden draft cover flow

* fix(douyin): wait for stable cover state

* fix(douyin): wait for cover detection result

* fix(douyin): require cover state transition

* fix(douyin): scope cover checks to quick panel

* fix(douyin): narrow quick-check state match

* fix(douyin): drop ambiguous quick-check match

* fix(douyin): test quick-check panel extraction

* fix(douyin): cover busy state extraction

* refactor(douyin): clean up draft tests — temp file cleanup, reduce boilerplate

- Add afterAll cleanup for temp dirs (fixes temp file leak)
- Extract createTempVideo/createTempCover/getDraftCommand helpers
- Remove repeated registry lookup + mkdtempSync boilerplate from each test

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 22:37:35 +08:00
AstroHan 519b3cfe85 fix: avoid in-page redirect in facebook search (#642)
* fix(facebook): split search navigation from extraction

* refactor: use settleMs instead of waitUntil:none + wait:4

Replace `waitUntil: none` + separate `wait: 4` step with `settleMs: 4000`
on the navigate step. This is consistent with other Facebook adapters
(feed.yaml, memories.yaml, profile.yaml) and lets the navigate step
handle the timing in one place.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 22:26:07 +08:00
jakevin 57534cf8b3 feat(daemon): replace 5min idle timeout with long-lived daemon model (#641)
* docs: add daemon lifecycle redesign spec

Replace the aggressive 5-minute idle timeout with a long-lived daemon
model that stays running for hours, reducing restart overhead during
development cycles.

* docs: add daemon lifecycle redesign implementation plan

8-task TDD plan for replacing aggressive 5-minute idle timeout with
long-lived daemon model (4h default, dual-condition exit).

* feat(daemon): add DEFAULT_DAEMON_IDLE_TIMEOUT constant (4 hours)

* feat(daemon): replace fixed 5min timeout with dual-condition idle manager (4h default)

* feat(extension): reduce WS reconnect backoff cap from 60s to 5s

* feat(daemon): improve CLI connection-waiting UX with progress messages and 200ms polling

* feat(daemon): add opencli daemon status/stop/restart commands

* test(daemon): add tests for daemon status/stop commands

* fix(daemon): address code review issues — stale constant, restart robustness, timer cleanup, test coverage

* docs: update daemon documentation for new lifecycle and CLI commands

- troubleshooting.md: replace manual curl/pkill with `opencli daemon status/stop/restart`
- browser-bridge.md (en/zh): add Daemon Lifecycle section
- README.md: add `opencli daemon status` to Quick Start
- README.zh-CN.md: add daemon management commands to tips
2026-03-31 22:17:54 +08:00
jakevin 62fde40aab fix(docs): use relative links in adapter index (#629)
VitePress base is /docs/, so absolute links like /adapters/browser/twitter
resolve incorrectly. Changed all links to relative paths (./browser/...,
./desktop/...) so they work correctly on the docs site.
2026-03-31 14:39:15 +08:00
muqiao215 0204dbb018 feat(notebooklm): add read commands and compatibility layer (#622)
* feat(notebooklm): add read commands and compatibility layer

* review: trim notebooklm artifacts and sync docs

---------

Co-authored-by: qiaoqiao147 <camtup044@gmail.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 13:19:47 +08:00
fii6 1858eace6e feat(instagram): add media download command (#623)
* feat(instagram): add media download command

* feat(instagram): add media download command

* fix(instagram): align download command with platform conventions

---------

Co-authored-by: fii6 <246637913+fii6@users.noreply.github.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 13:04:31 +08:00
Kagura 0fbeb2d77f fix(substack): update selectors for Substack DOM redesign (fixes #621) (#624)
* fix(substack): update selectors for Substack DOM redesign (fixes #621)

Substack replaced <article> elements with role="article" divs and a
new SPA-based feed. The wait() selector 'article' no longer matches,
causing 'Selector not found: article' on feed and publication commands.

- loadSubstackFeed: use 'a[href*="/p/"]' (matches actual post links)
- loadSubstackArchive: use '[role="article"]' (Substack's new ARIA roles)

The evaluate() scraping logic inside both functions is unchanged since
it already uses 'a' href pattern matching, not article tags.

* review: align substack wait selectors with scraper

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 12:58:22 +08:00
AstroHan 33ca81b785 fix(weread): recover book details from cached shelf fallback (#628) 2026-03-31 12:47:52 +08:00
GanFanNewOrder 4c3cd3878e fix(ctrip): update search adapter to live endpoint (#627)
* fix(ctrip): update search adapter to live endpoint

* review: make ctrip search a public fetch adapter

---------

Co-authored-by: 泽加武 <zejiawu@zejiawudeMac-mini.local>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 12:47:48 +08:00
dependabot[bot] 5f541ea42b chore(deps): bump vitest from 4.1.1 to 4.1.2 (#620)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.2
  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-03-31 12:43:16 +08:00
geegewu ca2165cbc7 fix(xiaohongshu): support full URL/short link and fix video extraction (#615)
* fix(xiaohongshu): support full URL/short link and fix video extraction

Two issues fixed:

1. URL handling: The download command only accepted bare note IDs and
   constructed `explore/{noteId}` URLs, which lack the `xsec_token`
   parameter now required by Xiaohongshu. This made all video/image
   downloads fail with "No media found". Now accepts full URLs
   (with xsec_token) and short links (xhslink.com) in addition to
   bare note IDs.

2. Video extraction: XHS video player uses blob: URLs in DOM, which
   cannot be downloaded via HTTP. Now extracts real video URLs from
   `window.__INITIAL_STATE__` (SSR data) and inline script JSON
   before falling back to DOM selectors, skipping blob: URLs.

Tested with a video note via short link — successfully downloaded
21.5 MB MP4.

* review: resolve xiaohongshu note id after redirects

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-31 00:32:08 +08:00
ahahaha d0803857f1 feat(xiaohongshu): add note command and nested reply support for comments (#599)
* feat(xiaohongshu): add note command and nested reply support for comments

Add `xiaohongshu note` command to read full note content (title, author,
description, engagement metrics, tags) from public note pages.

Enhance `xiaohongshu comments` with `--with-replies` flag to extract
nested replies (楼中楼), including reply_to attribution and per-reply
like counts. Limit logic counts only top-level comments so replies
are included for free.

Extract shared `parseNoteId` into side-effect-free `note-helpers.ts`
to avoid cross-module command registration leakage.

Normalize non-numeric engagement placeholders ("赞"/"收藏"/"评论")
to "0" for zero-count notes.

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

* docs(xiaohongshu): add note and comments --with-replies to adapter docs

Update xiaohongshu adapter documentation and README command table
to reflect the new note command and enhanced comments with nested
reply support.

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

* docs(xiaohongshu): fix download example to show both note-id and url

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

* fix(xiaohongshu): expand nested reply threads before scraping

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-30 23:29:30 +08:00
Kagura 701d9e859f fix(xiaohongshu): check login wall before autoScroll in search (fixes #597) (#608)
- Add early login-wall detection before autoScroll() in search.ts
  to prevent crash when XHS shows a login gate instead of results
- Add document.body null guard in autoScrollJs (dom-helpers.ts)
- Update search.test.ts: verify autoScroll is not called on login wall
- Add autoScrollJs null-body defense test in dom-helpers.test.ts
2026-03-30 23:12:02 +08:00
AstroHan 59d41f28e1 fix(zhihu): stop question command failing on unused detail fetch (#606)
* fix(zhihu): stop question command failing on unused detail fetch

* review: harden zhihu question fetch path

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-03-30 23:10:53 +08:00
jakevin fcdc15d385 fix: improve weixin article download extraction (#612) 2026-03-30 23:01:44 +08:00
jakevin 030adc9341 fix: restore root SKILL.md (#609) 2026-03-30 21:30:37 +08:00
jakevin 62e3c55993 chore(release): 1.5.6 (#596) v1.5.6 2026-03-30 13:27:19 +08:00