Skip to content
54 changes: 23 additions & 31 deletions profile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,45 @@

# md2wechat

面向 AI Agent 的微信公众号创作与发布 CLI,也是连接 Markdown、公众号排版、图片、预览校验和草稿流程的开放生态。
md2wechat 是面向 AI Agent 的微信公众号创作与发布 CLI。

把 Markdown 变成适合微信公众号的内容:你可以在线排版,也可以用 CLI 或 Skill 在自己的工作流中完成检查、预览、转换,以及在授权后创建草稿。

[在线编辑器](https://www.md2wechat.cn) · [CLI / Skill](https://github.com/geekjourneyx/md2wechat-skill) · [使用指南](https://github.com/md2wechat/md2wechat-guide) · [可执行模板](https://github.com/md2wechat/md2wechat-templates)

</div>

## 按任务选择入口

| 你要完成的任务 | 推荐入口 | 边界 |
|---|---|---|
| 在线编辑 Markdown 并复制微信富文本 | [在线编辑器](https://www.md2wechat.cn) | 人工编辑、预览和复制 |
| 在 Codex、Claude Code 等 Agent 中完成公众号工作流 | [md2wechat CLI / Skill](https://github.com/geekjourneyx/md2wechat-skill) | 核心产品与 Agent 运行协议 |
| 将 Markdown 转成微信兼容 HTML | [Convert API](https://www.md2wechat.cn/api-docs) | 只转换内容,不创建公众号草稿 |
| 接入素材与公众号草稿服务 | [Publishing API](https://md2wechat.com/api/v1) | 涉及外部写操作,需要凭证和用户确认 |
| 按步骤完成安装、发现、检查、预览和发布 | [Guide](https://github.com/md2wechat/md2wechat-guide) | 稳定任务教程 |
| 复用企业办公与创作者内容骨架 | [md2wechat Templates](https://github.com/md2wechat/md2wechat-templates) | 可验证的 Markdown 模板 |
| 查找微信 Markdown、发布、Skill 和 MCP 工具 | [Awesome](https://github.com/md2wechat/awesome-wechat-markdown) | 中立生态目录 |
| 核对版本事实、术语和平台证据 | [Wiki](https://github.com/md2wechat/md2wechat-wiki) | 事实来源与复核记录 |
## 选择使用方式

## 最短可验证路径
| 你想做什么 | 从这里开始 |
|---|---|
| 在线编辑 Markdown、预览并复制微信富文本 | [在线编辑器](https://www.md2wechat.cn) |
| 在本地工作流中处理公众号内容 | [md2wechat CLI / Skill](https://github.com/geekjourneyx/md2wechat-skill) |
| 将 Markdown 转为微信兼容 HTML | [Convert API](https://www.md2wechat.cn/api-docs):只转换 HTML,不创建草稿 |
| 上传素材并创建公众号草稿 | [Publishing API](https://md2wechat.com/api/v1):创建草稿不等于群发 |

具体命令、主题和 Layout 能力以当前安装版本的 Discovery 输出为准:
## 第一次使用

```bash
md2wechat version --json
md2wechat capabilities --json
md2wechat skills read md2wechat --json
```
想先看看排版效果,可直接打开[在线编辑器](https://www.md2wechat.cn),粘贴 Markdown 后预览并复制内容。

推荐流程:安装 → Discovery → 结构检查 → 排版 → 本地/API 预览 → 用户确认后的草稿操作。创建草稿不等于群发。
想把流程放进本地项目或日常写作工具,请从 [CLI / Skill](https://github.com/geekjourneyx/md2wechat-skill) 开始,再按 [Guide](https://github.com/md2wechat/md2wechat-guide) 的步骤安装和使用。

## 产品关系
## 在 AI 工具中使用

- **CLI / Skill**:Agent 原生的公众号创作与发布入口。
- **在线编辑器**:适合人工编辑、实时预览和复制 HTML。
- **Convert API**:`POST https://www.md2wechat.cn/api/convert`,负责 Markdown 到微信兼容 HTML 的转换。
- **Publishing API**:`https://md2wechat.com/api/v1`,负责需要授权的素材和草稿副作用服务。
能够运行本地命令的 AI 工具,可以通过 md2wechat 的 [Skill / CLI](https://github.com/geekjourneyx/md2wechat-skill) 接入内容工作流。不同工具的安装方法与使用记录请查看 [Guide](https://github.com/md2wechat/md2wechat-guide) 和 [Wiki](https://github.com/md2wechat/md2wechat-wiki)。

## 平台兼容性
## 文档与生态

办公 Agent 和技能市场变化很快。平台是否可安装、是否完成真实 smoke、是否能创建草稿,必须分开记录;组织主页不直接宣布未经复核的支持关系。查看 [Wiki 的状态与证据](https://github.com/md2wechat/md2wechat-wiki/tree/main/evidence)。
- [Guide](https://github.com/md2wechat/md2wechat-guide):安装、排版、预览和发布的分步说明
- [md2wechat Templates](https://github.com/md2wechat/md2wechat-templates):可复用的内容骨架
- [Awesome](https://github.com/md2wechat/awesome-wechat-markdown):微信 Markdown、发布、Skill 和 MCP 工具目录
- [Wiki](https://github.com/md2wechat/md2wechat-wiki):版本事实、术语与使用记录

## 参与维护
## 反馈

- CLI、渲染、安装和发布问题:[主项目 Issues](https://github.com/geekjourneyx/md2wechat-skill/issues)
- 教程错误:[Guide Issues](https://github.com/md2wechat/md2wechat-guide/issues)
- 生态项目新增或更正:[Awesome Issues](https://github.com/md2wechat/awesome-wechat-markdown/issues)
- 版本、术语或证据问题:[Wiki Issues](https://github.com/md2wechat/md2wechat-wiki/issues)
- 版本或术语问题:[Wiki Issues](https://github.com/md2wechat/md2wechat-wiki/issues)

提交问题前请删除 AppID、AppSecret、API Key、Cookie、草稿 ID 和未公开文章内容。
请勿在 Issue 中粘贴 AppID、AppSecret、API Key、Cookie、草稿 ID 或未公开文章内容。
12 changes: 10 additions & 2 deletions scripts/validate-facts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,16 @@ export function validateProfile(profile, facts) {
if (claim.test(profile)) {
errors.push("profile contains an evidence-gated platform support claim")
}
if (/Convert API.{0,16}(?:创建|生成).{0,8}草稿/s.test(profile)) {
errors.push("profile confuses Convert API with draft creation")
const convertDraftClaims = profile.match(/Convert API[^。!?\n]*/g) ?? []
for (const sentence of convertDraftClaims) {
const withoutNegativeClaims = sentence.replaceAll(
/(?:不|不会|不能|不提供|未)(?:创建|生成)[^。!?\n]{0,8}草稿/g,
"",
)
if (/(?:创建|生成)[^。!?\n]{0,8}草稿/.test(withoutNegativeClaims)) {
errors.push("profile confuses Convert API with draft creation")
break
}
}
return errors
}
Expand Down
44 changes: 44 additions & 0 deletions tests/validate-facts.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,50 @@ test("the validator accepts the repository contracts and rendered profile", () =
assert.equal(result.status, 0, result.stderr || result.stdout)
})


test("public profile uses reader-facing language", () => {
const profile = readFileSync(new URL("profile/README.md", root), "utf8")
const internalTerms = [
"最短可验证路径",
"产品关系",
"平台兼容性",
"smoke",
"publiclySupported",
"Discovery 输出",
"失效条件",
"核验基线",
"状态注册表",
"副作用",
"未经复核的支持关系",
"状态与证据",
]
for (const term of internalTerms) {
assert.equal(profile.includes(term), false, `profile must not contain internal term: ${term}`)
}
})

test("public profile uses real Markdown line breaks", () => {
const profile = readFileSync(new URL("profile/README.md", root), "utf8")
assert.equal(profile.includes("\\n"), false, "profile must not contain literal escaped line breaks")
})

test("profile guard distinguishes negative Convert API draft wording from claims", () => {
const facts = readJson("facts/product-routes.json")
for (const profile of [
"Convert API 不创建草稿",
"Convert API 只转换内容,不会生成草稿",
]) {
assert.doesNotMatch(
validator.validateProfile(profile, facts).join("\n"),
/profile confuses Convert API with draft creation/,
)
}
assert.match(
validator.validateProfile("Convert API 可以创建草稿", facts).join("\n"),
/profile confuses Convert API with draft creation/,
)
})

test("the validator reports immutable source SHA drift", () => {
const fixture = JSON.stringify({
schemaVersion: 1,
Expand Down
Loading