aiconductor-cli 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -1,107 +1,189 @@
1
- # Repository Guidelines
1
+ # 项目协作规范
2
+
3
+ ## 项目概述
4
+
5
+ `aiconductor-cli` 是 AIConductor 平台 API 的命令行封装:Node.js >= 18、CommonJS、唯一运行时依赖 `commander`,发布到 npm 供 agent 与终端用户直接调用。七组命令覆盖网页发布、豆包搜索、热点简报、抖音数据、小红书数据、公众号数据;`.agents/skills/` 存放面向 agent 的工作流(pi 在项目受信任时会自动发现项目级 `.agents/skills/`),指导如何调用这些命令,其中对外发布的技能(`xhs-note-publish`、`douyin-script-extract`)还要满足 WorkBuddy 上架字段,见 `references/workbuddy技能规范.md`。`README.md` 是对外命令契约,本文档是开发与维护契约。
6
+
7
+ ## 项目结构与模块组织
8
+
9
+ ```text
10
+ bin/aiconductor-cli.js 唯一入口:注册全部命令、参数与选项(Commander.js)
11
+ src/api.js 平台 HTTP 客户端:端点常量、请求体映射、鉴权、文件上传
12
+ src/lib/cli-utils.js 输出与错误:outputResult / outputError / resolveKeyOrExit / handleApiError / safeParseInt
13
+ src/commands/
14
+ html_publish.js html publish
15
+ md_publish.js webpage publish | list | delete
16
+ web_search.js search web | image
17
+ content.js content briefing
18
+ douyin.js douyin 的 7 个子命令
19
+ xhs.js xhs hot-list | note-publish
20
+ wx.js wx article-data | history
21
+ src/api.test.js 全部自动化测试(api 映射 + 纯格式化/聚合函数)
22
+ api_docs/<endpoint>.md 每个平台接口的请求/响应/计费契约(`aiconductor-platform` 对应文件的整文件副本)
23
+ references/ 平台侧规范(workbuddy技能规范.md),不参与 CLI 运行;已 gitignore + npmignore,只在本机
24
+ .agents/skills/<name>/ SKILL.md(路由与执行)+ references/(按条件加载)+ 可选 scripts/;仓库里唯一入库的 .agents 子目录
25
+ ```
2
26
 
3
- ## Project Structure & Module Organization
27
+ 推导规则:命令组名与文件名**不一一对应**(`webpage` → `md_publish.js`,`search` → `web_search.js`),找实现先看 `bin/aiconductor-cli.js` 的注册处。命令文件只做四件事:解析选项、调用 `src/api.js`、格式化输出、`process.exit`;共享逻辑进 `src/lib/cli-utils.js`,HTTP 与鉴权细节不允许出现在命令文件里。
4
28
 
