Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
88473e3
Update OPENCLAW.md
geekjourneyx Feb 6, 2026
bf52bc2
feat: add v2 API themes and background type support
Feb 10, 2026
7973176
docs: update CHANGELOG for v1.9.0 with all new features
Feb 10, 2026
ffe0a33
chore(release): bump version to 1.10.0
Feb 10, 2026
c0dd9dd
chore(release): bump version to 1.11.0
web-flow Mar 12, 2026
7c968b1
docs: add logo to README, clean up beta recruitment copy
web-flow Mar 12, 2026
49f1102
refactor: stabilize publish pipeline and release workflow
web-flow Mar 19, 2026
156c02e
fix: address review regressions in publish flow
web-flow Mar 19, 2026
e7da072
refactor: split openclaw skill packaging and install flow
web-flow Mar 19, 2026
898fdaa
docs: add config guidance and smoke verification
web-flow Mar 19, 2026
8d901d0
docs: clarify default api conversion mode
web-flow Mar 19, 2026
4f9c554
refactor: embed builtin themes and writer styles
web-flow Mar 20, 2026
c63bff9
feat: add prompt catalog and capability discovery
geekjourneyx Mar 20, 2026
5bf45cc
refactor: separate skill contracts from platform metadata
geekjourneyx Mar 20, 2026
55419dd
docs: align skill triggers and platform guidance
geekjourneyx Mar 20, 2026
5f2bc63
docs: improve onboarding and wechat setup guidance
geekjourneyx Mar 20, 2026
8e562fe
docs: align discovery guidance across docs and skills
geekjourneyx Mar 20, 2026
e72ccb6
feat: add image prompt presets and generation flows
geekjourneyx Mar 20, 2026
8bf0ad1
docs: align skills with latest image workflows
geekjourneyx Mar 20, 2026
8d6bb29
feat: add prompt attribution metadata
geekjourneyx Mar 20, 2026
0c83b29
feat: add infographic prompt variants
geekjourneyx Mar 20, 2026
c06efd4
refactor: model image prompt use cases explicitly
geekjourneyx Mar 20, 2026
87779b1
feat: add premium infographic preset and prompt guardrails
geekjourneyx Mar 20, 2026
b57d16d
fix: align gemini image sizing and defaults
geekjourneyx Mar 20, 2026
b8fa0e9
feat: add per-command image model overrides
geekjourneyx Mar 20, 2026
795b567
docs: align image provider guidance
geekjourneyx Mar 20, 2026
0e8126e
fix: align image provider defaults and docs
geekjourneyx Mar 20, 2026
5c7a305
docs: restructure readme onboarding flow
geekjourneyx Mar 20, 2026
2529db0
release: prepare v2.0.0
geekjourneyx Mar 20, 2026
29d1e27
fix: align release metadata and skill packaging
geekjourneyx Mar 20, 2026
bc474bd
build: align go version and lint gates
geekjourneyx Mar 20, 2026
569d696
Merge pull request #7 from geekjourneyx/v2-publish-pipeline-refactor
geekjourneyx Mar 20, 2026
117aed3
docs: remove emoji from readme tone
geekjourneyx Mar 20, 2026
169d1b2
fix: align release artifact paths in workflow
geekjourneyx Mar 20, 2026
addc31a
fix: inject release version into cli binary
geekjourneyx Mar 20, 2026
7c2d5eb
fix: run powershell installer smoke on windows
geekjourneyx Mar 20, 2026
727690c
fix: parse powershell smoke version output
geekjourneyx Mar 20, 2026
eda2811
docs: refresh readme header artwork
geekjourneyx Mar 20, 2026
2e9a7b5
docs: add favicon branding to readme
geekjourneyx Mar 20, 2026
407cee2
docs: tighten openclaw install guidance
geekjourneyx Mar 20, 2026
6356d46
release: prepare v2.0.1
geekjourneyx Mar 20, 2026
f0bdff7
docs: simplify openclaw setup flow
geekjourneyx Mar 20, 2026
4a3b374
docs: use runtime path in openclaw setup
geekjourneyx Mar 20, 2026
3cce48b
release: prepare v2.0.2
geekjourneyx Mar 21, 2026
a62ee2a
release: finalize v2.0.2 packaging and docs
geekjourneyx Mar 21, 2026
2131e06
Add Homebrew release automation
geekjourneyx Mar 21, 2026
b666add
Improve OpenClaw skill metadata
geekjourneyx Mar 21, 2026
fe3c9c8
release: prepare v2.0.3
geekjourneyx Mar 21, 2026
31ac444
docs: refine install guidance across agents
geekjourneyx Mar 21, 2026
de821c5
docs: update onboarding for brew and openclaw
geekjourneyx Mar 21, 2026
c61c913
Update README.md
geekjourneyx Mar 22, 2026
44dfa19
feat: release v2.0.4 - metadata flags and improvements
geekjourneyx Mar 25, 2026
db46f57
release: prepare v2.0.5
geekjourneyx Mar 27, 2026
3d10ae2
build: unify local and CI quality gates
geekjourneyx Mar 27, 2026
bb2e7d7
Update README.md
geekjourneyx Mar 27, 2026
f3856e3
Update README.md
geekjourneyx Mar 27, 2026
639b656
Update README.md
geekjourneyx Mar 29, 2026
ed72b05
release: v2.0.6
geekjourneyx Mar 29, 2026
20bbcbf
docs: add npmmirror sync release step
geekjourneyx Mar 29, 2026
1ca799a
Update README.md
geekjourneyx Mar 30, 2026
3306fd1
release: prepare v2.0.7
geekjourneyx Mar 30, 2026
02f1a4c
docs: add layout module catalog design spec
geekjourneyx Apr 26, 2026
caff654
feat(layoutcatalog): define LayoutSpec schema and ValidServes
geekjourneyx Apr 26, 2026
d1f87d8
feat(assets,layoutcatalog): embed layout catalog and add loader with …
geekjourneyx Apr 26, 2026
bfa260d
fix(layoutcatalog): correct override priority, DefaultCatalog error h…
geekjourneyx Apr 26, 2026
831f942
feat(layoutcatalog): implement render for fields and rows modes
geekjourneyx Apr 26, 2026
eb2296c
feat(layoutcatalog): add validator with unknown-module warn-not-block
geekjourneyx Apr 26, 2026
712c65b
fix: renderRows enum validation + validateBlock aliasing
geekjourneyx Apr 26, 2026
9345bc9
feat(cli): add 'md2wechat layout' command tree
geekjourneyx Apr 26, 2026
78dca27
fix(cli): use distinct code for validate errors, replace LAYOUT_TEST_…
geekjourneyx Apr 26, 2026
4d01ee8
feat(layout): add opening and judgment modules batch (1/42)
geekjourneyx Apr 26, 2026
7d5e0dc
feat(layout): add infographic modules batch (2/42)
geekjourneyx Apr 26, 2026
a80438c
feat(layout): add evidence modules batch (3/42)
geekjourneyx Apr 26, 2026
7f3d84c
feat(layout): add brand modules batch (4/42)
geekjourneyx Apr 26, 2026
0b82470
feat(layout): add conversion modules part 1 batch (5/42)
geekjourneyx Apr 26, 2026
24ca66e
feat(layout): add conversion modules part 2 batch (6/42)
geekjourneyx Apr 26, 2026
6c7c306
feat(layout): add sprint4 modules part 1 batch (7/42)
geekjourneyx Apr 26, 2026
c1be922
feat(layout): add sprint4 modules part 2 batch (8/42)
geekjourneyx Apr 26, 2026
10df87e
test(layoutcatalog): assert 38+ modules and metadata completeness
geekjourneyx Apr 26, 2026
be38a7e
test(layoutcatalog): integration fixtures for 3 article shapes
geekjourneyx Apr 26, 2026
b571f4f
test(e2e): layout module catalog vs /api/convert consistency
geekjourneyx Apr 26, 2026
38a2f48
docs: document md2wechat layout commands and discovery flow
geekjourneyx Apr 26, 2026
8ffd1af
docs(skill): add advanced layout decision flow to both skill manifests
geekjourneyx Apr 26, 2026
0fcfde2
docs: changelog entry for layout module catalog v2.1.0
geekjourneyx Apr 26, 2026
2472874
chore: align marketplace.json and package.json to v2.1.0
geekjourneyx Apr 26, 2026
463d99a
fix: validator regex for bracket-title syntax, rows render JSON input
geekjourneyx Apr 26, 2026
4b24d1d
fix(yaml): callout rows mode, definition removes fields to prevent fa…
geekjourneyx Apr 26, 2026
8cc7bc6
docs: add E2E rendering smoke test requirement and layout-e2e-test.md
geekjourneyx Apr 26, 2026
0db54fe
fix(layout): align YAML field docs with actual JSON keys for Agent ac…
geekjourneyx Apr 26, 2026
c3b9f17
docs: add API-mode-only hints for layout modules, remove URL from pub…
geekjourneyx Apr 26, 2026
1ebf357
docs: add 保姆级 layout tutorial, readme-header GIF, complete CHANGELOG …
geekjourneyx Apr 26, 2026
ca409ba
docs: restructure README as commercial landing page (1941 → 388 lines)
geekjourneyx Apr 26, 2026
022e0ad
feat(humanizer): add authentic intensity mode with standalone prompt
geekjourneyx Apr 26, 2026
ea766bd
docs: add HUMANIZE.md tutorial and sync authentic mode to SKILL.md/DI…
geekjourneyx Apr 26, 2026
686897a
docs(changelog): add authentic mode, README restructure, HUMANIZE.md …
geekjourneyx Apr 26, 2026
ab2298f
docs: align AGENTS.md, CLAUDE.md, copilot-instructions.md before v2.1…
geekjourneyx Apr 26, 2026
586a435
fix(lint): handle errcheck in layout_e2e_test.go postConvert helper
geekjourneyx Apr 26, 2026
d3a8123
docs: replace remote qrcode URL with local assets/wechat.png
geekjourneyx Apr 26, 2026
a155fc9
docs: add transform demo GIF after quickstart step 3
geekjourneyx Apr 26, 2026
0a5a64f
docs: remove promotional noise from copilot-instructions
geekjourneyx Apr 26, 2026
0e8d274
docs: remove promotional noise from AGENTS.md
geekjourneyx Apr 26, 2026
6f95861
docs: promote Volcengine Ark as primary image provider recommendation
geekjourneyx Apr 26, 2026
59dde89
chore: remove docs/superpowers/specs from tracking (gitignored)
geekjourneyx Apr 26, 2026
10de53f
Add WeChat group join information to README
geekjourneyx Apr 28, 2026
6da254c
Update README.md
geekjourneyx Apr 28, 2026
3cc52ea
Remove duplicate codesome recommendation
geekjourneyx Apr 30, 2026
1dd1e96
chore: upgrade license from MIT to Source Available (BUSL-1.1)
geekjourneyx May 7, 2026
166a929
Update README.md
geekjourneyx May 8, 2026
9c787af
Initial plan
Copilot May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"name": "md2wechat-tools",
"owner": {
"name": "geekjourney",
"email": "skrphper@gmail.com"
"name": "geekjourneyx",
"email": "zlisreallyli@outlook.com"
},
"plugins": [
{
"name": "md2wechat",
"source": ".",
"description": "Convert Markdown articles to WeChat Official Account formatted HTML with styled CSS. Supports API mode for quick conversion and AI mode for beautiful themed layouts (autumn-warm, spring-fresh, ocean-calm). Optionally upload to draft box.",
"version": "1.9.0",
"source": "./",
"description": "Convert Markdown articles to WeChat Official Account HTML, inspect resolved metadata and publish readiness, generate local preview artifacts, and optionally upload drafts.",
"version": "2.1.0",
"author": {
"name": "geekjourney"
"name": "geekjourneyx"
},
"homepage": "https://github.com/geekjourneyx/md2wechat-skill",
"repository": "https://github.com/geekjourneyx/md2wechat-skill",
"license": "MIT",
"license": "Source Available (BUSL-1.1)",
"keywords": ["wechat", "markdown", "blog", "publishing", "html", "converter", "official account", "公众号", "排版"],
"strict": false
}
Expand Down
173 changes: 173 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Copilot Instructions — md2wechat

**md2wechat** is a Go CLI tool that converts Markdown to WeChat Official Account format, with Claude Code and OpenClaw Skill support.

## Build, Test, Lint

```bash
# Build for current platform
make build

# Run all tests (use GOCACHE to avoid conflicts)
GOCACHE=/tmp/md2wechat-go-build go test ./...

# Run a single package test
GOCACHE=/tmp/md2wechat-go-build go test ./cmd/md2wechat/...

# Run a single test by name
GOCACHE=/tmp/md2wechat-go-build go test ./cmd/md2wechat -run TestRunVersionOutputsJSONEnvelope

# Full CI-equivalent gate (run this before any release or CI-sensitive work)
make quality-gates

# Individual checks
gofmt -l . # formatting check
go vet ./... # static analysis
make lint # golangci-lint (same as CI)
make release-check # version/doc consistency
```

`make quality-gates` runs: format check → `go vet` → golangci-lint → `go test -count=1` → npm pack dry-run → `make release-check`. It is the authoritative local gate — identical to what GitHub Actions runs.

## Architecture

The main pipeline is:

```
cmd/md2wechat → inspect/preview (confirmation layer) → publish orchestrators → AssetPipeline → draft/wechat adapters
```

- **`cmd/md2wechat/`** — Cobra commands only. Handles arg parsing, calls internal packages, emits JSON envelopes and exits. No business logic.
- **`internal/inspect`** — Single source of truth for resolved metadata, readiness, and publish checks. `preview` consumes inspect output; it does not re-implement business rules.
- **`internal/preview`** — Read-only HTML confirmation page rendered from inspect state.
- **`internal/publish`** — Main orchestration for article and image-post publish flows. Contains `AssetPipeline` (image upload/generate/download/rewrite) and `model.go` (canonical article/asset/artifact types).
- **`internal/converter`** — Markdown → HTML, frontmatter extraction, image ref parsing, AI/API conversion.
- **`internal/image`** — Image generation, compression, upload/download (injected at runtime).
- **`internal/draft`** — WeChat draft adapter (standard article + `newspic` image post).
- **`internal/wechat`** — WeChat SDK wrapper, material upload with retry, SSRF guard.
- **`internal/promptcatalog`** — Loads prompt YAML assets from `internal/assets/builtin/prompts/`.
- **`internal/config`** — Config loaded from file (`~/.md2wechat.yaml`) then environment variables.

**Two skill paths share the same CLI binary:**
- `skills/md2wechat/` — Claude Code / Codex / OpenCode agent skill
- `platforms/openclaw/md2wechat/` — OpenClaw / ClawHub structured skill

## Key Conventions

### Discovery-first
Before assuming any provider, theme, or prompt exists, query the running CLI:
```bash
md2wechat capabilities --json
md2wechat providers list --json
md2wechat themes list --json
md2wechat prompts list --json
md2wechat layout list --json # advanced layout modules (43 built-in)
```
These are the source of truth. Do not guess from docs or stale memory.

### Layout Module Discovery
Advanced layout modules (43 built-in, 6 categories) are discovered and validated via:
```bash
md2wechat layout list --json # list all modules
md2wechat layout list --serves attention --json # filter by goal
md2wechat layout show <name> --json # inspect a module
md2wechat layout render <name> --var KEY=VALUE # render syntax block
md2wechat layout validate --file article.md --json # validate syntax in file
```

**重要约束**:高级排版模块(`:::block` 语法)仅在 **API 模式**下渲染。
- `convert`(默认)= API 模式,模块正常渲染
- `convert --mode ai` = AI 模式,`:::block` 不渲染,以普通段落输出

The 4 `serves` values that every module is mapped to: `attention` | `readability` | `memorability` | `conversion`.

### E2E Rendering Smoke Test (required before every release)

Before tagging or releasing, verify that advanced layout syntax renders correctly through the real API:

```bash
# Build latest CLI
make build

# Convert a test file with core layout modules (--mode api hits localhost:3000)
./md2wechat convert examples/layout-e2e-test.md --mode api --output /tmp/layout-smoke.html

# Check no raw ::: syntax remains in the output HTML
python3 -c "
modules = ['hero','toc','verdict','audience-fit','myth-fact','metrics','compare','steps',
'timeline','quote','callout','definition','author-card','subscribe',
'faq','checklist','cta','notice','summary']
html = open('/tmp/layout-smoke.html').read()
failed = [m for m in modules if ':::' + m in html]
ok = [m for m in modules if ':::' + m not in html]
print(f'PASS {len(ok)}/{len(modules)}') if not failed else print('FAIL - not rendered:', failed)
"

# Validate syntax is correct before running convert
./md2wechat layout validate --file examples/layout-e2e-test.md --json
```

**Pass criteria:** Both checks pass (0 raw residuals, 0 validation errors). Do not tag or push a release until both are green.

The canonical test file is `examples/layout-e2e-test.md`. Update it when adding new modules.



### JSON Envelope Contract
Every command emits a stable JSON envelope (schema version `v1`):
```json
{
"success": true,
"code": "CODE_CONSTANT",
"message": "human text",
"schema_version": "v1",
"status": "completed|action_required|failed",
"retryable": false,
"data": {},
"error": ""
}
```
All `code` constants are declared in `cmd/md2wechat/main.go`. Adding a new command requires a new constant and a contract test in `main_contract_test.go`.

### Configuration Naming Layers
Three layers exist and must never be mixed in docs or guidance:
- **Config file YAML keys** — e.g., `api.image_base_url`
- **Environment variables** — e.g., `IMAGE_API_BASE`
- **`config show --format json` output keys** — e.g., `image_api_base`

### Prompt Catalog (YAML, not Go code)
Image/humanizer/refine prompts live in `internal/assets/builtin/prompts/`. Do not embed long prompts directly in Go code. Humanizer supports 4 intensity levels: `gentle` / `medium` / `aggressive` / `authentic` — the `authentic` mode uses a standalone YAML prompt (`authentic.yaml`) that bypasses the base template. Every new `image` prompt YAML must include: `name`, `kind`, `description`, `version`, `archetype`, `primary_use_case`, `recommended_aspect_ratios`, `default_aspect_ratio`, `metadata.author`, `metadata.provenance`, `template`. The `default_aspect_ratio` must appear in `recommended_aspect_ratios`.

### Test Discipline
Tests protect contracts, not coverage numbers. Before writing any test, ask:
1. Which failure would most damage user trust?
2. Which failure would most mislead an agent?
3. Which boundary must stay aligned between `inspect`, `preview`, `convert`, and `draft`?

Priority: CLI contract tests → confirmation-vs-execution consistency → blocking readiness matrix → publish-path core → minimal real smoke. Use table-driven tests when behavior depends on input combinations. Do not add tests just to raise coverage.

### Version Consistency
All of these must stay aligned on release:
- `VERSION` file
- `.claude-plugin/marketplace.json`
- `platforms/openclaw/md2wechat/SKILL.md` (install URLs)
- `CHANGELOG.md`

Quick check: `echo "VERSION: $(cat VERSION)" && grep '"version"' .claude-plugin/marketplace.json | head -1`

### Documentation Sync
Any change to CLI commands, flags, JSON output shape, providers, themes, or prompts must also update:
- `README.md`
- `docs/DISCOVERY.md`
- `docs/FAQ.md`
- `skills/md2wechat/SKILL.md`
- `platforms/openclaw/md2wechat/SKILL.md`
- `docs/HUMANIZE.md` when humanizer behavior or intensity levels change

If the change affects config, install, or setup: also update `docs/CONFIG.md`, `docs/QUICKSTART.md`, `docs/USAGE.md`.

### Git and Release Rules
- Never `git push`, `git tag`, or `gh release create` without explicit user confirmation.
- Never rebase or amend history unless the user explicitly asks.
- GitHub Release is created automatically by `release.yml` when a tag matching `v*.*.*` is pushed — `gh` CLI is not required.
- After `npm publish`, trigger `npx cnpm sync @geekjourneyx/md2wechat` so npmmirror stays current.
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: CI

on:
push:
branches:
- main
pull_request:

jobs:
quality-gates:
uses: ./.github/workflows/quality-gates.yml
29 changes: 29 additions & 0 deletions .github/workflows/quality-gates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Quality Gates

on:
workflow_call:
workflow_dispatch:

jobs:
quality-gates:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Download dependencies
run: go mod download

- name: Run unified quality gates
run: bash scripts/quality-gates.sh
Loading