Commit Graph

1548 Commits

Author SHA1 Message Date
jackwener 60c4884e9d fix: register the native host on npm install -g
`opencli host install` is no longer a required setup step. Global
postinstall writes the Chrome Native Messaging manifest; the first
browser command still repairs it if Chrome was not installed yet.
2026-08-24 02:52:08 +08:00
jackwener b03ac61afd chore: sync package-lock with main's undici 7.29.0
GitHub PR CI installs a merge of this branch into main. Main pinned
undici to 7.29.0; the lock still had 6.27.0, so npm ci failed on every job.
2026-08-24 02:49:12 +08:00
jackwener 10c41ce2f5 fix: harden the native host mux after review
Backoff reconnect until hello-ok, slice native frames by UTF-8 bytes,
and give each host a per-pid socket so shutdown cannot unlink a successor.
RPC failure is not ready. Rebuild the committed extension dist, bump it
to 1.0.24, and drop the daemonVersion alias. Replace the TCP e2e fake
daemon with a unix-socket host and a connectNative Chrome smoke.
2026-08-24 02:48:24 +08:00
jackwener 03a3218d2c feat!: replace the TCP daemon with a Chrome Native Messaging host
Chrome parents opencli-host via connectNative. The CLI only connects to a
unix socket under ~/.opencli/run. Drop :19825, HTTP, WebSocket, CORS, and
opencli daemon. Session leases and Command/Result stay in the host mux.
2026-08-24 02:48:24 +08:00
Anupam Mediratta 6d2b11e6ea fix: CVE-2026-13697 security vulnerability (#2326)
Automated dependency upgrade by OrbisAI Security
2026-08-24 02:26:21 +08:00
jakevin 87b60a3659 chore(release): bump version to 1.8.7 (#2359) v1.8.7 2026-08-23 23:58:41 +08:00
jakevin 432cf23101 chore(linkedin): share people search auth helpers (#2358) 2026-08-23 23:48:37 +08:00
jakevin dfc13ea69b chore(linkedin): share messaging thread URL helpers 2026-08-23 23:28:45 +08:00
jakevin f2de8ab808 chore(linkedin): reuse shared unwrap in connect flows 2026-08-23 23:02:43 +08:00
jakevin b158a4a831 chore(linkedin): reuse shared unwrap in salesnav 2026-08-23 22:46:36 +08:00
jakevin 77a4e19f0b chore(linkedin): reuse shared evaluate unwrap
Reuses the existing LinkedIn shared evaluate envelope unwrap helper across general messaging commands while preserving subsystem-local copies for later batches.
2026-08-23 22:28:52 +08:00
jakevin de16476e26 chore(linkedin): share safety URL decoder
Moves the duplicate Node-side LinkedIn safety URL decoder into the site shared helper while preserving page-realm copies and their browser-local contract.
2026-08-23 22:11:25 +08:00
jakevin e48aac2114 chore(xueqiu): share html stripping helper 2026-08-23 21:52:38 +08:00
jakevin dcab73fb95 chore(browser): share CDP page capabilities 2026-08-23 21:37:09 +08:00
jakevin 6058c1536a chore(instagram): share current user helper 2026-08-23 21:01:05 +08:00
jakevin 40999a5eee chore(instagram): share home navigation helper 2026-08-23 20:42:28 +08:00
jakevin a2dd8c2701 chore(slock): share task identity postcondition 2026-08-23 20:23:32 +08:00
jakevin 2929dfa2c0 chore(linux-do): share formatting helpers 2026-08-23 20:06:18 +08:00
jakevin 2beaf83d62 chore(zhihu): share answer normalization helpers 2026-08-23 19:53:24 +08:00
jakevin 9057441221 chore(zhihu): share answer target parser 2026-08-23 19:37:34 +08:00
jakevin 31d80af07d chore(grok): share site identity helpers (#2341) 2026-08-23 19:18:31 +08:00
jakevin c0c8e60b25 chore(12306): share limit normalization helper (#2340) 2026-08-23 19:00:31 +08:00
jakevin adddc5733a chore(twitter): share archive JSONL helpers (#2339) 2026-08-23 18:40:22 +08:00
jakevin 7145d8b5d0 chore(twitter): share user lookup URL builder (#2338) 2026-08-23 18:11:55 +08:00
jakevin 240930fc8c fix(twitter): repair block and hide reply flows
Fixes #2334, #2335, and #2336.\n\nRepairs Twitter block/unblock profile-state scoping and localized block menu matching, and makes hide-reply retry from the parent conversation using only the preceding article time permalink.\n\nLocal gates: focused block/unblock/hide-reply tests 20/20, full twitter tests 531/531, typecheck, build, validate twitter, typed-error lint new=0, silent-column-drop new=0, diff-check. Hosted checks terminal green on exact head 57d1927d.
2026-08-23 17:54:31 +08:00
jakevin bd4c1e39e1 feat(twitter): add muted word command
Add twitter mute-word <keyword> as a UI write command against the visible Twitter/X muted-word settings form. Confirmation only accepts click-after route transition, new success toast, or new exact muted-word row; pre-write targeting stays scoped to the settings surface.\n\nLocal gates: focused twitter write/block/unblock tests 21/21, full twitter tests 523/523, typecheck, build, validate twitter, diff-check. Hosted checks terminal green on exact head 114a7c7f.
2026-08-23 17:26:56 +08:00
jakevin ae86f7f5ff refactor(bilibili): share relation helpers
Share duplicated Bilibili follow/unfollow relation helpers in a site-local relation module while preserving command-specific validation text and the existing utils.js mock boundary.
2026-08-23 16:53:40 +08:00
jakevin 1d3c97e477 refactor(linkedin-learning): share API fetch helpers 2026-08-23 15:25:43 +08:00
jakevin 80d5d3d6c9 chore: remove orphan internal test hooks (#2330) 2026-08-23 15:02:06 +08:00
jakevin 07aee7cd9f chore(browser): remove dead internal error exports (#2329) 2026-08-23 14:50:15 +08:00
jakevin 14d4665f5d chore(tui): remove unused checkbox prompt (#2328) 2026-08-23 14:40:36 +08:00
jakevin a34705a67f chore(browser): remove legacy DOM click helpers (#2327) 2026-08-23 14:29:26 +08:00
jakevin 70890c7e26 chore(scripts): remove retired explore helpers (#2325) 2026-08-23 14:19:06 +08:00
jakevin 451cd0276c chore(browser): remove retired tab helpers (#2324) 2026-08-23 14:09:07 +08:00
jakevin ff1d59ffec chore(core): remove dead internal symbols (#2323) 2026-08-23 14:00:21 +08:00
jakevin 9846c59f1c fix(adapter): copy shared deps on eject (#2321) 2026-08-23 13:39:32 +08:00
bingame c45105d6d1 fix: 兼容 Windows prepare 脚本 (#2271)
* fix: 兼容 Windows prepare 脚本

* fix(prepare): handle native package-manager runners

---------

Co-authored-by: OpenCLI-sol <opencli-sol@users.noreply.github.com>
2026-08-23 03:29:00 +08:00
Bo Liu f909f1e27f fix(browser): prefer the main Electron window over routed auxiliary windows (#2244) 2026-08-23 03:26:27 +08:00
WeiHaoxuan 078984204c fix(completion): fall back on invalid manifests (#2298)
* fix(completion): fall back on invalid manifests

* test(completion): cover all manifest fallback paths

---------

Co-authored-by: OpenCLI-sol <opencli-sol@users.noreply.github.com>
2026-08-23 03:25:57 +08:00
WeiHaoxuan 60a94cab27 fix(plugin): honor caret ranges below 1.0.0 (#2299) 2026-08-23 03:25:22 +08:00
WeiHaoxuan aa0e6b0743 fix(args): reject invalid integer values (#2300) 2026-08-23 03:24:49 +08:00
Mai Hoàng Anh Vũ 083f78acf5 fix(chatgpt): use data-turn to detect upload previews vs generated images (#2292)
`chatgpt image` with 2+ --image attachments could return the just-uploaded
reference thumbnails instead of the actual generated image.

isUserUploadPreview() classified an <img> as a user upload (to exclude it
from waitForChatGPTImages' before/after diff) using two signals, both
broken against ChatGPT's current DOM:

- turn.querySelector('h4')?.innerText: the heading is visually hidden, so
  real Chrome's innerText resolves to '' (layout-dependent) even though
  .textContent correctly reads "You said:" / "ChatGPT said:". jsdom's
  innerText is always undefined, so the test suite never exercised this
  path either - it happened to pass via the aria-label/alt fallback below.
- button[aria-label^="Open image:"]: ChatGPT's current label for a
  multi-file attachment reads "Open image N of M: <name>", which no
  longer starts with "Open image:", so this selector stopped matching.

With both signals dead, classification fell through to alt-text sniffing.
Right after upload, an attachment thumbnail's alt/aria-label haven't
populated yet, so for a poll or two every uploaded image is misclassified
as "new". waitForChatGPTImages returns as soon as two consecutive polls
agree on a URL set - long enough for that transient window to win when
multiple attachments are involved, so it can return the uploads instead of
the real result.

Fix: check the turn <section>'s own data-turn="user"|"assistant"
attribute first. It's set structurally as soon as the turn mounts, not
tied to the attachment's async metadata, so it isn't subject to the race.
Keep the heading/aria-label checks as a fallback (now using textContent
and a substring aria-label match) for markup that lacks data-turn.

Verified live against chatgpt.com: reproduced the bug with 3 reference
images, then confirmed the patched build returns exactly the one real
generated image instead of the 3 uploaded thumbnails.

Adds regression tests for both the data-turn race and the aria-label
format change; confirmed both fail against the pre-fix code.


Claude-Session: https://claude.ai/code/session_01L29nrhaeQ4W5rjNr27z47h

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 03:21:56 +08:00
Coco-cielleo da333c99a7 fix(xiaohongshu): scope note title/desc/author to #noteContainer (#2317)
* fix(xiaohongshu): scope note fields to #noteContainer

`#detail-title, .title` was queried against the whole document. A note
detail page also renders a recommendation feed whose cards each carry a
`.title`, and `querySelector` returns the first match in document order.
For a note with no title of its own (`#detail-title` absent) the selector
fell through to that feed and reported an unrelated card's title as the
note's title -- on one real note, two consecutive runs returned two
different unrelated titles while the note itself has no title at all.

Scope title/desc/author to `#noteContainer` (falling back to `document`
for older layouts). This is the same class of fix already applied to the
`.interact-container` counts a few lines below.

Also adds JSDOM regression tests for NOTE_EXTRACT_JS, following the
pattern used in clis/aibase/news.test.js.

* fix(xiaohongshu): tighten note fallback scope

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-08-23 03:21:27 +08:00
一禅小和尚 b173b176aa fix(xiaohongshu): scan text-card media from publish roots (#2297)
* fix(xiaohongshu): detect composer media from document.body

opencli's currentComposerMediaCount() picked the composer root via
titleEl.closest('form, [class*=publish], ...'), but Xiaohongshu's new
React DOM renders the image/card editor in a different subtree, so the
matched root never contained the generated media and the count was
always 0. That broke the native '--card-text' (文字生成图片) flow with
'expected at least N visible media item(s), got 0'.

- Use document.body as the scan root so generated cards are found.
- Add 'image, svg' to the media selector for completeness.

This is the maintained fork of @jackwener/opencli (liuxinyea/OpenCLI).

* fix(xiaohongshu): scope text-card media count

* fix(xiaohongshu): keep publish media scan scoped

---------

Co-authored-by: liuxinye <liuxinye@zingfront.com>
Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-08-23 03:21:01 +08:00
Bo Liu ca25f148d6 fix(twitter): fail typed when a write command does not go through (#2256)
* fix(twitter): fail typed when a write command does not go through

* fix(twitter): preserve uncertain write outcomes

---------

Co-authored-by: OpenCLI-sol <opencli-sol@users.noreply.github.com>
2026-08-23 03:09:22 +08:00
HARRY-BEAR d981c8b1f3 fix(chatgpt): filter Chinese user-upload previews from generated images (#2261)
* fix(chatgpt): filter user-uploaded images in Chinese UI and allow large image payloads

- chatgpt image adapter: the attachment filter in getChatGPTVisibleImageUrls
  only matched the English 'Open image:' button label and English keywords
  (upload/uploaded/attachment). In the Chinese ChatGPT UI the button is
  labeled '打开图片:用户上传的图片' (Open image: user uploaded image) and
  the image alt is empty, so user-uploaded reference images escaped the
  filter and were reported as generated results (the original photo was
  downloaded instead of the generated image). Add the Chinese button label
  prefix and the '上传' keyword to the filter.
- daemon: raise MAX_BODY from 1 MB to 32 MB. The chatgpt image upload
  fallback (base64-in-evaluate) serializes the image into the command body;
  a typical 2 MB photo becomes a >1 MB base64 payload and the daemon
  rejected it with a connection reset ('fetch failed').

* test(chatgpt): cover Chinese upload previews

---------

Co-authored-by: OpenCLI-sol <opencli-sol@users.noreply.github.com>
2026-08-23 03:05:22 +08:00
HARRY-BEAR 7323deb885 fix(1688): extract detail images from shadow DOM with lazy-render scrolling (#2272)
* fix(1688): extract detail images from shadow DOM with lazy-render scrolling

The product detail section lives inside the shadow root of a custom
element (v-detail-e with class html-description). Plain CSS selectors
like `.html-description img` cannot pierce shadowRoot, so the detail
group never matched any element and detail_images was always empty.

Fix by collecting all img/source elements (walking shadow roots) and
checking ancestry through the shadow host chain with closest(), plus
scrolling further and settling on the detail container so its lazy
content renders before extraction.

Adds a jsdom regression test covering shadow-root detail images,
light-DOM main gallery images, and plain-class detail containers.

* fix(1688): address review — restore deleted tests, dedupe the traversal, poll instead of sleep

Review fixes on top of the shadow-DOM detail extraction:

- Restore the two tests this PR replaced. `normalizeAssets` (grouping,
  counts, blob: filtering) and `normalizeMediaUrl` both lost all coverage;
  the 14 -> 15 test count hid that, since three new cases were added while
  two existing ones were removed. Now 17, with the new jsdom cases
  alongside the originals rather than in place of them.

- Inject the module-level `inDetailContainer` via toString() instead of
  keeping a hand-copied twin inside the evaluated script. The copy meant
  the unit tests exercised code that was not what ran in the page, and the
  two could drift silently. This is the convention already used in
  clis/gov-policy/search.js and clis/codex/sidebar.js.

- Check `node.closest(selector)` at each level of the walk, not only
  `host.matches(...)`. A detail container that is a plain element inside a
  shadow root rather than the host itself was previously missed.

- Replace `autoScroll(6) + autoScroll(4) + wait(3)` with one autoScroll,
  a scrollIntoView, and a bounded poll on the deep detail-image count.
  autoScroll keeps no state between calls, so 6+4 was identical to a
  single 10 and the comment about a "second confirmation pass" described
  something that did not happen; the fixed 3s wait was then paid on every
  call even when the content had already rendered. The poll returns as
  soon as the count is stable, capped at ~5s.

- Use an <img> rather than a <source srcset> in the shadow fixture:
  defaultSrcProps does not read srcset, so asserting on it implied
  coverage the adapter does not actually have.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-08-23 03:01:18 +08:00
Kagura fea093fe05 fix(extension): omit credentials from daemon ping (fixes #2278) (#2282)
* fix(extension): omit credentials from daemon ping (fixes #2278)

A large localhost cookie jar can push the extension ping past the Node default header limit. The daemon then responds 431, but the extension silently retries and never reaches the WebSocket connection.

Send the ping without credentials so browser cookies are not attached, and log non-OK HTTP statuses so future probe failures remain visible. Keep connection errors quiet because a stopped daemon is the expected idle state.

* build(extension): rebuild dist for daemon ping credentials:omit

extension/dist/background.js is a tracked artifact (.gitignore un-ignores
it via !extension/dist/), so the source-only change in 62d1f202 never
reached the bundle Chrome actually loads — the #2278 431 wedge would have
persisted in production despite the fix being merged.

Rebuild only; no source change. Diff is exactly the credentials:'omit'
and the non-OK warn from the parent commit.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-08-23 02:57:31 +08:00
aliouswe 69454ae9e4 fix(doctor): use windowless connectivity probe (#2206) 2026-08-23 02:57:21 +08:00
haoyu zhang 5d6594f12e fix(boss): restore read-only job search and detail (#2291)
* fix(boss): read current search and detail pages

* fix(boss): harden read-only job discovery

* fix(boss): address review — drop the site-auth fork, flatten detail columns

Review fixes on top of the read-only search/detail restore:

- Drop the adapter-local fork of `_shared/site-auth.js`. The fork had
  already diverged — it lost `normalizeRefreshResult` and the
  `config.refresh` branch, which silently removes `opencli auth refresh`
  support for boss. `clis/_shared/site-auth.js` is imported by 65
  adapters; `adapter eject` not copying `_shared/` is a real bug, but it
  affects every one of them and belongs in `src/cli.ts` eject, not in a
  per-adapter copy. Also removes the tautological test that only
  `readFileSync`'d auth.js and asserted on its own import string.

- Flatten `detail`'s row and `columns` back to scalars. The nested
  `location` / `recruiter` / `companyInfo` objects rendered as
  `[object Object]` in table, plain, csv and markdown output, because
  every renderer coerces cells with `String(v)` (`src/output.ts`) and
  none resolves dotted paths — only `-f json/yaml` was usable. Field
  names match the previous flat contract.

- Fix `stageText`, which matched `/融资|上市|不需要融资/` and therefore
  never matched the common `D轮及以上` / `天使轮` forms, leaving `stage`
  permanently empty. The industry filter directly above already excluded
  `轮`.

- Prefer BOSS's semantic `.text-city` / `.text-experiece` / `.text-degree`
  classes over positional `limits[0..2]`, which shifted every field when
  the header gained or lost a node. Positional order remains a fallback.

- Drop the `district` column instead of shipping one that is always null:
  the extractor hardcoded `districtText: ''` and the rendered page
  exposes no district anywhere in the captured fixture.

- Classify a login bounce as `AuthRequiredError`. The retry loop swallows
  every read error, so a session pushed to the login wall previously
  surfaced as "did not expose a complete job posting" — the API path this
  replaced got that classification for free via `assertOk`.

Regenerates `cli-manifest.json` for the new columns.

---------

Co-authored-by: jackwener <jakevingoo@gmail.com>
2026-08-23 02:56:56 +08:00