5
- ```
6
- bin/aiconductor-cli.js CLI entry point (Commander.js)
7
- src/
8
- api.js HTTP API client — all platform calls live here
9
- lib/cli-utils.js Shared helpers: output, error handling, key resolution
10
- commands/
11
- html_publish.js `html publish` command
12
- md_publish.js `webpage publish` command (Markdown/HTML)
13
- web_search.js `search web` / `search image` commands
14
- douyin.js All `douyin` subcommands
15
- xhs.js `xhs note-publish` command
16
- .codex/skills/
17
- <skill-name>/
18
- SKILL.md Skill entry point and decision/execution workflow
19
- references/ Documentation loaded only when its stated condition applies
20
- scripts/ Optional deterministic, reusable helper scripts
21
- ```
29
+ ## 配套项目:aiconductor-platform(接口契约的源头)
30
+
31
+ 本 CLI 只是 `aiconductor-platform` 里 78 个插件端点的薄封装。接口行为、返回字段、计费口径、上游第三方服务的坑都在那边;CLI 侧遇到「字段对不上 / 端点是 404 / 参数被拒」,先回那边查,不要在本仓库猜。
32
+
33
+ - **路径**:`D:/Development/aiconductor-platform`(monorepo:`backend/` FastAPI 插件、`frontend/` Next.js 控制台,同机部署在平台那台 ECS 上)
34
+ - **路由推导**:`backend/plugins/<name>.py` → `/api/<name>`;`backend/plugins/<group>/<name>.py` → `/api/<group>/<name>`。删文件即下线路由,没有注册表
35
+ - **契约文档**:`backend/api_docs/<name>.md` 是唯一源头;`aiconductor-cli/api_docs/` 是它的**整文件副本**(例外:`china_stock_data.md` 只在 CLI 侧)。改契约先改 platform 再覆盖过来,不在 CLI 侧手改副本;已知 `xhs_note_publish.md` 两边已漂移,下次碰它时整文件对齐
36
+ - **平台侧的开发与运维规则**(新增插件、计费三件套、180s 超时预算、nginx 60s、发版自检清单、已验证的坑)全在 `aiconductor-platform/AGENTS.md`,动接口前读那里,本文档不复述
37
+
38
+ ### 端点到命令的落点
39
+
40
+ | 要做的事 | 改哪里 |
41
+ |---|---|
42
+ | 确认真实行为、字段、上游依赖 | `aiconductor-platform/backend/plugins/<name>.py` + `api_docs/<name>.md` |
43
+ | 新增/修改接口契约 | platform 侧插件与 `api_docs`,再覆盖到 `aiconductor-cli/api_docs/` |
44
+ | CLI 接入 | `src/api.js`(端点常量 + `httpPost` + `stripBilling`)→ `src/commands/<组>.js` → `bin/aiconductor-cli.js` 注册 |
45
+ | 测试 | `src/api.test.js`,请求字段抄 `api_docs`,不抄实现 |
46
+ | 对外文档与技能 | `README.md`、`.agents/skills/*/SKILL.md` |
47
+
48
+ ### 鉴权与计费的两侧分工
49
+
50
+ - **鉴权**:platform 框架会把 `Authorization: Bearer <key>` 与 body/query 里的 `api_key` 都塞进 `args.input.api_key`,所以插件两种都收;CLI 只照 `api_docs` 写的那一种发,不要"统一"。
51
+ - **计费**:单价、折扣、停用状态都在 platform 的 `api_services` 表(`service_code` 维度)。CLI 不写价格、不输出 `billing`;README 计费表里配置驱动的项写「以平台服务配置为准」,不写死数字。
52
+ - **失败面**:`wx_*` 系列把业务失败放在 HTTP 200 的响应体里(`success:false` + `message`),CLI 在 `api.js` 用 `throwOnBusinessFailure` 转成 `api_error`(退出码 1、错误进 stderr),不要改成"成功退出 + 空 data"。
53
+
54
+ ### 联调限制(别假设能做)
55
+
56
+ - `API_HOST` 是 `src/api.js` 里的常量 `plugin.aiconductor.fun`,**没有环境变量覆盖**:CLI 现在无法指向本地后端(本地起服务是 `cd aiconductor-platform/backend && uvicorn main:app --reload --port 8000`)。要做本地联调得先给 CLI 加 host 覆盖,未做之前不要在文档里声称支持。
57
+ - 线上端点是否在线可直接查:`curl -s https://plugin.aiconductor.fun/api/plugins`(2026-11-04 实测 78 个)。判断"某端点不存在"以它为准,不以本文档的数字为准。
58
+ - 返回不对时先用 `-f json` 看原始响应:能对上就是 CLI 映射/格式化的问题,对不上或报上游错误就是 platform 侧契约或第三方服务变了。
59
+
60
+ ### 公众号(wx_*)已接与未接
61
+
62
+ 已接 2 个(`wx` 组):`wx_article_data` → `wx article-data`、`wx_history_articles` → `wx history`。
63
+
64
+ platform 侧还有、CLI 未接 10 个:`wx_rss_reader`、`flow_wx_history_articles`、`wx_access_token`、`wx_md_to_html`、`md_to_wxhtml`、`wx_image_upload`、`wx_draft_add`、`wx_draft_publish`、`users/wx_article_style_rewrite`、`wx_article_analysis_data_push`(最后一个只是扣费触发器,不返回数据)。`wx_rss_reader` 与 `flow_wx_history_articles` **用户明确不要**(2026-11-04),不要再当成待补项;接发布链路时注意 `wx_draft_add` 要先用 `wx_image_upload` 拿 `thumb_media_id`。
65
+
66
+ ## 构建、测试与开发命令
67
+
68
+ | 命令 | 用途 |
69
+ |---|---|
70
+ | `npm install` | 安装唯一依赖 `commander`(有 lock) |
71
+ | `npm test` | `node --test`,27 个用例,离线打桩,不需要 API Key |
72
+ | `node bin/aiconductor-cli.js --help` | 不安装也能本地运行,核对命令面 |
73
+ | `node bin/aiconductor-cli.js <组> <子命令> --help` | 核对某个命令的参数与默认值;CLI 契约以它为准 |
74
+ | `npm pack --dry-run` | 确认发布内容:含 `src/**`(含测试)、`api_docs/`、`AGENTS.md`,不含 `.agents/` 与 `references/`(平台侧规范只在本机,已从 `.npmignore`/`.gitignore` 排掉) |
75
+
76
+ 无构建步骤、无 lint/formatter、无 CI。
77
+
78
+ ## 常见改动怎么做
79
+
80
+ ### 新增或修改命令
81
+
82
+ 1. 在对应 `src/commands/<组>.js` 加/改处理函数(薄封装,照现有文件风格)。
83
+ 2. 需要新端点时先读 `api_docs/<endpoint>.md`,在 `src/api.js` 加端点常量与函数,复用 `httpPost` + `stripBilling`。
84
+ 3. 在 `bin/aiconductor-cli.js` 注册子命令与选项——这是**唯一注册点**。`-k, --api-key`、`-f, --format` 每个命令各自声明,没有全局注入;可重复选项用 `collect`。
85
+ 4. 跑 `node bin/aiconductor-cli.js <组> <子命令> --help` 核对命令面,跑 `npm test`。
86
+ 5. 同步受影响产物:`README.md`(synopsis、选项表、示例)、对应的 `.agents/skills/*/SKILL.md`(命令、选项、`data.data.*` 路径)、`src/api.test.js`(改了请求映射或格式化时)。
22
87
 
23
- - Commands are thin wrappers: parse options, call `src/api.js`, format output, and exit.
24
- - Shared logic (key resolution, error formatting, output) goes into `src/lib/cli-utils.js`.
25
- - Each command file exports an async function; no side effects on load.
26
- - Skills are versioned source assets that guide use of one or more real CLI workflows. They are maintained with the corresponding command surface, but are not included in the npm package unless an explicit skill distribution mechanism is added.
88
+ ### 新增平台接口
27
89
 
28
- ## Build, Test, and Development Commands
90
+ - 先到 platform 侧读插件与 `api_docs`(见「配套项目:aiconductor-platform」),搞清上游依赖与超时预算,再动 CLI。
91
+ - 鉴权有两套并存写法,照 `api_docs` 与相邻实现选,不要"统一":搜索、热榜、网页列表/删除、R2 上传、小红书发布、抖音视频搜索、`wx_*` 全系用 `Authorization: Bearer <key>`;发布类(`html_publish`、`md_to_html`)与多数抖音接口把 `api_key` 放进请求体。
92
+ - 业务失败可能出现在 HTTP 200 的响应体里:`api.js` 内抛 `api_error`(搜索、热榜,以及用 `throwOnBusinessFailure` 包一层的 `wx_*`),或命令层用 `throwOnApiFailure`(网页列表/删除)。新接口选一种并补测试。
93
+ - 响应先过 `stripBilling`,`billing` 不进任何输出。
29
94
 
