feat(claude): add Claude adapter#1252
Merged
jackwener merged 5 commits intojackwener:mainfrom May 3, 2026
Merged
Conversation
Adds a Claude (claude.ai) browser adapter family with seven commands modeled on the existing clis/deepseek/ pattern: ask, send, new, status, read, history, detail. Closes jackwener#1251
There was a problem hiding this comment.
Pull request overview
Adds a new claude browser adapter family for claude.ai, aligning with existing chat adapters (e.g., DeepSeek) and wiring it into docs + CLI manifest.
Changes:
- Introduces
clis/claude/*commands (ask,send,new,status,read,history,detail) with Claude-specific DOM automation utilities. - Adds Vitest coverage for the new Claude utilities and
askcommand flows. - Updates documentation/navigation and registers commands in
cli-manifest.json+ READMEs.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/adapters/index.md | Adds Claude to the adapters index table. |
| docs/adapters/browser/claude.md | New Claude adapter documentation page (commands/options/caveats). |
| docs/.vitepress/config.mts | Adds Claude to the docs sidebar navigation. |
| clis/claude/utils.test.js | Unit tests for Claude utilities (bool flag parsing, file send, model select). |
| clis/claude/utils.js | Core Claude browser automation helpers (navigation, message readback, model/think toggles, file upload, retry). |
| clis/claude/status.js | Implements opencli claude status. |
| clis/claude/send.js | Implements opencli claude send. |
| clis/claude/read.js | Implements opencli claude read. |
| clis/claude/new.js | Implements opencli claude new. |
| clis/claude/history.js | Implements opencli claude history via /recents. |
| clis/claude/detail.js | Implements opencli claude detail <id>. |
| clis/claude/ask.test.js | Tests for ask flow covering --new, --model, --think, --file behaviors. |
| clis/claude/ask.js | Implements opencli claude ask including model selection, adaptive thinking, file attach, and response wait. |
| cli-manifest.json | Registers all new Claude commands in the CLI manifest. |
| README.zh-CN.md | Adds Claude to the Chinese README adapter list. |
| README.md | Adds Claude to the README adapter list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+44
to
+65
| export async function getVisibleMessages(page) { | ||
| const result = await page.evaluate(`(() => { | ||
| var rows = []; | ||
| document.querySelectorAll('[data-testid="user-message"]').forEach(function(el) { | ||
| var text = (el.innerText || '').trim(); | ||
| if (text) rows.push({ index: rows.length, role: 'user', text: text }); | ||
| }); | ||
| document.querySelectorAll('${MESSAGE_SELECTOR}').forEach(function(el) { | ||
| var raw = (el.innerText || '').trim(); | ||
| // Strip leading widget label paragraphs (Adaptive thinking, file thumbnail). | ||
| var parts = raw.split(/\\n\\n+/); | ||
| while (parts.length > 1 && /^(Thought|View)\\b/i.test(parts[0])) parts.shift(); | ||
| var text = parts.join('\\n\\n').trim(); | ||
| if (text) rows.push({ index: rows.length, role: 'assistant', text: text }); | ||
| }); | ||
| return rows; | ||
| })()`); | ||
| if (!Array.isArray(result)) return []; | ||
| // Stable order: user / assistant alternating by DOM order is preserved per-bucket above, | ||
| // but interleave them so the conversation reads top-to-bottom. | ||
| return result.map(function(r, i) { return { Index: i, Role: r.role, Text: r.text }; }); | ||
| } |
| uploaded = true; | ||
| } catch (err) { | ||
| const msg = String(err?.message || err); | ||
| if (!msg.includes('Unknown action') && !msg.includes('not supported') && !msg.includes('Not allowed')) { |
Comment on lines
+287
to
+294
| const ready = await page.evaluate(`(() => { | ||
| // Claude renders attachments as data-testid="file-thumbnail" cards with | ||
| // a sibling Remove button. Either signal indicates the file took. | ||
| if (document.querySelector('[data-testid="file-thumbnail"]')) return true; | ||
| var removeBtn = Array.from(document.querySelectorAll('button')) | ||
| .find(function(b) { return (b.getAttribute('aria-label') || '') === 'Remove'; }); | ||
| return !!removeBtn; | ||
| })()`); |
Match the established Status / SubmittedBy / InjectedText shape used by doubao send so agent loops can rely on a consistent fire-and-forget output across AI chat adapters.
The previous implementation queried user-message and assistant-message nodes in two passes, which serialized as [u1, u2, u3, a1, a2, a3] for multi-turn chats instead of the correct conversation order. Single combined query preserves DOM order so claude read / detail return turns in the order the user reads them on the page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a Claude adapter family for
claude.ai, matching the surface of the existing AI chat adapters (ChatGPT, Gemini, DeepSeek, Doubao, Yuanbao). Modeled on the mergedclis/deepseek/pattern.Closes #1251
Seven commands:
claude ask <prompt>: send a prompt and return the responseclaude send <prompt>: fire-and-forget send (output shape aligned withdoubao send: Status / SubmittedBy / InjectedText)claude new: start a fresh conversationclaude status: login state and page availabilityclaude read: read the current conversation (use--liveon the prior command or chain afterclaude detail <id>so the tab stays on the chat)claude history: list recent conversations from/recentsclaude detail <id>: open a conversation by ID and read its messagesaskargs:prompt(positional, required),--timeout,--new,--model <sonnet|opus|haiku>(opus on free tier surfaces aCliError('ARGUMENT', ...)with upgrade hint),--think(Adaptive thinking),--file(image / PDF / text, up to ~1 MB raw because of the daemon body limit atsrc/daemon.ts:152).Implementation notes worth flagging:
[data-testid="chat-input"]ProseMirror contenteditable; clearing uses Range +execCommand('delete')because.value/.textContentare ignored by ProseMirrorpage.setFileInput(CDP, no body) followed by manual__reactProps$*.onChangeinvocation because Chrome's CDP file write does not fire React's controlled-input onChange.font-claude-response; Adaptive thinking and file-thumbnail widgets render duplicated label paragraphs (Thought process/View uploaded image) at the top of the response, stripped via paragraph split[data-testid="file-thumbnail"]andbutton[aria-label="Remove"]getVisibleMessagesqueries user and assistant nodes in a single combined pass to preserve DOM order in multi-turn conversationsType of Change
Checklist
Documentation (if adding/modifying an adapter)
docs/adapters/browser/claude.mddocs/adapters/index.mdtabledocs/.vitepress/config.mtsREADME.md/README.zh-CN.md<prompt>for ask/send,<id>for detail)CliErrorsubclasses (CliError,CommandExecutionError)Screenshots / Output
Vitest:
npx vitest run clis/claude/-> 22/22 pass.End-to-end validated against current claude.ai DOM with a real free-tier Sonnet 4.6 account:
Backward compatibility: this PR adds files under
clis/claude/only; no shared utils, framework code, or existing adapter manifests were touched.chatgpt image --help/deepseek ask --helpparse cleanly post-change (smoke check).Known limitation:
--fileis bounded by the daemon HTTP body limit (1 MB atsrc/daemon.ts:152); files up to ~700 KB raw work, larger images may fail withECONNRESET. Same constraint applies to other adapters usingpage.setFileInput; not introduced by this PR.