opencli-adapter-author
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseopencli-adapter-author
opencli-adapter-author
你是要给一个站点写 adapter 的 agent。这份 skill 目标:从零到通过 的 30 分钟内闭环。
opencli browser verify全程用现有工具: / / / 。没有新命令。
opencli browser *opencli doctoropencli browser initopencli browser verifyYou are an agent tasked with writing an adapter for a site. The goal of this skill: Complete the closed loop from scratch to passing within 30 minutes.
opencli browser verifyUse existing tools throughout the process: / / / . No new commands are required.
opencli browser *opencli doctoropencli browser initopencli browser verify前置:看你落在哪
Pre-work: Confirm Your Starting Point
先拿 快速自测。三个问题:
coverage-matrix.md- 数据在浏览器里看得到吗?(否 → 先解决鉴权)
- 数据是 HTTP/JSON/HTML 吗?(否 → 不在 skill 范围)
- 需要实时推送吗?(是 → 找同数据 HTTP 接口;没有就放弃)
三个都 yes 继续。
First, take a quick self-assessment using with three questions:
coverage-matrix.md- Can the data be viewed in the browser? (No → Resolve authentication first)
- Is the data in HTTP/JSON/HTML format? (No → Out of this skill's scope)
- Is real-time push required? (Yes → Find the corresponding HTTP interface for the data; abandon if none exists)
Proceed only if all three answers are yes.
顶层决策树
Top-level Decision Tree
START
│
▼
┌──────────────────────────┐
│ opencli doctor 通? │── no ──→ 修桥接(doctor 输出里的提示)
└──────────────────────────┘
│ yes
▼
┌────────────────────────────────────────────────────┐
│ 读站点记忆: │
│ 1. ~/.opencli/sites/<site>/endpoints.json │
│ 2. ~/.opencli/sites/<site>/notes.md │
│ 3. references/site-memory/<site>.md │
└────────────────────────────────────────────────────┘
│ 命中 endpoint + 字段 → 直接跳到【endpoint 验证】(不跳写 adapter!memory 可能过期)
│ 没命中 → 继续
▼
┌──────────────────────────┐
│ 站点侦察(site-recon) │ → Pattern A/B/C/D/E
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ API 发现(api-discovery)│ §1 network → §2 state → §3 bundle → §4 token → §5 intercept
└──────────────────────────┘
│ 拿到候选 endpoint
▼
┌────────────────────────────────────────────┐
│ 直接 fetch 验证 endpoint(memory 命中也要跑)│── 401/403 ──→ 回到 §4 排 token
│ 数据非空 + 200 │── 空/HTML ──→ 回到 site-recon 换 Pattern
│ memory 里的值还活着吗? │── 站点换版 ──→ 标记旧 endpoint,回 api-discovery
└────────────────────────────────────────────┘
│ OK
▼
┌───────────────────────────────────────┐
│ 字段解码(memory 里的 field-map 也要抽查)│ 自解释 → 直接 / 已知代号 → field-conventions / 未知 → decode-playbook
│ 比一条已知字段和网页肉眼值,确认没错位 │
└───────────────────────────────────────┘
│
▼
┌──────────────────────────┐
│ 设计 columns (output) │ 对照 output-design.md 的命名 / 类型 / 顺序
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ opencli browser init │ 生成 ~/.opencli/clis/<site>/<name>.js 骨架
│ 复制最像的邻居 adapter │
│ 改 name / URL / 映射三处 │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ opencli browser verify │── 失败 ──→ autofix skill,回对应步骤
└──────────────────────────┘
│ 成功
▼
┌──────────────────────────┐
│ 字段 vs 网页肉眼对一遍 │── 数值不对 ──→ 回字段解码
└──────────────────────────┘
│ 对得上
▼
┌──────────────────────────┐
│ 回写 ~/.opencli/sites/ │ endpoints / field-map / notes / fixtures
└──────────────────────────┘
│
▼
DONESTART
│
▼
┌──────────────────────────┐
│ Is opencli doctor passing? │── no ──→ Fix the bridge (follow prompts in doctor output)
└──────────────────────────┘
│ yes
▼
┌────────────────────────────────────────────────────┐
│ Read site memory: │
│ 1. ~/.opencli/sites/<site>/endpoints.json │
│ 2. ~/.opencli/sites/<site>/notes.md │
│ 3. references/site-memory/<site>.md │
└────────────────────────────────────────────────────┘
│ If endpoint + fields are found → Jump directly to [Endpoint Verification] (do not jump to write adapter! Memory may be outdated)
│ If not found → Continue
▼
┌──────────────────────────┐
│ Site Reconnaissance (site-recon) │ → Pattern A/B/C/D/E
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ API Discovery (api-discovery)│ §1 network → §2 state → §3 bundle → §4 token → §5 intercept
└──────────────────────────┘
│ Obtain candidate endpoints
▼
┌────────────────────────────────────────────┐
│ Direct fetch to verify endpoint (run even if memory hits)│── 401/403 ──→ Return to §4 to troubleshoot token
│ Non-empty data + 200 status │── Empty/HTML ──→ Return to site-recon and switch Pattern
│ Is the value in memory still valid? │── Site updated ──→ Mark old endpoint, return to api-discovery
└────────────────────────────────────────────┘
│ OK
▼
┌───────────────────────────────────────┐
│ Field Decoding (spot-check field-map in memory too)│ Self-explanatory → Use directly / Known code → field-conventions / Unknown → decode-playbook
│ Compare one known field with the value visible on the webpage to confirm no misalignment │
└───────────────────────────────────────┘
│
▼
┌──────────────────────────┐
│ Design columns (output) │ Follow naming / type / order in output-design.md
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ opencli browser init │ Generate skeleton file ~/.opencli/clis/<site>/<name>.js
│ Copy the most similar neighbor adapter │
│ Modify name / URL / field mapping in three places │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ opencli browser verify │── Failed ──→ Use autofix skill, return to corresponding step
└──────────────────────────┘
│ Success
▼
┌──────────────────────────┐
│ Cross-check fields with visible webpage values │── Incorrect values ──→ Return to field decoding
└──────────────────────────┘
│ Values match
▼
┌──────────────────────────┐
│ Write back to ~/.opencli/sites/ │ endpoints / field-map / notes / fixtures
└──────────────────────────┘
│
▼
DONERunbook(一步一步勾选)
Runbook (Check off step by step)
[ ] 1. opencli doctor 返回 "Everything looks good"
[ ] 2. 读站点记忆:
[ ] ~/.opencli/sites/<site>/endpoints.json 存在?里面有想要的 endpoint?
[ ] references/site-memory/<site>.md 存在?看"已知 endpoint"节
[ ] 命中后:**跳到第 5(endpoint 验证) + 第 7(字段核对)**,不能直接跳第 9 写 adapter
[ ] memory 写入超过 30 天(看 `verified_at`)→ 当作过期,按冷启动走 Step 3 → 4
[ ] 3. 侦察(site-recon.md):
[ ] opencli browser open <url>
[ ] opencli browser wait time 3
[ ] opencli browser network
[ ] 定 Pattern(A / B / C / D / E)
[ ] 4. API 发现(api-discovery.md)按 Pattern 选 §:
[ ] Pattern A → §1 network 精读
[ ] Pattern B → §2 state 抽取 + §1 深层数据
[ ] Pattern C → §3 bundle / script src 搜索
[ ] Pattern D → §4 token 来源 + 降级 §5
[ ] Pattern E → 找 HTTP 轮询接口;找不到才 §5
[ ] 5. 直接 fetch 候选 endpoint 验证:
[ ] 返回 200
[ ] 响应含目标数据(不是 HTML / 广告)
[ ] 6. 定鉴权策略:裸 fetch 通 → PUBLIC;要 cookie → COOKIE;要 header → HEADER;拿不到签名 → INTERCEPT
[ ] 7. 字段解码:
[ ] 自解释 → 直接用 key
[ ] 已知代号 → field-conventions.md 查表
[ ] 未知代号 → field-decode-playbook.md(排序键对比 / 结构差分 / 常量排查)
[ ] 8. 设计 columns(output-design.md):
[ ] 命名 camelCase 且对齐邻居 adapter
[ ] 类型 / 单位 / 百分比格式清楚
[ ] 顺序:识别列 → 业务数字 → metadata
[ ] 9. 写 adapter(adapter-template.md):
[ ] opencli browser init <site>/<name>
[ ] 找同站点或同类型最像的 adapter,cp 过来
[ ] 改 name / URL / 字段映射
[ ] 10. opencli browser verify <site>/<name>
[ ] 11. 字段值 vs 网页肉眼比对(别只看 "Adapter works!")
[ ] 12. 回写站点记忆(**verify 通过 + 肉眼比对对得上之后**,schema 见 `references/site-memory.md`):
[ ] `endpoints.json`:以 endpoint 的短名为 key,value = `{url, method, params.{required,optional}, response, verified_at: YYYY-MM-DD, notes}`
[ ] `field-map.json`:只追加新代号。key = 字段代号,value = `{meaning, verified_at: YYYY-MM-DD, source}`;**已存在的 key 不要覆盖**,有冲突先和网页肉眼值对齐再写
[ ] `notes.md`:顶部追加一段 `## YYYY-MM-DD by <agent/user>`,写本次写 adapter 时遇到的新坑 / 新结论
[ ] `fixtures/<cmd>-<YYYYMMDDHHMM>.json`:存一份该 endpoint 的完整响应样本(去掉 cookie / token / 用户私有字段后再存),给后续 regression / 字段对比用[ ] 1. opencli doctor returns "Everything looks good"
[ ] 2. Read site memory:
[ ] Does ~/.opencli/sites/<site>/endpoints.json exist? Does it contain the desired endpoint?
[ ] Does references/site-memory/<site>.md exist? Check the "Known endpoints" section
[ ] If hit: **Jump to Step 5 (Endpoint Verification) + Step 7 (Field Check)**; do not jump directly to Step 9 to write adapter
[ ] If memory was written over 30 days ago (check `verified_at`) → Treat as expired, follow cold start steps Step 3 → 4
[ ] 3. Reconnaissance (site-recon.md):
[ ] opencli browser open <url>
[ ] opencli browser wait time 3
[ ] opencli browser network
[ ] Determine Pattern (A / B / C / D / E)
[ ] 4. API Discovery (api-discovery.md) select section based on Pattern:
[ ] Pattern A → Read §1 network in detail
[ ] Pattern B → Extract §2 state + §1 deep data
[ ] Pattern C → Search §3 bundle / script src
[ ] Pattern D → Check §4 token source + fallback to §5
[ ] Pattern E → Find HTTP polling interface; use §5 only if not found
[ ] 5. Direct fetch to verify candidate endpoint:
[ ] Returns 200 status
[ ] Response contains target data (not HTML / ads)
[ ] 6. Determine authentication strategy: Bare fetch works → PUBLIC; Requires cookie → COOKIE; Requires header → HEADER; Cannot obtain signature → INTERCEPT
[ ] 7. Field Decoding:
[ ] Self-explanatory → Use key directly
[ ] Known code → Look up in field-conventions.md
[ ] Unknown code → Follow field-decode-playbook.md (sort key comparison / structure difference / constant check)
[ ] 8. Design columns (output-design.md):
[ ] Naming uses camelCase and aligns with neighbor adapters
[ ] Type / unit / percentage format is clear
[ ] Order: Identification columns → Business figures → metadata
[ ] 9. Write adapter (adapter-template.md):
[ ] opencli browser init <site>/<name>
[ ] Find the most similar adapter for the same site or type, copy it over
[ ] Modify name / URL / field mapping
[ ] 10. opencli browser verify <site>/<name>
[ ] 11. Cross-check field values with visible webpage values (don't just rely on "Adapter works!")
[ ] 12. Write back to site memory (**After passing verify + cross-check matches**, see schema in `references/site-memory.md`):
[ ] `endpoints.json`: Use the short name of the endpoint as the key, value = `{url, method, params.{required,optional}, response, verified_at: YYYY-MM-DD, notes}`
[ ] `field-map.json`: Only append new codes. Key = field code, value = `{meaning, verified_at: YYYY-MM-DD, source}`; **Do not overwrite existing keys**, align with webpage values first if there's a conflict before writing
[ ] `notes.md`: Append a section `## YYYY-MM-DD by <agent/user>` at the top, documenting new pitfalls / conclusions encountered during this adapter writing process
[ ] `fixtures/<cmd>-<YYYYMMDDHHMM>.json`: Save a complete response sample of this endpoint (remove cookies / tokens / user private fields first), for subsequent regression / field comparison降级路径(某步卡住跳到哪)
Fallback Paths (Where to jump if stuck at a step)
| 卡在 | 现象 | 跳去 |
|---|---|---|
| Step 4 API 发现 | | §3 bundle 搜 baseURL |
| bundle 搜不到 baseURL | §5 intercept | |
| Step 5 endpoint 验证 | 401 / 403 | §4 token 排查 |
| 200 但响应是 HTML | 回 Step 3 换 Pattern 判断 | |
200 但 | 参数传错 / 接口换版,回 §1 看 network 里真实请求头 | |
| Step 7 字段解码 | 排序键对比推不出 | field-decode-playbook.md §3 结构差分 |
| 还推不出 | 先输出 raw,adapter 跑起来再迭代 | |
| Step 10 verify 失败 | | autofix skill |
某列永远是 | 字段路径错了,回 Step 7 | |
| Step 11 数值不对 | 差 10000 倍 | 单位不统一("万" vs "元") |
| 百分比小 100 倍 | 响应已是 |
| Stuck at | Phenomenon | Jump to |
|---|---|---|
| Step 4 API Discovery | | §3 bundle to search baseURL |
| Cannot find baseURL in bundle | §5 intercept | |
| Step 5 Endpoint Verification | 401 / 403 status | §4 token troubleshooting |
| 200 status but response is HTML | Return to Step 3 to re-judge Pattern | |
200 status but | Wrong parameters passed / interface updated, return to §1 to check real request headers in network | |
| Step 7 Field Decoding | Cannot deduce via sort key comparison | §3 structure difference in field-decode-playbook.md |
| Still cannot deduce | Output raw data first, iterate after adapter runs | |
| Step 10 Verify Failed | Missing | Use autofix skill |
A column is always | Wrong field path, return to Step 7 | |
| Step 11 Incorrect Values | 10000x difference | Inconsistent units ("ten thousand" vs "yuan") |
| Percentage is 100x smaller | Response is already |
参考文件
Reference Files
| 文件 | 什么时候翻 |
|---|---|
| 动手前做"是否在范围内"自测 |
| Step 3 定站点类型 |
| Step 4 找 endpoint |
| Step 7 查已知字段代号 |
| Step 7 字段不在词典时 |
| Step 8 命名 / 类型 / 顺序 |
| Step 9 文件结构 + 活例子 |
| 总览:in-repo 种子 + 本地 |
| Step 2 读站点公共知识(eastmoney / xueqiu / bilibili / tonghuashun 已铺) |
| File | When to refer to it |
|---|---|
| Self-assess "whether within scope" before starting |
| Determine site type in Step 3 |
| Find endpoints in Step 4 |
| Look up known field codes in Step 7 |
| When fields are not in the dictionary in Step 7 |
| Naming / type / order in Step 8 |
| File structure + live example |
| Overview: Two-layer structure of in-repo seeds + local |
| Read site public knowledge in Step 2 (eastmoney / xueqiu / bilibili / tonghuashun are already covered) |
关键约定
Key Conventions
- adapter 只引 +
@jackwener/opencli/registry,不用第三方@jackwener/opencli/errors - 数组和
columns返回对象 keys 完全对齐(含顺序)func - 已知失败抛 或
CliError('CODE', 'msg'),不要 silentAuthRequiredError(domain)return [] - 写私人 adapter 用 (免 build);要提 PR 才 copy 到
~/.opencli/clis/<site>/<name>.jsclis/<site>/<name>.js - 站点记忆每轮回写:没记忆 → 用 skill → 产生记忆 → 下次变 5 分钟
- Adapters only import +
@jackwener/opencli/registry, no third-party dependencies@jackwener/opencli/errors - The array must exactly align with the keys (including order) of the object returned by
columnsfunc - Throw or
CliError('CODE', 'msg')for known failures, do not silentlyAuthRequiredError(domain)return [] - Use for private adapters (no build required); copy to
~/.opencli/clis/<site>/<name>.jsonly when submitting a PRclis/<site>/<name>.js - Site memory write-back each cycle: No memory → Use skill → Generate memory → Next time takes 5 minutes
卡住了
Stuck?
- 诊断类:→ 看
opencli doctor→ 搜 autofix skillnotes.md - 字段解码类:全三节走完 → 先输出 raw 迭代
field-decode-playbook.md - endpoint 找不到:api-discovery §5 intercept 兜底
不要猜。猜错了 verify 能通过但数据是错的,用户看到乱码才发现。
- Diagnosis: → Check
opencli doctor→ Search autofix skillnotes.md - Field decoding: Complete all three sections in → Output raw data first and iterate
field-decode-playbook.md - Cannot find endpoint: Use §5 intercept in api-discovery as fallback
Do not guess. If you guess wrong, verify may pass but the data will be incorrect, and users will only notice when they see garbled content.