30
- - `node bin/aiconductor-cli.js --help` — run locally without a build step
31
- - `npm install` — install the single runtime dependency (`commander`)
32
- - `npm test` — run the Node.js built-in test suite (`node --test`)
95
+ ### 维护 skill
33
96
 
34
- ## Coding Style & Naming Conventions
97
+ - 技能放 `.agents/skills/<name>/`(2026-11-04 从 `.codex/skills/` 迁来,内容逐字未变,`git mv` 效果):pi 从 cwd 向上到仓库根发现项目级 `.agents/skills/`(`dist/core/package-manager.js` 的 `collectAncestorAgentsSkillDirs`),`.codex/skills/` 从来不是 pi 的发现路径。代价:项目里有 `.agents/skills/` 会触发**项目信任门禁**(`hasTrustRequiringProjectResources` 返回 true),未信任时这 11 个技能不加载。**这是故意的**(2026-11-04):本仓技能是**上架产物**(WorkBuddy / 技能仓库的发布件),不是本机开发时要用的上下文,所以 `~/.pi/agent/trust.json` 已给 `D:/Development/aiconductor-cli` 显式写 `false`——pi 不弹信任提示、技能不进上下文;需要某条技能内容时直接 `read .agents/skills/<name>/SKILL.md`,**不要为了加载它去信任项目**。
98
+ - `.gitignore` 用 `.agents/*` + `!.agents/skills/` 只放行技能,`.agents/ledger.md`、`.agents/plans/` 属本机脚手架不入库——**别把 `.agents/` 整目录 ignore**,那会让技能从版本控制里消失(`git status` 表现为 `.codex/` 全删、新目录全是 `??`)。
99
+ - 目录名、frontmatter `name`、实际调用的命令必须一致;`description` 写能力 + 用户原话触发 + 与相邻 skill 的边界(简报→content-briefing,单点搜索→doubao-search,网页→webpage-publish,抖音数据→douyin-toolbox,抖音文案→douyin-script-extract,抖音选题→douyin-topic-radar,抖音评论→douyin-comment-insight,抖音账号→douyin-account-analyze,小红书→xhs-note-publish,公众号发文列表→wx-account-articles,单篇公众号数据→wx-article-data)。
100
+ - `SKILL.md` 只放路由、决策、命令行、响应路径、安全规则;长选项表、安装与密钥恢复放 `references/`,并写明何时读。
101
+ - 默认 JSON 输出,文档写稳定的 `data.data.*` 路径(`outputResult` 会额外包一层 `{success, data}`)。
102
+ - 用户请求执行即等同授权:不要每次预检安装或密钥;安装说明只在需要时读一次,修复后重试原命令一次。
103
+ - 安装说明被复制成 11 份 `references/aiconductor-skills-setup.md`(技能是独立安装单元,无法跨目录引用);改它必须同步 11 份。改完跑 `md5sum .agents/skills/*/references/aiconductor-skills-setup.md | awk '{print $1}' | sort -u | wc -l`,结果必须是 **1**。
35
104
 
36
- - 2-space indentation, no tabs
37
- - CommonJS (`require` / `module.exports`), no ESM
38
- - camelCase for JS identifiers; snake_case for API request fields
39
- - Every exported function gets a JSDoc block describing parameters and return type
40
- - Use `const` by default; `let` only when reassignment is needed
41
- - No formatter or linter configured — follow surrounding code style
105
+ ### 上架到 WorkBuddy
42
106
 
43
- ## Error Handling
107
+ 对外发布的技能比仓库内自用的多一层要求,规范全文在 `references/workbuddy技能规范.md`:
44
108
 
45
- - Never swallow errors with empty `catch`. At minimum, log and re-throw.
46
- - API errors carry a `.type` property (`http_error`, `network_error`, `validation_error`, `api_error`)
47
- - Commands exit with code 0 on success, 1 on failure
109
+ - **frontmatter 8 项必填**:`name`、`display_name`、`display_name_en`、`description`、`description_zh`、`description_en`、`version`、`author`;`author` 固定写 `"AI指挥家"`(带引号)。缺一项详情页就是残的。
110
+ - **`examples_zh` / `examples_en` 各 3 条**,展示在详情页「试试这样用」;用真能跑通的链接,别塞占位符。
111
+ - **正文顶部写 `## 概述`**,口吻是"默认已装好 CLI 与 API Key",只有出错时才引导去读 `references/aiconductor-skills-setup.md`。用户第一眼要看到能力,不是安装步骤。
112
+ - **别在正文里谈钱**:价格、单价、扣费规则、"免费"这类内容不进 `SKILL.md`——用户读技能时感觉自己在按次付费就会心疼,这是体验问题。该保留的行为约束改写成与钱无关的说法("重跑会再扣一次下载费" → "重跑等于从下载重来一遍");但故障解释里该说还得说,"余额不足"能帮用户定位问题。
113
+ - **子资源用 Markdown 链接** `[references/x.md](references/x.md)`,不用规范文档里的 `@references/x.md`:全库实测 0 处 `@`、549 处链接,已上架的 `xhs-note-publish` 也是链接。
114
+ - **交付物就是可上传的目录本身**:`SKILL.md` + `references/`(必要时 `scripts/`)随目录走,不依赖仓库内其他路径——技能是独立安装单元。交付时另附一份可直接复制进后台的清单:中英名、中英简介、3 条案例、作者、版本。
48
115
 
49
- ## Testing Guidelines
116
+ ## 关键机制(改代码前必读)
50
117
 
51
- Use the Node.js built-in test runner via `npm test`. Place tests next to the module they cover when practical (for example, `src/commands/web_search.test.js`).
118
+ - **输出分层**:`outputResult` 在 JSON 模式打印 `{success:true, data:<API 原始响应>}`,服务端字段落在 `data.data.*`(如 `content briefing` 的 `data.data.sources`);text 模式只打印自定义 formatter 的文本。错误一律走 stderr:JSON 为 `{success:false, error}`,text 为 `✗ 错误: ...`。
119
+ - **退出码**:成功 0、失败 1,每个处理函数结尾显式 `process.exit()`,因此 `await` 之后的收尾逻辑不会执行。不带参数调用时 Commander 直接向 stderr 打帮助并退出 1(bin 末尾的 `outputHelp()` 在该路径不可达)。
120
+ - **错误分类**:`http_error`(状态码 >= 400)、`network_error`、`validation_error`(本地参数校验)、`api_error`(HTTP 200 但业务失败);`handleApiError` 按 `.type` 生成中文提示。新抛错带 `.type`。
121
+ - **传输层**:请求打到 `plugin.aiconductor.fun/api/<endpoint>`。多数走 HTTPS;`hot_list_mixed` 与 `xhs_hot_list` 走明文 HTTP(`transport = http`,`api_docs` 也写作 `http://`,测试锁定 `port 80`)。线上 HTTPS 同样可达,属历史选择,别当成必须。
122
+ - **本地先校验**:`validatePositiveInt` / `validateInt` 与各命令的显式检查负责区间(`limit` 1–30、搜索 `count` 网页 ≤ 50 / 图片 ≤ 5、图文 ≤ 18 张等),失败不请求、不计费。
123
+ - **`webpage publish` 分流**:按扩展名或内容特征判定 `md`/`html`(`--type` 可强制)。html 分支直接打 `html_publish`,md 分支打 `md_to_html` 并支持 `--copy-button`;两者是不同端点。
124
+ - **小红书发布是两段式**:本地文件或 Base64 先经 `r2Upload` 换成临时公开 URL(`valid_days` 仅 1 或 7,默认 7;图片单张 ≤ 32MB,本地视频 ≤ 100MB),再调用计费接口生成 H5 页与二维码。Base64 参数支持 `@文件路径`。
125
+ - **热点简报是部分成功语义**:热榜与小红书热榜并行请求,任一成功即返回 `success:true`,失败写入 `data.failed_sources` / `data.failed_services`;仅两个服务都失败才退出 1。不要简化成"全有或全无"。
126
+ - **`wx` 组线上真实字段**(2026-11-04 实测调用):`wx_article_data` 返回 `read` / `zan` / `looking`(在看)/ `share_num` / `collect_num` / `comment_count`;`wx_history_articles` 用 `--name` 定位时业务层只有 `mp_nickname` 与 `mp_ghid`——**`api_docs` 写的 `mp_wxid` / `head_img` 实际不返回**;文章项字段与文档一致(`post_time_str` / `read` / `zan` / `original` / `url` / `digest`)。改 formatter 按实测字段,不要按文档新增字段。
127
+ - **`wx_history_articles` 的上游失败藏在 `data.code`**:平台侧仍回 `success:true`,只有 `data.code` 非 0 才是失败(实测 `107` = 名称/链接对不上,`20001` = 平台侧上游故障),`src/api.js` 的 `throwOnWxHistoryFailure` 把它转成 `api_error`(退出码 1)。别用「数组为空」推断「这个号没发文」。
128
+ - **抖音字段单位不统一**:`video-search` 的 `video.duration` 是**毫秒**,`user-videos` 的 `duration` 是 `"MM:SS"` 字符串——同名不同单位,跨端点复用代码必翻车。
129
+ - **抖音时间戳是北京时间编码**:`create_time` 按 UTC 渲染出来就是北京时间,**不要再 +8 小时**(2026-10-28 实测 `video-search`/`video-comments`/`user-videos` 三处:+8 会让半小时前发的视频落到 7 小时后)。`user-videos` 另带 `create_time_formatted`,同口径。
130
+ - **密钥解析**:`-k` > `AICONDUCTOR_API_KEY` > **当前工作目录**的 `.env`(不向上查找);缺失时 `resolveKeyOrExit` 打印错误并退出 1。
52
131
 
53
- For changes to a CLI contract (commands, arguments, options, output, or errors), verify:
54
- - The affected `--help` output exposes the intended command surface.
55
- - A representative successful response is parsed and formatted correctly.
56
- - A representative validation, authentication, or upstream API failure reports a non-zero exit path with useful error output.
132
+ ## 禁区
57
133
 
58
- ## Skill Design & Maintenance
134
+ - 不输出、不提交 `billing`、API Key、`.env` 内容、Base64 素材;密钥只走环境变量或命令行参数。
135
+ - 不手改 `api_docs/` 去迁就实现——它是接口契约(源头在 platform),契约变了才更新,并同时改测试。
136
+ - 不把 platform 侧计费单价写进 CLI 代码、README 或测试断言(价格在 `api_services` 表)。
137
+ - 不把 `hot_list_mixed` / `xhs_hot_list` 的明文 HTTP 顺手改成 HTTPS(测试锁定 `port 80`;确需改则测试、文档一起改并验证线上)。
138
+ - 不在命令文件里重写 HTTP、鉴权或格式化,不在 `src/lib` 之外复制共享工具。
139
+ - 不新增运行时依赖、不引入 ESM(当前只有 `commander`,用原生 `http/https`)。
140
+ - 不在 `src/` 内注册命令;命令注册只在 `bin/aiconductor-cli.js`。
59
141
 
60
- Skills in `.codex/skills` turn the CLI's verified capabilities into agent workflows. Keep them concise and operational; do not treat them as a second, independently authored API reference.
142
+ ## Agent 自主决策与复用约定
61
143
 
62
- ### Structure & Triggering
144
+ - 默认复用:`httpPost` / `stripBilling` / `validatePositiveInt` / `outputResult` / `handleApiError` / `resolveKeyOrExit`;新增代码照同目录文件写,不另起一套。
145
+ - 默认选型:CommonJS + `commander` + 原生 `http/https` + `node:test`;不引入 axios、node-fetch 或测试框架。
146
+ - 目录落点:一组命令一个 `src/commands/<组>.js`;HTTP 接口进 `src/api.js`;纯函数(格式化、聚合)留在命令文件内并导出以便测试。
147
+ - 直接做:读改代码、跑 `npm test`、跑 `--help`、`npm pack --dry-run`。
148
+ - 先确认:`npm publish`/发版、`git push`、技能上架到 WorkBuddy、任何带 API Key 的真实计费调用(`search`、`douyin`、`xhs`、`content`、`wx`)、`webpage delete`(不可逆,会失效公开链接)、批量改写 skills。
149
+ - 缺 API Key 时提示配置方式,不伪造、不复用示例输出。接任务先补齐背景、交付物、不做边界、约束、验收;"优化一下/完善一下"先翻译成可测量标准(哪条命令、哪个字段、什么退出码)。
63
150
 
64
- - The skill directory name and the `name` field in `SKILL.md` frontmatter must identify the same skill.
65
- - The frontmatter `description` must state the capability, likely user phrasing or context, and boundaries with adjacent skills. Define one clear owner for overlapping workflows so similar skills do not compete for the same request.
66
- - Keep `SKILL.md` focused on routing, decisions, command invocation, response handling, and safety rules. Move long option tables, platform-specific setup, and detailed background material into `references/`, and state exactly when that reference should be read.
67
- - Add `scripts/` only for deterministic, reusable work that avoids repeated implementation. Do not add scripts solely to wrap a single documented CLI command.
68
- - Add platform-specific metadata (such as files under `agents/`) only after validating its schema and behavior in the target runtime. Remove obsolete or unverified metadata rather than preserving it by convention.
151
+ ## 最短验证闭环
69
152
 
70
- ### CLI Contract & Execution
153
+ `npm test`(27 个用例,离线打桩,不需要 API Key)。改动涉及 `bin/`、`README.md`、skill 文字或新增命令时,再补一条人工核对:`node bin/aiconductor-cli.js <组> <子命令> --help`——`bin/` 的接线没有自动化测试覆盖。
71
154
 
72
- - Derive command names, arguments, option names, defaults, response fields, and error semantics from the local `--help` output, implementation, or tests. Do not copy stale documentation or infer unsupported behavior.
73
- - Default to JSON output and document stable response paths for the information the agent must return. Use text output only when the user asks for terminal-readable results.
74
- - A user's request for a CLI operation authorizes direct execution. Do not preflight installation, API Key availability, or environment setup on every invocation.
75
- - Put installation, upgrade, and API Key recovery instructions in an on-demand reference. Read it only when the user requests configuration or the command reports a missing CLI, authentication failure, or option/version incompatibility; after recovery, retry the original command at most once.
155
+ ## 任务执行与报告约定
76
156
 
77
- ### Safety & External Effects
157
+ 复杂任务先定位根因或明确方案,再拆分实施与验证;≤3 文件的局部改动直接改并验证。步骤 ≥3 用 todo 跟踪,一次一个 in_progress,做完立即标 completed。交付用通俗语言报告改了什么、验证结果(命令 + 实际输出)、对外影响(命令面、计费、技能)。
78
158
 
79
- - Never write, commit, or echo API Keys, `.env` content, Base64 media, or other sensitive user material.
80
- - Describe externally visible effects such as paid calls, temporary links, and public publishing accurately, including their success condition. Do not expose internal billing fields in user-facing output.
81
- - For irreversible actions, including deletion or invalidating public links, first show the exact target and obtain explicit confirmation unless the user already supplied the unique target and explicitly requested deletion.
159
+ ## 编码风格与命名约定
82
160
 
83
- ## CLI & Skill Synchronization
161
+ - 2 空格缩进,无 tab;CommonJS(`require` / `module.exports`),不写 ESM。
162
+ - JS 标识符 camelCase;请求字段用 API 的 snake_case(`need_content`、`max_pages`),映射在 `api.js` 完成,命令层保留 camelCase 选项名。
163
+ - 导出函数写 JSDoc(参数 + 返回类型);`const` 优先,必要时 `let`。
164
+ - 用户可见文本用中文;默认 JSON 输出,text 输出用 `✓` / `✗` 前缀与对齐字段名。
165
+ - 无 formatter/linter,跟随相邻文件风格。
84
166
 
85
- - When a command, argument, option, default, output shape, or error behavior is added, renamed, or removed, search for affected skills, README sections, and tests. Update all impacted artifacts in the same change.
86
- - New or changed skills must be added to Git with their `.codex/skills/**` files. Keep `.codex/` excluded from `.npmignore` so skills remain versioned repository assets without being included in the npm package.
87
- - Before finalizing a skill-related change, validate the referenced command's `--help` output and the documented JSON response path against implementation or tests.
167
+ ## 测试指南
88
168
 
89
- ## Commit & Pull Request Guidelines
169
+ - 框架:Node 内置 `node:test` + `node:assert/strict`,`npm test` 一次跑完;测试与模块同目录(目前集中在 `src/api.test.js`)。
170
+ - 网络必须打桩:`captureRequest` 替换 `https.request` / `http.request`,断言 `options.path`、`options.port`、`Authorization` 与请求体,同时校验返回值。测试不依赖 API Key、不发真实请求。
171
+ - 期望值独立于实现:请求字段以 `api_docs/<endpoint>.md` 为准;text 输出断言关键行(如 `结果数`、`URL`、`H5 地址`),不用整段快照。
172
+ - CLI 契约改动覆盖三类:`--help` 暴露的命令面(人工核对)、成功响应的解析与格式化(单测)、校验/鉴权/上游失败的非零退出(单测 + 一次手工失败调用)。
90
173
 
91
- From the existing history:
174
+ ## 提交与 PR 规范
92
175
 
93
- - Messages are in English, often prefixed with conventional commit tags: `feat:`, `fix:`, `refactor:`, `chore:`, `style:`, `ci:`
94
- - Agent-authored commits include `[Agent]` before the description
95
- - PRs should describe the change, note API surface impacts, and keep diffs focused
176
+ - 格式 `<tag>: <描述>`,tag 取自既有历史:`feat:`、`fix:`、`refactor:`、`docs:`、`skills:`、`search:`、`content:`、`release:`;agent 提交在前面加 `[Agent]`(如 `[Agent] release(cli): 1.4.0 —— ...`),描述可用中文。
177
+ - 发版提交只改 `package.json` + `package-lock.json` 的版本号;发版前先跑 `npm test`。
178
+ - 新增或修改 skill 必须随 `.agents/skills/**` 一起进 Git(`.npmignore` 已排除 `.agents/`,所以技能在仓库里版本化、不进 npm 包)。
179
+ - 历史只有单作者、无 PR 记录,可直接在 `master` 提交;若走 PR,描述写清命令面/API 影响与验证命令,保持 diff 聚焦。
96
180
 
97
- ## Adding a New Command
181
+ ## 安全与配置
98
182
 
99
- 1. Create `src/commands/<name>.js` with an async handler that calls `src/api.js`
100
- 2. Add the API function to `src/api.js` if it calls a new endpoint
101
- 3. Register the subcommand in `bin/aiconductor-cli.js`
102
- 4. Update `README.md` — command synopsis, option table, and example
183
+ - 只需一个环境变量 `AICONDUCTOR_API_KEY`(只写变量名,值不入库);解析顺序 `-k` > 环境变量 > 当前目录 `.env`。
184
+ - `.env`、`*.log`、`node_modules/` 已在 `.gitignore`;Base64 素材文件同样不得入库。
185
+ - 平台接口域名与各端点契约见 `api_docs/`,不要在代码外另维护第二份接口清单。
103
186
 
104
- ## Security & Configuration
187
+ ## 文档维护约定(常驻,不删除)
105
188
 
106
- - API Key is read from three sources in order: `-k` CLI argument → `AICONDUCTOR_API_KEY` env var → `.env` file
107
- - Never commit `.env` files or hardcoded credentials
189
+ 当本文档缺失/过时导致你走弯路时,在任务收尾顺手更新对应章节,只改受影响的最小范围。公共接口、命令、目录约定变化必须同步更新;一次性的会话经验不写入,只收下次还会踩的坑。
package/README.md CHANGED
@@ -353,6 +353,29 @@ aiconductor-cli xhs note-publish video \
353
353
 
354
354
  本地文件会在 CLI 内转换成 data URL,与 Base64 素材统一通过 JSON 接口免费上传为临时公开 URL,不使用 multipart。图片合计最多 18 张、单张最多 32MB;本地/Base64 视频受上传接口限制为 100MB,URL 视频上限为 200MB。
355
355
 
356
+ ### 微信公众号数据工具
357
+
358
+ 两个子命令:取单篇文章的互动数据、取公众号历史文章列表。
359
+
360
+ ```bash
361
+ # 单篇文章互动数据(阅读 / 点赞 / 在看 等)
362
+ aiconductor-cli wx article-data "https://mp.weixin.qq.com/s?__biz=xxxx&mid=xxxx&idx=1&sn=xxxx"
363
+
364
+ # 公众号历史文章列表:用公众号名称或任意一篇文章链接定位
365
+ aiconductor-cli wx history --name "人民日报" --max-pages 3 --max-seconds 50
366
+ aiconductor-cli wx history "https://mp.weixin.qq.com/s?__biz=xxxx" -f text
367
+ ```
368
+
369
+ | 选项 | 适用命令 | 说明 | 默认值 |
370
+ |------|----------|------|--------|
371
+ | `--name <name>` | `history` | 公众号名称或微信 ID(与 `url` 至少提供一个) | 无 |
372
+ | `--max-pages <n>` | `history` | 最大翻页数量 | 1 |
373
+ | `--max-seconds <n>` | `history` | 最长运行时间(秒),上限 170 | 50 |
374
+
375
+ 返回路径:`article-data` 的互动数据在 `data.data`(`read` / `zan` / `looking` / `share_num` / `collect_num` / `comment_count`,text 模式渲染成阅读/点赞/在看/分享/收藏/评论,未知字段原样输出);`history` 的文章在 `data.data.data[]`(标题 `title`、时间 `post_time_str`、阅读 `read`、点赞 `zan`、链接 `url`)。
376
+
377
+ `history` 另带 `data.data.code`(上游返回码):`0` 才表示成功;非 0(如 `107` 名称/链接对不上、`20001` 平台侧上游故障)时 CLI 以退出码 1 报 `api_error`,不会用空列表冒充成功。
378
+
356
379
  ### 通用选项
357
380
 
358
381
  所有命令支持:
@@ -375,6 +398,8 @@ aiconductor-cli xhs note-publish video \
375
398
  | 抖音链接转文字 | 0.01 元/次 + 0.0003 元/秒 |
376
399
  | 小红书热榜 | 以平台服务配置为准 |
377
400
  | 小红书扫码发布 | 0.05 元/次 |
401
+ | 公众号文章互动数据 | 以平台服务配置为准(按次) |
402
+ | 公众号历史文章列表 | 以平台服务配置为准(按成功翻页数) |
378
403
 
379
404
  > 搜索/调用失败不扣费,仅成功时计费。
380
405
 
@@ -386,8 +411,8 @@ cd aiconductor-cli
386
411
  npm install
387
412
  node bin/aiconductor-cli.js --help # 本地运行
388
413
  ```
389
-
390
- 贡献前请阅读 [AGENTS.md](./AGENTS.md) 了解项目结构、编码风格与提交流程。
414
+
415
+ 贡献前请阅读 [AGENTS.md](./AGENTS.md) 了解项目结构、编码风格与提交流程。
391
416
 
392
417
  ## License
393
418
 
@@ -12,7 +12,7 @@
12
12
  |--------|------|------|--------|------|
13
13
  | home_page | string | 是 | - | 抖音用户主页URL |
14
14
  | api_key | string | 是 | - | 计费系统API密钥 |
15
- | max_seconds | integer | 否 | 50 | 最长运行时间(秒),最大50 |
15
+ | max_seconds | integer | 否 | 50 | 最长运行时间(秒),内部上限 180 秒 |
16
16
  | max_pages | integer | 否 | 1 | 最大页数 |
17
17
 
18
18
  ## 响应参数
@@ -44,6 +44,6 @@
44
44
 
45
45
  ## 注意事项
46
46
  1. 支持抖音短链接和长链接,自动解析
47
- 2. max_seconds最大值为50秒
47
+ 2. max_seconds 最大值为 180 秒
48
48
  3. 按页收费,每成功获取一页数据扣费一次
49
49
  4. 达到时间限制或页数限制时会自动停止翻页
@@ -5,16 +5,16 @@
5
5
  - **鉴权**: 请求头 `Authorization: Bearer <api_key>`(兼容 body/query 中 `api_key` 参数)
6
6
 
7
7
  ## 功能说明
8
- 获取微信公众号历史文章列表,支持自动翻页与按页计费。为**计费插件**:按成功翻页次数计费(每翻一页扣费一次),费用以 `api_services` 表(`service_code=get_wx_history_article`)配置为准(源码注释提示:链接短链 0.08/次、长链 0.06/次、按名称 0.08 元/次,实际以表配置为准)。
8
+ 获取微信公众号历史文章列表,支持自动翻页与按页计费。为**计费插件**:按成功翻页次数计费(每翻一页扣费一次),费用以 `api_services` 表(`service_code=get_wx_history_article`)配置为准。底层已由 `page` 迁移至 `offset + is_end` 翻页(兼容旧版 `total_page/now_page`),可通过 `max_pages` / `max_seconds` 控制自动翻页。
9
9
 
10
10
  ## 请求参数
11
11
 
12
12
  | 参数名 | 类型 | 必填 | 默认值 | 说明 |
13
13
  |--------|------|------|--------|------|
14
14
  | url | string | 否* | - | 微信文章链接(用于定位公众号)。与 `name` 至少提供一个 |
15
- | name | string | 否* | - | 公众号名称或微信 ID(调用参数名 `name`) |
15
+ | name | string | 否* | - | 公众号名称或微信 ID(调用参数名 `name`,上游映射为 `nickname`) |
16
16
  | max_pages | int | 否 | `1` | 最大翻页数量 |
17
- | max_seconds | int | 否 | `50` | 最长运行时长(秒),超时即停止翻页 |
17
+ | max_seconds | int | 否 | `50` | 最长运行时长(秒),超时即停止翻页,**最大值 170**(默认50,传值>170自动截断为170,预留10s给平台180s超时) |
18
18
 
19
19
  > **说明**:`url` 与 `name` 二者至少提供一个,否则返回失败。
20
20
  > **鉴权参数**:api_key 通过请求头 `Authorization: Bearer <api_key>` 传递,不再列入请求参数表。
@@ -34,20 +34,39 @@
34
34
  | billing.pages_billed | int | 实际成功计费(翻页)页数 |
35
35
  | billing.total_service_fee | float | 累计扣费总额 |
36
36
  | billing.transaction_ids | array | 交易流水 ID 列表(每页一条) |
37
- | data | object | 历史文章结果数据,含以下字段 |
38
- | data.code | int | 最后一页的 API 返回码(`0` 为正常) |
37
+ | data | object | 业务数据 |
38
+ | data.code | int | 上游返回码,`0` 为成功 |
39
39
  | data.msg | string | `success` / `error` |
40
- | data.data | array | 文章列表,每项为文章对象(含标题、链接、发布时间等字段,结构取决于数据源) |
41
- | data.total_num | int | 该公众号历史文章总数(仅第一页返回) |
42
- | data.total_page | int | 总页数(仅第一页返回) |
43
- | data.publish_count | int | 发布次数(仅第一页返回) |
44
- | data.masssend_count | int | 群发次数(仅第一页返回) |
45
- | data.now_page | int | 实际已翻页数 |
46
- | data.now_page_articles_num | int | 已获取文章总数 |
47
- | data.mp_nickname | string | 公众号昵称(使用 `name` 参数时返回) |
48
- | data.mp_wxid | string | 公众号 wxid(使用 `name` 参数时返回) |
49
- | data.mp_ghid | string | 公众号 ghid(使用 `name` 参数时返回) |
50
- | data.head_img | string | 公众号头像(使用 `name` 参数时返回) |
40
+ | data.data | array | 文章列表(已自动合并多页),每项结构见下表 |
41
+ | data.data[].position | int | 当次群发中的位置(1 开始) |
42
+ | data.data[].url | string | 文章链接(`mp.weixin.qq.com/s?...`) |
43
+ | data.data[].sn | string | 文章唯一 sn |
44
+ | data.data[].post_time | int | 发布时间戳(秒) |
45
+ | data.data[].post_time_str | string | 发布时间字符串,如 `2026-08-27 16:32:59` |
46
+ | data.data[].cover_url | string | 封面图 URL |
47
+ | data.data[].original | int | 是否原创:`0` 否 `1` 是 |
48
+ | data.data[].item_show_type | int | 展示类型 |
49
+ | data.data[].digest | string | 摘要(可能为空) |
50
+ | data.data[].title | string | 文章标题 |
51
+ | data.data[].appmsgid | int | appmsg ID |
52
+ | data.data[].update_time | int | 更新时间戳(秒) |
53
+ | data.data[].types | int | 类型标识 |
54
+ | data.data[].pic_cdn_url_235_1 | string | 封面 CDN 2.35:1 |
55
+ | data.data[].pic_cdn_url_16_9 | string | 封面 CDN 16:9 |
56
+ | data.data[].pic_cdn_url_1_1 | string | 封面 CDN 1:1 |
57
+ | data.data[].source_url | string | 原文链接(转载时有值,否则为空) |
58
+ | data.data[].read | int | 阅读数 |
59
+ | data.data[].zan | int | 点赞数 |
60
+ | data.total_num | int | 历史文章总数(旧版上游返回,新版通常为 `0`,以 `data.data.length` 为准) |
61
+ | data.total_page | int | 总页数(旧版上游返回,新版通常为 `0`) |
62
+ | data.publish_count | int | 发布次数(旧版上游返回,新版为 `0`) |
63
+ | data.masssend_count | int | 群发次数(旧版上游返回,新版为 `0`) |
64
+ | data.now_page | int | 实际已翻页数(等于 `billing.pages_billed`) |
65
+ | data.now_page_articles_num | int | 已获取文章总数(等于 `data.data.length`) |
66
+ | data.mp_nickname | string | 公众号昵称(使用 `name` 参数时返回,兼容 `nickname`) |
67
+ | data.mp_wxid | string | 公众号 wxid(兼容 `wxid`) |
68
+ | data.mp_ghid | string | 公众号 ghid(兼容 `ghid`) |
69
+ | data.head_img | string | 公众号头像 |
51
70
 
52
71
  ## 请求示例
53
72
 
@@ -63,8 +82,8 @@ curl -X POST "http://plugin.aiconductor.fun/api/wx_history_articles" \
63
82
  ```
64
83
 
65
84
  ## 注意事项
66
- 1. 本接口**按页计费**,每成功翻一页扣费一次;已扣费的页不退还。
67
- 2. **停止翻页条件**:余额不足、API 返回错误、无更多页、达到 `max_pages` 或超过 `max_seconds` 任一满足即停止;`billing.pages_billed` / `total_service_fee` 反映实际扣费。
85
+ 1. 本接口**按页计费**,每成功翻一页扣费一次;已扣费的页不退还。新版翻页依据上游 `offset` + `is_end`(`0` 表示还有下页),已兼容旧版 `total_page/now_page`。
86
+ 2. **停止翻页条件**:余额不足、API 返回错误(`code!=0`)、`is_end=1` 或 `offset` 为空、达到 `max_pages` 或超过 `max_seconds` 任一满足即停止;`billing.pages_billed` / `total_service_fee` 反映实际扣费。
68
87
  3. **不扣费场景**:缺少 `url` 与 `name`、API 密钥无效、账户被禁用——此时 `pages_billed=0`、`total_service_fee=0`、余额不变。
69
- 4. `data.data[]` 为文章对象列表,字段结构由第三方数据源决定,需做容错解析。
70
- 5. 每页请求最多重试 10 次;建议合理设置 `max_seconds` 以避免单次调用过长触发平台 180 秒超时。
88
+ 4. `data.data[]` 为跨页合并后的文章列表,单页条数由上游决定;`data.total_num/total_page/publish_count/masssend_count` 在新版上游中可能为 `0`,请以 `data.data.length` / `now_page_articles_num` 为准。
89
+ 5. 每页请求最多重试 10 次;`max_seconds` 默认 50s,最大 170s(平台兜底180s),建议按需设置以避免触发平台 504 超时。
@@ -5,7 +5,11 @@
5
5
  - **鉴权**: 请求头 `Authorization: Bearer <api_key>`(兼容 body/query 中 `api_key` 参数)
6
6
 
7
7
  ## 功能说明
8
- 根据用户ID获取小红书用户详情,包括基本信息、互动数据(关注/粉丝/获赞与收藏)、标签等。按次计费。
8
+ 根据用户ID获取小红书用户详情,包括基本信息、互动数据(关注/粉丝/获赞与收藏/获赞/收藏)、标签等。按次计费。
9
+
10
+ > **数据源变更(2026-11-05)**:上游由 YDDM `/xhs/user_detail`(实测 8.2s)切换为 TikHub `GET /api/v1/xiaohongshu/app_v2/get_user_info`(实测 2.3s),**入参与出参形状完全不变**:
11
+ > `user_info.basic_info{nickname, avatar, red_id, gender, ip_location, desc}` + `user_info.interactions[5]{type, name, count}`(关注/粉丝/获赞与收藏/获赞/收藏)+ `user_info.tags[string]`。
12
+ > 两个口径差异需知悉:① `ip_location` 统一给**中文省份**(优先取资料地区省份,回落英文 IP 归属地,如 `福建`);② `获赞与收藏` 取上游自带的合计值,缺失时用 `获赞 + 收藏` 兜底。
9
13
 
10
14
  ## 请求参数
11
15
 
@@ -7,6 +7,8 @@
7
7
  ## 功能说明
8
8
  根据用户 ID 获取小红书用户笔记列表,支持自动翻页(cursor 机制),兼容图文与视频笔记,按页计费。费用以 api_services 表配置为准(service_code: `xhs_user_notes_v2`)。
9
9
 
10
+ > **数据源变更(2026-11-05)**:上游由 YDDM `/xhs/user_post2`(持续返回 `code 5003 网络连接失败`,接口表现为 `success:true` + 空 `notes`)切换为 TikHub `GET /api/v1/xiaohongshu/app_v2/get_user_posted_notes`(实测 20 条/页、1.9s)。**入参与出参形状完全不变**,与 `xhs_user_notes_v2` 同一上游、同一输出结构(差别只在 `desc` 等字段的原始内容)。
11
+
10
12
  ## 请求参数
11
13
 
12
14
  | 参数名 | 类型 | 必填 | 默认值 | 说明 |