{"owner":"doocs","repo":"md","hasSkills":true,"totalSkillsCount":16,"totalTokensCount":18832,"categories":["anthropic-skill","mcp-config","copilot-instructions","root-instruction","claude-rule","plugin-manifest","project-spec"],"hasMcp":true,"mcpConfig":{"mcpServers":{"md":{"command":"node","args":["--import","tsx/esm","${workspaceFolder}/packages/mcp-server/run.mjs"],"cwd":"${workspaceFolder}/packages/mcp-server"}}},"found":[".agents/skills/create-pr/SKILL.md",".agents/skills/git-commit/SKILL.md",".agents/skills/wechat-svg/SKILL.md",".agents/skills/wechat-svg/references/core-principles.md",".agents/skills/wechat-svg/references/image-integration.md",".cursor/mcp.json",".github/copilot-instructions.md","AGENTS.md","CLAUDE.md","apps/utools/README.md","apps/utools/plugin.json","docs/architecture.md","packages/core/README.md","packages/mcp-server/README.md","packages/md-cli/README.md","packages/shared/README.md"],"skills":{".agents/skills/create-pr/SKILL.md":"---\nname: create-pr\ndescription: Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool.\n---\n\n# Create PR\n\nThis skill guides you through creating a well-structured GitHub pull request that follows project conventions and best practices.\n\nDo **not** assume Bash. On Windows PowerShell, avoid `&&`, `$(...)`, and POSIX tests; run git/`gh` commands as separate invocations and use `$env:TEMP` for the PR body file.\n\n## Prerequisites Check\n\nBefore proceeding, verify the following:\n\n### 1. Check if `gh` CLI is installed\n\n```bash\ngh --version\n```\n\nIf not installed, inform the user:\n> The GitHub CLI (`gh`) is required but not installed. Please install it:\n> - macOS: `brew install gh`\n> - Other: https://cli.github.com/\n\n### 2. Check if authenticated with GitHub\n\n```bash\ngh auth status\n```\n\nIf not authenticated, guide the user to run `gh auth login`.\n\n### 3. Verify clean working directory\n\n```bash\ngit status\n```\n\nIf there are uncommitted changes, ask the user whether to:\n- Commit them as part of this PR\n- Stash them temporarily\n- Discard them (with caution)\n\n## Gather Context\n\n### 1. Identify the current branch\n\n```bash\ngit branch --show-current\n```\n\nEnsure you're not on `main` or `master`. If so, ask the user to create or switch to a feature branch.\n\n### 2. Find the base branch\n\nResolve the default branch once and reuse it as `BASE_BRANCH`. Do **not** assume Bash (`$(...)`, `sed`, `[ -z ... ]` fail in PowerShell).\n\n```bash\ngit symbolic-ref refs/remotes/origin/HEAD\n```\n\nThis prints `refs/remotes/origin/<branch>` (usually `main`). Use the last path segment.\n\n```powershell\n# PowerShell\n$BASE_BRANCH = (git symbolic-ref refs/remotes/origin/HEAD).Split('/')[-1]\n```\n\nIf that fails, run `git remote show origin` and parse the `HEAD branch:` line.\n\nThis is typically `main` or `master`, but may differ per repo.\n\n### 3. Analyze recent commits relevant to this PR\n\n```bash\n# Bash / zsh\ngit log \"origin/${BASE_BRANCH}..HEAD\" --oneline --no-decorate\n```\n\n```powershell\n# PowerShell\ngit log \"origin/$BASE_BRANCH..HEAD\" --oneline --no-decorate\n```\n\nReview these commits to understand:\n- What changes are being introduced\n- The scope of the PR (single feature/fix or multiple changes)\n- Whether commits should be squashed or reorganized\n\n### 4. Review the diff\n\n```bash\n# Bash / zsh\ngit diff \"origin/${BASE_BRANCH}..HEAD\" --stat\n```\n\n```powershell\n# PowerShell\ngit diff \"origin/$BASE_BRANCH..HEAD\" --stat\n```\n\nThis shows which files changed and helps identify the type of change.\n\n## Information Gathering\n\nBefore creating the PR, you need the following information. Check if it can be inferred from:\n- Commit messages\n- Branch name (e.g., `fix/upload-timeout`, `feat/custom-shortcuts`)\n- Changed files and their content\n\nIf any critical information is missing, ask the user directly:\n\n### Required Information\n\n1. **Related Issue Number** (optional): Look for patterns like `#123`, `fixes #123`, or `closes #123` in commit messages. If none is found, **omit the Related Issue section** from the PR body — do not use placeholders like `#XXXX`.\n2. **Description**: What problem does this solve? Why were these changes made?\n3. **Type of Change**: Bug fix, new feature, breaking change, refactor, cosmetic, documentation, or workflow\n4. **Test Procedure**: How was this tested? What could break?\n\nOnly ask about a related issue when the change clearly looks like it should close one (e.g. branch name `fix/issue-123`). For small or self-contained changes, skip the question and leave the section out.\n\n## Git Best Practices\n\nBefore creating the PR, consider these best practices:\n\n### Commit Hygiene\n\n1. **Atomic commits**: Each commit should represent a single logical change\n2. **Clear commit messages**: Follow conventional commit format when possible\n3. **No merge commits**: Prefer rebasing over merging to keep history clean\n\n### Branch Management\n\n1. **Rebase on latest base branch** (if needed):\n   ```bash\n   git fetch origin\n   git rebase \"origin/${BASE_BRANCH}\"\n   ```\n   In PowerShell, use `\"origin/$BASE_BRANCH\"`.\n\n2. **Squash if appropriate**: If history is messy, ask the user whether they want commits squashed. Do **not** run `git rebase -i` (interactive; agents cannot complete it).\n\n### Push Changes\n\nEnsure all commits are pushed:\n```bash\ngit push origin HEAD\n```\n\nIf the branch was rebased, you may need:\n```bash\ngit push origin HEAD --force-with-lease\n```\n\n## Create the Pull Request\n\nUse `CONTRIBUTING.md` (Pull Request 流程) as the source of truth for PR content. Follow [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) exactly:\n\n- **Summary** — what changed and why\n- **Type of Change** — check applicable boxes\n- **Test Procedure** — how you verified the change\n- **Pre-flight Checklist** — mark items that apply\n\nWhen filling out the PR body:\n- Fill in all template sections with relevant information gathered from commits and context\n- Mark the appropriate \"Type of Change\" checkbox(es)\n- Complete the \"Pre-flight Checklist\" items that apply\n- **Related Issue is not in the template.** Add a `## Related Issue` section with `Closes #123` only when this PR actually fixes an issue. Never add `#XXXX` or an empty Related Issue heading.\n\n### Create PR with gh CLI\n\n**Use a temporary file for the PR body** to avoid shell escaping issues, newline problems, and other command-line flakiness:\n\n1. Write the PR body to a temporary file (`$env:TEMP/pr-body.md` on Windows PowerShell, `/tmp/pr-body.md` on macOS/Linux).\n\n2. Create the PR using the file:\n\n   ```bash\n   # Bash / zsh\n   gh pr create --title \"PR_TITLE\" --body-file /tmp/pr-body.md --base \"$BASE_BRANCH\"\n   ```\n\n   ```powershell\n   # PowerShell\n   gh pr create --title \"PR_TITLE\" --body-file \"$env:TEMP/pr-body.md\" --base $BASE_BRANCH\n   ```\n\n3. Clean up the temporary file after the PR is created.\n\nFor draft PRs, add `--draft` to the same command.\n\n**Why use a file?** Passing complex markdown with newlines, special characters, and checkboxes directly via `--body` is error-prone. The `--body-file` flag handles all content reliably.\n\n## Post-Creation\n\nAfter creating the PR:\n\n1. **Display the PR URL** so the user can review it\n2. **Remind about CI checks**: Tests and linting will run automatically\n3. **Suggest next steps**:\n   - Add reviewers if needed: `gh pr edit --add-reviewer USERNAME`\n   - Add labels if needed: `gh pr edit --add-label \"bug\"`\n\n## Error Handling\n\n### Common Issues\n\n1. **No commits ahead of base branch**: The branch has no changes to submit\n   - Ask if the user meant to work on a different branch\n\n2. **Branch not pushed**: Remote doesn't have the branch\n   - Push the branch first: `git push -u origin HEAD`\n\n3. **PR already exists**: A PR for this branch already exists\n   - Show the existing PR: `gh pr view`\n   - Ask if they want to update it instead\n\n4. **Merge conflicts**: Branch conflicts with base\n   - Guide user through resolving conflicts or rebasing\n\n## Summary Checklist\n\nBefore finalizing, ensure:\n- [ ] `gh` CLI is installed and authenticated\n- [ ] Working directory is clean\n- [ ] All commits are pushed\n- [ ] Branch is up-to-date with base branch\n- [ ] Related Issue included only when a real issue is linked (no empty heading, no `#XXXX` placeholder)\n- [ ] PR description follows the template or project conventions\n- [ ] Appropriate type of change is selected\n- [ ] Pre-flight checklist items are addressed\n",".agents/skills/git-commit/SKILL.md":"---\nname: git-commit\ndescription: 'Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions \"/commit\". Supports: (1) Auto-detecting type and scope from changes, (2) Creating a feature branch when on main/master before committing, (3) Generating conventional commit messages from diff, (4) Interactive commit with optional type/scope/description overrides, (5) Intelligent file staging for logical grouping'\nlicense: MIT\n---\n\n# Git Commit with Conventional Commits\n\n## Overview\n\nCreate standardized, semantic git commits using the Conventional Commits specification. Analyze the actual diff to determine appropriate type, scope, and message.\n\n## Conventional Commit Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n## Commit Types\n\n| Type       | Purpose                        |\n| ---------- | ------------------------------ |\n| `feat`     | New feature                    |\n| `fix`      | Bug fix                        |\n| `docs`     | Documentation only             |\n| `style`    | Formatting/style (no logic)    |\n| `refactor` | Code refactor (no feature/fix) |\n| `perf`     | Performance improvement        |\n| `test`     | Add/update tests               |\n| `build`    | Build system/dependencies      |\n| `ci`       | CI/config changes              |\n| `chore`    | Maintenance/misc               |\n| `revert`   | Revert commit                  |\n\n## Breaking Changes\n\n```\n# Exclamation mark after type/scope\nfeat!: remove deprecated endpoint\n\n# BREAKING CHANGE footer\nfeat: allow config to extend other configs\n\nBREAKING CHANGE: `extends` key behavior changed\n```\n\n## Host shell\n\nDo **not** assume Bash. Cursor on Windows uses PowerShell, where `&&`, `$(cat <<'EOF')`, and POSIX `[ -z ... ]` fail.\n\n- Prefer **separate git invocations** over chained one-liners.\n- If you must chain: PowerShell uses `;` (or separate calls). Bash/zsh may use `&&`.\n- Examples below show Bash and PowerShell when the syntax differs.\n\n## Workflow\n\n### 1. Analyze Diff\n\n```bash\n# If files are staged, use staged diff\ngit diff --staged\n\n# If nothing staged, use working tree diff\ngit diff\n\n# Also check status\ngit status --porcelain\n```\n\nFrom the diff, determine the commit **type** and a short **description** (needed for branch naming in step 2).\n\n### 2. Ensure Feature Branch\n\nIf the current branch is `main` or `master`, create a feature branch **before** staging or committing.\n\n```bash\ngit branch --show-current\n```\n\n**Branch naming** — documented prefixes in `CONTRIBUTING.md`: `feat/`, `fix/`, `docs/`. For other commit types, use the commit type as prefix (e.g. `chore/`):\n\n```\n<type>/<kebab-case-description>\n```\n\n| Commit type | Branch prefix | Example |\n| ----------- | ------------- | ------- |\n| `feat`      | `feat/`       | `feat/custom-shortcuts` |\n| `fix`       | `fix/`        | `fix/upload-timeout` |\n| `docs`      | `docs/`       | `docs/contributing-guide` |\n| other types | `<type>/`     | `chore/add-create-pr-skill` (aligns with commit type; not listed in CONTRIBUTING.md) |\n\nRules for `<kebab-case-description>`:\n\n- Lowercase, words separated by hyphens\n- Derived from the commit description (drop scope, articles, punctuation)\n- Keep it short (2–5 words), e.g. `add create pr skill` → `add-create-pr-skill`\n\n```bash\n# Example: chore commit about adding create-pr skill\ngit checkout -b chore/add-create-pr-skill\n```\n\nDo **not** commit directly on `main` or `master`. If the user explicitly asks to commit on the default branch, confirm before proceeding.\n\n### 3. Stage Files (if needed)\n\nIf nothing is staged or you want to group changes differently:\n\n```bash\n# Stage specific files\ngit add path/to/file1 path/to/file2\n\n# Stage by pattern\ngit add *.test.*\ngit add src/components/*\n```\n\nDo **not** run `git add -p` (interactive; agents cannot complete it). Stage explicit paths instead.\n\n**Never commit secrets** (.env, credentials.json, private keys).\n\n### 4. Generate Commit Message\n\nAnalyze the diff to determine:\n\n- **Type**: What kind of change is this?\n- **Scope**: What area/module is affected?\n- **Description**: One-line summary of what changed (present tense, imperative mood, <72 chars)\n\n### 5. Execute Commit\n\nSingle line (any shell):\n\n```bash\ngit commit -m \"<type>[scope]: <description>\"\n```\n\nMulti-line with body/footer:\n\n```bash\n# Bash / zsh\ngit commit -m \"$(cat <<'EOF'\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\nEOF\n)\"\n```\n\n```powershell\n# PowerShell\ngit commit -m @\"\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\n\"@\n```\n\n## Best Practices\n\n- One logical change per commit\n- Present tense: \"add\" not \"added\"\n- Imperative mood: \"fix bug\" not \"fixes bug\"\n- Reference issues: `Closes #123`, `Refs #456`\n- Keep description under 72 characters\n\n## Git Safety Protocol\n\n- NEVER update git config\n- NEVER run destructive commands (--force, hard reset) without explicit request\n- NEVER skip hooks (--no-verify) unless user asks\n- NEVER force push to main/master\n- If commit fails due to hooks, fix and create NEW commit (don't amend)\n\n## Project Notes (doocs/md)\n\n- Commit messages and PR titles must be in **English** (see `AGENTS.md` and `CONTRIBUTING.md`)\n- Branch naming: `feat/`, `fix/`, `docs/` per `CONTRIBUTING.md`; for other commit types use `<type>/` prefix; never commit on `main`/`master` — create a branch first (step 2)\n- Pre-commit runs `eslint --fix` via lint-staged; if the hook modifies files, fix and create a new commit instead of amending\n",".agents/skills/wechat-svg/SKILL.md":"---\nname: wechat-svg\ndescription: >-\n  WeChat / 微信公众号 SVG constraints and bubbling-group interaction design.\n  Use when adapting SVG for WeChat paste, fixing missing arrows or oversized\n  diagrams, designing pure-SVG interactions without JS, or working with\n  id/class/defs/marker/foreignObject compatibility. Includes inline\n  SVG AttributeName whitelist.\n---\n\n# WeChat SVG Skill\n\n适用于微信公众号、小程序等强约束 SVG 环境。\n\n## 何时调用\n\n- 用户要把 SVG 粘贴到微信公众号，或排查粘贴后样式/交互失效\n- 需要纯 SVG、无 JS、无块级 CSS 的交互动画\n- 约束包含：无 `id` / `class` / `defs` / `href` 依赖\n- 需要深层 `<g>` 嵌套、透明触发器、事件冒泡组织动画\n- 需要接入 `<image>`、文本卡、外部素材，或排查 transform 串层、箭头消失、尺寸异常\n\n## SVG AttributeName 白名单\n\n微信生态对 SVG 动画的 **AttributeName** 有白名单。超出白名单的标签、指令或属性名，可能在保存后被平台过滤。\n\n| 元素 | Name | 说明 |\n| --- | --- | --- |\n| `animate` | `x` | 控制简单几何体 x 轴方向移动 |\n| `animate` | `y` | 控制简单几何体 y 轴方向移动 |\n| `animate` | `width` | 控制简单几何体宽度变化 |\n| `animate` | `height` | 控制简单几何体高度变化 |\n| `animate` | `opacity` | 控制透明度变化，数值通常为 0 到 1 |\n| `animate` | `d` | 控制贝塞尔曲线补间，表现可能有随机性 |\n| `animate` | `points` | 控制多边形补间，表现可能有随机性 |\n| `animate` | `stroke-width` | 控制描边宽度 |\n| `animate` | `stroke-linecap` | 控制描边端点样式 |\n| `animate` | `stroke-dashoffset` | 控制描边偏移，常用于线性遮罩/进度线 |\n| `animate` | `fill` | 控制填充色过渡变化 |\n| `set` | `visibility` | 控制可见性：`visible` / `hidden` / `collapse` / `inherit` |\n| `animateTransform` | `translate` | 控制路径和编组位移 |\n| `animateTransform` | `scale` | 控制路径和编组缩放，可用于翻转 |\n| `animateTransform` | `rotate` | 控制路径和编组旋转 |\n| `animateTransform` | `skewX` | 控制 x 轴倾斜 |\n| `animateTransform` | `skewY` | 控制 y 轴倾斜 |\n| `animateMotion` | `path` | 复杂轨迹动画，可配合 `rotate` 定义朝向 |\n\n### 禁用边界\n\n在设计或适配 SVG 时，默认遵守：\n\n- 不使用 `id`\n- 不使用 `class`\n- 不使用 `href` / `xlink:href` 作为样式与结构依赖（含 `url(#id)` 引用）\n- 不使用 `defs`\n- 不使用 `embed`\n- 不使用块级 CSS 与 JS 动画\n- 样式尽量以内联属性或 `style=\"\"` 的最小必要形式书写\n\n### 静态图表适配要点（非交互动画）\n\n第三方 SVG（如 Mermaid）粘贴到微信时，常见问题与修法：\n\n| 现象 | 原因 | 修法 |\n| --- | --- | --- |\n| 箭头消失 | `<defs>` + `<marker>` + `url(#id)` 被过滤 | 将 marker 展开为内联 `<path>` / `<polygon>`，移除 `marker-end` |\n| 图表过大 | `width=\"100%\"` 或 CSS `max-width` 被忽略，按 viewBox 1:1 渲染 | 设置显式像素 `width` / `height`（不超过正文栏可用宽度），保留 `viewBox` |\n| 文字错位 | `foreignObject` 兼容性差 | 转为 `<text>` / `<tspan>` 或外层 HTML `<section>` |\n\n## 核心使用原则\n\n1. 先判断这是不是「真正的无 ID 冒泡编组问题」\n2. 先搭结构，再写动画\n3. 区分世界层 / 遭遇层 / 触发层\n4. 最深层透明触发器放在整条父子链最底部\n5. 每个遭遇物做成闭环模块：施加层 → 姿态层 → 抵消层\n6. 先统一交互模式，再统一全链实现\n\n详细原则见 [core-principles.md](./references/core-principles.md)。\n\n## 已验证的交互写法\n\n```xml\n<animateTransform\n  begin=\"click\"\n  dur=\"30s\"\n  fill=\"freeze\"\n  restart=\"never\"\n  ... />\n```\n\n固定要求：\n\n- 所有交互动画统一 `begin=\"click\"`\n- 所有交互动画统一 `fill=\"freeze\"`\n- 所有交互动画统一 `restart=\"never\"`\n- 删除所有旧的 `touchend;mouseup` 回位链\n- 不允许一部分层保留旧长按逻辑，一部分层改成 click-only\n\n## 嵌套与变换\n\n### 嵌套规则\n\n- 必须形成连续不间断的绝对父子链，不是「很多 `<g>` 平铺」\n- 任何平级断链都会让冒泡和补偿逻辑失效\n\n### 变换规则\n\n- 标准写法：**施加 → 抵消 → 再施加**\n- 父层改变参考系，子层拿回局部控制权，更深层通过补偿层回到干净坐标基准\n\n## `<image>` 接入\n\n- `<image>` 不能直接丢到 SVG 根部\n- 必须挂在对应对象的局部姿态层或遭遇层内部\n- 位移、旋转、出场时机由外层 `<g>` 的 `animateTransform` 控制\n- 位置用 `x` / `y`，尺寸用 `width` / `height`，不依赖外部 CSS\n\n```xml\n<g>\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g>\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n  </g>\n</g>\n```\n\n详细规则与排错见 [image-integration.md](./references/image-integration.md)。\n\n## 排错顺序\n\n按顺序排查，不要跳步：\n\n1. 是否还是绝对父子链\n2. 触发器是否在最深层\n3. 补偿层是否成对存在\n4. 坐标是否跑出视口\n5. `opacity` / `visibility` 是否误伤深层\n6. `keyTimes` 与出现窗口\n7. （静态 SVG）是否仍依赖 `defs` / `id` / 百分比宽度\n\n## 常见错误与固定修法\n\n| 错误 | 现象 | 修法 |\n| --- | --- | --- |\n| 平级 `<g>` 当深层结构 | 事件链断 | 回到单一路径父子链 |\n| 只施加，不抵消 | 后续对象继承前一层轨迹 | 每个遭遇物补上抵消层 |\n| 局部闪烁挂在公共父层 | 深层对象一起透明 | 把 `opacity` 动画缩到最小局部组 |\n| 文案/字幕放错逻辑层 | 视觉居中但脱离编组 | 绑对象局部层，或放最深层补偿后的视口坐标层 |\n| 交互模式半新半旧 | 部分层仍用旧长按逻辑 | 全链统一 `begin` / `fill` / `restart` |\n| marker 箭头依赖 defs | 粘贴后箭头消失 | 内联展开箭头，移除 `marker-end` |\n| SVG 使用 width 100% | 粘贴后撑满编辑器 | 写死像素宽高并保留 viewBox |\n\n## 新模块实施顺序\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n\n## 延伸阅读\n\n- [core-principles.md](./references/core-principles.md) — 洋葱式嵌套、模块化、局部效果收口\n- [image-integration.md](./references/image-integration.md) — `<image>` 接入与典型陷阱\n",".agents/skills/wechat-svg/references/core-principles.md":"# Core Principles\n\n## 1. 绝对父子链原则\n\n真正有效的无 ID 冒泡交互，不是「看起来层很多」，而是：\n\n- 最外层到最深层之间是一条连续不间断的父子链\n- 透明触发器必须在整条链的最底部\n- 任何平级断链都会让方法论失效\n\n**错误示意：**\n\n- 很多 `<g>` 平行摆放\n- 触发器只是在视觉上「放在下面」\n- 某一层动画和触发器不是父子关系而是兄弟关系\n\n**正确目标：**\n\n- 每一层动画都在触发器的祖先链上\n\n## 2. 世界层 / 遭遇层 / 触发层三分法\n\n### 世界层\n\n- 承担大场景运动\n- 例如背景上升、地面后退、天空密度变化\n\n### 遭遇层\n\n- 承担单个事件对象\n- 例如气球、直升机、飞机、火箭、第二个 UFO\n\n### 触发层\n\n- 只负责接收事件和向上冒泡\n- 不负责视觉叙事\n\n## 3. 施加 → 抵消 → 再施加\n\n复杂变换串层时，固定采用三段式：\n\n1. 先施加外层参考系变化\n2. 在下一层抵消这段变化\n3. 再在更深层只对当前对象施加自己的局部运动\n\n好处：\n\n- 父层控制大结构\n- 子层拿回局部控制权\n- 更深层总能回到干净坐标系\n\n## 4. 遭遇物必须模块化闭环\n\n每个遭遇物最小结构：\n\n```xml\n<g> <!-- 位移施加层 -->\n  <animateTransform ... />\n  <g> <!-- 姿态层 -->\n    <animateTransform ... />\n    <!-- 对象本体、文本卡、image -->\n  </g>\n  <g> <!-- 位移抵消层 -->\n    <animateTransform ... />\n    <!-- 下一个更深层模块 -->\n  </g>\n</g>\n```\n\n这样后续对象不会继承前一个对象的轨迹、旋转、透明度或姿态残留。\n\n## 5. 交互模式必须全链统一\n\n推荐正式规范：\n\n```xml\nbegin=\"click\"\nfill=\"freeze\"\nrestart=\"never\"\n```\n\n固定要求：\n\n- 不允许主链是 `click`，补偿层还是 `touchstart/touchend`\n- 不允许提示文案、遮挡层、字幕层停留在旧交互语义\n- 交互模式一旦切换，必须全文件统一\n\n## 6. 局部效果必须就地收口\n\n以下效果只能包裹在最小局部范围里：\n\n- 红灯闪烁\n- 尾焰\n- 呼吸发光\n- 小幅摇摆\n- 局部透明度变化\n\n否则它们会误伤更深层链路。\n\n## 7. 全局收尾层也必须在链内\n\n常见误区：视觉上想让字幕固定在屏幕中央，就把它直接挂到 SVG 根部最外层。\n\n正确做法：\n\n- 把收尾字幕接在最深层内部补偿组之后\n- 让它位于「已经抵消完成的视口坐标层」中\n- 这样既能稳定居中，又不脱离方法论\n\n## 8. 固定实施顺序\n\n后续新模块一律按这个顺序实现：\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n",".agents/skills/wechat-svg/references/image-integration.md":"# Image Integration And Pitfalls\n\n## 1. `<image>` 的正确接入方式\n\n核心原则：\n\n- `<image>` 只是视觉内容，不应该自己决定时间轴\n- 时间轴、旋转、进场和冻结全部由外层 `<g>` 接管\n- `<image>` 必须属于某个对象模块，而不是脱链挂在 SVG 根部\n\n标准结构：\n\n```xml\n<g> <!-- 遭遇物位移施加层 -->\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g> <!-- 遭遇物姿态层 -->\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n    <image x=\"0\" y=\"-1900\" width=\"609\" height=\"343\" href=\"...\" />\n  </g>\n</g>\n```\n\n## 2. `<image>` 的固定约束\n\n- 不要依赖外部 CSS 调位置\n- 不要把尺寸交给响应式布局\n- 不要让 `<image>` 自己承担运动逻辑\n- 不要把 `<image>` 放到与本体平级但不在同一局部姿态组的位置\n\n推荐做法：\n\n- 位置用 `x` / `y`\n- 尺寸用 `width` / `height`\n- 序列排布用不同的 `y`\n- 组级运动用外层 `transform`\n\n## 3. 文本卡与 `<image>` 的关系\n\n如果对象既有文本卡，也有 `<image>`：\n\n- 文本卡和 `<image>` 都应该属于同一对象的局部层级\n- 但它们不一定要放在同一最小组里\n- 判断标准不是「看起来近不近」，而是「是否应该共享同一轨迹和同一姿态」\n\n## 4. 典型错误与修法\n\n### 错误 1：`<image>` 放在 SVG 根部\n\n- 结果：图片能显示，但完全脱离编组时间轴\n- 修法：挂回对应遭遇物的姿态层或其内部子组\n\n### 错误 2：`<image>` 跟在错误的补偿层下面\n\n- 结果：图片方向对，但位置始终不对，或者跟着下一个对象一起移动\n- 修法：确认它位于「当前对象的姿态层内部」，而不是「下一个对象的补偿层之后」\n\n### 错误 3：只调 `x/y`，不看外层 `transform`\n\n- 结果：怎么挪都不对，因为真正决定运动的是外层位移和旋转\n- 修法：先定外层轨迹，再微调 `x/y`\n\n### 错误 4：收尾字幕放在最外层\n\n- 结果：视觉上居中，但逻辑上不属于最深层编组体系\n- 修法：把字幕接入最深层补偿后的内部视口坐标层\n\n### 错误 5：交互模式切换不彻底\n\n- 结果：`<image>` 所在段落已经 click-only，但同一链上的遮挡层、字幕层或对象层仍保留旧回位逻辑\n- 修法：统一整条链的 `begin` / `fill` / `restart`\n\n## 5. 固定结论\n\n### 结论 1\n\n- `<image>` 是「局部视觉载荷」，不是「独立时间轴节点」\n\n### 结论 2\n\n- 居中文案虽然视觉上像 HUD，但如果它属于故事收尾的一部分，仍然应该放进最深层链内\n\n### 结论 3\n\n- 如果视觉感觉不对，优先排查时序、补偿层、父子链\n- 不要第一反应只去改 `x/y/width/height`\n\n## 6. 推荐排错顺序\n\n1. 先看 `<image>` 在不在正确对象模块里\n2. 再看它是不是放在姿态层里\n3. 再看外层位移与旋转\n4. 再看它的 `x/y/width/height`\n5. 最后再看是否被透明度或遮挡层影响\n",".cursor/mcp.json":"{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n",".github/copilot-instructions.md":"# Copilot Instructions\n\nThis repository is a pnpm monorepo for **doocs/md**, a WeChat Markdown editor. Canonical agent guidance lives in [AGENTS.md](../AGENTS.md); keep this file aligned with it.\n\n- **Node:** `>=22.22.2` (`.nvmrc`: v22.22.2)\n- **Package manager:** pnpm (`packageManager` in the root `package.json`)\n- **npm registry:** https://registry.npmmirror.com (`.npmrc`)\n\n## Build, Test, and Lint\n\n### Global Commands\n\n- **Install:** `pnpm install`\n- **Lint (ESLint + Prettier):** `pnpm run lint`\n- **Type Check:** `pnpm run type-check`\n- **Tests:** `pnpm run test` (`@md/shared`, `@md/core`, `@md/web`, `@md/api`)\n\n### Web App (`@md/web`)\n\n- **Development Server:** `pnpm web dev`\n- **Production Build:** `pnpm web build`\n- **Browser Extension:** `pnpm web ext:zip` (WXT; Chrome) / `pnpm web firefox:zip`\n\n### Other Workspaces\n\n- **API (`@md/api`):** `pnpm api dev` / `pnpm api test`\n- **VS Code (`doocs-md`):** `pnpm vscode compile` / `pnpm vscode package`\n- **CLI (`@doocs/md-cli`):** `pnpm run build:cli`\n- **MCP (`@md/mcp-server`):** `pnpm mcp dev`\n- **uTools (`@md/utools`):** `pnpm utools:package`\n\n## High-Level Architecture\n\n### Monorepo Structure\n\n- **`apps/web`**: Vue 3 + Vite + Pinia + Tailwind CSS 4. Web app and browser extension (WXT).\n- **`apps/api`**: Cloudflare Workers + Hono + D1 (auth, cloud sync, billing, upload, share, marketplace, emoji).\n- **`apps/vscode`**: VS Code extension (webpack). Marketplace ID: `doocs.doocs-md`.\n- **`apps/utools`**: uTools plugin packaging shell (artifacts from `@md/web`).\n- **`packages/core`**: Markdown renderer (`marked` + custom extensions, theme CSS variables).\n- **`packages/shared`**: Shared config, types, CodeMirror wrapper, theme CSS.\n- **`packages/config`**: Shared TypeScript config.\n- **`packages/md-cli`**: Published npm CLI that serves the built web app.\n- **`packages/mcp-server`**: MCP tools (`render_markdown`, `list_themes`, `list_colors`).\n- **`docs/examples/wechat-openapi-worker/`**: standalone WeChat OpenAPI proxy (not in the pnpm workspace).\n\nDetails: [docs/architecture.md](../docs/architecture.md).\n\n### Key Technologies\n\n- **Frontend:** Vue 3 (Composition API), Pinia, Tailwind CSS 4 + PostCSS\n- **Editor:** CodeMirror 6\n- **Markdown:** `marked` in `@md/core`; `juice` inlines CSS for WeChat paste; `isomorphic-dompurify` sanitizes output\n- **Web build:** Vite 8; extension build: WXT\n- **API:** Hono on Cloudflare Workers, D1\n- **i18n (web only):** `vue-i18n` — zh-CN, zh-TW, en-US, ja-JP\n\n## Key Conventions\n\n### Development Patterns\n\n- **`@md/core` and `@md/shared` export TypeScript source** (`src/index.ts`). Do not pre-build them; consumers (Vite/webpack) compile them.\n- **UI:** Shadcn-Vue components in `apps/web/src/components/ui`. Prefer these over raw HTML/CSS.\n- **Stores:** Domain Pinia stores in `apps/web/src/stores` (`useEditorStore`, `useThemeStore`, `useUiStore`, `useLocaleStore`, …).\n- **Comments:** English only. Explain non-obvious why / constraints; do not narrate the next line. Do not rewrite user-facing i18n copy unless asked.\n\n### Internationalization (`@md/web`)\n\n- Messages: `apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`\n- Components: `useI18n()` + `t('key')`. Stores/utils: `@/i18n/translate`.\n- New user-visible strings must be added in all four locales. VS Code, uTools, CLI, and MCP are not localized.\n\n### Styling & Theming\n\n- Theme injection: `@md/core/src/theme` (CSS variables).\n- Theme CSS sources: `packages/shared/src/configs/theme-css/` (`default.css`, `grace.css`, `simple.css`).\n\n### Markdown Extensions\n\n- Implement new Markdown features as extensions in `packages/core/src/extensions`.\n- Register them in the renderer configuration.\n\n### Dependencies\n\n- Shared toolchain versions live in `pnpm-workspace.yaml` `catalog`; workspace packages use `\"catalog:\"`.\n- Root `package.json` is publishable (`private: false`) — use plain semver there, not `catalog:`.\n- Prettier is pinned to **2.8.8**. Do not remove security `overrides` unless upstream fixed the CVE.\n- If a patched dependency is upgraded, update the matching file in `patches/` and `patchedDependencies`.\n\n### Git Conventions\n\n- **Commit messages and PR titles:** Conventional Commits, **English** (`feat`, `fix`, `docs`, `chore`, …).\n- **Branches:** `feat/description`, `fix/description`, `docs/description`; other types use `<type>/`.\n- Never commit on `main`. Follow `.github/pull_request_template.md` when opening a PR.\n\n### Agent Skills\n\nCanonical workflows: `.agents/skills/` (`git-commit`, `create-pr`, `wechat-svg`). Claude Code discovers them via git symlinks under `.claude/skills/`.\n","AGENTS.md":"# Agent Instructions\n\n本文件为 AI Agent（Claude Code、OpenCode、Cursor、Copilot 等）在本仓库中工作时提供统一入口。\n\n## 项目概览\n\n**doocs/md** — 一款微信 Markdown 编辑器，将 Markdown 渲染为微信公众号文章格式。支持自定义主题样式、多图床、AI 助手、浏览器扩展、**zh-CN / zh-TW / en-US / ja-JP 界面**等特性。\n\n- **在线地址:** https://md.doocs.org\n- **Node 版本:** >= 22.22.2（`.nvmrc`: v22.22.2）\n- **包管理器:** pnpm（monorepo）\n- **npm 镜像:** https://registry.npmmirror.com（`.npmrc`）\n\n## Monorepo 结构\n\n| 工作区           | 路径                  | 说明                                                                                                  |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | 主应用，Vue 3 + 浏览器扩展（WXT: Chrome/Firefox）                                                     |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID: `doocs.doocs-md`）                                        |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包                                                                                       |\n| `@md/core`       | `packages/core`       | 核心 Markdown 渲染引擎（marked + 自定义扩展）                                                         |\n| `@md/shared`     | `packages/shared`     | 共享工具函数、配置、类型、编辑器配置                                                                  |\n| `@md/config`     | `packages/config`     | TypeScript 配置基础文件                                                                               |\n| `@doocs/md-cli`  | `packages/md-cli`     | CLI 工具（Express 服务托管构建产物）                                                                  |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务，为 AI Agent 暴露接口                                                                        |\n| `@md/api`        | `apps/api`            | 后端 API：账户、云同步、计费、上传代理、分享、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n\n独立示例（不在 workspace 内）：`docs/examples/wechat-openapi-worker/` — 微信公众号 OpenAPI 代理 Worker。\n\n## 常用命令\n\n### 根目录\n\n```bash\npnpm install          # 安装所有依赖\npnpm start            # 等同于 `pnpm web dev`\npnpm run lint         # ESLint --fix 全项目检查\npnpm run type-check   # vue-tsc 类型检查\npnpm run build:cli    # 构建 web + 复制到 md-cli + npm pack\npnpm run release:cli  # 通过 scripts/release.js 发布 CLI\npnpm utools:package   # 打包 uTools 插件\npnpm run inspector    # node-modules-inspector 查看依赖树\n```\n\n### Web 应用 (`@md/web`)\n\n```bash\npnpm web dev          # 启动 Vite 开发服务器\npnpm web build        # 生产构建 + 类型检查\npnpm web build:h5-netlify   # 构建用于 Netlify 根目录部署\npnpm web build:analyze      # 构建并生成 rollup-plugin-visualizer 分析\npnpm web ext:dev      # WXT Chrome 扩展开发模式\npnpm web ext:zip      # 打包 Chrome 扩展\npnpm web firefox:dev  # WXT Firefox 扩展开发模式\npnpm web firefox:zip  # 打包 Firefox 扩展\npnpm web wrangler:dev    # Cloudflare Workers 开发\npnpm web wrangler:deploy   # Cloudflare Workers 部署\n```\n\n### VSCode 扩展\n\n```bash\npnpm vscode compile   # webpack 编译\npnpm vscode watch     # webpack 监听\npnpm vscode build     # 生产 webpack 构建\npnpm vscode package   # vsce 打包\n```\n\n### CLI & MCP\n\n```bash\npnpm cli <cmd>        # 在 @doocs/md-cli 中执行命令\npnpm mcp <cmd>        # 在 @md/mcp-server 中执行命令（render_markdown 等 MCP 工具）\npnpm mcp dev          # MCP Server 监听模式\n```\n\n`@md/mcp-server` 通过 stdio 暴露 `render_markdown`、`list_themes`、`list_colors` 等工具，配置见 [packages/mcp-server/README.md](./packages/mcp-server/README.md)、[`.vscode/mcp.json`](./.vscode/mcp.json) 与 [`.cursor/mcp.json`](./.cursor/mcp.json)。\n\n## 架构\n\n### 渲染管线\n\n1. `@md/core` 封装 `marked`，实现自定义扩展（Mermaid、PlantUML、Ruby、KaTeX、TOC、alert 块、infographic、slider、markup、emoji、脚注）\n2. `juice` 内联 CSS 以兼容微信\n3. `isomorphic-dompurify` 净化输出\n4. 主题系统（`@md/core/src/theme/`）注入 CSS 变量\n\n### 构建系统\n\n- **`@md/core` 和 `@md/shared` 直接导出 TypeScript 源码**（不预构建）。由消费方的构建工具（Vite/webpack）编译。\n- Web 应用使用 Vite 8，VSCode 扩展使用 webpack，浏览器扩展使用 WXT\n\n### 样式与主题\n\n- Web 应用使用 Tailwind CSS 4 + PostCSS\n- 主题 CSS 文件位于 `packages/shared/src/configs/theme-css/`（default.css、grace.css、simple.css）\n- 部分主题文件使用 Less\n\n### 状态管理\n\n- Pinia store 位于 `apps/web/src/stores/`（按领域划分：`useEditorStore`、`useThemeStore`、`useUiStore`、`useLocaleStore` 等）\n- UI 组件遵循 Shadcn-Vue 模式，位于 `apps/web/src/components/ui`\n- 跨 feature 通用组件位于 `apps/web/src/components/shared`\n- 架构详情见 [docs/architecture.md](./docs/architecture.md)\n\n### 国际化（i18n，`@md/web`）\n\nWeb 主应用与部分浏览器扩展 UI 支持 **zh-CN**、**zh-TW**、**en-US**、**ja-JP**；VS Code 扩展、uTools、CLI、MCP **未**国际化。\n\n- **库**：`vue-i18n`（composition API，`legacy: false`），在 `apps/web/vite.config.ts` 中通过 `unplugin-auto-import` 自动导入 `useI18n`\n- **文案**：`apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`（`common`、`editor`、`dialog`、`store`、`ai`、`upload`、`chrome`、`marketplace`、`notifications`）\n- **组件内**：`useI18n()` + `t('key')`；**Store / 工具函数**：`@/i18n/translate` 的 `t()` / `getLocale()` / `formatLocalDateTime()`\n- **语言状态**：`useLocaleStore`（持久化 key：`locale`）；用户可在 **偏好设置**（`Ctrl+,`）→ General 切换\n- **启动**：`await initStorage()` → `setupI18n(detectInitialLocale())` → Pinia → `useLocaleStore()`（见 `apps/web/src/bootstrap.ts`）；`index.html` 启动屏从 `localStorage` 读取 locale\n- **云同步**：`locale` 在 `SYNC_SETTING_KEYS` 中，远端应用后由 `hydrateSyncedSettings` 热更新\n- **约定**：新增用户可见文案须同时维护 zh-CN、zh-TW、en-US 与 ja-JP；在 computed 中调用 `t()` 且需随语言切换更新时，应依赖 `locale`（例如 `void locale.value`）\n\n## Lint 与格式化\n\n- **ESLint:** `@antfu/eslint-config` + Vue + TypeScript + formatter\n- **Prettier:** 固定版本 `2.8.8`（通过 `pnpm-workspace.yaml` 的 `overrides` 强制）\n- **Pre-commit 钩子:** `lint-staged` 对所有文件执行 `eslint --fix`\n- 规则：不使用分号，关闭 `no-unused-vars`、`no-console`、`no-debugger`\n- **代码注释：** 统一英文。保留非显而易见的 why / 约束 / 兼容性说明；删除复述下一行代码的噪音注释。勿改动 `i18n/messages` 等用户可见文案。\n\n## 依赖管理\n\n这是一个 pnpm monorepo，`pnpm-workspace.yaml` 中包含大量安全覆盖（overrides）。\n\n### 升级依赖\n\n1. **共享版本用 catalog** — 跨包共用的工具链版本集中在 `pnpm-workspace.yaml` 的 `catalog`（`typescript`、`vitest`、`wrangler`、`@types/node`、`marked`、`@codemirror/state|view` 等）；workspace 内各 `package.json` 用 `\"catalog:\"` 引用。**仓库根 `package.json` 因 `private: false` 可被 npm 消费，须写普通 semver，勿用 `catalog:`。**包专属依赖可继续写版本号（`pnpm/json-enforce-catalog` 已关闭）\n2. **Prettier 必须固定在 `2.8.8`** — 通过 catalog + `overrides.prettier` 强制（根 package 直接写 `2.8.8`）\n3. **Patch 文件：** 如果打了 patch 的依赖升级了，必须同步更新 `patches/` 中对应的 patch 文件：\n   - `@codemirror/view` → `patches/@codemirror__view@6.43.15.patch`（导出 `MeasureRequest` 接口，修复 macOS 上 Alt+Shift 快捷键处理）\n   - `mermaid` → `patches/mermaid@12.2.0.patch`（流程图 HTML 标签在非整数 DPR 下按宽度换行，避免文字被裁切）\n   - `juice` 12.2.0 已在上游处理 `parseCSS` 空返回值，不再需要本地 patch\n4. 更新 `pnpm-workspace.yaml` 中的 `patchedDependencies` 以匹配新版本\n5. 运行 `pnpm install` 重新生成 `pnpm-lock.yaml`；可用 `pnpm dedupe` 收敛可合并的间接依赖\n\n### 安全覆盖\n\n`pnpm-workspace.yaml` 的 `overrides` 部分强制了存在漏洞的间接依赖的最低版本（ajv、dompurify、undici、minimatch 等）。除非上游已修复漏洞，否则不要移除这些覆盖。\n\n### allowBuilds\n\n`pnpm-workspace.yaml` 包含 `allowBuilds` 列表，用于需要原生构建脚本的依赖（`esbuild`、`sharp`、`keytar`、`workerd` 等）。新增需要原生构建的依赖可能需要添加到此列表。\n\n## Git 规范\n\n- **提交信息 / PR 标题:** 遵循 Conventional Commits（`feat`、`fix`、`docs`、`style`、`refactor`、`perf`、`test`、`build`、`chore`），**一律使用英文**（见 `CONTRIBUTING.md`）\n- **分支命名:** `feat/description`、`fix/description`、`docs/description`；其他类型用 `<type>/`\n- **PR 说明:** 按 [`.github/pull_request_template.md`](./.github/pull_request_template.md) 填写；无关联 Issue 时不要写 Related Issue 占位符\n\n## Skills\n\nReusable workflows live in [`.agents/skills/`](./.agents/skills/) (canonical). Claude Code discovers each skill through a git symlink:\n\n```text\n.claude/skills/<name> → ../../.agents/skills/<name>\n```\n\n| Skill        | When to use                                                                           |\n| ------------ | ------------------------------------------------------------------------------------- |\n| `git-commit` | Commit changes with Conventional Commits (`/git-commit` or \"commit my changes\")       |\n| `create-pr`  | Create a GitHub pull request (`/create-pr` or \"open a PR\")                            |\n| `wechat-svg` | WeChat SVG whitelist, bubbling-group interaction, paste compatibility (`/wechat-svg`) |\n\nInvoke manually: `/skill-name` in Cursor or Claude Code; OpenCode uses the `skill` tool.\n","CLAUDE.md":"@AGENTS.md\n","apps/utools/README.md":"# uTools 插件打包指引\n\n该目录包含将微信 Markdown 编辑器打包为 [uTools](https://u.tools) 插件所需的脚本与配置。\n\n## 快速开始\n\n```sh\npnpm utools:package\n```\n\n该命令将完成以下动作：\n\n1. 调用 `pnpm --filter @md/web run build:utools` 构建前端资源至 `apps/utools/dist`，该构建将自动使用相对路径，确保在 uTools 的 `file://` 协议下能够正常加载。MathJax 从 `node_modules` 复制到构建产物中，Mermaid 作为 npm 模块打包。\n2. 将仓库根目录的版本号写入 `apps/utools/plugin.json`，保持与主项目同步。\n3. 从 `apps/web/public/mpmd/icon-256.png` 拷贝插件图标至 `apps/utools/logo.png`。\n4. 生成形如 `apps/utools/release/md-utools-vX.Y.Z.zip` 的安装包，可直接导入到 uTools。\n\n> 注意：命令执行前请确认已安装 pnpm 10+ 与 Node.js 22+，并在仓库根目录执行 `pnpm install` 安装依赖。\n\n## 手动导入调试\n\n1. 运行 `pnpm --filter @md/web run build:utools`。\n2. 打开 uTools，进入插件面板中的「开发者工具」。\n3. 选择「载入本地插件」，指向 `apps/utools` 目录即可。\n\n## 目录说明\n\n- `plugin.json`：uTools 插件的清单文件。\n- `preload.js`：在 uTools 渲染进程和 Web 前端之间建立通信的脚本，用于处理插件唤起事件。\n- `package.json`：将此目录标记为 CommonJS 模块以兼容 uTools。\n- `dist/`：由 Vite 构建输出的静态资源目录。\n- `release/`：运行打包命令后生成的插件安装包。\n","apps/utools/plugin.json":"{\n  \"pluginName\": \"微信 Markdown 编辑器\",\n  \"description\": \"Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用\",\n  \"version\": \"2.1.0\",\n  \"author\": \"doocs\",\n  \"homepage\": \"https://github.com/doocs/md\",\n  \"pluginType\": \"tool\",\n  \"platform\": [\n    \"win32\",\n    \"darwin\",\n    \"linux\"\n  ],\n  \"logo\": \"logo.png\",\n  \"main\": \"dist/index.html\",\n  \"preload\": \"preload.js\",\n  \"features\": [\n    {\n      \"code\": \"wechat-md\",\n      \"explain\": \"打开微信 Markdown 编辑器\",\n      \"cmds\": [\n        \"微信排版\",\n        \"Markdown 编辑器\",\n        \"doocs md\"\n      ]\n    }\n  ]\n}\n","docs/architecture.md":"# 架构概览\n\n本文档简述 doocs/md 的核心模块与数据流，供贡献者快速定位代码。\n\n## Monorepo 结构\n\n| 包               | 路径                  | 职责                                                                                            |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | Vue 3 主应用、WXT 浏览器扩展（Chrome/Firefox）、CF Workers 部署                                 |\n| `@md/api`        | `apps/api`            | 账户、云同步、计费、上传代理、分享链接、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID 为 `doocs.doocs-md`）                                |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包壳（构建产物来自 `@md/web`）                                                     |\n| `@md/core`       | `packages/core`       | Markdown → HTML 渲染引擎                                                                        |\n| `@md/shared`     | `packages/shared`     | 配置、类型、CodeMirror 编辑器封装、主题 CSS                                                     |\n| `@md/config`     | `packages/config`     | 共享 TypeScript 配置                                                                            |\n| `@doocs/md-cli`  | `packages/md-cli`     | 已发布 npm CLI（Express 静态服务）                                                              |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务（`render_markdown` 等工具）                                                            |\n\n独立示例（不在 pnpm workspace 内）：\n\n| 示例              | 路径                                   | 说明                    |\n| ----------------- | -------------------------------------- | ----------------------- |\n| 微信 OpenAPI 代理 | `docs/examples/wechat-openapi-worker/` | 最小 CF Worker 转发示例 |\n\n### 依赖关系\n\n```\napps/web, apps/vscode, packages/mcp-server\n  └── @md/core\n        └── @md/shared\n              └── @md/config (dev)\n```\n\n`@md/core` 与 `@md/shared` **直接导出 TypeScript 源码**，由消费方构建工具（Vite / webpack）编译。\n\n## 渲染管线\n\n```\nMarkdown 原文\n  → @md/core (marked + 自定义扩展)\n  → isomorphic-dompurify 净化\n  → 注入主题 CSS 变量 (@md/core/theme)\n  → HTML 输出（预览）\n  → juice 内联 CSS（仅复制到微信时，在 `@md/web` 导出层）\n  → 剪贴板 HTML（公众号）\n```\n\nWeb 端入口：\n\n1. `useRenderStore`（`apps/web/src/stores/render.ts`）调用 `initRenderer` / `renderMarkdown`\n2. `useThemeStore` 通过 `applyTheme` 将主题 CSS 写入 `<style>` 标签\n3. 编辑器内容变更经 debounce 后触发 `render()`\n\n扩展列表见 `packages/core/src/extensions/`（Mermaid、PlantUML、KaTeX、Ruby、alert、脚注等）。\n\n## Web 应用目录约定（`apps/web/src`）\n\n| 目录                 | 职责                                                                    |\n| -------------------- | ----------------------------------------------------------------------- |\n| `i18n/`              | vue-i18n 配置、locale 检测、按领域拆分的 message 模块                   |\n| `stores/`            | Pinia 全局状态，按领域划分                                              |\n| `composables/`       | 跨组件复用的响应式逻辑                                                  |\n| `services/`          | 外部 API 与领域服务（account / sync / share / upload / export）         |\n| `storage/`           | IndexedDB 抽象层、键前缀与安全读写                                      |\n| `lib/`               | 纯函数与浏览器辅助（bootstrap / browser / format / markdown / preview） |\n| `components/ui/`     | Shadcn-Vue 设计系统（无业务逻辑）                                       |\n| `components/editor/` | 编辑器主界面                                                            |\n| `components/ai/`     | AI 相关 UI                                                              |\n| `components/shared/` | 跨 feature 通用组件                                                     |\n| `entrypoints/`       | WXT 浏览器扩展入口                                                      |\n\n## 状态管理（Web）\n\nPinia stores 按领域划分：\n\n- `useEditorStore` — 编辑器实例与文档内容\n- `useThemeStore` — 主题与样式（含 per-theme 配置持久化）\n- `useRenderStore` — 渲染结果与目录标题\n- `useUIStore` — 布局、对话框、视图模式\n- `useLocaleStore` — 界面语言（zh-CN / zh-TW / en-US / ja-JP），同步 `document.title` 与 i18n 实例\n- `useSyncStore` / `useAuthStore` — 云同步与账户\n- `useMarketplaceStore` — 主题/组件市场目录、安装与发布\n- `useConfirmStore` — 全局确认对话框（`components/shared/confirm-dialog/`）\n\n样式变更后通过 `useEditorRefresh()`（`apps/web/src/composables/useEditorRefresh.ts`）触发预览重渲染。\n\n## 云同步\n\n- **白名单**：`apps/web/src/services/sync/settings.ts` 中的 `SYNC_SETTING_KEYS`（含 `marketplace_installed_themes` / `marketplace_installed_components`）\n- **合并策略**：LWW，元数据存于 `sync_settings_meta`\n- **热更新**：远端设置应用后由 `hydrateSyncedSettings`（`services/sync/hydrate.ts`）写入 Store（含 `locale`），无需刷新页面\n- **用户说明**：见 [cloud-sync.md](./cloud-sync.md)\n\n## 主题 / 组件市场\n\n- **API**：`/marketplace/*`（公开浏览；登录发布；`ADMIN_GITHUB_LOGINS` 审核）\n- **主题包**：安装后以 `mp:<uuid>` 作为独立主题出现在主题选择器；CSS 经 `applyTheme({ themeCSS })` 动态注入\n- **组件包**：安装后写入 `custom_components` 注册表\n- **Web UI**：`MarketplaceDialog`（文件菜单 / 右侧主题栏 / 组件对话框入口）\n\n## 本地存储\n\n- **IndexedDB**（`apps/web/src/storage/`）：文章正文、偏好设置、图床/AI 密钥、缓存分层存储\n- **StorageEngine 抽象**（`storage/manager.ts`）：`store.reactive()` / `store.getJSON()` 统一入口\n- **文章持久化**：`documentRepo` 按篇读写，避免整包 JSON 写入\n- **云同步元数据**：`services/sync/settings.ts` 通过 `store` 读写设置白名单\n- **配额提示**：`storage/quota.ts`（IndexedDB 配额远大于 localStorage，保留 toast 兜底）\n\n### 启动顺序\n\n1. `main.ts` → `bootstrap()`（`apps/web/src/bootstrap.ts`）\n2. `initComponentDarkVars()` + `setupComponents()`\n3. `await initStorage()`（迁移 localStorage、预加载 KV 缓存、加载文档）\n4. `setupI18n(detectInitialLocale())` + `setAppI18n()`，注册 vue-i18n 插件\n5. `createApp`、Pinia、`useLocaleStore()` 并挂载\n6. `App.vue` 中 `usePlatformEnv()`、`useAccountSyncBootstrap()`、`useDeepLinkImport()` 完成账户与深链引导\n\n### 国际化（i18n）\n\n- **范围**：`apps/web` 主应用 UI；扩展 popup / background 部分文案。VS Code、uTools、CLI、MCP 无 i18n。\n- **入口**：`apps/web/src/i18n/`（`detect.ts`、`translate.ts`、`messages/`）\n- **偏好**：`PreferencesDialog`（文件菜单或 `Ctrl+,`）→ General → Language\n- **动态 UI**：命令面板、快捷键列表、Slash 命令、CodeMirror placeholder 等在 `locale` 变化时重建；Store 内 toast 使用 `@/i18n/translate` 的 `t()`\n\n## 构建\n\n- Web：Vite 8，`manualChunks` 拆分 codemirror、katex、highlight 等\n- VSCode 扩展：webpack，预览渲染复用 `@md/core`（见 `apps/vscode/src/previewRenderer.ts`）\n- 浏览器扩展：WXT，`src/entrypoints/` 为入口\n- Core / Shared：**直接导出 TypeScript 源码**，由消费方构建工具编译\n\n## 静态资源\n\nWeb 应用静态资源统一放在 `apps/web/public/`（如 `mpmd/` 图标）。根目录不再有 `public/` 副本。\n","packages/core/README.md":"# @md/core\n\nMarkdown 渲染引擎：将 Markdown 转为适合微信公众号的 HTML。\n\n## 导出\n\n| 路径                  | 说明                                                      |\n| --------------------- | --------------------------------------------------------- |\n| `@md/core`            | 主入口：`initRenderer`、`renderMarkdown`、`applyTheme` 等 |\n| `@md/core/renderer`   | 渲染器实现                                                |\n| `@md/core/extensions` | marked 扩展（Mermaid、KaTeX、alert 等）                   |\n| `@md/core/utils`      | `postProcessHtml`、`renderMarkdown` 辅助                  |\n| `@md/core/theme`      | 主题注入与 CSS 变量                                       |\n\n## 基本用法\n\n```ts\nimport { initRenderer, renderMarkdown } from '@md/core'\nimport { postProcessHtml } from '@md/core/utils'\n\nconst renderer = initRenderer({\n  isMacCodeBlock: true,\n  isShowLineNumber: true,\n})\n\nconst html = postProcessHtml(renderMarkdown(renderer, markdown))\n```\n\n主题样式需配合 `@md/core/theme` 的 `applyTheme` 或 Web 端 `useThemeStore.applyCurrentTheme()` 注入 CSS。\n\n## 扩展\n\n扩展位于 `src/extensions/`，在 `renderer-impl.ts` 中注册。新增扩展时：\n\n1. 在 `src/extensions/` 实现 marked 扩展\n2. 在 `src/extensions/index.ts` 导出\n3. 在 `initRenderer` 中注册\n\n## 依赖说明\n\n- **marked** — Markdown 解析\n- **highlight.js** — 代码高亮\n- **mermaid / @antv/infographic** — 图表（按需加载仍建议在消费方做 code-splitting）\n- **isomorphic-dompurify** — HTML 净化（`sanitizeHtml`）\n- **juice** — CSS 内联（仅 Web 端复制到微信时使用，不在本包内）\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n","packages/mcp-server/README.md":"# @md/mcp-server\n\nMCP (Model Context Protocol) server for [doocs/md](https://github.com/doocs/md).\n\nExposes the `doocs/md` markdown rendering engine and AI service configuration to AI agent runtimes (Claude Desktop, Cursor, VS Code Copilot, etc.) via the standard MCP protocol over **stdio**.\n\n## Prerequisites\n\n- **Node.js** ≥ 22.22.2（与 monorepo 根目录 `.nvmrc` 一致）\n- **pnpm** ≥ 9（monorepo workspace）\n- Clone the monorepo and install dependencies:\n\n```bash\ngit clone https://github.com/doocs/md.git\ncd md\npnpm install\n```\n\n## Tools\n\n### `render_markdown`\n\nConvert Markdown text to styled HTML using the full doocs/md rendering pipeline.\n\n| Parameter          | Type                               | Default     | Description                                            |\n| ------------------ | ---------------------------------- | ----------- | ------------------------------------------------------ |\n| `markdown`         | `string`                           | —           | Markdown source text                                   |\n| `theme`            | `\"default\" \\| \"grace\" \\| \"simple\"` | `\"default\"` | Visual theme (经典 / 优雅 / 简洁)                      |\n| `primaryColor`     | `string (hex)`                     | `\"#0F4C81\"` | Primary accent color (see `list_colors`)               |\n| `fontFamily`       | `string`                           | 无衬线预设  | Font family stack (see `list_fonts`)                   |\n| `fontSize`         | `string (px)`                      | `\"16px\"`    | Base font size (see `list_font_sizes`)                 |\n| `legend`           | `string`                           | `\"alt\"`     | Image caption format (see `list_legend_formats`)       |\n| `isMacCodeBlock`   | `boolean`                          | `false`     | Render code blocks with a macOS-style title bar        |\n| `isShowLineNumber` | `boolean`                          | `false`     | Show line numbers in code blocks                       |\n| `citeStatus`       | `boolean`                          | `false`     | Convert links to footnote-style citations              |\n| `countStatus`      | `boolean`                          | `false`     | Prepend a reading-time estimate                        |\n| `themeMode`        | `\"light\" \\| \"dark\"`                | `\"light\"`   | Color mode for diagram extensions                      |\n| `isUseIndent`      | `boolean`                          | `false`     | Indent paragraph first lines                           |\n| `isUseJustify`     | `boolean`                          | `false`     | Justify paragraph text                                 |\n| `headingStyles`    | `object`                           | `{}`        | Per-level heading styles (see `list_heading_styles`)   |\n| `codeBlockTheme`   | preset URL                         | GitHub 主题 | highlight.js preset from `list_code_block_themes` only |\n| `customCSS`        | `string`                           | `\"\"`        | Additional custom CSS (highest priority)               |\n\nReturns `{ html, frontMatter, readingTime: { words, minutes } }`.\n\n### Other tools\n\n| Tool                     | Description                                                                       |\n| ------------------------ | --------------------------------------------------------------------------------- |\n| `list_themes`            | List all available visual themes with labels and authors                          |\n| `list_colors`            | List all available primary accent colors                                          |\n| `list_fonts`             | List preset font family options                                                   |\n| `list_font_sizes`        | List preset font size options                                                     |\n| `list_legend_formats`    | List image caption format options                                                 |\n| `list_heading_styles`    | List heading style presets                                                        |\n| `list_code_block_themes` | List highlight.js code block theme URLs                                           |\n| `list_ai_services`       | List all built-in AI service providers with endpoints and models                  |\n| `explain_extensions`     | Describe every Markdown extension beyond CommonMark (KaTeX, Mermaid, PlantUML, …) |\n| `get_renderer_options`   | Describe all renderer configuration options                                       |\n\n## Setup\n\n### VS Code (GitHub Copilot)\n\nAdd to `.vscode/mcp.json` in the project root (already included in this repo):\n\n```json\n{\n  \"servers\": {\n    \"md\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"--import\", \"tsx/esm\", \"${workspaceFolder}/packages/mcp-server/run.mjs\"],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open the **MCP** panel in VS Code and start the `md` server.\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"C:/path/to/md/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"C:/path/to/md/packages/mcp-server\"\n    }\n  }\n}\n```\n\nReplace `C:/path/to/md` with the absolute path to your cloned repository.\n\n### Cursor\n\nAdd to `.cursor/mcp.json` at the project root (already included in this repo):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open **Cursor Settings → MCP** and enable the `md` server.\n\n### Windsurf / Other MCP Clients\n\nUse the same stdio pattern:\n\n```json\n{\n  \"command\": \"node\",\n  \"args\": [\"--import\", \"tsx/esm\", \"/absolute/path/to/packages/mcp-server/run.mjs\"],\n  \"cwd\": \"/absolute/path/to/packages/mcp-server\"\n}\n```\n\n## Example Prompts\n\nOnce the server is connected, you can ask your AI assistant:\n\n```\n使用 grace 主题将下面的 Markdown 渲染为 HTML，开启代码行号：\n# Hello World\n```\n\n```\n列出所有可用主题，并解释每个主题的风格特点。\n```\n\n```\nrender_markdown 支持哪些 Markdown 扩展？给我每个扩展的示例写法。\n```\n\n```\n列出所有内置 AI 服务，帮我找一个支持 DeepSeek-V3 的接入点。\n```\n\n## Development\n\n```bash\n# Run server directly (connects to stdin/stdout — for manual testing)\npnpm --filter @md/mcp-server start\n\n# Watch mode (auto-restart on changes)\npnpm --filter @md/mcp-server dev\n```\n\nTo test manually, use [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector node --import tsx/esm run.mjs\n```\n","packages/md-cli/README.md":"# md-cli\n\nA powerful yet simple tool for rendering Markdown documents locally during development.\n\n## Installation\n\nTo get started with `md-cli`, you can install it either globally or locally, depending on your needs.\n\n### Install locally\n\nIf you only need it for a specific project, you can install it locally by running:\n\n```bash\nnpm install @doocs/md-cli\n```\n\n### Install globally\n\nFor global access across all your projects, install it globally with:\n\n```bash\nnpm install -g @doocs/md-cli\n```\n\n## Usage\n\nOnce installed, running `md-cli` is a breeze. Here’s how to get started:\n\n### Default setup\n\nTo launch `md-cli` with the default settings, simply run:\n\n```bash\nmd-cli\n```\n\n### Custom port\n\nIf you prefer to run `md-cli` on a different port, say `8899`, just specify it like this:\n\n```bash\nmd-cli port=8899\n```\n\n## Maintainers\n\n- [yanglbme](https://github.com/yanglbme) – Core maintainer.\n- [YangFong](https://github.com/yangfong) – Core maintainer.\n- [xw](https://github.com/wll8) – Contributor.\n- [thinkasany](https://www.npmjs.com/~thinkerwing) – Contributor.\n","packages/shared/README.md":"# @md/shared\n\n跨应用共享的配置、类型、工具与 CodeMirror 编辑器封装。\n\n## 导出\n\n| 路径                   | 说明                                   |\n| ---------------------- | -------------------------------------- |\n| `@md/shared`           | 主入口                                 |\n| `@md/shared/configs`   | 主题、字体、颜色等默认配置与选项列表   |\n| `@md/shared/constants` | 常量                                   |\n| `@md/shared/types`     | 共享 TypeScript 类型                   |\n| `@md/shared/utils`     | fetch、tokenTools 等工具               |\n| `@md/shared/editor`    | CodeMirror 6 setup、格式化命令、快捷键 |\n\n## 主要配置（`configs`）\n\n- `themeOptions` / `defaultStyleConfig` — 主题名与默认样式\n- `defaultPerThemeSettings` — 每个主题的独立配置结构\n- `fontFamilyOptions` / `fontSizeOptions` / `colorOptions` — 样式面板选项\n- `ctrlKey` / `ctrlSign` — 平台相关快捷键展示\n\n主题 CSS 源文件位于 `src/configs/theme-css/`（如 `default.css`、`grace.css`）。\n\n## 编辑器（`editor`）\n\nWeb 与 VSCode 扩展共用 CodeMirror 配置：\n\n```ts\nimport { applyHeading, formatBold, markdownSetup, theme } from '@md/shared/editor'\n```\n\n## 消费方\n\n- `apps/web` — 主编辑器 UI\n- `apps/vscode` — VSCode 预览侧边栏\n- `packages/core` — 渲染相关类型与工具\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n"},"files":{".agents/skills/create-pr/SKILL.md":"---\nname: create-pr\ndescription: Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool.\n---\n\n# Create PR\n\nThis skill guides you through creating a well-structured GitHub pull request that follows project conventions and best practices.\n\nDo **not** assume Bash. On Windows PowerShell, avoid `&&`, `$(...)`, and POSIX tests; run git/`gh` commands as separate invocations and use `$env:TEMP` for the PR body file.\n\n## Prerequisites Check\n\nBefore proceeding, verify the following:\n\n### 1. Check if `gh` CLI is installed\n\n```bash\ngh --version\n```\n\nIf not installed, inform the user:\n> The GitHub CLI (`gh`) is required but not installed. Please install it:\n> - macOS: `brew install gh`\n> - Other: https://cli.github.com/\n\n### 2. Check if authenticated with GitHub\n\n```bash\ngh auth status\n```\n\nIf not authenticated, guide the user to run `gh auth login`.\n\n### 3. Verify clean working directory\n\n```bash\ngit status\n```\n\nIf there are uncommitted changes, ask the user whether to:\n- Commit them as part of this PR\n- Stash them temporarily\n- Discard them (with caution)\n\n## Gather Context\n\n### 1. Identify the current branch\n\n```bash\ngit branch --show-current\n```\n\nEnsure you're not on `main` or `master`. If so, ask the user to create or switch to a feature branch.\n\n### 2. Find the base branch\n\nResolve the default branch once and reuse it as `BASE_BRANCH`. Do **not** assume Bash (`$(...)`, `sed`, `[ -z ... ]` fail in PowerShell).\n\n```bash\ngit symbolic-ref refs/remotes/origin/HEAD\n```\n\nThis prints `refs/remotes/origin/<branch>` (usually `main`). Use the last path segment.\n\n```powershell\n# PowerShell\n$BASE_BRANCH = (git symbolic-ref refs/remotes/origin/HEAD).Split('/')[-1]\n```\n\nIf that fails, run `git remote show origin` and parse the `HEAD branch:` line.\n\nThis is typically `main` or `master`, but may differ per repo.\n\n### 3. Analyze recent commits relevant to this PR\n\n```bash\n# Bash / zsh\ngit log \"origin/${BASE_BRANCH}..HEAD\" --oneline --no-decorate\n```\n\n```powershell\n# PowerShell\ngit log \"origin/$BASE_BRANCH..HEAD\" --oneline --no-decorate\n```\n\nReview these commits to understand:\n- What changes are being introduced\n- The scope of the PR (single feature/fix or multiple changes)\n- Whether commits should be squashed or reorganized\n\n### 4. Review the diff\n\n```bash\n# Bash / zsh\ngit diff \"origin/${BASE_BRANCH}..HEAD\" --stat\n```\n\n```powershell\n# PowerShell\ngit diff \"origin/$BASE_BRANCH..HEAD\" --stat\n```\n\nThis shows which files changed and helps identify the type of change.\n\n## Information Gathering\n\nBefore creating the PR, you need the following information. Check if it can be inferred from:\n- Commit messages\n- Branch name (e.g., `fix/upload-timeout`, `feat/custom-shortcuts`)\n- Changed files and their content\n\nIf any critical information is missing, ask the user directly:\n\n### Required Information\n\n1. **Related Issue Number** (optional): Look for patterns like `#123`, `fixes #123`, or `closes #123` in commit messages. If none is found, **omit the Related Issue section** from the PR body — do not use placeholders like `#XXXX`.\n2. **Description**: What problem does this solve? Why were these changes made?\n3. **Type of Change**: Bug fix, new feature, breaking change, refactor, cosmetic, documentation, or workflow\n4. **Test Procedure**: How was this tested? What could break?\n\nOnly ask about a related issue when the change clearly looks like it should close one (e.g. branch name `fix/issue-123`). For small or self-contained changes, skip the question and leave the section out.\n\n## Git Best Practices\n\nBefore creating the PR, consider these best practices:\n\n### Commit Hygiene\n\n1. **Atomic commits**: Each commit should represent a single logical change\n2. **Clear commit messages**: Follow conventional commit format when possible\n3. **No merge commits**: Prefer rebasing over merging to keep history clean\n\n### Branch Management\n\n1. **Rebase on latest base branch** (if needed):\n   ```bash\n   git fetch origin\n   git rebase \"origin/${BASE_BRANCH}\"\n   ```\n   In PowerShell, use `\"origin/$BASE_BRANCH\"`.\n\n2. **Squash if appropriate**: If history is messy, ask the user whether they want commits squashed. Do **not** run `git rebase -i` (interactive; agents cannot complete it).\n\n### Push Changes\n\nEnsure all commits are pushed:\n```bash\ngit push origin HEAD\n```\n\nIf the branch was rebased, you may need:\n```bash\ngit push origin HEAD --force-with-lease\n```\n\n## Create the Pull Request\n\nUse `CONTRIBUTING.md` (Pull Request 流程) as the source of truth for PR content. Follow [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) exactly:\n\n- **Summary** — what changed and why\n- **Type of Change** — check applicable boxes\n- **Test Procedure** — how you verified the change\n- **Pre-flight Checklist** — mark items that apply\n\nWhen filling out the PR body:\n- Fill in all template sections with relevant information gathered from commits and context\n- Mark the appropriate \"Type of Change\" checkbox(es)\n- Complete the \"Pre-flight Checklist\" items that apply\n- **Related Issue is not in the template.** Add a `## Related Issue` section with `Closes #123` only when this PR actually fixes an issue. Never add `#XXXX` or an empty Related Issue heading.\n\n### Create PR with gh CLI\n\n**Use a temporary file for the PR body** to avoid shell escaping issues, newline problems, and other command-line flakiness:\n\n1. Write the PR body to a temporary file (`$env:TEMP/pr-body.md` on Windows PowerShell, `/tmp/pr-body.md` on macOS/Linux).\n\n2. Create the PR using the file:\n\n   ```bash\n   # Bash / zsh\n   gh pr create --title \"PR_TITLE\" --body-file /tmp/pr-body.md --base \"$BASE_BRANCH\"\n   ```\n\n   ```powershell\n   # PowerShell\n   gh pr create --title \"PR_TITLE\" --body-file \"$env:TEMP/pr-body.md\" --base $BASE_BRANCH\n   ```\n\n3. Clean up the temporary file after the PR is created.\n\nFor draft PRs, add `--draft` to the same command.\n\n**Why use a file?** Passing complex markdown with newlines, special characters, and checkboxes directly via `--body` is error-prone. The `--body-file` flag handles all content reliably.\n\n## Post-Creation\n\nAfter creating the PR:\n\n1. **Display the PR URL** so the user can review it\n2. **Remind about CI checks**: Tests and linting will run automatically\n3. **Suggest next steps**:\n   - Add reviewers if needed: `gh pr edit --add-reviewer USERNAME`\n   - Add labels if needed: `gh pr edit --add-label \"bug\"`\n\n## Error Handling\n\n### Common Issues\n\n1. **No commits ahead of base branch**: The branch has no changes to submit\n   - Ask if the user meant to work on a different branch\n\n2. **Branch not pushed**: Remote doesn't have the branch\n   - Push the branch first: `git push -u origin HEAD`\n\n3. **PR already exists**: A PR for this branch already exists\n   - Show the existing PR: `gh pr view`\n   - Ask if they want to update it instead\n\n4. **Merge conflicts**: Branch conflicts with base\n   - Guide user through resolving conflicts or rebasing\n\n## Summary Checklist\n\nBefore finalizing, ensure:\n- [ ] `gh` CLI is installed and authenticated\n- [ ] Working directory is clean\n- [ ] All commits are pushed\n- [ ] Branch is up-to-date with base branch\n- [ ] Related Issue included only when a real issue is linked (no empty heading, no `#XXXX` placeholder)\n- [ ] PR description follows the template or project conventions\n- [ ] Appropriate type of change is selected\n- [ ] Pre-flight checklist items are addressed\n",".agents/skills/git-commit/SKILL.md":"---\nname: git-commit\ndescription: 'Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions \"/commit\". Supports: (1) Auto-detecting type and scope from changes, (2) Creating a feature branch when on main/master before committing, (3) Generating conventional commit messages from diff, (4) Interactive commit with optional type/scope/description overrides, (5) Intelligent file staging for logical grouping'\nlicense: MIT\n---\n\n# Git Commit with Conventional Commits\n\n## Overview\n\nCreate standardized, semantic git commits using the Conventional Commits specification. Analyze the actual diff to determine appropriate type, scope, and message.\n\n## Conventional Commit Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n## Commit Types\n\n| Type       | Purpose                        |\n| ---------- | ------------------------------ |\n| `feat`     | New feature                    |\n| `fix`      | Bug fix                        |\n| `docs`     | Documentation only             |\n| `style`    | Formatting/style (no logic)    |\n| `refactor` | Code refactor (no feature/fix) |\n| `perf`     | Performance improvement        |\n| `test`     | Add/update tests               |\n| `build`    | Build system/dependencies      |\n| `ci`       | CI/config changes              |\n| `chore`    | Maintenance/misc               |\n| `revert`   | Revert commit                  |\n\n## Breaking Changes\n\n```\n# Exclamation mark after type/scope\nfeat!: remove deprecated endpoint\n\n# BREAKING CHANGE footer\nfeat: allow config to extend other configs\n\nBREAKING CHANGE: `extends` key behavior changed\n```\n\n## Host shell\n\nDo **not** assume Bash. Cursor on Windows uses PowerShell, where `&&`, `$(cat <<'EOF')`, and POSIX `[ -z ... ]` fail.\n\n- Prefer **separate git invocations** over chained one-liners.\n- If you must chain: PowerShell uses `;` (or separate calls). Bash/zsh may use `&&`.\n- Examples below show Bash and PowerShell when the syntax differs.\n\n## Workflow\n\n### 1. Analyze Diff\n\n```bash\n# If files are staged, use staged diff\ngit diff --staged\n\n# If nothing staged, use working tree diff\ngit diff\n\n# Also check status\ngit status --porcelain\n```\n\nFrom the diff, determine the commit **type** and a short **description** (needed for branch naming in step 2).\n\n### 2. Ensure Feature Branch\n\nIf the current branch is `main` or `master`, create a feature branch **before** staging or committing.\n\n```bash\ngit branch --show-current\n```\n\n**Branch naming** — documented prefixes in `CONTRIBUTING.md`: `feat/`, `fix/`, `docs/`. For other commit types, use the commit type as prefix (e.g. `chore/`):\n\n```\n<type>/<kebab-case-description>\n```\n\n| Commit type | Branch prefix | Example |\n| ----------- | ------------- | ------- |\n| `feat`      | `feat/`       | `feat/custom-shortcuts` |\n| `fix`       | `fix/`        | `fix/upload-timeout` |\n| `docs`      | `docs/`       | `docs/contributing-guide` |\n| other types | `<type>/`     | `chore/add-create-pr-skill` (aligns with commit type; not listed in CONTRIBUTING.md) |\n\nRules for `<kebab-case-description>`:\n\n- Lowercase, words separated by hyphens\n- Derived from the commit description (drop scope, articles, punctuation)\n- Keep it short (2–5 words), e.g. `add create pr skill` → `add-create-pr-skill`\n\n```bash\n# Example: chore commit about adding create-pr skill\ngit checkout -b chore/add-create-pr-skill\n```\n\nDo **not** commit directly on `main` or `master`. If the user explicitly asks to commit on the default branch, confirm before proceeding.\n\n### 3. Stage Files (if needed)\n\nIf nothing is staged or you want to group changes differently:\n\n```bash\n# Stage specific files\ngit add path/to/file1 path/to/file2\n\n# Stage by pattern\ngit add *.test.*\ngit add src/components/*\n```\n\nDo **not** run `git add -p` (interactive; agents cannot complete it). Stage explicit paths instead.\n\n**Never commit secrets** (.env, credentials.json, private keys).\n\n### 4. Generate Commit Message\n\nAnalyze the diff to determine:\n\n- **Type**: What kind of change is this?\n- **Scope**: What area/module is affected?\n- **Description**: One-line summary of what changed (present tense, imperative mood, <72 chars)\n\n### 5. Execute Commit\n\nSingle line (any shell):\n\n```bash\ngit commit -m \"<type>[scope]: <description>\"\n```\n\nMulti-line with body/footer:\n\n```bash\n# Bash / zsh\ngit commit -m \"$(cat <<'EOF'\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\nEOF\n)\"\n```\n\n```powershell\n# PowerShell\ngit commit -m @\"\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\n\"@\n```\n\n## Best Practices\n\n- One logical change per commit\n- Present tense: \"add\" not \"added\"\n- Imperative mood: \"fix bug\" not \"fixes bug\"\n- Reference issues: `Closes #123`, `Refs #456`\n- Keep description under 72 characters\n\n## Git Safety Protocol\n\n- NEVER update git config\n- NEVER run destructive commands (--force, hard reset) without explicit request\n- NEVER skip hooks (--no-verify) unless user asks\n- NEVER force push to main/master\n- If commit fails due to hooks, fix and create NEW commit (don't amend)\n\n## Project Notes (doocs/md)\n\n- Commit messages and PR titles must be in **English** (see `AGENTS.md` and `CONTRIBUTING.md`)\n- Branch naming: `feat/`, `fix/`, `docs/` per `CONTRIBUTING.md`; for other commit types use `<type>/` prefix; never commit on `main`/`master` — create a branch first (step 2)\n- Pre-commit runs `eslint --fix` via lint-staged; if the hook modifies files, fix and create a new commit instead of amending\n",".agents/skills/wechat-svg/SKILL.md":"---\nname: wechat-svg\ndescription: >-\n  WeChat / 微信公众号 SVG constraints and bubbling-group interaction design.\n  Use when adapting SVG for WeChat paste, fixing missing arrows or oversized\n  diagrams, designing pure-SVG interactions without JS, or working with\n  id/class/defs/marker/foreignObject compatibility. Includes inline\n  SVG AttributeName whitelist.\n---\n\n# WeChat SVG Skill\n\n适用于微信公众号、小程序等强约束 SVG 环境。\n\n## 何时调用\n\n- 用户要把 SVG 粘贴到微信公众号，或排查粘贴后样式/交互失效\n- 需要纯 SVG、无 JS、无块级 CSS 的交互动画\n- 约束包含：无 `id` / `class` / `defs` / `href` 依赖\n- 需要深层 `<g>` 嵌套、透明触发器、事件冒泡组织动画\n- 需要接入 `<image>`、文本卡、外部素材，或排查 transform 串层、箭头消失、尺寸异常\n\n## SVG AttributeName 白名单\n\n微信生态对 SVG 动画的 **AttributeName** 有白名单。超出白名单的标签、指令或属性名，可能在保存后被平台过滤。\n\n| 元素 | Name | 说明 |\n| --- | --- | --- |\n| `animate` | `x` | 控制简单几何体 x 轴方向移动 |\n| `animate` | `y` | 控制简单几何体 y 轴方向移动 |\n| `animate` | `width` | 控制简单几何体宽度变化 |\n| `animate` | `height` | 控制简单几何体高度变化 |\n| `animate` | `opacity` | 控制透明度变化，数值通常为 0 到 1 |\n| `animate` | `d` | 控制贝塞尔曲线补间，表现可能有随机性 |\n| `animate` | `points` | 控制多边形补间，表现可能有随机性 |\n| `animate` | `stroke-width` | 控制描边宽度 |\n| `animate` | `stroke-linecap` | 控制描边端点样式 |\n| `animate` | `stroke-dashoffset` | 控制描边偏移，常用于线性遮罩/进度线 |\n| `animate` | `fill` | 控制填充色过渡变化 |\n| `set` | `visibility` | 控制可见性：`visible` / `hidden` / `collapse` / `inherit` |\n| `animateTransform` | `translate` | 控制路径和编组位移 |\n| `animateTransform` | `scale` | 控制路径和编组缩放，可用于翻转 |\n| `animateTransform` | `rotate` | 控制路径和编组旋转 |\n| `animateTransform` | `skewX` | 控制 x 轴倾斜 |\n| `animateTransform` | `skewY` | 控制 y 轴倾斜 |\n| `animateMotion` | `path` | 复杂轨迹动画，可配合 `rotate` 定义朝向 |\n\n### 禁用边界\n\n在设计或适配 SVG 时，默认遵守：\n\n- 不使用 `id`\n- 不使用 `class`\n- 不使用 `href` / `xlink:href` 作为样式与结构依赖（含 `url(#id)` 引用）\n- 不使用 `defs`\n- 不使用 `embed`\n- 不使用块级 CSS 与 JS 动画\n- 样式尽量以内联属性或 `style=\"\"` 的最小必要形式书写\n\n### 静态图表适配要点（非交互动画）\n\n第三方 SVG（如 Mermaid）粘贴到微信时，常见问题与修法：\n\n| 现象 | 原因 | 修法 |\n| --- | --- | --- |\n| 箭头消失 | `<defs>` + `<marker>` + `url(#id)` 被过滤 | 将 marker 展开为内联 `<path>` / `<polygon>`，移除 `marker-end` |\n| 图表过大 | `width=\"100%\"` 或 CSS `max-width` 被忽略，按 viewBox 1:1 渲染 | 设置显式像素 `width` / `height`（不超过正文栏可用宽度），保留 `viewBox` |\n| 文字错位 | `foreignObject` 兼容性差 | 转为 `<text>` / `<tspan>` 或外层 HTML `<section>` |\n\n## 核心使用原则\n\n1. 先判断这是不是「真正的无 ID 冒泡编组问题」\n2. 先搭结构，再写动画\n3. 区分世界层 / 遭遇层 / 触发层\n4. 最深层透明触发器放在整条父子链最底部\n5. 每个遭遇物做成闭环模块：施加层 → 姿态层 → 抵消层\n6. 先统一交互模式，再统一全链实现\n\n详细原则见 [core-principles.md](./references/core-principles.md)。\n\n## 已验证的交互写法\n\n```xml\n<animateTransform\n  begin=\"click\"\n  dur=\"30s\"\n  fill=\"freeze\"\n  restart=\"never\"\n  ... />\n```\n\n固定要求：\n\n- 所有交互动画统一 `begin=\"click\"`\n- 所有交互动画统一 `fill=\"freeze\"`\n- 所有交互动画统一 `restart=\"never\"`\n- 删除所有旧的 `touchend;mouseup` 回位链\n- 不允许一部分层保留旧长按逻辑，一部分层改成 click-only\n\n## 嵌套与变换\n\n### 嵌套规则\n\n- 必须形成连续不间断的绝对父子链，不是「很多 `<g>` 平铺」\n- 任何平级断链都会让冒泡和补偿逻辑失效\n\n### 变换规则\n\n- 标准写法：**施加 → 抵消 → 再施加**\n- 父层改变参考系，子层拿回局部控制权，更深层通过补偿层回到干净坐标基准\n\n## `<image>` 接入\n\n- `<image>` 不能直接丢到 SVG 根部\n- 必须挂在对应对象的局部姿态层或遭遇层内部\n- 位移、旋转、出场时机由外层 `<g>` 的 `animateTransform` 控制\n- 位置用 `x` / `y`，尺寸用 `width` / `height`，不依赖外部 CSS\n\n```xml\n<g>\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g>\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n  </g>\n</g>\n```\n\n详细规则与排错见 [image-integration.md](./references/image-integration.md)。\n\n## 排错顺序\n\n按顺序排查，不要跳步：\n\n1. 是否还是绝对父子链\n2. 触发器是否在最深层\n3. 补偿层是否成对存在\n4. 坐标是否跑出视口\n5. `opacity` / `visibility` 是否误伤深层\n6. `keyTimes` 与出现窗口\n7. （静态 SVG）是否仍依赖 `defs` / `id` / 百分比宽度\n\n## 常见错误与固定修法\n\n| 错误 | 现象 | 修法 |\n| --- | --- | --- |\n| 平级 `<g>` 当深层结构 | 事件链断 | 回到单一路径父子链 |\n| 只施加，不抵消 | 后续对象继承前一层轨迹 | 每个遭遇物补上抵消层 |\n| 局部闪烁挂在公共父层 | 深层对象一起透明 | 把 `opacity` 动画缩到最小局部组 |\n| 文案/字幕放错逻辑层 | 视觉居中但脱离编组 | 绑对象局部层，或放最深层补偿后的视口坐标层 |\n| 交互模式半新半旧 | 部分层仍用旧长按逻辑 | 全链统一 `begin` / `fill` / `restart` |\n| marker 箭头依赖 defs | 粘贴后箭头消失 | 内联展开箭头，移除 `marker-end` |\n| SVG 使用 width 100% | 粘贴后撑满编辑器 | 写死像素宽高并保留 viewBox |\n\n## 新模块实施顺序\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n\n## 延伸阅读\n\n- [core-principles.md](./references/core-principles.md) — 洋葱式嵌套、模块化、局部效果收口\n- [image-integration.md](./references/image-integration.md) — `<image>` 接入与典型陷阱\n",".agents/skills/wechat-svg/references/core-principles.md":"# Core Principles\n\n## 1. 绝对父子链原则\n\n真正有效的无 ID 冒泡交互，不是「看起来层很多」，而是：\n\n- 最外层到最深层之间是一条连续不间断的父子链\n- 透明触发器必须在整条链的最底部\n- 任何平级断链都会让方法论失效\n\n**错误示意：**\n\n- 很多 `<g>` 平行摆放\n- 触发器只是在视觉上「放在下面」\n- 某一层动画和触发器不是父子关系而是兄弟关系\n\n**正确目标：**\n\n- 每一层动画都在触发器的祖先链上\n\n## 2. 世界层 / 遭遇层 / 触发层三分法\n\n### 世界层\n\n- 承担大场景运动\n- 例如背景上升、地面后退、天空密度变化\n\n### 遭遇层\n\n- 承担单个事件对象\n- 例如气球、直升机、飞机、火箭、第二个 UFO\n\n### 触发层\n\n- 只负责接收事件和向上冒泡\n- 不负责视觉叙事\n\n## 3. 施加 → 抵消 → 再施加\n\n复杂变换串层时，固定采用三段式：\n\n1. 先施加外层参考系变化\n2. 在下一层抵消这段变化\n3. 再在更深层只对当前对象施加自己的局部运动\n\n好处：\n\n- 父层控制大结构\n- 子层拿回局部控制权\n- 更深层总能回到干净坐标系\n\n## 4. 遭遇物必须模块化闭环\n\n每个遭遇物最小结构：\n\n```xml\n<g> <!-- 位移施加层 -->\n  <animateTransform ... />\n  <g> <!-- 姿态层 -->\n    <animateTransform ... />\n    <!-- 对象本体、文本卡、image -->\n  </g>\n  <g> <!-- 位移抵消层 -->\n    <animateTransform ... />\n    <!-- 下一个更深层模块 -->\n  </g>\n</g>\n```\n\n这样后续对象不会继承前一个对象的轨迹、旋转、透明度或姿态残留。\n\n## 5. 交互模式必须全链统一\n\n推荐正式规范：\n\n```xml\nbegin=\"click\"\nfill=\"freeze\"\nrestart=\"never\"\n```\n\n固定要求：\n\n- 不允许主链是 `click`，补偿层还是 `touchstart/touchend`\n- 不允许提示文案、遮挡层、字幕层停留在旧交互语义\n- 交互模式一旦切换，必须全文件统一\n\n## 6. 局部效果必须就地收口\n\n以下效果只能包裹在最小局部范围里：\n\n- 红灯闪烁\n- 尾焰\n- 呼吸发光\n- 小幅摇摆\n- 局部透明度变化\n\n否则它们会误伤更深层链路。\n\n## 7. 全局收尾层也必须在链内\n\n常见误区：视觉上想让字幕固定在屏幕中央，就把它直接挂到 SVG 根部最外层。\n\n正确做法：\n\n- 把收尾字幕接在最深层内部补偿组之后\n- 让它位于「已经抵消完成的视口坐标层」中\n- 这样既能稳定居中，又不脱离方法论\n\n## 8. 固定实施顺序\n\n后续新模块一律按这个顺序实现：\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n",".agents/skills/wechat-svg/references/image-integration.md":"# Image Integration And Pitfalls\n\n## 1. `<image>` 的正确接入方式\n\n核心原则：\n\n- `<image>` 只是视觉内容，不应该自己决定时间轴\n- 时间轴、旋转、进场和冻结全部由外层 `<g>` 接管\n- `<image>` 必须属于某个对象模块，而不是脱链挂在 SVG 根部\n\n标准结构：\n\n```xml\n<g> <!-- 遭遇物位移施加层 -->\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g> <!-- 遭遇物姿态层 -->\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n    <image x=\"0\" y=\"-1900\" width=\"609\" height=\"343\" href=\"...\" />\n  </g>\n</g>\n```\n\n## 2. `<image>` 的固定约束\n\n- 不要依赖外部 CSS 调位置\n- 不要把尺寸交给响应式布局\n- 不要让 `<image>` 自己承担运动逻辑\n- 不要把 `<image>` 放到与本体平级但不在同一局部姿态组的位置\n\n推荐做法：\n\n- 位置用 `x` / `y`\n- 尺寸用 `width` / `height`\n- 序列排布用不同的 `y`\n- 组级运动用外层 `transform`\n\n## 3. 文本卡与 `<image>` 的关系\n\n如果对象既有文本卡，也有 `<image>`：\n\n- 文本卡和 `<image>` 都应该属于同一对象的局部层级\n- 但它们不一定要放在同一最小组里\n- 判断标准不是「看起来近不近」，而是「是否应该共享同一轨迹和同一姿态」\n\n## 4. 典型错误与修法\n\n### 错误 1：`<image>` 放在 SVG 根部\n\n- 结果：图片能显示，但完全脱离编组时间轴\n- 修法：挂回对应遭遇物的姿态层或其内部子组\n\n### 错误 2：`<image>` 跟在错误的补偿层下面\n\n- 结果：图片方向对，但位置始终不对，或者跟着下一个对象一起移动\n- 修法：确认它位于「当前对象的姿态层内部」，而不是「下一个对象的补偿层之后」\n\n### 错误 3：只调 `x/y`，不看外层 `transform`\n\n- 结果：怎么挪都不对，因为真正决定运动的是外层位移和旋转\n- 修法：先定外层轨迹，再微调 `x/y`\n\n### 错误 4：收尾字幕放在最外层\n\n- 结果：视觉上居中，但逻辑上不属于最深层编组体系\n- 修法：把字幕接入最深层补偿后的内部视口坐标层\n\n### 错误 5：交互模式切换不彻底\n\n- 结果：`<image>` 所在段落已经 click-only，但同一链上的遮挡层、字幕层或对象层仍保留旧回位逻辑\n- 修法：统一整条链的 `begin` / `fill` / `restart`\n\n## 5. 固定结论\n\n### 结论 1\n\n- `<image>` 是「局部视觉载荷」，不是「独立时间轴节点」\n\n### 结论 2\n\n- 居中文案虽然视觉上像 HUD，但如果它属于故事收尾的一部分，仍然应该放进最深层链内\n\n### 结论 3\n\n- 如果视觉感觉不对，优先排查时序、补偿层、父子链\n- 不要第一反应只去改 `x/y/width/height`\n\n## 6. 推荐排错顺序\n\n1. 先看 `<image>` 在不在正确对象模块里\n2. 再看它是不是放在姿态层里\n3. 再看外层位移与旋转\n4. 再看它的 `x/y/width/height`\n5. 最后再看是否被透明度或遮挡层影响\n",".cursor/mcp.json":"{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n",".github/copilot-instructions.md":"# Copilot Instructions\n\nThis repository is a pnpm monorepo for **doocs/md**, a WeChat Markdown editor. Canonical agent guidance lives in [AGENTS.md](../AGENTS.md); keep this file aligned with it.\n\n- **Node:** `>=22.22.2` (`.nvmrc`: v22.22.2)\n- **Package manager:** pnpm (`packageManager` in the root `package.json`)\n- **npm registry:** https://registry.npmmirror.com (`.npmrc`)\n\n## Build, Test, and Lint\n\n### Global Commands\n\n- **Install:** `pnpm install`\n- **Lint (ESLint + Prettier):** `pnpm run lint`\n- **Type Check:** `pnpm run type-check`\n- **Tests:** `pnpm run test` (`@md/shared`, `@md/core`, `@md/web`, `@md/api`)\n\n### Web App (`@md/web`)\n\n- **Development Server:** `pnpm web dev`\n- **Production Build:** `pnpm web build`\n- **Browser Extension:** `pnpm web ext:zip` (WXT; Chrome) / `pnpm web firefox:zip`\n\n### Other Workspaces\n\n- **API (`@md/api`):** `pnpm api dev` / `pnpm api test`\n- **VS Code (`doocs-md`):** `pnpm vscode compile` / `pnpm vscode package`\n- **CLI (`@doocs/md-cli`):** `pnpm run build:cli`\n- **MCP (`@md/mcp-server`):** `pnpm mcp dev`\n- **uTools (`@md/utools`):** `pnpm utools:package`\n\n## High-Level Architecture\n\n### Monorepo Structure\n\n- **`apps/web`**: Vue 3 + Vite + Pinia + Tailwind CSS 4. Web app and browser extension (WXT).\n- **`apps/api`**: Cloudflare Workers + Hono + D1 (auth, cloud sync, billing, upload, share, marketplace, emoji).\n- **`apps/vscode`**: VS Code extension (webpack). Marketplace ID: `doocs.doocs-md`.\n- **`apps/utools`**: uTools plugin packaging shell (artifacts from `@md/web`).\n- **`packages/core`**: Markdown renderer (`marked` + custom extensions, theme CSS variables).\n- **`packages/shared`**: Shared config, types, CodeMirror wrapper, theme CSS.\n- **`packages/config`**: Shared TypeScript config.\n- **`packages/md-cli`**: Published npm CLI that serves the built web app.\n- **`packages/mcp-server`**: MCP tools (`render_markdown`, `list_themes`, `list_colors`).\n- **`docs/examples/wechat-openapi-worker/`**: standalone WeChat OpenAPI proxy (not in the pnpm workspace).\n\nDetails: [docs/architecture.md](../docs/architecture.md).\n\n### Key Technologies\n\n- **Frontend:** Vue 3 (Composition API), Pinia, Tailwind CSS 4 + PostCSS\n- **Editor:** CodeMirror 6\n- **Markdown:** `marked` in `@md/core`; `juice` inlines CSS for WeChat paste; `isomorphic-dompurify` sanitizes output\n- **Web build:** Vite 8; extension build: WXT\n- **API:** Hono on Cloudflare Workers, D1\n- **i18n (web only):** `vue-i18n` — zh-CN, zh-TW, en-US, ja-JP\n\n## Key Conventions\n\n### Development Patterns\n\n- **`@md/core` and `@md/shared` export TypeScript source** (`src/index.ts`). Do not pre-build them; consumers (Vite/webpack) compile them.\n- **UI:** Shadcn-Vue components in `apps/web/src/components/ui`. Prefer these over raw HTML/CSS.\n- **Stores:** Domain Pinia stores in `apps/web/src/stores` (`useEditorStore`, `useThemeStore`, `useUiStore`, `useLocaleStore`, …).\n- **Comments:** English only. Explain non-obvious why / constraints; do not narrate the next line. Do not rewrite user-facing i18n copy unless asked.\n\n### Internationalization (`@md/web`)\n\n- Messages: `apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`\n- Components: `useI18n()` + `t('key')`. Stores/utils: `@/i18n/translate`.\n- New user-visible strings must be added in all four locales. VS Code, uTools, CLI, and MCP are not localized.\n\n### Styling & Theming\n\n- Theme injection: `@md/core/src/theme` (CSS variables).\n- Theme CSS sources: `packages/shared/src/configs/theme-css/` (`default.css`, `grace.css`, `simple.css`).\n\n### Markdown Extensions\n\n- Implement new Markdown features as extensions in `packages/core/src/extensions`.\n- Register them in the renderer configuration.\n\n### Dependencies\n\n- Shared toolchain versions live in `pnpm-workspace.yaml` `catalog`; workspace packages use `\"catalog:\"`.\n- Root `package.json` is publishable (`private: false`) — use plain semver there, not `catalog:`.\n- Prettier is pinned to **2.8.8**. Do not remove security `overrides` unless upstream fixed the CVE.\n- If a patched dependency is upgraded, update the matching file in `patches/` and `patchedDependencies`.\n\n### Git Conventions\n\n- **Commit messages and PR titles:** Conventional Commits, **English** (`feat`, `fix`, `docs`, `chore`, …).\n- **Branches:** `feat/description`, `fix/description`, `docs/description`; other types use `<type>/`.\n- Never commit on `main`. Follow `.github/pull_request_template.md` when opening a PR.\n\n### Agent Skills\n\nCanonical workflows: `.agents/skills/` (`git-commit`, `create-pr`, `wechat-svg`). Claude Code discovers them via git symlinks under `.claude/skills/`.\n","AGENTS.md":"# Agent Instructions\n\n本文件为 AI Agent（Claude Code、OpenCode、Cursor、Copilot 等）在本仓库中工作时提供统一入口。\n\n## 项目概览\n\n**doocs/md** — 一款微信 Markdown 编辑器，将 Markdown 渲染为微信公众号文章格式。支持自定义主题样式、多图床、AI 助手、浏览器扩展、**zh-CN / zh-TW / en-US / ja-JP 界面**等特性。\n\n- **在线地址:** https://md.doocs.org\n- **Node 版本:** >= 22.22.2（`.nvmrc`: v22.22.2）\n- **包管理器:** pnpm（monorepo）\n- **npm 镜像:** https://registry.npmmirror.com（`.npmrc`）\n\n## Monorepo 结构\n\n| 工作区           | 路径                  | 说明                                                                                                  |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | 主应用，Vue 3 + 浏览器扩展（WXT: Chrome/Firefox）                                                     |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID: `doocs.doocs-md`）                                        |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包                                                                                       |\n| `@md/core`       | `packages/core`       | 核心 Markdown 渲染引擎（marked + 自定义扩展）                                                         |\n| `@md/shared`     | `packages/shared`     | 共享工具函数、配置、类型、编辑器配置                                                                  |\n| `@md/config`     | `packages/config`     | TypeScript 配置基础文件                                                                               |\n| `@doocs/md-cli`  | `packages/md-cli`     | CLI 工具（Express 服务托管构建产物）                                                                  |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务，为 AI Agent 暴露接口                                                                        |\n| `@md/api`        | `apps/api`            | 后端 API：账户、云同步、计费、上传代理、分享、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n\n独立示例（不在 workspace 内）：`docs/examples/wechat-openapi-worker/` — 微信公众号 OpenAPI 代理 Worker。\n\n## 常用命令\n\n### 根目录\n\n```bash\npnpm install          # 安装所有依赖\npnpm start            # 等同于 `pnpm web dev`\npnpm run lint         # ESLint --fix 全项目检查\npnpm run type-check   # vue-tsc 类型检查\npnpm run build:cli    # 构建 web + 复制到 md-cli + npm pack\npnpm run release:cli  # 通过 scripts/release.js 发布 CLI\npnpm utools:package   # 打包 uTools 插件\npnpm run inspector    # node-modules-inspector 查看依赖树\n```\n\n### Web 应用 (`@md/web`)\n\n```bash\npnpm web dev          # 启动 Vite 开发服务器\npnpm web build        # 生产构建 + 类型检查\npnpm web build:h5-netlify   # 构建用于 Netlify 根目录部署\npnpm web build:analyze      # 构建并生成 rollup-plugin-visualizer 分析\npnpm web ext:dev      # WXT Chrome 扩展开发模式\npnpm web ext:zip      # 打包 Chrome 扩展\npnpm web firefox:dev  # WXT Firefox 扩展开发模式\npnpm web firefox:zip  # 打包 Firefox 扩展\npnpm web wrangler:dev    # Cloudflare Workers 开发\npnpm web wrangler:deploy   # Cloudflare Workers 部署\n```\n\n### VSCode 扩展\n\n```bash\npnpm vscode compile   # webpack 编译\npnpm vscode watch     # webpack 监听\npnpm vscode build     # 生产 webpack 构建\npnpm vscode package   # vsce 打包\n```\n\n### CLI & MCP\n\n```bash\npnpm cli <cmd>        # 在 @doocs/md-cli 中执行命令\npnpm mcp <cmd>        # 在 @md/mcp-server 中执行命令（render_markdown 等 MCP 工具）\npnpm mcp dev          # MCP Server 监听模式\n```\n\n`@md/mcp-server` 通过 stdio 暴露 `render_markdown`、`list_themes`、`list_colors` 等工具，配置见 [packages/mcp-server/README.md](./packages/mcp-server/README.md)、[`.vscode/mcp.json`](./.vscode/mcp.json) 与 [`.cursor/mcp.json`](./.cursor/mcp.json)。\n\n## 架构\n\n### 渲染管线\n\n1. `@md/core` 封装 `marked`，实现自定义扩展（Mermaid、PlantUML、Ruby、KaTeX、TOC、alert 块、infographic、slider、markup、emoji、脚注）\n2. `juice` 内联 CSS 以兼容微信\n3. `isomorphic-dompurify` 净化输出\n4. 主题系统（`@md/core/src/theme/`）注入 CSS 变量\n\n### 构建系统\n\n- **`@md/core` 和 `@md/shared` 直接导出 TypeScript 源码**（不预构建）。由消费方的构建工具（Vite/webpack）编译。\n- Web 应用使用 Vite 8，VSCode 扩展使用 webpack，浏览器扩展使用 WXT\n\n### 样式与主题\n\n- Web 应用使用 Tailwind CSS 4 + PostCSS\n- 主题 CSS 文件位于 `packages/shared/src/configs/theme-css/`（default.css、grace.css、simple.css）\n- 部分主题文件使用 Less\n\n### 状态管理\n\n- Pinia store 位于 `apps/web/src/stores/`（按领域划分：`useEditorStore`、`useThemeStore`、`useUiStore`、`useLocaleStore` 等）\n- UI 组件遵循 Shadcn-Vue 模式，位于 `apps/web/src/components/ui`\n- 跨 feature 通用组件位于 `apps/web/src/components/shared`\n- 架构详情见 [docs/architecture.md](./docs/architecture.md)\n\n### 国际化（i18n，`@md/web`）\n\nWeb 主应用与部分浏览器扩展 UI 支持 **zh-CN**、**zh-TW**、**en-US**、**ja-JP**；VS Code 扩展、uTools、CLI、MCP **未**国际化。\n\n- **库**：`vue-i18n`（composition API，`legacy: false`），在 `apps/web/vite.config.ts` 中通过 `unplugin-auto-import` 自动导入 `useI18n`\n- **文案**：`apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`（`common`、`editor`、`dialog`、`store`、`ai`、`upload`、`chrome`、`marketplace`、`notifications`）\n- **组件内**：`useI18n()` + `t('key')`；**Store / 工具函数**：`@/i18n/translate` 的 `t()` / `getLocale()` / `formatLocalDateTime()`\n- **语言状态**：`useLocaleStore`（持久化 key：`locale`）；用户可在 **偏好设置**（`Ctrl+,`）→ General 切换\n- **启动**：`await initStorage()` → `setupI18n(detectInitialLocale())` → Pinia → `useLocaleStore()`（见 `apps/web/src/bootstrap.ts`）；`index.html` 启动屏从 `localStorage` 读取 locale\n- **云同步**：`locale` 在 `SYNC_SETTING_KEYS` 中，远端应用后由 `hydrateSyncedSettings` 热更新\n- **约定**：新增用户可见文案须同时维护 zh-CN、zh-TW、en-US 与 ja-JP；在 computed 中调用 `t()` 且需随语言切换更新时，应依赖 `locale`（例如 `void locale.value`）\n\n## Lint 与格式化\n\n- **ESLint:** `@antfu/eslint-config` + Vue + TypeScript + formatter\n- **Prettier:** 固定版本 `2.8.8`（通过 `pnpm-workspace.yaml` 的 `overrides` 强制）\n- **Pre-commit 钩子:** `lint-staged` 对所有文件执行 `eslint --fix`\n- 规则：不使用分号，关闭 `no-unused-vars`、`no-console`、`no-debugger`\n- **代码注释：** 统一英文。保留非显而易见的 why / 约束 / 兼容性说明；删除复述下一行代码的噪音注释。勿改动 `i18n/messages` 等用户可见文案。\n\n## 依赖管理\n\n这是一个 pnpm monorepo，`pnpm-workspace.yaml` 中包含大量安全覆盖（overrides）。\n\n### 升级依赖\n\n1. **共享版本用 catalog** — 跨包共用的工具链版本集中在 `pnpm-workspace.yaml` 的 `catalog`（`typescript`、`vitest`、`wrangler`、`@types/node`、`marked`、`@codemirror/state|view` 等）；workspace 内各 `package.json` 用 `\"catalog:\"` 引用。**仓库根 `package.json` 因 `private: false` 可被 npm 消费，须写普通 semver，勿用 `catalog:`。**包专属依赖可继续写版本号（`pnpm/json-enforce-catalog` 已关闭）\n2. **Prettier 必须固定在 `2.8.8`** — 通过 catalog + `overrides.prettier` 强制（根 package 直接写 `2.8.8`）\n3. **Patch 文件：** 如果打了 patch 的依赖升级了，必须同步更新 `patches/` 中对应的 patch 文件：\n   - `@codemirror/view` → `patches/@codemirror__view@6.43.15.patch`（导出 `MeasureRequest` 接口，修复 macOS 上 Alt+Shift 快捷键处理）\n   - `mermaid` → `patches/mermaid@12.2.0.patch`（流程图 HTML 标签在非整数 DPR 下按宽度换行，避免文字被裁切）\n   - `juice` 12.2.0 已在上游处理 `parseCSS` 空返回值，不再需要本地 patch\n4. 更新 `pnpm-workspace.yaml` 中的 `patchedDependencies` 以匹配新版本\n5. 运行 `pnpm install` 重新生成 `pnpm-lock.yaml`；可用 `pnpm dedupe` 收敛可合并的间接依赖\n\n### 安全覆盖\n\n`pnpm-workspace.yaml` 的 `overrides` 部分强制了存在漏洞的间接依赖的最低版本（ajv、dompurify、undici、minimatch 等）。除非上游已修复漏洞，否则不要移除这些覆盖。\n\n### allowBuilds\n\n`pnpm-workspace.yaml` 包含 `allowBuilds` 列表，用于需要原生构建脚本的依赖（`esbuild`、`sharp`、`keytar`、`workerd` 等）。新增需要原生构建的依赖可能需要添加到此列表。\n\n## Git 规范\n\n- **提交信息 / PR 标题:** 遵循 Conventional Commits（`feat`、`fix`、`docs`、`style`、`refactor`、`perf`、`test`、`build`、`chore`），**一律使用英文**（见 `CONTRIBUTING.md`）\n- **分支命名:** `feat/description`、`fix/description`、`docs/description`；其他类型用 `<type>/`\n- **PR 说明:** 按 [`.github/pull_request_template.md`](./.github/pull_request_template.md) 填写；无关联 Issue 时不要写 Related Issue 占位符\n\n## Skills\n\nReusable workflows live in [`.agents/skills/`](./.agents/skills/) (canonical). Claude Code discovers each skill through a git symlink:\n\n```text\n.claude/skills/<name> → ../../.agents/skills/<name>\n```\n\n| Skill        | When to use                                                                           |\n| ------------ | ------------------------------------------------------------------------------------- |\n| `git-commit` | Commit changes with Conventional Commits (`/git-commit` or \"commit my changes\")       |\n| `create-pr`  | Create a GitHub pull request (`/create-pr` or \"open a PR\")                            |\n| `wechat-svg` | WeChat SVG whitelist, bubbling-group interaction, paste compatibility (`/wechat-svg`) |\n\nInvoke manually: `/skill-name` in Cursor or Claude Code; OpenCode uses the `skill` tool.\n","CLAUDE.md":"@AGENTS.md\n","apps/utools/README.md":"# uTools 插件打包指引\n\n该目录包含将微信 Markdown 编辑器打包为 [uTools](https://u.tools) 插件所需的脚本与配置。\n\n## 快速开始\n\n```sh\npnpm utools:package\n```\n\n该命令将完成以下动作：\n\n1. 调用 `pnpm --filter @md/web run build:utools` 构建前端资源至 `apps/utools/dist`，该构建将自动使用相对路径，确保在 uTools 的 `file://` 协议下能够正常加载。MathJax 从 `node_modules` 复制到构建产物中，Mermaid 作为 npm 模块打包。\n2. 将仓库根目录的版本号写入 `apps/utools/plugin.json`，保持与主项目同步。\n3. 从 `apps/web/public/mpmd/icon-256.png` 拷贝插件图标至 `apps/utools/logo.png`。\n4. 生成形如 `apps/utools/release/md-utools-vX.Y.Z.zip` 的安装包，可直接导入到 uTools。\n\n> 注意：命令执行前请确认已安装 pnpm 10+ 与 Node.js 22+，并在仓库根目录执行 `pnpm install` 安装依赖。\n\n## 手动导入调试\n\n1. 运行 `pnpm --filter @md/web run build:utools`。\n2. 打开 uTools，进入插件面板中的「开发者工具」。\n3. 选择「载入本地插件」，指向 `apps/utools` 目录即可。\n\n## 目录说明\n\n- `plugin.json`：uTools 插件的清单文件。\n- `preload.js`：在 uTools 渲染进程和 Web 前端之间建立通信的脚本，用于处理插件唤起事件。\n- `package.json`：将此目录标记为 CommonJS 模块以兼容 uTools。\n- `dist/`：由 Vite 构建输出的静态资源目录。\n- `release/`：运行打包命令后生成的插件安装包。\n","apps/utools/plugin.json":"{\n  \"pluginName\": \"微信 Markdown 编辑器\",\n  \"description\": \"Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用\",\n  \"version\": \"2.1.0\",\n  \"author\": \"doocs\",\n  \"homepage\": \"https://github.com/doocs/md\",\n  \"pluginType\": \"tool\",\n  \"platform\": [\n    \"win32\",\n    \"darwin\",\n    \"linux\"\n  ],\n  \"logo\": \"logo.png\",\n  \"main\": \"dist/index.html\",\n  \"preload\": \"preload.js\",\n  \"features\": [\n    {\n      \"code\": \"wechat-md\",\n      \"explain\": \"打开微信 Markdown 编辑器\",\n      \"cmds\": [\n        \"微信排版\",\n        \"Markdown 编辑器\",\n        \"doocs md\"\n      ]\n    }\n  ]\n}\n","docs/architecture.md":"# 架构概览\n\n本文档简述 doocs/md 的核心模块与数据流，供贡献者快速定位代码。\n\n## Monorepo 结构\n\n| 包               | 路径                  | 职责                                                                                            |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | Vue 3 主应用、WXT 浏览器扩展（Chrome/Firefox）、CF Workers 部署                                 |\n| `@md/api`        | `apps/api`            | 账户、云同步、计费、上传代理、分享链接、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID 为 `doocs.doocs-md`）                                |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包壳（构建产物来自 `@md/web`）                                                     |\n| `@md/core`       | `packages/core`       | Markdown → HTML 渲染引擎                                                                        |\n| `@md/shared`     | `packages/shared`     | 配置、类型、CodeMirror 编辑器封装、主题 CSS                                                     |\n| `@md/config`     | `packages/config`     | 共享 TypeScript 配置                                                                            |\n| `@doocs/md-cli`  | `packages/md-cli`     | 已发布 npm CLI（Express 静态服务）                                                              |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务（`render_markdown` 等工具）                                                            |\n\n独立示例（不在 pnpm workspace 内）：\n\n| 示例              | 路径                                   | 说明                    |\n| ----------------- | -------------------------------------- | ----------------------- |\n| 微信 OpenAPI 代理 | `docs/examples/wechat-openapi-worker/` | 最小 CF Worker 转发示例 |\n\n### 依赖关系\n\n```\napps/web, apps/vscode, packages/mcp-server\n  └── @md/core\n        └── @md/shared\n              └── @md/config (dev)\n```\n\n`@md/core` 与 `@md/shared` **直接导出 TypeScript 源码**，由消费方构建工具（Vite / webpack）编译。\n\n## 渲染管线\n\n```\nMarkdown 原文\n  → @md/core (marked + 自定义扩展)\n  → isomorphic-dompurify 净化\n  → 注入主题 CSS 变量 (@md/core/theme)\n  → HTML 输出（预览）\n  → juice 内联 CSS（仅复制到微信时，在 `@md/web` 导出层）\n  → 剪贴板 HTML（公众号）\n```\n\nWeb 端入口：\n\n1. `useRenderStore`（`apps/web/src/stores/render.ts`）调用 `initRenderer` / `renderMarkdown`\n2. `useThemeStore` 通过 `applyTheme` 将主题 CSS 写入 `<style>` 标签\n3. 编辑器内容变更经 debounce 后触发 `render()`\n\n扩展列表见 `packages/core/src/extensions/`（Mermaid、PlantUML、KaTeX、Ruby、alert、脚注等）。\n\n## Web 应用目录约定（`apps/web/src`）\n\n| 目录                 | 职责                                                                    |\n| -------------------- | ----------------------------------------------------------------------- |\n| `i18n/`              | vue-i18n 配置、locale 检测、按领域拆分的 message 模块                   |\n| `stores/`            | Pinia 全局状态，按领域划分                                              |\n| `composables/`       | 跨组件复用的响应式逻辑                                                  |\n| `services/`          | 外部 API 与领域服务（account / sync / share / upload / export）         |\n| `storage/`           | IndexedDB 抽象层、键前缀与安全读写                                      |\n| `lib/`               | 纯函数与浏览器辅助（bootstrap / browser / format / markdown / preview） |\n| `components/ui/`     | Shadcn-Vue 设计系统（无业务逻辑）                                       |\n| `components/editor/` | 编辑器主界面                                                            |\n| `components/ai/`     | AI 相关 UI                                                              |\n| `components/shared/` | 跨 feature 通用组件                                                     |\n| `entrypoints/`       | WXT 浏览器扩展入口                                                      |\n\n## 状态管理（Web）\n\nPinia stores 按领域划分：\n\n- `useEditorStore` — 编辑器实例与文档内容\n- `useThemeStore` — 主题与样式（含 per-theme 配置持久化）\n- `useRenderStore` — 渲染结果与目录标题\n- `useUIStore` — 布局、对话框、视图模式\n- `useLocaleStore` — 界面语言（zh-CN / zh-TW / en-US / ja-JP），同步 `document.title` 与 i18n 实例\n- `useSyncStore` / `useAuthStore` — 云同步与账户\n- `useMarketplaceStore` — 主题/组件市场目录、安装与发布\n- `useConfirmStore` — 全局确认对话框（`components/shared/confirm-dialog/`）\n\n样式变更后通过 `useEditorRefresh()`（`apps/web/src/composables/useEditorRefresh.ts`）触发预览重渲染。\n\n## 云同步\n\n- **白名单**：`apps/web/src/services/sync/settings.ts` 中的 `SYNC_SETTING_KEYS`（含 `marketplace_installed_themes` / `marketplace_installed_components`）\n- **合并策略**：LWW，元数据存于 `sync_settings_meta`\n- **热更新**：远端设置应用后由 `hydrateSyncedSettings`（`services/sync/hydrate.ts`）写入 Store（含 `locale`），无需刷新页面\n- **用户说明**：见 [cloud-sync.md](./cloud-sync.md)\n\n## 主题 / 组件市场\n\n- **API**：`/marketplace/*`（公开浏览；登录发布；`ADMIN_GITHUB_LOGINS` 审核）\n- **主题包**：安装后以 `mp:<uuid>` 作为独立主题出现在主题选择器；CSS 经 `applyTheme({ themeCSS })` 动态注入\n- **组件包**：安装后写入 `custom_components` 注册表\n- **Web UI**：`MarketplaceDialog`（文件菜单 / 右侧主题栏 / 组件对话框入口）\n\n## 本地存储\n\n- **IndexedDB**（`apps/web/src/storage/`）：文章正文、偏好设置、图床/AI 密钥、缓存分层存储\n- **StorageEngine 抽象**（`storage/manager.ts`）：`store.reactive()` / `store.getJSON()` 统一入口\n- **文章持久化**：`documentRepo` 按篇读写，避免整包 JSON 写入\n- **云同步元数据**：`services/sync/settings.ts` 通过 `store` 读写设置白名单\n- **配额提示**：`storage/quota.ts`（IndexedDB 配额远大于 localStorage，保留 toast 兜底）\n\n### 启动顺序\n\n1. `main.ts` → `bootstrap()`（`apps/web/src/bootstrap.ts`）\n2. `initComponentDarkVars()` + `setupComponents()`\n3. `await initStorage()`（迁移 localStorage、预加载 KV 缓存、加载文档）\n4. `setupI18n(detectInitialLocale())` + `setAppI18n()`，注册 vue-i18n 插件\n5. `createApp`、Pinia、`useLocaleStore()` 并挂载\n6. `App.vue` 中 `usePlatformEnv()`、`useAccountSyncBootstrap()`、`useDeepLinkImport()` 完成账户与深链引导\n\n### 国际化（i18n）\n\n- **范围**：`apps/web` 主应用 UI；扩展 popup / background 部分文案。VS Code、uTools、CLI、MCP 无 i18n。\n- **入口**：`apps/web/src/i18n/`（`detect.ts`、`translate.ts`、`messages/`）\n- **偏好**：`PreferencesDialog`（文件菜单或 `Ctrl+,`）→ General → Language\n- **动态 UI**：命令面板、快捷键列表、Slash 命令、CodeMirror placeholder 等在 `locale` 变化时重建；Store 内 toast 使用 `@/i18n/translate` 的 `t()`\n\n## 构建\n\n- Web：Vite 8，`manualChunks` 拆分 codemirror、katex、highlight 等\n- VSCode 扩展：webpack，预览渲染复用 `@md/core`（见 `apps/vscode/src/previewRenderer.ts`）\n- 浏览器扩展：WXT，`src/entrypoints/` 为入口\n- Core / Shared：**直接导出 TypeScript 源码**，由消费方构建工具编译\n\n## 静态资源\n\nWeb 应用静态资源统一放在 `apps/web/public/`（如 `mpmd/` 图标）。根目录不再有 `public/` 副本。\n","packages/core/README.md":"# @md/core\n\nMarkdown 渲染引擎：将 Markdown 转为适合微信公众号的 HTML。\n\n## 导出\n\n| 路径                  | 说明                                                      |\n| --------------------- | --------------------------------------------------------- |\n| `@md/core`            | 主入口：`initRenderer`、`renderMarkdown`、`applyTheme` 等 |\n| `@md/core/renderer`   | 渲染器实现                                                |\n| `@md/core/extensions` | marked 扩展（Mermaid、KaTeX、alert 等）                   |\n| `@md/core/utils`      | `postProcessHtml`、`renderMarkdown` 辅助                  |\n| `@md/core/theme`      | 主题注入与 CSS 变量                                       |\n\n## 基本用法\n\n```ts\nimport { initRenderer, renderMarkdown } from '@md/core'\nimport { postProcessHtml } from '@md/core/utils'\n\nconst renderer = initRenderer({\n  isMacCodeBlock: true,\n  isShowLineNumber: true,\n})\n\nconst html = postProcessHtml(renderMarkdown(renderer, markdown))\n```\n\n主题样式需配合 `@md/core/theme` 的 `applyTheme` 或 Web 端 `useThemeStore.applyCurrentTheme()` 注入 CSS。\n\n## 扩展\n\n扩展位于 `src/extensions/`，在 `renderer-impl.ts` 中注册。新增扩展时：\n\n1. 在 `src/extensions/` 实现 marked 扩展\n2. 在 `src/extensions/index.ts` 导出\n3. 在 `initRenderer` 中注册\n\n## 依赖说明\n\n- **marked** — Markdown 解析\n- **highlight.js** — 代码高亮\n- **mermaid / @antv/infographic** — 图表（按需加载仍建议在消费方做 code-splitting）\n- **isomorphic-dompurify** — HTML 净化（`sanitizeHtml`）\n- **juice** — CSS 内联（仅 Web 端复制到微信时使用，不在本包内）\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n","packages/mcp-server/README.md":"# @md/mcp-server\n\nMCP (Model Context Protocol) server for [doocs/md](https://github.com/doocs/md).\n\nExposes the `doocs/md` markdown rendering engine and AI service configuration to AI agent runtimes (Claude Desktop, Cursor, VS Code Copilot, etc.) via the standard MCP protocol over **stdio**.\n\n## Prerequisites\n\n- **Node.js** ≥ 22.22.2（与 monorepo 根目录 `.nvmrc` 一致）\n- **pnpm** ≥ 9（monorepo workspace）\n- Clone the monorepo and install dependencies:\n\n```bash\ngit clone https://github.com/doocs/md.git\ncd md\npnpm install\n```\n\n## Tools\n\n### `render_markdown`\n\nConvert Markdown text to styled HTML using the full doocs/md rendering pipeline.\n\n| Parameter          | Type                               | Default     | Description                                            |\n| ------------------ | ---------------------------------- | ----------- | ------------------------------------------------------ |\n| `markdown`         | `string`                           | —           | Markdown source text                                   |\n| `theme`            | `\"default\" \\| \"grace\" \\| \"simple\"` | `\"default\"` | Visual theme (经典 / 优雅 / 简洁)                      |\n| `primaryColor`     | `string (hex)`                     | `\"#0F4C81\"` | Primary accent color (see `list_colors`)               |\n| `fontFamily`       | `string`                           | 无衬线预设  | Font family stack (see `list_fonts`)                   |\n| `fontSize`         | `string (px)`                      | `\"16px\"`    | Base font size (see `list_font_sizes`)                 |\n| `legend`           | `string`                           | `\"alt\"`     | Image caption format (see `list_legend_formats`)       |\n| `isMacCodeBlock`   | `boolean`                          | `false`     | Render code blocks with a macOS-style title bar        |\n| `isShowLineNumber` | `boolean`                          | `false`     | Show line numbers in code blocks                       |\n| `citeStatus`       | `boolean`                          | `false`     | Convert links to footnote-style citations              |\n| `countStatus`      | `boolean`                          | `false`     | Prepend a reading-time estimate                        |\n| `themeMode`        | `\"light\" \\| \"dark\"`                | `\"light\"`   | Color mode for diagram extensions                      |\n| `isUseIndent`      | `boolean`                          | `false`     | Indent paragraph first lines                           |\n| `isUseJustify`     | `boolean`                          | `false`     | Justify paragraph text                                 |\n| `headingStyles`    | `object`                           | `{}`        | Per-level heading styles (see `list_heading_styles`)   |\n| `codeBlockTheme`   | preset URL                         | GitHub 主题 | highlight.js preset from `list_code_block_themes` only |\n| `customCSS`        | `string`                           | `\"\"`        | Additional custom CSS (highest priority)               |\n\nReturns `{ html, frontMatter, readingTime: { words, minutes } }`.\n\n### Other tools\n\n| Tool                     | Description                                                                       |\n| ------------------------ | --------------------------------------------------------------------------------- |\n| `list_themes`            | List all available visual themes with labels and authors                          |\n| `list_colors`            | List all available primary accent colors                                          |\n| `list_fonts`             | List preset font family options                                                   |\n| `list_font_sizes`        | List preset font size options                                                     |\n| `list_legend_formats`    | List image caption format options                                                 |\n| `list_heading_styles`    | List heading style presets                                                        |\n| `list_code_block_themes` | List highlight.js code block theme URLs                                           |\n| `list_ai_services`       | List all built-in AI service providers with endpoints and models                  |\n| `explain_extensions`     | Describe every Markdown extension beyond CommonMark (KaTeX, Mermaid, PlantUML, …) |\n| `get_renderer_options`   | Describe all renderer configuration options                                       |\n\n## Setup\n\n### VS Code (GitHub Copilot)\n\nAdd to `.vscode/mcp.json` in the project root (already included in this repo):\n\n```json\n{\n  \"servers\": {\n    \"md\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"--import\", \"tsx/esm\", \"${workspaceFolder}/packages/mcp-server/run.mjs\"],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open the **MCP** panel in VS Code and start the `md` server.\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"C:/path/to/md/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"C:/path/to/md/packages/mcp-server\"\n    }\n  }\n}\n```\n\nReplace `C:/path/to/md` with the absolute path to your cloned repository.\n\n### Cursor\n\nAdd to `.cursor/mcp.json` at the project root (already included in this repo):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open **Cursor Settings → MCP** and enable the `md` server.\n\n### Windsurf / Other MCP Clients\n\nUse the same stdio pattern:\n\n```json\n{\n  \"command\": \"node\",\n  \"args\": [\"--import\", \"tsx/esm\", \"/absolute/path/to/packages/mcp-server/run.mjs\"],\n  \"cwd\": \"/absolute/path/to/packages/mcp-server\"\n}\n```\n\n## Example Prompts\n\nOnce the server is connected, you can ask your AI assistant:\n\n```\n使用 grace 主题将下面的 Markdown 渲染为 HTML，开启代码行号：\n# Hello World\n```\n\n```\n列出所有可用主题，并解释每个主题的风格特点。\n```\n\n```\nrender_markdown 支持哪些 Markdown 扩展？给我每个扩展的示例写法。\n```\n\n```\n列出所有内置 AI 服务，帮我找一个支持 DeepSeek-V3 的接入点。\n```\n\n## Development\n\n```bash\n# Run server directly (connects to stdin/stdout — for manual testing)\npnpm --filter @md/mcp-server start\n\n# Watch mode (auto-restart on changes)\npnpm --filter @md/mcp-server dev\n```\n\nTo test manually, use [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector node --import tsx/esm run.mjs\n```\n","packages/md-cli/README.md":"# md-cli\n\nA powerful yet simple tool for rendering Markdown documents locally during development.\n\n## Installation\n\nTo get started with `md-cli`, you can install it either globally or locally, depending on your needs.\n\n### Install locally\n\nIf you only need it for a specific project, you can install it locally by running:\n\n```bash\nnpm install @doocs/md-cli\n```\n\n### Install globally\n\nFor global access across all your projects, install it globally with:\n\n```bash\nnpm install -g @doocs/md-cli\n```\n\n## Usage\n\nOnce installed, running `md-cli` is a breeze. Here’s how to get started:\n\n### Default setup\n\nTo launch `md-cli` with the default settings, simply run:\n\n```bash\nmd-cli\n```\n\n### Custom port\n\nIf you prefer to run `md-cli` on a different port, say `8899`, just specify it like this:\n\n```bash\nmd-cli port=8899\n```\n\n## Maintainers\n\n- [yanglbme](https://github.com/yanglbme) – Core maintainer.\n- [YangFong](https://github.com/yangfong) – Core maintainer.\n- [xw](https://github.com/wll8) – Contributor.\n- [thinkasany](https://www.npmjs.com/~thinkerwing) – Contributor.\n","packages/shared/README.md":"# @md/shared\n\n跨应用共享的配置、类型、工具与 CodeMirror 编辑器封装。\n\n## 导出\n\n| 路径                   | 说明                                   |\n| ---------------------- | -------------------------------------- |\n| `@md/shared`           | 主入口                                 |\n| `@md/shared/configs`   | 主题、字体、颜色等默认配置与选项列表   |\n| `@md/shared/constants` | 常量                                   |\n| `@md/shared/types`     | 共享 TypeScript 类型                   |\n| `@md/shared/utils`     | fetch、tokenTools 等工具               |\n| `@md/shared/editor`    | CodeMirror 6 setup、格式化命令、快捷键 |\n\n## 主要配置（`configs`）\n\n- `themeOptions` / `defaultStyleConfig` — 主题名与默认样式\n- `defaultPerThemeSettings` — 每个主题的独立配置结构\n- `fontFamilyOptions` / `fontSizeOptions` / `colorOptions` — 样式面板选项\n- `ctrlKey` / `ctrlSign` — 平台相关快捷键展示\n\n主题 CSS 源文件位于 `src/configs/theme-css/`（如 `default.css`、`grace.css`）。\n\n## 编辑器（`editor`）\n\nWeb 与 VSCode 扩展共用 CodeMirror 配置：\n\n```ts\nimport { applyHeading, formatBold, markdownSetup, theme } from '@md/shared/editor'\n```\n\n## 消费方\n\n- `apps/web` — 主编辑器 UI\n- `apps/vscode` — VSCode 预览侧边栏\n- `packages/core` — 渲染相关类型与工具\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Instructions\n\n本文件为 AI Agent（Claude Code、OpenCode、Cursor、Copilot 等）在本仓库中工作时提供统一入口。\n\n## 项目概览\n\n**doocs/md** — 一款微信 Markdown 编辑器，将 Markdown 渲染为微信公众号文章格式。支持自定义主题样式、多图床、AI 助手、浏览器扩展、**zh-CN / zh-TW / en-US / ja-JP 界面**等特性。\n\n- **在线地址:** https://md.doocs.org\n- **Node 版本:** >= 22.22.2（`.nvmrc`: v22.22.2）\n- **包管理器:** pnpm（monorepo）\n- **npm 镜像:** https://registry.npmmirror.com（`.npmrc`）\n\n## Monorepo 结构\n\n| 工作区           | 路径                  | 说明                                                                                                  |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | 主应用，Vue 3 + 浏览器扩展（WXT: Chrome/Firefox）                                                     |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID: `doocs.doocs-md`）                                        |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包                                                                                       |\n| `@md/core`       | `packages/core`       | 核心 Markdown 渲染引擎（marked + 自定义扩展）                                                         |\n| `@md/shared`     | `packages/shared`     | 共享工具函数、配置、类型、编辑器配置                                                                  |\n| `@md/config`     | `packages/config`     | TypeScript 配置基础文件                                                                               |\n| `@doocs/md-cli`  | `packages/md-cli`     | CLI 工具（Express 服务托管构建产物）                                                                  |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务，为 AI Agent 暴露接口                                                                        |\n| `@md/api`        | `apps/api`            | 后端 API：账户、云同步、计费、上传代理、分享、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n\n独立示例（不在 workspace 内）：`docs/examples/wechat-openapi-worker/` — 微信公众号 OpenAPI 代理 Worker。\n\n## 常用命令\n\n### 根目录\n\n```bash\npnpm install          # 安装所有依赖\npnpm start            # 等同于 `pnpm web dev`\npnpm run lint         # ESLint --fix 全项目检查\npnpm run type-check   # vue-tsc 类型检查\npnpm run build:cli    # 构建 web + 复制到 md-cli + npm pack\npnpm run release:cli  # 通过 scripts/release.js 发布 CLI\npnpm utools:package   # 打包 uTools 插件\npnpm run inspector    # node-modules-inspector 查看依赖树\n```\n\n### Web 应用 (`@md/web`)\n\n```bash\npnpm web dev          # 启动 Vite 开发服务器\npnpm web build        # 生产构建 + 类型检查\npnpm web build:h5-netlify   # 构建用于 Netlify 根目录部署\npnpm web build:analyze      # 构建并生成 rollup-plugin-visualizer 分析\npnpm web ext:dev      # WXT Chrome 扩展开发模式\npnpm web ext:zip      # 打包 Chrome 扩展\npnpm web firefox:dev  # WXT Firefox 扩展开发模式\npnpm web firefox:zip  # 打包 Firefox 扩展\npnpm web wrangler:dev    # Cloudflare Workers 开发\npnpm web wrangler:deploy   # Cloudflare Workers 部署\n```\n\n### VSCode 扩展\n\n```bash\npnpm vscode compile   # webpack 编译\npnpm vscode watch     # webpack 监听\npnpm vscode build     # 生产 webpack 构建\npnpm vscode package   # vsce 打包\n```\n\n### CLI & MCP\n\n```bash\npnpm cli <cmd>        # 在 @doocs/md-cli 中执行命令\npnpm mcp <cmd>        # 在 @md/mcp-server 中执行命令（render_markdown 等 MCP 工具）\npnpm mcp dev          # MCP Server 监听模式\n```\n\n`@md/mcp-server` 通过 stdio 暴露 `render_markdown`、`list_themes`、`list_colors` 等工具，配置见 [packages/mcp-server/README.md](./packages/mcp-server/README.md)、[`.vscode/mcp.json`](./.vscode/mcp.json) 与 [`.cursor/mcp.json`](./.cursor/mcp.json)。\n\n## 架构\n\n### 渲染管线\n\n1. `@md/core` 封装 `marked`，实现自定义扩展（Mermaid、PlantUML、Ruby、KaTeX、TOC、alert 块、infographic、slider、markup、emoji、脚注）\n2. `juice` 内联 CSS 以兼容微信\n3. `isomorphic-dompurify` 净化输出\n4. 主题系统（`@md/core/src/theme/`）注入 CSS 变量\n\n### 构建系统\n\n- **`@md/core` 和 `@md/shared` 直接导出 TypeScript 源码**（不预构建）。由消费方的构建工具（Vite/webpack）编译。\n- Web 应用使用 Vite 8，VSCode 扩展使用 webpack，浏览器扩展使用 WXT\n\n### 样式与主题\n\n- Web 应用使用 Tailwind CSS 4 + PostCSS\n- 主题 CSS 文件位于 `packages/shared/src/configs/theme-css/`（default.css、grace.css、simple.css）\n- 部分主题文件使用 Less\n\n### 状态管理\n\n- Pinia store 位于 `apps/web/src/stores/`（按领域划分：`useEditorStore`、`useThemeStore`、`useUiStore`、`useLocaleStore` 等）\n- UI 组件遵循 Shadcn-Vue 模式，位于 `apps/web/src/components/ui`\n- 跨 feature 通用组件位于 `apps/web/src/components/shared`\n- 架构详情见 [docs/architecture.md](./docs/architecture.md)\n\n### 国际化（i18n，`@md/web`）\n\nWeb 主应用与部分浏览器扩展 UI 支持 **zh-CN**、**zh-TW**、**en-US**、**ja-JP**；VS Code 扩展、uTools、CLI、MCP **未**国际化。\n\n- **库**：`vue-i18n`（composition API，`legacy: false`），在 `apps/web/vite.config.ts` 中通过 `unplugin-auto-import` 自动导入 `useI18n`\n- **文案**：`apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`（`common`、`editor`、`dialog`、`store`、`ai`、`upload`、`chrome`、`marketplace`、`notifications`）\n- **组件内**：`useI18n()` + `t('key')`；**Store / 工具函数**：`@/i18n/translate` 的 `t()` / `getLocale()` / `formatLocalDateTime()`\n- **语言状态**：`useLocaleStore`（持久化 key：`locale`）；用户可在 **偏好设置**（`Ctrl+,`）→ General 切换\n- **启动**：`await initStorage()` → `setupI18n(detectInitialLocale())` → Pinia → `useLocaleStore()`（见 `apps/web/src/bootstrap.ts`）；`index.html` 启动屏从 `localStorage` 读取 locale\n- **云同步**：`locale` 在 `SYNC_SETTING_KEYS` 中，远端应用后由 `hydrateSyncedSettings` 热更新\n- **约定**：新增用户可见文案须同时维护 zh-CN、zh-TW、en-US 与 ja-JP；在 computed 中调用 `t()` 且需随语言切换更新时，应依赖 `locale`（例如 `void locale.value`）\n\n## Lint 与格式化\n\n- **ESLint:** `@antfu/eslint-config` + Vue + TypeScript + formatter\n- **Prettier:** 固定版本 `2.8.8`（通过 `pnpm-workspace.yaml` 的 `overrides` 强制）\n- **Pre-commit 钩子:** `lint-staged` 对所有文件执行 `eslint --fix`\n- 规则：不使用分号，关闭 `no-unused-vars`、`no-console`、`no-debugger`\n- **代码注释：** 统一英文。保留非显而易见的 why / 约束 / 兼容性说明；删除复述下一行代码的噪音注释。勿改动 `i18n/messages` 等用户可见文案。\n\n## 依赖管理\n\n这是一个 pnpm monorepo，`pnpm-workspace.yaml` 中包含大量安全覆盖（overrides）。\n\n### 升级依赖\n\n1. **共享版本用 catalog** — 跨包共用的工具链版本集中在 `pnpm-workspace.yaml` 的 `catalog`（`typescript`、`vitest`、`wrangler`、`@types/node`、`marked`、`@codemirror/state|view` 等）；workspace 内各 `package.json` 用 `\"catalog:\"` 引用。**仓库根 `package.json` 因 `private: false` 可被 npm 消费，须写普通 semver，勿用 `catalog:`。**包专属依赖可继续写版本号（`pnpm/json-enforce-catalog` 已关闭）\n2. **Prettier 必须固定在 `2.8.8`** — 通过 catalog + `overrides.prettier` 强制（根 package 直接写 `2.8.8`）\n3. **Patch 文件：** 如果打了 patch 的依赖升级了，必须同步更新 `patches/` 中对应的 patch 文件：\n   - `@codemirror/view` → `patches/@codemirror__view@6.43.15.patch`（导出 `MeasureRequest` 接口，修复 macOS 上 Alt+Shift 快捷键处理）\n   - `mermaid` → `patches/mermaid@12.2.0.patch`（流程图 HTML 标签在非整数 DPR 下按宽度换行，避免文字被裁切）\n   - `juice` 12.2.0 已在上游处理 `parseCSS` 空返回值，不再需要本地 patch\n4. 更新 `pnpm-workspace.yaml` 中的 `patchedDependencies` 以匹配新版本\n5. 运行 `pnpm install` 重新生成 `pnpm-lock.yaml`；可用 `pnpm dedupe` 收敛可合并的间接依赖\n\n### 安全覆盖\n\n`pnpm-workspace.yaml` 的 `overrides` 部分强制了存在漏洞的间接依赖的最低版本（ajv、dompurify、undici、minimatch 等）。除非上游已修复漏洞，否则不要移除这些覆盖。\n\n### allowBuilds\n\n`pnpm-workspace.yaml` 包含 `allowBuilds` 列表，用于需要原生构建脚本的依赖（`esbuild`、`sharp`、`keytar`、`workerd` 等）。新增需要原生构建的依赖可能需要添加到此列表。\n\n## Git 规范\n\n- **提交信息 / PR 标题:** 遵循 Conventional Commits（`feat`、`fix`、`docs`、`style`、`refactor`、`perf`、`test`、`build`、`chore`），**一律使用英文**（见 `CONTRIBUTING.md`）\n- **分支命名:** `feat/description`、`fix/description`、`docs/description`；其他类型用 `<type>/`\n- **PR 说明:** 按 [`.github/pull_request_template.md`](./.github/pull_request_template.md) 填写；无关联 Issue 时不要写 Related Issue 占位符\n\n## Skills\n\nReusable workflows live in [`.agents/skills/`](./.agents/skills/) (canonical). Claude Code discovers each skill through a git symlink:\n\n```text\n.claude/skills/<name> → ../../.agents/skills/<name>\n```\n\n| Skill        | When to use                                                                           |\n| ------------ | ------------------------------------------------------------------------------------- |\n| `git-commit` | Commit changes with Conventional Commits (`/git-commit` or \"commit my changes\")       |\n| `create-pr`  | Create a GitHub pull request (`/create-pr` or \"open a PR\")                            |\n| `wechat-svg` | WeChat SVG whitelist, bubbling-group interaction, paste compatibility (`/wechat-svg`) |\n\nInvoke manually: `/skill-name` in Cursor or Claude Code; OpenCode uses the `skill` tool.\n","isInternal":false,"tokens":3234,"sizeBytes":10410},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"@AGENTS.md\n","isInternal":false,"tokens":5,"sizeBytes":11},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# Copilot Instructions\n\nThis repository is a pnpm monorepo for **doocs/md**, a WeChat Markdown editor. Canonical agent guidance lives in [AGENTS.md](../AGENTS.md); keep this file aligned with it.\n\n- **Node:** `>=22.22.2` (`.nvmrc`: v22.22.2)\n- **Package manager:** pnpm (`packageManager` in the root `package.json`)\n- **npm registry:** https://registry.npmmirror.com (`.npmrc`)\n\n## Build, Test, and Lint\n\n### Global Commands\n\n- **Install:** `pnpm install`\n- **Lint (ESLint + Prettier):** `pnpm run lint`\n- **Type Check:** `pnpm run type-check`\n- **Tests:** `pnpm run test` (`@md/shared`, `@md/core`, `@md/web`, `@md/api`)\n\n### Web App (`@md/web`)\n\n- **Development Server:** `pnpm web dev`\n- **Production Build:** `pnpm web build`\n- **Browser Extension:** `pnpm web ext:zip` (WXT; Chrome) / `pnpm web firefox:zip`\n\n### Other Workspaces\n\n- **API (`@md/api`):** `pnpm api dev` / `pnpm api test`\n- **VS Code (`doocs-md`):** `pnpm vscode compile` / `pnpm vscode package`\n- **CLI (`@doocs/md-cli`):** `pnpm run build:cli`\n- **MCP (`@md/mcp-server`):** `pnpm mcp dev`\n- **uTools (`@md/utools`):** `pnpm utools:package`\n\n## High-Level Architecture\n\n### Monorepo Structure\n\n- **`apps/web`**: Vue 3 + Vite + Pinia + Tailwind CSS 4. Web app and browser extension (WXT).\n- **`apps/api`**: Cloudflare Workers + Hono + D1 (auth, cloud sync, billing, upload, share, marketplace, emoji).\n- **`apps/vscode`**: VS Code extension (webpack). Marketplace ID: `doocs.doocs-md`.\n- **`apps/utools`**: uTools plugin packaging shell (artifacts from `@md/web`).\n- **`packages/core`**: Markdown renderer (`marked` + custom extensions, theme CSS variables).\n- **`packages/shared`**: Shared config, types, CodeMirror wrapper, theme CSS.\n- **`packages/config`**: Shared TypeScript config.\n- **`packages/md-cli`**: Published npm CLI that serves the built web app.\n- **`packages/mcp-server`**: MCP tools (`render_markdown`, `list_themes`, `list_colors`).\n- **`docs/examples/wechat-openapi-worker/`**: standalone WeChat OpenAPI proxy (not in the pnpm workspace).\n\nDetails: [docs/architecture.md](../docs/architecture.md).\n\n### Key Technologies\n\n- **Frontend:** Vue 3 (Composition API), Pinia, Tailwind CSS 4 + PostCSS\n- **Editor:** CodeMirror 6\n- **Markdown:** `marked` in `@md/core`; `juice` inlines CSS for WeChat paste; `isomorphic-dompurify` sanitizes output\n- **Web build:** Vite 8; extension build: WXT\n- **API:** Hono on Cloudflare Workers, D1\n- **i18n (web only):** `vue-i18n` — zh-CN, zh-TW, en-US, ja-JP\n\n## Key Conventions\n\n### Development Patterns\n\n- **`@md/core` and `@md/shared` export TypeScript source** (`src/index.ts`). Do not pre-build them; consumers (Vite/webpack) compile them.\n- **UI:** Shadcn-Vue components in `apps/web/src/components/ui`. Prefer these over raw HTML/CSS.\n- **Stores:** Domain Pinia stores in `apps/web/src/stores` (`useEditorStore`, `useThemeStore`, `useUiStore`, `useLocaleStore`, …).\n- **Comments:** English only. Explain non-obvious why / constraints; do not narrate the next line. Do not rewrite user-facing i18n copy unless asked.\n\n### Internationalization (`@md/web`)\n\n- Messages: `apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`\n- Components: `useI18n()` + `t('key')`. Stores/utils: `@/i18n/translate`.\n- New user-visible strings must be added in all four locales. VS Code, uTools, CLI, and MCP are not localized.\n\n### Styling & Theming\n\n- Theme injection: `@md/core/src/theme` (CSS variables).\n- Theme CSS sources: `packages/shared/src/configs/theme-css/` (`default.css`, `grace.css`, `simple.css`).\n\n### Markdown Extensions\n\n- Implement new Markdown features as extensions in `packages/core/src/extensions`.\n- Register them in the renderer configuration.\n\n### Dependencies\n\n- Shared toolchain versions live in `pnpm-workspace.yaml` `catalog`; workspace packages use `\"catalog:\"`.\n- Root `package.json` is publishable (`private: false`) — use plain semver there, not `catalog:`.\n- Prettier is pinned to **2.8.8**. Do not remove security `overrides` unless upstream fixed the CVE.\n- If a patched dependency is upgraded, update the matching file in `patches/` and `patchedDependencies`.\n\n### Git Conventions\n\n- **Commit messages and PR titles:** Conventional Commits, **English** (`feat`, `fix`, `docs`, `chore`, …).\n- **Branches:** `feat/description`, `fix/description`, `docs/description`; other types use `<type>/`.\n- Never commit on `main`. Follow `.github/pull_request_template.md` when opening a PR.\n\n### Agent Skills\n\nCanonical workflows: `.agents/skills/` (`git-commit`, `create-pr`, `wechat-svg`). Claude Code discovers them via git symlinks under `.claude/skills/`.\n","isInternal":false,"tokens":1302,"sizeBytes":4605},{"name":"SKILL.md","path":".agents/skills/create-pr/SKILL.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.agents/skills/create-pr/SKILL.md","title":"create-pr","category":"anthropic-skill","format":"markdown","content":"---\nname: create-pr\ndescription: Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool.\n---\n\n# Create PR\n\nThis skill guides you through creating a well-structured GitHub pull request that follows project conventions and best practices.\n\nDo **not** assume Bash. On Windows PowerShell, avoid `&&`, `$(...)`, and POSIX tests; run git/`gh` commands as separate invocations and use `$env:TEMP` for the PR body file.\n\n## Prerequisites Check\n\nBefore proceeding, verify the following:\n\n### 1. Check if `gh` CLI is installed\n\n```bash\ngh --version\n```\n\nIf not installed, inform the user:\n> The GitHub CLI (`gh`) is required but not installed. Please install it:\n> - macOS: `brew install gh`\n> - Other: https://cli.github.com/\n\n### 2. Check if authenticated with GitHub\n\n```bash\ngh auth status\n```\n\nIf not authenticated, guide the user to run `gh auth login`.\n\n### 3. Verify clean working directory\n\n```bash\ngit status\n```\n\nIf there are uncommitted changes, ask the user whether to:\n- Commit them as part of this PR\n- Stash them temporarily\n- Discard them (with caution)\n\n## Gather Context\n\n### 1. Identify the current branch\n\n```bash\ngit branch --show-current\n```\n\nEnsure you're not on `main` or `master`. If so, ask the user to create or switch to a feature branch.\n\n### 2. Find the base branch\n\nResolve the default branch once and reuse it as `BASE_BRANCH`. Do **not** assume Bash (`$(...)`, `sed`, `[ -z ... ]` fail in PowerShell).\n\n```bash\ngit symbolic-ref refs/remotes/origin/HEAD\n```\n\nThis prints `refs/remotes/origin/<branch>` (usually `main`). Use the last path segment.\n\n```powershell\n# PowerShell\n$BASE_BRANCH = (git symbolic-ref refs/remotes/origin/HEAD).Split('/')[-1]\n```\n\nIf that fails, run `git remote show origin` and parse the `HEAD branch:` line.\n\nThis is typically `main` or `master`, but may differ per repo.\n\n### 3. Analyze recent commits relevant to this PR\n\n```bash\n# Bash / zsh\ngit log \"origin/${BASE_BRANCH}..HEAD\" --oneline --no-decorate\n```\n\n```powershell\n# PowerShell\ngit log \"origin/$BASE_BRANCH..HEAD\" --oneline --no-decorate\n```\n\nReview these commits to understand:\n- What changes are being introduced\n- The scope of the PR (single feature/fix or multiple changes)\n- Whether commits should be squashed or reorganized\n\n### 4. Review the diff\n\n```bash\n# Bash / zsh\ngit diff \"origin/${BASE_BRANCH}..HEAD\" --stat\n```\n\n```powershell\n# PowerShell\ngit diff \"origin/$BASE_BRANCH..HEAD\" --stat\n```\n\nThis shows which files changed and helps identify the type of change.\n\n## Information Gathering\n\nBefore creating the PR, you need the following information. Check if it can be inferred from:\n- Commit messages\n- Branch name (e.g., `fix/upload-timeout`, `feat/custom-shortcuts`)\n- Changed files and their content\n\nIf any critical information is missing, ask the user directly:\n\n### Required Information\n\n1. **Related Issue Number** (optional): Look for patterns like `#123`, `fixes #123`, or `closes #123` in commit messages. If none is found, **omit the Related Issue section** from the PR body — do not use placeholders like `#XXXX`.\n2. **Description**: What problem does this solve? Why were these changes made?\n3. **Type of Change**: Bug fix, new feature, breaking change, refactor, cosmetic, documentation, or workflow\n4. **Test Procedure**: How was this tested? What could break?\n\nOnly ask about a related issue when the change clearly looks like it should close one (e.g. branch name `fix/issue-123`). For small or self-contained changes, skip the question and leave the section out.\n\n## Git Best Practices\n\nBefore creating the PR, consider these best practices:\n\n### Commit Hygiene\n\n1. **Atomic commits**: Each commit should represent a single logical change\n2. **Clear commit messages**: Follow conventional commit format when possible\n3. **No merge commits**: Prefer rebasing over merging to keep history clean\n\n### Branch Management\n\n1. **Rebase on latest base branch** (if needed):\n   ```bash\n   git fetch origin\n   git rebase \"origin/${BASE_BRANCH}\"\n   ```\n   In PowerShell, use `\"origin/$BASE_BRANCH\"`.\n\n2. **Squash if appropriate**: If history is messy, ask the user whether they want commits squashed. Do **not** run `git rebase -i` (interactive; agents cannot complete it).\n\n### Push Changes\n\nEnsure all commits are pushed:\n```bash\ngit push origin HEAD\n```\n\nIf the branch was rebased, you may need:\n```bash\ngit push origin HEAD --force-with-lease\n```\n\n## Create the Pull Request\n\nUse `CONTRIBUTING.md` (Pull Request 流程) as the source of truth for PR content. Follow [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) exactly:\n\n- **Summary** — what changed and why\n- **Type of Change** — check applicable boxes\n- **Test Procedure** — how you verified the change\n- **Pre-flight Checklist** — mark items that apply\n\nWhen filling out the PR body:\n- Fill in all template sections with relevant information gathered from commits and context\n- Mark the appropriate \"Type of Change\" checkbox(es)\n- Complete the \"Pre-flight Checklist\" items that apply\n- **Related Issue is not in the template.** Add a `## Related Issue` section with `Closes #123` only when this PR actually fixes an issue. Never add `#XXXX` or an empty Related Issue heading.\n\n### Create PR with gh CLI\n\n**Use a temporary file for the PR body** to avoid shell escaping issues, newline problems, and other command-line flakiness:\n\n1. Write the PR body to a temporary file (`$env:TEMP/pr-body.md` on Windows PowerShell, `/tmp/pr-body.md` on macOS/Linux).\n\n2. Create the PR using the file:\n\n   ```bash\n   # Bash / zsh\n   gh pr create --title \"PR_TITLE\" --body-file /tmp/pr-body.md --base \"$BASE_BRANCH\"\n   ```\n\n   ```powershell\n   # PowerShell\n   gh pr create --title \"PR_TITLE\" --body-file \"$env:TEMP/pr-body.md\" --base $BASE_BRANCH\n   ```\n\n3. Clean up the temporary file after the PR is created.\n\nFor draft PRs, add `--draft` to the same command.\n\n**Why use a file?** Passing complex markdown with newlines, special characters, and checkboxes directly via `--body` is error-prone. The `--body-file` flag handles all content reliably.\n\n## Post-Creation\n\nAfter creating the PR:\n\n1. **Display the PR URL** so the user can review it\n2. **Remind about CI checks**: Tests and linting will run automatically\n3. **Suggest next steps**:\n   - Add reviewers if needed: `gh pr edit --add-reviewer USERNAME`\n   - Add labels if needed: `gh pr edit --add-label \"bug\"`\n\n## Error Handling\n\n### Common Issues\n\n1. **No commits ahead of base branch**: The branch has no changes to submit\n   - Ask if the user meant to work on a different branch\n\n2. **Branch not pushed**: Remote doesn't have the branch\n   - Push the branch first: `git push -u origin HEAD`\n\n3. **PR already exists**: A PR for this branch already exists\n   - Show the existing PR: `gh pr view`\n   - Ask if they want to update it instead\n\n4. **Merge conflicts**: Branch conflicts with base\n   - Guide user through resolving conflicts or rebasing\n\n## Summary Checklist\n\nBefore finalizing, ensure:\n- [ ] `gh` CLI is installed and authenticated\n- [ ] Working directory is clean\n- [ ] All commits are pushed\n- [ ] Branch is up-to-date with base branch\n- [ ] Related Issue included only when a real issue is linked (no empty heading, no `#XXXX` placeholder)\n- [ ] PR description follows the template or project conventions\n- [ ] Appropriate type of change is selected\n- [ ] Pre-flight checklist items are addressed\n","frontmatter":{"name":"create-pr","description":"Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool."},"isInternal":false,"tokens":1847,"sizeBytes":7579},{"name":"SKILL.md","path":".agents/skills/git-commit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.agents/skills/git-commit/SKILL.md","title":"git-commit","category":"anthropic-skill","format":"markdown","content":"---\nname: git-commit\ndescription: 'Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions \"/commit\". Supports: (1) Auto-detecting type and scope from changes, (2) Creating a feature branch when on main/master before committing, (3) Generating conventional commit messages from diff, (4) Interactive commit with optional type/scope/description overrides, (5) Intelligent file staging for logical grouping'\nlicense: MIT\n---\n\n# Git Commit with Conventional Commits\n\n## Overview\n\nCreate standardized, semantic git commits using the Conventional Commits specification. Analyze the actual diff to determine appropriate type, scope, and message.\n\n## Conventional Commit Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n## Commit Types\n\n| Type       | Purpose                        |\n| ---------- | ------------------------------ |\n| `feat`     | New feature                    |\n| `fix`      | Bug fix                        |\n| `docs`     | Documentation only             |\n| `style`    | Formatting/style (no logic)    |\n| `refactor` | Code refactor (no feature/fix) |\n| `perf`     | Performance improvement        |\n| `test`     | Add/update tests               |\n| `build`    | Build system/dependencies      |\n| `ci`       | CI/config changes              |\n| `chore`    | Maintenance/misc               |\n| `revert`   | Revert commit                  |\n\n## Breaking Changes\n\n```\n# Exclamation mark after type/scope\nfeat!: remove deprecated endpoint\n\n# BREAKING CHANGE footer\nfeat: allow config to extend other configs\n\nBREAKING CHANGE: `extends` key behavior changed\n```\n\n## Host shell\n\nDo **not** assume Bash. Cursor on Windows uses PowerShell, where `&&`, `$(cat <<'EOF')`, and POSIX `[ -z ... ]` fail.\n\n- Prefer **separate git invocations** over chained one-liners.\n- If you must chain: PowerShell uses `;` (or separate calls). Bash/zsh may use `&&`.\n- Examples below show Bash and PowerShell when the syntax differs.\n\n## Workflow\n\n### 1. Analyze Diff\n\n```bash\n# If files are staged, use staged diff\ngit diff --staged\n\n# If nothing staged, use working tree diff\ngit diff\n\n# Also check status\ngit status --porcelain\n```\n\nFrom the diff, determine the commit **type** and a short **description** (needed for branch naming in step 2).\n\n### 2. Ensure Feature Branch\n\nIf the current branch is `main` or `master`, create a feature branch **before** staging or committing.\n\n```bash\ngit branch --show-current\n```\n\n**Branch naming** — documented prefixes in `CONTRIBUTING.md`: `feat/`, `fix/`, `docs/`. For other commit types, use the commit type as prefix (e.g. `chore/`):\n\n```\n<type>/<kebab-case-description>\n```\n\n| Commit type | Branch prefix | Example |\n| ----------- | ------------- | ------- |\n| `feat`      | `feat/`       | `feat/custom-shortcuts` |\n| `fix`       | `fix/`        | `fix/upload-timeout` |\n| `docs`      | `docs/`       | `docs/contributing-guide` |\n| other types | `<type>/`     | `chore/add-create-pr-skill` (aligns with commit type; not listed in CONTRIBUTING.md) |\n\nRules for `<kebab-case-description>`:\n\n- Lowercase, words separated by hyphens\n- Derived from the commit description (drop scope, articles, punctuation)\n- Keep it short (2–5 words), e.g. `add create pr skill` → `add-create-pr-skill`\n\n```bash\n# Example: chore commit about adding create-pr skill\ngit checkout -b chore/add-create-pr-skill\n```\n\nDo **not** commit directly on `main` or `master`. If the user explicitly asks to commit on the default branch, confirm before proceeding.\n\n### 3. Stage Files (if needed)\n\nIf nothing is staged or you want to group changes differently:\n\n```bash\n# Stage specific files\ngit add path/to/file1 path/to/file2\n\n# Stage by pattern\ngit add *.test.*\ngit add src/components/*\n```\n\nDo **not** run `git add -p` (interactive; agents cannot complete it). Stage explicit paths instead.\n\n**Never commit secrets** (.env, credentials.json, private keys).\n\n### 4. Generate Commit Message\n\nAnalyze the diff to determine:\n\n- **Type**: What kind of change is this?\n- **Scope**: What area/module is affected?\n- **Description**: One-line summary of what changed (present tense, imperative mood, <72 chars)\n\n### 5. Execute Commit\n\nSingle line (any shell):\n\n```bash\ngit commit -m \"<type>[scope]: <description>\"\n```\n\nMulti-line with body/footer:\n\n```bash\n# Bash / zsh\ngit commit -m \"$(cat <<'EOF'\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\nEOF\n)\"\n```\n\n```powershell\n# PowerShell\ngit commit -m @\"\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\n\"@\n```\n\n## Best Practices\n\n- One logical change per commit\n- Present tense: \"add\" not \"added\"\n- Imperative mood: \"fix bug\" not \"fixes bug\"\n- Reference issues: `Closes #123`, `Refs #456`\n- Keep description under 72 characters\n\n## Git Safety Protocol\n\n- NEVER update git config\n- NEVER run destructive commands (--force, hard reset) without explicit request\n- NEVER skip hooks (--no-verify) unless user asks\n- NEVER force push to main/master\n- If commit fails due to hooks, fix and create NEW commit (don't amend)\n\n## Project Notes (doocs/md)\n\n- Commit messages and PR titles must be in **English** (see `AGENTS.md` and `CONTRIBUTING.md`)\n- Branch naming: `feat/`, `fix/`, `docs/` per `CONTRIBUTING.md`; for other commit types use `<type>/` prefix; never commit on `main`/`master` — create a branch first (step 2)\n- Pre-commit runs `eslint --fix` via lint-staged; if the hook modifies files, fix and create a new commit instead of amending\n","frontmatter":{"name":"git-commit","description":"Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions \"/commit\". Supports: (1) Auto-detecting type and scope from changes, (2) Creating a feature branch when on main/master before committing, (3) Generating conventional commit messages from diff, (4) Interactive commit with optional type/scope/description overrides, (5) Intelligent file staging for logical grouping","license":"MIT"},"isInternal":false,"tokens":1379,"sizeBytes":5596},{"name":"core-principles.md","path":".agents/skills/wechat-svg/references/core-principles.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.agents/skills/wechat-svg/references/core-principles.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Core Principles\n\n## 1. 绝对父子链原则\n\n真正有效的无 ID 冒泡交互，不是「看起来层很多」，而是：\n\n- 最外层到最深层之间是一条连续不间断的父子链\n- 透明触发器必须在整条链的最底部\n- 任何平级断链都会让方法论失效\n\n**错误示意：**\n\n- 很多 `<g>` 平行摆放\n- 触发器只是在视觉上「放在下面」\n- 某一层动画和触发器不是父子关系而是兄弟关系\n\n**正确目标：**\n\n- 每一层动画都在触发器的祖先链上\n\n## 2. 世界层 / 遭遇层 / 触发层三分法\n\n### 世界层\n\n- 承担大场景运动\n- 例如背景上升、地面后退、天空密度变化\n\n### 遭遇层\n\n- 承担单个事件对象\n- 例如气球、直升机、飞机、火箭、第二个 UFO\n\n### 触发层\n\n- 只负责接收事件和向上冒泡\n- 不负责视觉叙事\n\n## 3. 施加 → 抵消 → 再施加\n\n复杂变换串层时，固定采用三段式：\n\n1. 先施加外层参考系变化\n2. 在下一层抵消这段变化\n3. 再在更深层只对当前对象施加自己的局部运动\n\n好处：\n\n- 父层控制大结构\n- 子层拿回局部控制权\n- 更深层总能回到干净坐标系\n\n## 4. 遭遇物必须模块化闭环\n\n每个遭遇物最小结构：\n\n```xml\n<g> <!-- 位移施加层 -->\n  <animateTransform ... />\n  <g> <!-- 姿态层 -->\n    <animateTransform ... />\n    <!-- 对象本体、文本卡、image -->\n  </g>\n  <g> <!-- 位移抵消层 -->\n    <animateTransform ... />\n    <!-- 下一个更深层模块 -->\n  </g>\n</g>\n```\n\n这样后续对象不会继承前一个对象的轨迹、旋转、透明度或姿态残留。\n\n## 5. 交互模式必须全链统一\n\n推荐正式规范：\n\n```xml\nbegin=\"click\"\nfill=\"freeze\"\nrestart=\"never\"\n```\n\n固定要求：\n\n- 不允许主链是 `click`，补偿层还是 `touchstart/touchend`\n- 不允许提示文案、遮挡层、字幕层停留在旧交互语义\n- 交互模式一旦切换，必须全文件统一\n\n## 6. 局部效果必须就地收口\n\n以下效果只能包裹在最小局部范围里：\n\n- 红灯闪烁\n- 尾焰\n- 呼吸发光\n- 小幅摇摆\n- 局部透明度变化\n\n否则它们会误伤更深层链路。\n\n## 7. 全局收尾层也必须在链内\n\n常见误区：视觉上想让字幕固定在屏幕中央，就把它直接挂到 SVG 根部最外层。\n\n正确做法：\n\n- 把收尾字幕接在最深层内部补偿组之后\n- 让它位于「已经抵消完成的视口坐标层」中\n- 这样既能稳定居中，又不脱离方法论\n\n## 8. 固定实施顺序\n\n后续新模块一律按这个顺序实现：\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n","isInternal":false,"tokens":1214,"sizeBytes":2819},{"name":"image-integration.md","path":".agents/skills/wechat-svg/references/image-integration.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.agents/skills/wechat-svg/references/image-integration.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Image Integration And Pitfalls\n\n## 1. `<image>` 的正确接入方式\n\n核心原则：\n\n- `<image>` 只是视觉内容，不应该自己决定时间轴\n- 时间轴、旋转、进场和冻结全部由外层 `<g>` 接管\n- `<image>` 必须属于某个对象模块，而不是脱链挂在 SVG 根部\n\n标准结构：\n\n```xml\n<g> <!-- 遭遇物位移施加层 -->\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g> <!-- 遭遇物姿态层 -->\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n    <image x=\"0\" y=\"-1900\" width=\"609\" height=\"343\" href=\"...\" />\n  </g>\n</g>\n```\n\n## 2. `<image>` 的固定约束\n\n- 不要依赖外部 CSS 调位置\n- 不要把尺寸交给响应式布局\n- 不要让 `<image>` 自己承担运动逻辑\n- 不要把 `<image>` 放到与本体平级但不在同一局部姿态组的位置\n\n推荐做法：\n\n- 位置用 `x` / `y`\n- 尺寸用 `width` / `height`\n- 序列排布用不同的 `y`\n- 组级运动用外层 `transform`\n\n## 3. 文本卡与 `<image>` 的关系\n\n如果对象既有文本卡，也有 `<image>`：\n\n- 文本卡和 `<image>` 都应该属于同一对象的局部层级\n- 但它们不一定要放在同一最小组里\n- 判断标准不是「看起来近不近」，而是「是否应该共享同一轨迹和同一姿态」\n\n## 4. 典型错误与修法\n\n### 错误 1：`<image>` 放在 SVG 根部\n\n- 结果：图片能显示，但完全脱离编组时间轴\n- 修法：挂回对应遭遇物的姿态层或其内部子组\n\n### 错误 2：`<image>` 跟在错误的补偿层下面\n\n- 结果：图片方向对，但位置始终不对，或者跟着下一个对象一起移动\n- 修法：确认它位于「当前对象的姿态层内部」，而不是「下一个对象的补偿层之后」\n\n### 错误 3：只调 `x/y`，不看外层 `transform`\n\n- 结果：怎么挪都不对，因为真正决定运动的是外层位移和旋转\n- 修法：先定外层轨迹，再微调 `x/y`\n\n### 错误 4：收尾字幕放在最外层\n\n- 结果：视觉上居中，但逻辑上不属于最深层编组体系\n- 修法：把字幕接入最深层补偿后的内部视口坐标层\n\n### 错误 5：交互模式切换不彻底\n\n- 结果：`<image>` 所在段落已经 click-only，但同一链上的遮挡层、字幕层或对象层仍保留旧回位逻辑\n- 修法：统一整条链的 `begin` / `fill` / `restart`\n\n## 5. 固定结论\n\n### 结论 1\n\n- `<image>` 是「局部视觉载荷」，不是「独立时间轴节点」\n\n### 结论 2\n\n- 居中文案虽然视觉上像 HUD，但如果它属于故事收尾的一部分，仍然应该放进最深层链内\n\n### 结论 3\n\n- 如果视觉感觉不对，优先排查时序、补偿层、父子链\n- 不要第一反应只去改 `x/y/width/height`\n\n## 6. 推荐排错顺序\n\n1. 先看 `<image>` 在不在正确对象模块里\n2. 再看它是不是放在姿态层里\n3. 再看外层位移与旋转\n4. 再看它的 `x/y/width/height`\n5. 最后再看是否被透明度或遮挡层影响\n","isInternal":false,"tokens":1282,"sizeBytes":3337},{"name":"SKILL.md","path":".agents/skills/wechat-svg/SKILL.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.agents/skills/wechat-svg/SKILL.md","title":"wechat-svg","category":"anthropic-skill","format":"markdown","content":"---\nname: wechat-svg\ndescription: >-\n  WeChat / 微信公众号 SVG constraints and bubbling-group interaction design.\n  Use when adapting SVG for WeChat paste, fixing missing arrows or oversized\n  diagrams, designing pure-SVG interactions without JS, or working with\n  id/class/defs/marker/foreignObject compatibility. Includes inline\n  SVG AttributeName whitelist.\n---\n\n# WeChat SVG Skill\n\n适用于微信公众号、小程序等强约束 SVG 环境。\n\n## 何时调用\n\n- 用户要把 SVG 粘贴到微信公众号，或排查粘贴后样式/交互失效\n- 需要纯 SVG、无 JS、无块级 CSS 的交互动画\n- 约束包含：无 `id` / `class` / `defs` / `href` 依赖\n- 需要深层 `<g>` 嵌套、透明触发器、事件冒泡组织动画\n- 需要接入 `<image>`、文本卡、外部素材，或排查 transform 串层、箭头消失、尺寸异常\n\n## SVG AttributeName 白名单\n\n微信生态对 SVG 动画的 **AttributeName** 有白名单。超出白名单的标签、指令或属性名，可能在保存后被平台过滤。\n\n| 元素 | Name | 说明 |\n| --- | --- | --- |\n| `animate` | `x` | 控制简单几何体 x 轴方向移动 |\n| `animate` | `y` | 控制简单几何体 y 轴方向移动 |\n| `animate` | `width` | 控制简单几何体宽度变化 |\n| `animate` | `height` | 控制简单几何体高度变化 |\n| `animate` | `opacity` | 控制透明度变化，数值通常为 0 到 1 |\n| `animate` | `d` | 控制贝塞尔曲线补间，表现可能有随机性 |\n| `animate` | `points` | 控制多边形补间，表现可能有随机性 |\n| `animate` | `stroke-width` | 控制描边宽度 |\n| `animate` | `stroke-linecap` | 控制描边端点样式 |\n| `animate` | `stroke-dashoffset` | 控制描边偏移，常用于线性遮罩/进度线 |\n| `animate` | `fill` | 控制填充色过渡变化 |\n| `set` | `visibility` | 控制可见性：`visible` / `hidden` / `collapse` / `inherit` |\n| `animateTransform` | `translate` | 控制路径和编组位移 |\n| `animateTransform` | `scale` | 控制路径和编组缩放，可用于翻转 |\n| `animateTransform` | `rotate` | 控制路径和编组旋转 |\n| `animateTransform` | `skewX` | 控制 x 轴倾斜 |\n| `animateTransform` | `skewY` | 控制 y 轴倾斜 |\n| `animateMotion` | `path` | 复杂轨迹动画，可配合 `rotate` 定义朝向 |\n\n### 禁用边界\n\n在设计或适配 SVG 时，默认遵守：\n\n- 不使用 `id`\n- 不使用 `class`\n- 不使用 `href` / `xlink:href` 作为样式与结构依赖（含 `url(#id)` 引用）\n- 不使用 `defs`\n- 不使用 `embed`\n- 不使用块级 CSS 与 JS 动画\n- 样式尽量以内联属性或 `style=\"\"` 的最小必要形式书写\n\n### 静态图表适配要点（非交互动画）\n\n第三方 SVG（如 Mermaid）粘贴到微信时，常见问题与修法：\n\n| 现象 | 原因 | 修法 |\n| --- | --- | --- |\n| 箭头消失 | `<defs>` + `<marker>` + `url(#id)` 被过滤 | 将 marker 展开为内联 `<path>` / `<polygon>`，移除 `marker-end` |\n| 图表过大 | `width=\"100%\"` 或 CSS `max-width` 被忽略，按 viewBox 1:1 渲染 | 设置显式像素 `width` / `height`（不超过正文栏可用宽度），保留 `viewBox` |\n| 文字错位 | `foreignObject` 兼容性差 | 转为 `<text>` / `<tspan>` 或外层 HTML `<section>` |\n\n## 核心使用原则\n\n1. 先判断这是不是「真正的无 ID 冒泡编组问题」\n2. 先搭结构，再写动画\n3. 区分世界层 / 遭遇层 / 触发层\n4. 最深层透明触发器放在整条父子链最底部\n5. 每个遭遇物做成闭环模块：施加层 → 姿态层 → 抵消层\n6. 先统一交互模式，再统一全链实现\n\n详细原则见 [core-principles.md](./references/core-principles.md)。\n\n## 已验证的交互写法\n\n```xml\n<animateTransform\n  begin=\"click\"\n  dur=\"30s\"\n  fill=\"freeze\"\n  restart=\"never\"\n  ... />\n```\n\n固定要求：\n\n- 所有交互动画统一 `begin=\"click\"`\n- 所有交互动画统一 `fill=\"freeze\"`\n- 所有交互动画统一 `restart=\"never\"`\n- 删除所有旧的 `touchend;mouseup` 回位链\n- 不允许一部分层保留旧长按逻辑，一部分层改成 click-only\n\n## 嵌套与变换\n\n### 嵌套规则\n\n- 必须形成连续不间断的绝对父子链，不是「很多 `<g>` 平铺」\n- 任何平级断链都会让冒泡和补偿逻辑失效\n\n### 变换规则\n\n- 标准写法：**施加 → 抵消 → 再施加**\n- 父层改变参考系，子层拿回局部控制权，更深层通过补偿层回到干净坐标基准\n\n## `<image>` 接入\n\n- `<image>` 不能直接丢到 SVG 根部\n- 必须挂在对应对象的局部姿态层或遭遇层内部\n- 位移、旋转、出场时机由外层 `<g>` 的 `animateTransform` 控制\n- 位置用 `x` / `y`，尺寸用 `width` / `height`，不依赖外部 CSS\n\n```xml\n<g>\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g>\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n  </g>\n</g>\n```\n\n详细规则与排错见 [image-integration.md](./references/image-integration.md)。\n\n## 排错顺序\n\n按顺序排查，不要跳步：\n\n1. 是否还是绝对父子链\n2. 触发器是否在最深层\n3. 补偿层是否成对存在\n4. 坐标是否跑出视口\n5. `opacity` / `visibility` 是否误伤深层\n6. `keyTimes` 与出现窗口\n7. （静态 SVG）是否仍依赖 `defs` / `id` / 百分比宽度\n\n## 常见错误与固定修法\n\n| 错误 | 现象 | 修法 |\n| --- | --- | --- |\n| 平级 `<g>` 当深层结构 | 事件链断 | 回到单一路径父子链 |\n| 只施加，不抵消 | 后续对象继承前一层轨迹 | 每个遭遇物补上抵消层 |\n| 局部闪烁挂在公共父层 | 深层对象一起透明 | 把 `opacity` 动画缩到最小局部组 |\n| 文案/字幕放错逻辑层 | 视觉居中但脱离编组 | 绑对象局部层，或放最深层补偿后的视口坐标层 |\n| 交互模式半新半旧 | 部分层仍用旧长按逻辑 | 全链统一 `begin` / `fill` / `restart` |\n| marker 箭头依赖 defs | 粘贴后箭头消失 | 内联展开箭头，移除 `marker-end` |\n| SVG 使用 width 100% | 粘贴后撑满编辑器 | 写死像素宽高并保留 viewBox |\n\n## 新模块实施顺序\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n\n## 延伸阅读\n\n- [core-principles.md](./references/core-principles.md) — 洋葱式嵌套、模块化、局部效果收口\n- [image-integration.md](./references/image-integration.md) — `<image>` 接入与典型陷阱\n","frontmatter":{"name":"wechat-svg","description":"WeChat / 微信公众号 SVG constraints and bubbling-group interaction design. Use when adapting SVG for WeChat paste, fixing missing arrows or oversized diagrams, designing pure-SVG interactions without JS, or working with id/class/defs/marker/foreignObject compatibility. Includes inline SVG AttributeName whitelist."},"isInternal":false,"tokens":2658,"sizeBytes":6922},{"name":"architecture.md","path":"docs/architecture.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/docs/architecture.md","title":"docs - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# 架构概览\n\n本文档简述 doocs/md 的核心模块与数据流，供贡献者快速定位代码。\n\n## Monorepo 结构\n\n| 包               | 路径                  | 职责                                                                                            |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | Vue 3 主应用、WXT 浏览器扩展（Chrome/Firefox）、CF Workers 部署                                 |\n| `@md/api`        | `apps/api`            | 账户、云同步、计费、上传代理、分享链接、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID 为 `doocs.doocs-md`）                                |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包壳（构建产物来自 `@md/web`）                                                     |\n| `@md/core`       | `packages/core`       | Markdown → HTML 渲染引擎                                                                        |\n| `@md/shared`     | `packages/shared`     | 配置、类型、CodeMirror 编辑器封装、主题 CSS                                                     |\n| `@md/config`     | `packages/config`     | 共享 TypeScript 配置                                                                            |\n| `@doocs/md-cli`  | `packages/md-cli`     | 已发布 npm CLI（Express 静态服务）                                                              |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务（`render_markdown` 等工具）                                                            |\n\n独立示例（不在 pnpm workspace 内）：\n\n| 示例              | 路径                                   | 说明                    |\n| ----------------- | -------------------------------------- | ----------------------- |\n| 微信 OpenAPI 代理 | `docs/examples/wechat-openapi-worker/` | 最小 CF Worker 转发示例 |\n\n### 依赖关系\n\n```\napps/web, apps/vscode, packages/mcp-server\n  └── @md/core\n        └── @md/shared\n              └── @md/config (dev)\n```\n\n`@md/core` 与 `@md/shared` **直接导出 TypeScript 源码**，由消费方构建工具（Vite / webpack）编译。\n\n## 渲染管线\n\n```\nMarkdown 原文\n  → @md/core (marked + 自定义扩展)\n  → isomorphic-dompurify 净化\n  → 注入主题 CSS 变量 (@md/core/theme)\n  → HTML 输出（预览）\n  → juice 内联 CSS（仅复制到微信时，在 `@md/web` 导出层）\n  → 剪贴板 HTML（公众号）\n```\n\nWeb 端入口：\n\n1. `useRenderStore`（`apps/web/src/stores/render.ts`）调用 `initRenderer` / `renderMarkdown`\n2. `useThemeStore` 通过 `applyTheme` 将主题 CSS 写入 `<style>` 标签\n3. 编辑器内容变更经 debounce 后触发 `render()`\n\n扩展列表见 `packages/core/src/extensions/`（Mermaid、PlantUML、KaTeX、Ruby、alert、脚注等）。\n\n## Web 应用目录约定（`apps/web/src`）\n\n| 目录                 | 职责                                                                    |\n| -------------------- | ----------------------------------------------------------------------- |\n| `i18n/`              | vue-i18n 配置、locale 检测、按领域拆分的 message 模块                   |\n| `stores/`            | Pinia 全局状态，按领域划分                                              |\n| `composables/`       | 跨组件复用的响应式逻辑                                                  |\n| `services/`          | 外部 API 与领域服务（account / sync / share / upload / export）         |\n| `storage/`           | IndexedDB 抽象层、键前缀与安全读写                                      |\n| `lib/`               | 纯函数与浏览器辅助（bootstrap / browser / format / markdown / preview） |\n| `components/ui/`     | Shadcn-Vue 设计系统（无业务逻辑）                                       |\n| `components/editor/` | 编辑器主界面                                                            |\n| `components/ai/`     | AI 相关 UI                                                              |\n| `components/shared/` | 跨 feature 通用组件                                                     |\n| `entrypoints/`       | WXT 浏览器扩展入口                                                      |\n\n## 状态管理（Web）\n\nPinia stores 按领域划分：\n\n- `useEditorStore` — 编辑器实例与文档内容\n- `useThemeStore` — 主题与样式（含 per-theme 配置持久化）\n- `useRenderStore` — 渲染结果与目录标题\n- `useUIStore` — 布局、对话框、视图模式\n- `useLocaleStore` — 界面语言（zh-CN / zh-TW / en-US / ja-JP），同步 `document.title` 与 i18n 实例\n- `useSyncStore` / `useAuthStore` — 云同步与账户\n- `useMarketplaceStore` — 主题/组件市场目录、安装与发布\n- `useConfirmStore` — 全局确认对话框（`components/shared/confirm-dialog/`）\n\n样式变更后通过 `useEditorRefresh()`（`apps/web/src/composables/useEditorRefresh.ts`）触发预览重渲染。\n\n## 云同步\n\n- **白名单**：`apps/web/src/services/sync/settings.ts` 中的 `SYNC_SETTING_KEYS`（含 `marketplace_installed_themes` / `marketplace_installed_components`）\n- **合并策略**：LWW，元数据存于 `sync_settings_meta`\n- **热更新**：远端设置应用后由 `hydrateSyncedSettings`（`services/sync/hydrate.ts`）写入 Store（含 `locale`），无需刷新页面\n- **用户说明**：见 [cloud-sync.md](./cloud-sync.md)\n\n## 主题 / 组件市场\n\n- **API**：`/marketplace/*`（公开浏览；登录发布；`ADMIN_GITHUB_LOGINS` 审核）\n- **主题包**：安装后以 `mp:<uuid>` 作为独立主题出现在主题选择器；CSS 经 `applyTheme({ themeCSS })` 动态注入\n- **组件包**：安装后写入 `custom_components` 注册表\n- **Web UI**：`MarketplaceDialog`（文件菜单 / 右侧主题栏 / 组件对话框入口）\n\n## 本地存储\n\n- **IndexedDB**（`apps/web/src/storage/`）：文章正文、偏好设置、图床/AI 密钥、缓存分层存储\n- **StorageEngine 抽象**（`storage/manager.ts`）：`store.reactive()` / `store.getJSON()` 统一入口\n- **文章持久化**：`documentRepo` 按篇读写，避免整包 JSON 写入\n- **云同步元数据**：`services/sync/settings.ts` 通过 `store` 读写设置白名单\n- **配额提示**：`storage/quota.ts`（IndexedDB 配额远大于 localStorage，保留 toast 兜底）\n\n### 启动顺序\n\n1. `main.ts` → `bootstrap()`（`apps/web/src/bootstrap.ts`）\n2. `initComponentDarkVars()` + `setupComponents()`\n3. `await initStorage()`（迁移 localStorage、预加载 KV 缓存、加载文档）\n4. `setupI18n(detectInitialLocale())` + `setAppI18n()`，注册 vue-i18n 插件\n5. `createApp`、Pinia、`useLocaleStore()` 并挂载\n6. `App.vue` 中 `usePlatformEnv()`、`useAccountSyncBootstrap()`、`useDeepLinkImport()` 完成账户与深链引导\n\n### 国际化（i18n）\n\n- **范围**：`apps/web` 主应用 UI；扩展 popup / background 部分文案。VS Code、uTools、CLI、MCP 无 i18n。\n- **入口**：`apps/web/src/i18n/`（`detect.ts`、`translate.ts`、`messages/`）\n- **偏好**：`PreferencesDialog`（文件菜单或 `Ctrl+,`）→ General → Language\n- **动态 UI**：命令面板、快捷键列表、Slash 命令、CodeMirror placeholder 等在 `locale` 变化时重建；Store 内 toast 使用 `@/i18n/translate` 的 `t()`\n\n## 构建\n\n- Web：Vite 8，`manualChunks` 拆分 codemirror、katex、highlight 等\n- VSCode 扩展：webpack，预览渲染复用 `@md/core`（见 `apps/vscode/src/previewRenderer.ts`）\n- 浏览器扩展：WXT，`src/entrypoints/` 为入口\n- Core / Shared：**直接导出 TypeScript 源码**，由消费方构建工具编译\n\n## 静态资源\n\nWeb 应用静态资源统一放在 `apps/web/public/`（如 `mpmd/` 图标）。根目录不再有 `public/` 副本。\n","isInternal":false,"tokens":2342,"sizeBytes":8090},{"name":"mcp.json","path":".cursor/mcp.json","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/.cursor/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n","frontmatter":{"mcpServers":{"md":{"command":"node","args":["--import","tsx/esm","${workspaceFolder}/packages/mcp-server/run.mjs"],"cwd":"${workspaceFolder}/packages/mcp-server"}}},"isInternal":false,"tokens":68,"sizeBytes":244},{"name":"plugin.json","path":"apps/utools/plugin.json","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/apps/utools/plugin.json","title":"utools Plugin Manifest","category":"plugin-manifest","format":"json","content":"{\n  \"pluginName\": \"微信 Markdown 编辑器\",\n  \"description\": \"Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用\",\n  \"version\": \"2.1.0\",\n  \"author\": \"doocs\",\n  \"homepage\": \"https://github.com/doocs/md\",\n  \"pluginType\": \"tool\",\n  \"platform\": [\n    \"win32\",\n    \"darwin\",\n    \"linux\"\n  ],\n  \"logo\": \"logo.png\",\n  \"main\": \"dist/index.html\",\n  \"preload\": \"preload.js\",\n  \"features\": [\n    {\n      \"code\": \"wechat-md\",\n      \"explain\": \"打开微信 Markdown 编辑器\",\n      \"cmds\": [\n        \"微信排版\",\n        \"Markdown 编辑器\",\n        \"doocs md\"\n      ]\n    }\n  ]\n}\n","frontmatter":{"pluginName":"微信 Markdown 编辑器","description":"Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用","version":"2.1.0","author":"doocs","homepage":"https://github.com/doocs/md","pluginType":"tool","platform":["win32","darwin","linux"],"logo":"logo.png","main":"dist/index.html","preload":"preload.js","features":[{"code":"wechat-md","explain":"打开微信 Markdown 编辑器","cmds":["微信排版","Markdown 编辑器","doocs md"]}]},"isInternal":false,"tokens":193,"sizeBytes":603},{"name":"README.md","path":"apps/utools/README.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/apps/utools/README.md","title":"utools Documentation","category":"plugin-manifest","format":"markdown","content":"# uTools 插件打包指引\n\n该目录包含将微信 Markdown 编辑器打包为 [uTools](https://u.tools) 插件所需的脚本与配置。\n\n## 快速开始\n\n```sh\npnpm utools:package\n```\n\n该命令将完成以下动作：\n\n1. 调用 `pnpm --filter @md/web run build:utools` 构建前端资源至 `apps/utools/dist`，该构建将自动使用相对路径，确保在 uTools 的 `file://` 协议下能够正常加载。MathJax 从 `node_modules` 复制到构建产物中，Mermaid 作为 npm 模块打包。\n2. 将仓库根目录的版本号写入 `apps/utools/plugin.json`，保持与主项目同步。\n3. 从 `apps/web/public/mpmd/icon-256.png` 拷贝插件图标至 `apps/utools/logo.png`。\n4. 生成形如 `apps/utools/release/md-utools-vX.Y.Z.zip` 的安装包，可直接导入到 uTools。\n\n> 注意：命令执行前请确认已安装 pnpm 10+ 与 Node.js 22+，并在仓库根目录执行 `pnpm install` 安装依赖。\n\n## 手动导入调试\n\n1. 运行 `pnpm --filter @md/web run build:utools`。\n2. 打开 uTools，进入插件面板中的「开发者工具」。\n3. 选择「载入本地插件」，指向 `apps/utools` 目录即可。\n\n## 目录说明\n\n- `plugin.json`：uTools 插件的清单文件。\n- `preload.js`：在 uTools 渲染进程和 Web 前端之间建立通信的脚本，用于处理插件唤起事件。\n- `package.json`：将此目录标记为 CommonJS 模块以兼容 uTools。\n- `dist/`：由 Vite 构建输出的静态资源目录。\n- `release/`：运行打包命令后生成的插件安装包。\n","isInternal":false,"tokens":548,"sizeBytes":1534},{"name":"README.md","path":"packages/core/README.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/packages/core/README.md","title":"core Documentation","category":"plugin-manifest","format":"markdown","content":"# @md/core\n\nMarkdown 渲染引擎：将 Markdown 转为适合微信公众号的 HTML。\n\n## 导出\n\n| 路径                  | 说明                                                      |\n| --------------------- | --------------------------------------------------------- |\n| `@md/core`            | 主入口：`initRenderer`、`renderMarkdown`、`applyTheme` 等 |\n| `@md/core/renderer`   | 渲染器实现                                                |\n| `@md/core/extensions` | marked 扩展（Mermaid、KaTeX、alert 等）                   |\n| `@md/core/utils`      | `postProcessHtml`、`renderMarkdown` 辅助                  |\n| `@md/core/theme`      | 主题注入与 CSS 变量                                       |\n\n## 基本用法\n\n```ts\nimport { initRenderer, renderMarkdown } from '@md/core'\nimport { postProcessHtml } from '@md/core/utils'\n\nconst renderer = initRenderer({\n  isMacCodeBlock: true,\n  isShowLineNumber: true,\n})\n\nconst html = postProcessHtml(renderMarkdown(renderer, markdown))\n```\n\n主题样式需配合 `@md/core/theme` 的 `applyTheme` 或 Web 端 `useThemeStore.applyCurrentTheme()` 注入 CSS。\n\n## 扩展\n\n扩展位于 `src/extensions/`，在 `renderer-impl.ts` 中注册。新增扩展时：\n\n1. 在 `src/extensions/` 实现 marked 扩展\n2. 在 `src/extensions/index.ts` 导出\n3. 在 `initRenderer` 中注册\n\n## 依赖说明\n\n- **marked** — Markdown 解析\n- **highlight.js** — 代码高亮\n- **mermaid / @antv/infographic** — 图表（按需加载仍建议在消费方做 code-splitting）\n- **isomorphic-dompurify** — HTML 净化（`sanitizeHtml`）\n- **juice** — CSS 内联（仅 Web 端复制到微信时使用，不在本包内）\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n","isInternal":false,"tokens":499,"sizeBytes":1789},{"name":"README.md","path":"packages/mcp-server/README.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/packages/mcp-server/README.md","title":"mcp-server Documentation","category":"plugin-manifest","format":"markdown","content":"# @md/mcp-server\n\nMCP (Model Context Protocol) server for [doocs/md](https://github.com/doocs/md).\n\nExposes the `doocs/md` markdown rendering engine and AI service configuration to AI agent runtimes (Claude Desktop, Cursor, VS Code Copilot, etc.) via the standard MCP protocol over **stdio**.\n\n## Prerequisites\n\n- **Node.js** ≥ 22.22.2（与 monorepo 根目录 `.nvmrc` 一致）\n- **pnpm** ≥ 9（monorepo workspace）\n- Clone the monorepo and install dependencies:\n\n```bash\ngit clone https://github.com/doocs/md.git\ncd md\npnpm install\n```\n\n## Tools\n\n### `render_markdown`\n\nConvert Markdown text to styled HTML using the full doocs/md rendering pipeline.\n\n| Parameter          | Type                               | Default     | Description                                            |\n| ------------------ | ---------------------------------- | ----------- | ------------------------------------------------------ |\n| `markdown`         | `string`                           | —           | Markdown source text                                   |\n| `theme`            | `\"default\" \\| \"grace\" \\| \"simple\"` | `\"default\"` | Visual theme (经典 / 优雅 / 简洁)                      |\n| `primaryColor`     | `string (hex)`                     | `\"#0F4C81\"` | Primary accent color (see `list_colors`)               |\n| `fontFamily`       | `string`                           | 无衬线预设  | Font family stack (see `list_fonts`)                   |\n| `fontSize`         | `string (px)`                      | `\"16px\"`    | Base font size (see `list_font_sizes`)                 |\n| `legend`           | `string`                           | `\"alt\"`     | Image caption format (see `list_legend_formats`)       |\n| `isMacCodeBlock`   | `boolean`                          | `false`     | Render code blocks with a macOS-style title bar        |\n| `isShowLineNumber` | `boolean`                          | `false`     | Show line numbers in code blocks                       |\n| `citeStatus`       | `boolean`                          | `false`     | Convert links to footnote-style citations              |\n| `countStatus`      | `boolean`                          | `false`     | Prepend a reading-time estimate                        |\n| `themeMode`        | `\"light\" \\| \"dark\"`                | `\"light\"`   | Color mode for diagram extensions                      |\n| `isUseIndent`      | `boolean`                          | `false`     | Indent paragraph first lines                           |\n| `isUseJustify`     | `boolean`                          | `false`     | Justify paragraph text                                 |\n| `headingStyles`    | `object`                           | `{}`        | Per-level heading styles (see `list_heading_styles`)   |\n| `codeBlockTheme`   | preset URL                         | GitHub 主题 | highlight.js preset from `list_code_block_themes` only |\n| `customCSS`        | `string`                           | `\"\"`        | Additional custom CSS (highest priority)               |\n\nReturns `{ html, frontMatter, readingTime: { words, minutes } }`.\n\n### Other tools\n\n| Tool                     | Description                                                                       |\n| ------------------------ | --------------------------------------------------------------------------------- |\n| `list_themes`            | List all available visual themes with labels and authors                          |\n| `list_colors`            | List all available primary accent colors                                          |\n| `list_fonts`             | List preset font family options                                                   |\n| `list_font_sizes`        | List preset font size options                                                     |\n| `list_legend_formats`    | List image caption format options                                                 |\n| `list_heading_styles`    | List heading style presets                                                        |\n| `list_code_block_themes` | List highlight.js code block theme URLs                                           |\n| `list_ai_services`       | List all built-in AI service providers with endpoints and models                  |\n| `explain_extensions`     | Describe every Markdown extension beyond CommonMark (KaTeX, Mermaid, PlantUML, …) |\n| `get_renderer_options`   | Describe all renderer configuration options                                       |\n\n## Setup\n\n### VS Code (GitHub Copilot)\n\nAdd to `.vscode/mcp.json` in the project root (already included in this repo):\n\n```json\n{\n  \"servers\": {\n    \"md\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"--import\", \"tsx/esm\", \"${workspaceFolder}/packages/mcp-server/run.mjs\"],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open the **MCP** panel in VS Code and start the `md` server.\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"C:/path/to/md/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"C:/path/to/md/packages/mcp-server\"\n    }\n  }\n}\n```\n\nReplace `C:/path/to/md` with the absolute path to your cloned repository.\n\n### Cursor\n\nAdd to `.cursor/mcp.json` at the project root (already included in this repo):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open **Cursor Settings → MCP** and enable the `md` server.\n\n### Windsurf / Other MCP Clients\n\nUse the same stdio pattern:\n\n```json\n{\n  \"command\": \"node\",\n  \"args\": [\"--import\", \"tsx/esm\", \"/absolute/path/to/packages/mcp-server/run.mjs\"],\n  \"cwd\": \"/absolute/path/to/packages/mcp-server\"\n}\n```\n\n## Example Prompts\n\nOnce the server is connected, you can ask your AI assistant:\n\n```\n使用 grace 主题将下面的 Markdown 渲染为 HTML，开启代码行号：\n# Hello World\n```\n\n```\n列出所有可用主题，并解释每个主题的风格特点。\n```\n\n```\nrender_markdown 支持哪些 Markdown 扩展？给我每个扩展的示例写法。\n```\n\n```\n列出所有内置 AI 服务，帮我找一个支持 DeepSeek-V3 的接入点。\n```\n\n## Development\n\n```bash\n# Run server directly (connects to stdin/stdout — for manual testing)\npnpm --filter @md/mcp-server start\n\n# Watch mode (auto-restart on changes)\npnpm --filter @md/mcp-server dev\n```\n\nTo test manually, use [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector node --import tsx/esm run.mjs\n```\n","isInternal":false,"tokens":1540,"sizeBytes":6863},{"name":"README.md","path":"packages/md-cli/README.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/packages/md-cli/README.md","title":"md-cli Documentation","category":"plugin-manifest","format":"markdown","content":"# md-cli\n\nA powerful yet simple tool for rendering Markdown documents locally during development.\n\n## Installation\n\nTo get started with `md-cli`, you can install it either globally or locally, depending on your needs.\n\n### Install locally\n\nIf you only need it for a specific project, you can install it locally by running:\n\n```bash\nnpm install @doocs/md-cli\n```\n\n### Install globally\n\nFor global access across all your projects, install it globally with:\n\n```bash\nnpm install -g @doocs/md-cli\n```\n\n## Usage\n\nOnce installed, running `md-cli` is a breeze. Here’s how to get started:\n\n### Default setup\n\nTo launch `md-cli` with the default settings, simply run:\n\n```bash\nmd-cli\n```\n\n### Custom port\n\nIf you prefer to run `md-cli` on a different port, say `8899`, just specify it like this:\n\n```bash\nmd-cli port=8899\n```\n\n## Maintainers\n\n- [yanglbme](https://github.com/yanglbme) – Core maintainer.\n- [YangFong](https://github.com/yangfong) – Core maintainer.\n- [xw](https://github.com/wll8) – Contributor.\n- [thinkasany](https://www.npmjs.com/~thinkerwing) – Contributor.\n","isInternal":false,"tokens":279,"sizeBytes":1079},{"name":"README.md","path":"packages/shared/README.md","rawUrl":"https://raw.githubusercontent.com/doocs/md/HEAD/packages/shared/README.md","title":"shared Documentation","category":"plugin-manifest","format":"markdown","content":"# @md/shared\n\n跨应用共享的配置、类型、工具与 CodeMirror 编辑器封装。\n\n## 导出\n\n| 路径                   | 说明                                   |\n| ---------------------- | -------------------------------------- |\n| `@md/shared`           | 主入口                                 |\n| `@md/shared/configs`   | 主题、字体、颜色等默认配置与选项列表   |\n| `@md/shared/constants` | 常量                                   |\n| `@md/shared/types`     | 共享 TypeScript 类型                   |\n| `@md/shared/utils`     | fetch、tokenTools 等工具               |\n| `@md/shared/editor`    | CodeMirror 6 setup、格式化命令、快捷键 |\n\n## 主要配置（`configs`）\n\n- `themeOptions` / `defaultStyleConfig` — 主题名与默认样式\n- `defaultPerThemeSettings` — 每个主题的独立配置结构\n- `fontFamilyOptions` / `fontSizeOptions` / `colorOptions` — 样式面板选项\n- `ctrlKey` / `ctrlSign` — 平台相关快捷键展示\n\n主题 CSS 源文件位于 `src/configs/theme-css/`（如 `default.css`、`grace.css`）。\n\n## 编辑器（`editor`）\n\nWeb 与 VSCode 扩展共用 CodeMirror 配置：\n\n```ts\nimport { applyHeading, formatBold, markdownSetup, theme } from '@md/shared/editor'\n```\n\n## 消费方\n\n- `apps/web` — 主编辑器 UI\n- `apps/vscode` — VSCode 预览侧边栏\n- `packages/core` — 渲染相关类型与工具\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n","isInternal":false,"tokens":442,"sizeBytes":1498}],"systemPromptSnippet":"<yakaai_skills repo=\"doocs/md\">\n<!-- File: AGENTS.md (Tokens: ~3234 | Category: root-instruction) -->\n# Agent Instructions\n\n本文件为 AI Agent（Claude Code、OpenCode、Cursor、Copilot 等）在本仓库中工作时提供统一入口。\n\n## 项目概览\n\n**doocs/md** — 一款微信 Markdown 编辑器，将 Markdown 渲染为微信公众号文章格式。支持自定义主题样式、多图床、AI 助手、浏览器扩展、**zh-CN / zh-TW / en-US / ja-JP 界面**等特性。\n\n- **在线地址:** https://md.doocs.org\n- **Node 版本:** >= 22.22.2（`.nvmrc`: v22.22.2）\n- **包管理器:** pnpm（monorepo）\n- **npm 镜像:** https://registry.npmmirror.com（`.npmrc`）\n\n## Monorepo 结构\n\n| 工作区           | 路径                  | 说明                                                                                                  |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | 主应用，Vue 3 + 浏览器扩展（WXT: Chrome/Firefox）                                                     |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID: `doocs.doocs-md`）                                        |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包                                                                                       |\n| `@md/core`       | `packages/core`       | 核心 Markdown 渲染引擎（marked + 自定义扩展）                                                         |\n| `@md/shared`     | `packages/shared`     | 共享工具函数、配置、类型、编辑器配置                                                                  |\n| `@md/config`     | `packages/config`     | TypeScript 配置基础文件                                                                               |\n| `@doocs/md-cli`  | `packages/md-cli`     | CLI 工具（Express 服务托管构建产物）                                                                  |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务，为 AI Agent 暴露接口                                                                        |\n| `@md/api`        | `apps/api`            | 后端 API：账户、云同步、计费、上传代理、分享、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n\n独立示例（不在 workspace 内）：`docs/examples/wechat-openapi-worker/` — 微信公众号 OpenAPI 代理 Worker。\n\n## 常用命令\n\n### 根目录\n\n```bash\npnpm install          # 安装所有依赖\npnpm start            # 等同于 `pnpm web dev`\npnpm run lint         # ESLint --fix 全项目检查\npnpm run type-check   # vue-tsc 类型检查\npnpm run build:cli    # 构建 web + 复制到 md-cli + npm pack\npnpm run release:cli  # 通过 scripts/release.js 发布 CLI\npnpm utools:package   # 打包 uTools 插件\npnpm run inspector    # node-modules-inspector 查看依赖树\n```\n\n### Web 应用 (`@md/web`)\n\n```bash\npnpm web dev          # 启动 Vite 开发服务器\npnpm web build        # 生产构建 + 类型检查\npnpm web build:h5-netlify   # 构建用于 Netlify 根目录部署\npnpm web build:analyze      # 构建并生成 rollup-plugin-visualizer 分析\npnpm web ext:dev      # WXT Chrome 扩展开发模式\npnpm web ext:zip      # 打包 Chrome 扩展\npnpm web firefox:dev  # WXT Firefox 扩展开发模式\npnpm web firefox:zip  # 打包 Firefox 扩展\npnpm web wrangler:dev    # Cloudflare Workers 开发\npnpm web wrangler:deploy   # Cloudflare Workers 部署\n```\n\n### VSCode 扩展\n\n```bash\npnpm vscode compile   # webpack 编译\npnpm vscode watch     # webpack 监听\npnpm vscode build     # 生产 webpack 构建\npnpm vscode package   # vsce 打包\n```\n\n### CLI & MCP\n\n```bash\npnpm cli <cmd>        # 在 @doocs/md-cli 中执行命令\npnpm mcp <cmd>        # 在 @md/mcp-server 中执行命令（render_markdown 等 MCP 工具）\npnpm mcp dev          # MCP Server 监听模式\n```\n\n`@md/mcp-server` 通过 stdio 暴露 `render_markdown`、`list_themes`、`list_colors` 等工具，配置见 [packages/mcp-server/README.md](./packages/mcp-server/README.md)、[`.vscode/mcp.json`](./.vscode/mcp.json) 与 [`.cursor/mcp.json`](./.cursor/mcp.json)。\n\n## 架构\n\n### 渲染管线\n\n1. `@md/core` 封装 `marked`，实现自定义扩展（Mermaid、PlantUML、Ruby、KaTeX、TOC、alert 块、infographic、slider、markup、emoji、脚注）\n2. `juice` 内联 CSS 以兼容微信\n3. `isomorphic-dompurify` 净化输出\n4. 主题系统（`@md/core/src/theme/`）注入 CSS 变量\n\n### 构建系统\n\n- **`@md/core` 和 `@md/shared` 直接导出 TypeScript 源码**（不预构建）。由消费方的构建工具（Vite/webpack）编译。\n- Web 应用使用 Vite 8，VSCode 扩展使用 webpack，浏览器扩展使用 WXT\n\n### 样式与主题\n\n- Web 应用使用 Tailwind CSS 4 + PostCSS\n- 主题 CSS 文件位于 `packages/shared/src/configs/theme-css/`（default.css、grace.css、simple.css）\n- 部分主题文件使用 Less\n\n### 状态管理\n\n- Pinia store 位于 `apps/web/src/stores/`（按领域划分：`useEditorStore`、`useThemeStore`、`useUiStore`、`useLocaleStore` 等）\n- UI 组件遵循 Shadcn-Vue 模式，位于 `apps/web/src/components/ui`\n- 跨 feature 通用组件位于 `apps/web/src/components/shared`\n- 架构详情见 [docs/architecture.md](./docs/architecture.md)\n\n### 国际化（i18n，`@md/web`）\n\nWeb 主应用与部分浏览器扩展 UI 支持 **zh-CN**、**zh-TW**、**en-US**、**ja-JP**；VS Code 扩展、uTools、CLI、MCP **未**国际化。\n\n- **库**：`vue-i18n`（composition API，`legacy: false`），在 `apps/web/vite.config.ts` 中通过 `unplugin-auto-import` 自动导入 `useI18n`\n- **文案**：`apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`（`common`、`editor`、`dialog`、`store`、`ai`、`upload`、`chrome`、`marketplace`、`notifications`）\n- **组件内**：`useI18n()` + `t('key')`；**Store / 工具函数**：`@/i18n/translate` 的 `t()` / `getLocale()` / `formatLocalDateTime()`\n- **语言状态**：`useLocaleStore`（持久化 key：`locale`）；用户可在 **偏好设置**（`Ctrl+,`）→ General 切换\n- **启动**：`await initStorage()` → `setupI18n(detectInitialLocale())` → Pinia → `useLocaleStore()`（见 `apps/web/src/bootstrap.ts`）；`index.html` 启动屏从 `localStorage` 读取 locale\n- **云同步**：`locale` 在 `SYNC_SETTING_KEYS` 中，远端应用后由 `hydrateSyncedSettings` 热更新\n- **约定**：新增用户可见文案须同时维护 zh-CN、zh-TW、en-US 与 ja-JP；在 computed 中调用 `t()` 且需随语言切换更新时，应依赖 `locale`（例如 `void locale.value`）\n\n## Lint 与格式化\n\n- **ESLint:** `@antfu/eslint-config` + Vue + TypeScript + formatter\n- **Prettier:** 固定版本 `2.8.8`（通过 `pnpm-workspace.yaml` 的 `overrides` 强制）\n- **Pre-commit 钩子:** `lint-staged` 对所有文件执行 `eslint --fix`\n- 规则：不使用分号，关闭 `no-unused-vars`、`no-console`、`no-debugger`\n- **代码注释：** 统一英文。保留非显而易见的 why / 约束 / 兼容性说明；删除复述下一行代码的噪音注释。勿改动 `i18n/messages` 等用户可见文案。\n\n## 依赖管理\n\n这是一个 pnpm monorepo，`pnpm-workspace.yaml` 中包含大量安全覆盖（overrides）。\n\n### 升级依赖\n\n1. **共享版本用 catalog** — 跨包共用的工具链版本集中在 `pnpm-workspace.yaml` 的 `catalog`（`typescript`、`vitest`、`wrangler`、`@types/node`、`marked`、`@codemirror/state|view` 等）；workspace 内各 `package.json` 用 `\"catalog:\"` 引用。**仓库根 `package.json` 因 `private: false` 可被 npm 消费，须写普通 semver，勿用 `catalog:`。**包专属依赖可继续写版本号（`pnpm/json-enforce-catalog` 已关闭）\n2. **Prettier 必须固定在 `2.8.8`** — 通过 catalog + `overrides.prettier` 强制（根 package 直接写 `2.8.8`）\n3. **Patch 文件：** 如果打了 patch 的依赖升级了，必须同步更新 `patches/` 中对应的 patch 文件：\n   - `@codemirror/view` → `patches/@codemirror__view@6.43.15.patch`（导出 `MeasureRequest` 接口，修复 macOS 上 Alt+Shift 快捷键处理）\n   - `mermaid` → `patches/mermaid@12.2.0.patch`（流程图 HTML 标签在非整数 DPR 下按宽度换行，避免文字被裁切）\n   - `juice` 12.2.0 已在上游处理 `parseCSS` 空返回值，不再需要本地 patch\n4. 更新 `pnpm-workspace.yaml` 中的 `patchedDependencies` 以匹配新版本\n5. 运行 `pnpm install` 重新生成 `pnpm-lock.yaml`；可用 `pnpm dedupe` 收敛可合并的间接依赖\n\n### 安全覆盖\n\n`pnpm-workspace.yaml` 的 `overrides` 部分强制了存在漏洞的间接依赖的最低版本（ajv、dompurify、undici、minimatch 等）。除非上游已修复漏洞，否则不要移除这些覆盖。\n\n### allowBuilds\n\n`pnpm-workspace.yaml` 包含 `allowBuilds` 列表，用于需要原生构建脚本的依赖（`esbuild`、`sharp`、`keytar`、`workerd` 等）。新增需要原生构建的依赖可能需要添加到此列表。\n\n## Git 规范\n\n- **提交信息 / PR 标题:** 遵循 Conventional Commits（`feat`、`fix`、`docs`、`style`、`refactor`、`perf`、`test`、`build`、`chore`），**一律使用英文**（见 `CONTRIBUTING.md`）\n- **分支命名:** `feat/description`、`fix/description`、`docs/description`；其他类型用 `<type>/`\n- **PR 说明:** 按 [`.github/pull_request_template.md`](./.github/pull_request_template.md) 填写；无关联 Issue 时不要写 Related Issue 占位符\n\n## Skills\n\nReusable workflows live in [`.agents/skills/`](./.agents/skills/) (canonical). Claude Code discovers each skill through a git symlink:\n\n```text\n.claude/skills/<name> → ../../.agents/skills/<name>\n```\n\n| Skill        | When to use                                                                           |\n| ------------ | ------------------------------------------------------------------------------------- |\n| `git-commit` | Commit changes with Conventional Commits (`/git-commit` or \"commit my changes\")       |\n| `create-pr`  | Create a GitHub pull request (`/create-pr` or \"open a PR\")                            |\n| `wechat-svg` | WeChat SVG whitelist, bubbling-group interaction, paste compatibility (`/wechat-svg`) |\n\nInvoke manually: `/skill-name` in Cursor or Claude Code; OpenCode uses the `skill` tool.\n\n<!-- File: CLAUDE.md (Tokens: ~5 | Category: claude-rule) -->\n@AGENTS.md\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~1302 | Category: copilot-instructions) -->\n# Copilot Instructions\n\nThis repository is a pnpm monorepo for **doocs/md**, a WeChat Markdown editor. Canonical agent guidance lives in [AGENTS.md](../AGENTS.md); keep this file aligned with it.\n\n- **Node:** `>=22.22.2` (`.nvmrc`: v22.22.2)\n- **Package manager:** pnpm (`packageManager` in the root `package.json`)\n- **npm registry:** https://registry.npmmirror.com (`.npmrc`)\n\n## Build, Test, and Lint\n\n### Global Commands\n\n- **Install:** `pnpm install`\n- **Lint (ESLint + Prettier):** `pnpm run lint`\n- **Type Check:** `pnpm run type-check`\n- **Tests:** `pnpm run test` (`@md/shared`, `@md/core`, `@md/web`, `@md/api`)\n\n### Web App (`@md/web`)\n\n- **Development Server:** `pnpm web dev`\n- **Production Build:** `pnpm web build`\n- **Browser Extension:** `pnpm web ext:zip` (WXT; Chrome) / `pnpm web firefox:zip`\n\n### Other Workspaces\n\n- **API (`@md/api`):** `pnpm api dev` / `pnpm api test`\n- **VS Code (`doocs-md`):** `pnpm vscode compile` / `pnpm vscode package`\n- **CLI (`@doocs/md-cli`):** `pnpm run build:cli`\n- **MCP (`@md/mcp-server`):** `pnpm mcp dev`\n- **uTools (`@md/utools`):** `pnpm utools:package`\n\n## High-Level Architecture\n\n### Monorepo Structure\n\n- **`apps/web`**: Vue 3 + Vite + Pinia + Tailwind CSS 4. Web app and browser extension (WXT).\n- **`apps/api`**: Cloudflare Workers + Hono + D1 (auth, cloud sync, billing, upload, share, marketplace, emoji).\n- **`apps/vscode`**: VS Code extension (webpack). Marketplace ID: `doocs.doocs-md`.\n- **`apps/utools`**: uTools plugin packaging shell (artifacts from `@md/web`).\n- **`packages/core`**: Markdown renderer (`marked` + custom extensions, theme CSS variables).\n- **`packages/shared`**: Shared config, types, CodeMirror wrapper, theme CSS.\n- **`packages/config`**: Shared TypeScript config.\n- **`packages/md-cli`**: Published npm CLI that serves the built web app.\n- **`packages/mcp-server`**: MCP tools (`render_markdown`, `list_themes`, `list_colors`).\n- **`docs/examples/wechat-openapi-worker/`**: standalone WeChat OpenAPI proxy (not in the pnpm workspace).\n\nDetails: [docs/architecture.md](../docs/architecture.md).\n\n### Key Technologies\n\n- **Frontend:** Vue 3 (Composition API), Pinia, Tailwind CSS 4 + PostCSS\n- **Editor:** CodeMirror 6\n- **Markdown:** `marked` in `@md/core`; `juice` inlines CSS for WeChat paste; `isomorphic-dompurify` sanitizes output\n- **Web build:** Vite 8; extension build: WXT\n- **API:** Hono on Cloudflare Workers, D1\n- **i18n (web only):** `vue-i18n` — zh-CN, zh-TW, en-US, ja-JP\n\n## Key Conventions\n\n### Development Patterns\n\n- **`@md/core` and `@md/shared` export TypeScript source** (`src/index.ts`). Do not pre-build them; consumers (Vite/webpack) compile them.\n- **UI:** Shadcn-Vue components in `apps/web/src/components/ui`. Prefer these over raw HTML/CSS.\n- **Stores:** Domain Pinia stores in `apps/web/src/stores` (`useEditorStore`, `useThemeStore`, `useUiStore`, `useLocaleStore`, …).\n- **Comments:** English only. Explain non-obvious why / constraints; do not narrate the next line. Do not rewrite user-facing i18n copy unless asked.\n\n### Internationalization (`@md/web`)\n\n- Messages: `apps/web/src/i18n/messages/{zh-CN,zh-TW,en-US,ja-JP}/`\n- Components: `useI18n()` + `t('key')`. Stores/utils: `@/i18n/translate`.\n- New user-visible strings must be added in all four locales. VS Code, uTools, CLI, and MCP are not localized.\n\n### Styling & Theming\n\n- Theme injection: `@md/core/src/theme` (CSS variables).\n- Theme CSS sources: `packages/shared/src/configs/theme-css/` (`default.css`, `grace.css`, `simple.css`).\n\n### Markdown Extensions\n\n- Implement new Markdown features as extensions in `packages/core/src/extensions`.\n- Register them in the renderer configuration.\n\n### Dependencies\n\n- Shared toolchain versions live in `pnpm-workspace.yaml` `catalog`; workspace packages use `\"catalog:\"`.\n- Root `package.json` is publishable (`private: false`) — use plain semver there, not `catalog:`.\n- Prettier is pinned to **2.8.8**. Do not remove security `overrides` unless upstream fixed the CVE.\n- If a patched dependency is upgraded, update the matching file in `patches/` and `patchedDependencies`.\n\n### Git Conventions\n\n- **Commit messages and PR titles:** Conventional Commits, **English** (`feat`, `fix`, `docs`, `chore`, …).\n- **Branches:** `feat/description`, `fix/description`, `docs/description`; other types use `<type>/`.\n- Never commit on `main`. Follow `.github/pull_request_template.md` when opening a PR.\n\n### Agent Skills\n\nCanonical workflows: `.agents/skills/` (`git-commit`, `create-pr`, `wechat-svg`). Claude Code discovers them via git symlinks under `.claude/skills/`.\n\n<!-- File: .agents/skills/create-pr/SKILL.md (Tokens: ~1847 | Category: anthropic-skill) -->\n---\nname: create-pr\ndescription: Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool.\n---\n\n# Create PR\n\nThis skill guides you through creating a well-structured GitHub pull request that follows project conventions and best practices.\n\nDo **not** assume Bash. On Windows PowerShell, avoid `&&`, `$(...)`, and POSIX tests; run git/`gh` commands as separate invocations and use `$env:TEMP` for the PR body file.\n\n## Prerequisites Check\n\nBefore proceeding, verify the following:\n\n### 1. Check if `gh` CLI is installed\n\n```bash\ngh --version\n```\n\nIf not installed, inform the user:\n> The GitHub CLI (`gh`) is required but not installed. Please install it:\n> - macOS: `brew install gh`\n> - Other: https://cli.github.com/\n\n### 2. Check if authenticated with GitHub\n\n```bash\ngh auth status\n```\n\nIf not authenticated, guide the user to run `gh auth login`.\n\n### 3. Verify clean working directory\n\n```bash\ngit status\n```\n\nIf there are uncommitted changes, ask the user whether to:\n- Commit them as part of this PR\n- Stash them temporarily\n- Discard them (with caution)\n\n## Gather Context\n\n### 1. Identify the current branch\n\n```bash\ngit branch --show-current\n```\n\nEnsure you're not on `main` or `master`. If so, ask the user to create or switch to a feature branch.\n\n### 2. Find the base branch\n\nResolve the default branch once and reuse it as `BASE_BRANCH`. Do **not** assume Bash (`$(...)`, `sed`, `[ -z ... ]` fail in PowerShell).\n\n```bash\ngit symbolic-ref refs/remotes/origin/HEAD\n```\n\nThis prints `refs/remotes/origin/<branch>` (usually `main`). Use the last path segment.\n\n```powershell\n# PowerShell\n$BASE_BRANCH = (git symbolic-ref refs/remotes/origin/HEAD).Split('/')[-1]\n```\n\nIf that fails, run `git remote show origin` and parse the `HEAD branch:` line.\n\nThis is typically `main` or `master`, but may differ per repo.\n\n### 3. Analyze recent commits relevant to this PR\n\n```bash\n# Bash / zsh\ngit log \"origin/${BASE_BRANCH}..HEAD\" --oneline --no-decorate\n```\n\n```powershell\n# PowerShell\ngit log \"origin/$BASE_BRANCH..HEAD\" --oneline --no-decorate\n```\n\nReview these commits to understand:\n- What changes are being introduced\n- The scope of the PR (single feature/fix or multiple changes)\n- Whether commits should be squashed or reorganized\n\n### 4. Review the diff\n\n```bash\n# Bash / zsh\ngit diff \"origin/${BASE_BRANCH}..HEAD\" --stat\n```\n\n```powershell\n# PowerShell\ngit diff \"origin/$BASE_BRANCH..HEAD\" --stat\n```\n\nThis shows which files changed and helps identify the type of change.\n\n## Information Gathering\n\nBefore creating the PR, you need the following information. Check if it can be inferred from:\n- Commit messages\n- Branch name (e.g., `fix/upload-timeout`, `feat/custom-shortcuts`)\n- Changed files and their content\n\nIf any critical information is missing, ask the user directly:\n\n### Required Information\n\n1. **Related Issue Number** (optional): Look for patterns like `#123`, `fixes #123`, or `closes #123` in commit messages. If none is found, **omit the Related Issue section** from the PR body — do not use placeholders like `#XXXX`.\n2. **Description**: What problem does this solve? Why were these changes made?\n3. **Type of Change**: Bug fix, new feature, breaking change, refactor, cosmetic, documentation, or workflow\n4. **Test Procedure**: How was this tested? What could break?\n\nOnly ask about a related issue when the change clearly looks like it should close one (e.g. branch name `fix/issue-123`). For small or self-contained changes, skip the question and leave the section out.\n\n## Git Best Practices\n\nBefore creating the PR, consider these best practices:\n\n### Commit Hygiene\n\n1. **Atomic commits**: Each commit should represent a single logical change\n2. **Clear commit messages**: Follow conventional commit format when possible\n3. **No merge commits**: Prefer rebasing over merging to keep history clean\n\n### Branch Management\n\n1. **Rebase on latest base branch** (if needed):\n   ```bash\n   git fetch origin\n   git rebase \"origin/${BASE_BRANCH}\"\n   ```\n   In PowerShell, use `\"origin/$BASE_BRANCH\"`.\n\n2. **Squash if appropriate**: If history is messy, ask the user whether they want commits squashed. Do **not** run `git rebase -i` (interactive; agents cannot complete it).\n\n### Push Changes\n\nEnsure all commits are pushed:\n```bash\ngit push origin HEAD\n```\n\nIf the branch was rebased, you may need:\n```bash\ngit push origin HEAD --force-with-lease\n```\n\n## Create the Pull Request\n\nUse `CONTRIBUTING.md` (Pull Request 流程) as the source of truth for PR content. Follow [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) exactly:\n\n- **Summary** — what changed and why\n- **Type of Change** — check applicable boxes\n- **Test Procedure** — how you verified the change\n- **Pre-flight Checklist** — mark items that apply\n\nWhen filling out the PR body:\n- Fill in all template sections with relevant information gathered from commits and context\n- Mark the appropriate \"Type of Change\" checkbox(es)\n- Complete the \"Pre-flight Checklist\" items that apply\n- **Related Issue is not in the template.** Add a `## Related Issue` section with `Closes #123` only when this PR actually fixes an issue. Never add `#XXXX` or an empty Related Issue heading.\n\n### Create PR with gh CLI\n\n**Use a temporary file for the PR body** to avoid shell escaping issues, newline problems, and other command-line flakiness:\n\n1. Write the PR body to a temporary file (`$env:TEMP/pr-body.md` on Windows PowerShell, `/tmp/pr-body.md` on macOS/Linux).\n\n2. Create the PR using the file:\n\n   ```bash\n   # Bash / zsh\n   gh pr create --title \"PR_TITLE\" --body-file /tmp/pr-body.md --base \"$BASE_BRANCH\"\n   ```\n\n   ```powershell\n   # PowerShell\n   gh pr create --title \"PR_TITLE\" --body-file \"$env:TEMP/pr-body.md\" --base $BASE_BRANCH\n   ```\n\n3. Clean up the temporary file after the PR is created.\n\nFor draft PRs, add `--draft` to the same command.\n\n**Why use a file?** Passing complex markdown with newlines, special characters, and checkboxes directly via `--body` is error-prone. The `--body-file` flag handles all content reliably.\n\n## Post-Creation\n\nAfter creating the PR:\n\n1. **Display the PR URL** so the user can review it\n2. **Remind about CI checks**: Tests and linting will run automatically\n3. **Suggest next steps**:\n   - Add reviewers if needed: `gh pr edit --add-reviewer USERNAME`\n   - Add labels if needed: `gh pr edit --add-label \"bug\"`\n\n## Error Handling\n\n### Common Issues\n\n1. **No commits ahead of base branch**: The branch has no changes to submit\n   - Ask if the user meant to work on a different branch\n\n2. **Branch not pushed**: Remote doesn't have the branch\n   - Push the branch first: `git push -u origin HEAD`\n\n3. **PR already exists**: A PR for this branch already exists\n   - Show the existing PR: `gh pr view`\n   - Ask if they want to update it instead\n\n4. **Merge conflicts**: Branch conflicts with base\n   - Guide user through resolving conflicts or rebasing\n\n## Summary Checklist\n\nBefore finalizing, ensure:\n- [ ] `gh` CLI is installed and authenticated\n- [ ] Working directory is clean\n- [ ] All commits are pushed\n- [ ] Branch is up-to-date with base branch\n- [ ] Related Issue included only when a real issue is linked (no empty heading, no `#XXXX` placeholder)\n- [ ] PR description follows the template or project conventions\n- [ ] Appropriate type of change is selected\n- [ ] Pre-flight checklist items are addressed\n\n<!-- File: .agents/skills/git-commit/SKILL.md (Tokens: ~1379 | Category: anthropic-skill) -->\n---\nname: git-commit\ndescription: 'Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions \"/commit\". Supports: (1) Auto-detecting type and scope from changes, (2) Creating a feature branch when on main/master before committing, (3) Generating conventional commit messages from diff, (4) Interactive commit with optional type/scope/description overrides, (5) Intelligent file staging for logical grouping'\nlicense: MIT\n---\n\n# Git Commit with Conventional Commits\n\n## Overview\n\nCreate standardized, semantic git commits using the Conventional Commits specification. Analyze the actual diff to determine appropriate type, scope, and message.\n\n## Conventional Commit Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n## Commit Types\n\n| Type       | Purpose                        |\n| ---------- | ------------------------------ |\n| `feat`     | New feature                    |\n| `fix`      | Bug fix                        |\n| `docs`     | Documentation only             |\n| `style`    | Formatting/style (no logic)    |\n| `refactor` | Code refactor (no feature/fix) |\n| `perf`     | Performance improvement        |\n| `test`     | Add/update tests               |\n| `build`    | Build system/dependencies      |\n| `ci`       | CI/config changes              |\n| `chore`    | Maintenance/misc               |\n| `revert`   | Revert commit                  |\n\n## Breaking Changes\n\n```\n# Exclamation mark after type/scope\nfeat!: remove deprecated endpoint\n\n# BREAKING CHANGE footer\nfeat: allow config to extend other configs\n\nBREAKING CHANGE: `extends` key behavior changed\n```\n\n## Host shell\n\nDo **not** assume Bash. Cursor on Windows uses PowerShell, where `&&`, `$(cat <<'EOF')`, and POSIX `[ -z ... ]` fail.\n\n- Prefer **separate git invocations** over chained one-liners.\n- If you must chain: PowerShell uses `;` (or separate calls). Bash/zsh may use `&&`.\n- Examples below show Bash and PowerShell when the syntax differs.\n\n## Workflow\n\n### 1. Analyze Diff\n\n```bash\n# If files are staged, use staged diff\ngit diff --staged\n\n# If nothing staged, use working tree diff\ngit diff\n\n# Also check status\ngit status --porcelain\n```\n\nFrom the diff, determine the commit **type** and a short **description** (needed for branch naming in step 2).\n\n### 2. Ensure Feature Branch\n\nIf the current branch is `main` or `master`, create a feature branch **before** staging or committing.\n\n```bash\ngit branch --show-current\n```\n\n**Branch naming** — documented prefixes in `CONTRIBUTING.md`: `feat/`, `fix/`, `docs/`. For other commit types, use the commit type as prefix (e.g. `chore/`):\n\n```\n<type>/<kebab-case-description>\n```\n\n| Commit type | Branch prefix | Example |\n| ----------- | ------------- | ------- |\n| `feat`      | `feat/`       | `feat/custom-shortcuts` |\n| `fix`       | `fix/`        | `fix/upload-timeout` |\n| `docs`      | `docs/`       | `docs/contributing-guide` |\n| other types | `<type>/`     | `chore/add-create-pr-skill` (aligns with commit type; not listed in CONTRIBUTING.md) |\n\nRules for `<kebab-case-description>`:\n\n- Lowercase, words separated by hyphens\n- Derived from the commit description (drop scope, articles, punctuation)\n- Keep it short (2–5 words), e.g. `add create pr skill` → `add-create-pr-skill`\n\n```bash\n# Example: chore commit about adding create-pr skill\ngit checkout -b chore/add-create-pr-skill\n```\n\nDo **not** commit directly on `main` or `master`. If the user explicitly asks to commit on the default branch, confirm before proceeding.\n\n### 3. Stage Files (if needed)\n\nIf nothing is staged or you want to group changes differently:\n\n```bash\n# Stage specific files\ngit add path/to/file1 path/to/file2\n\n# Stage by pattern\ngit add *.test.*\ngit add src/components/*\n```\n\nDo **not** run `git add -p` (interactive; agents cannot complete it). Stage explicit paths instead.\n\n**Never commit secrets** (.env, credentials.json, private keys).\n\n### 4. Generate Commit Message\n\nAnalyze the diff to determine:\n\n- **Type**: What kind of change is this?\n- **Scope**: What area/module is affected?\n- **Description**: One-line summary of what changed (present tense, imperative mood, <72 chars)\n\n### 5. Execute Commit\n\nSingle line (any shell):\n\n```bash\ngit commit -m \"<type>[scope]: <description>\"\n```\n\nMulti-line with body/footer:\n\n```bash\n# Bash / zsh\ngit commit -m \"$(cat <<'EOF'\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\nEOF\n)\"\n```\n\n```powershell\n# PowerShell\ngit commit -m @\"\n<type>[scope]: <description>\n\n<optional body>\n\n<optional footer>\n\"@\n```\n\n## Best Practices\n\n- One logical change per commit\n- Present tense: \"add\" not \"added\"\n- Imperative mood: \"fix bug\" not \"fixes bug\"\n- Reference issues: `Closes #123`, `Refs #456`\n- Keep description under 72 characters\n\n## Git Safety Protocol\n\n- NEVER update git config\n- NEVER run destructive commands (--force, hard reset) without explicit request\n- NEVER skip hooks (--no-verify) unless user asks\n- NEVER force push to main/master\n- If commit fails due to hooks, fix and create NEW commit (don't amend)\n\n## Project Notes (doocs/md)\n\n- Commit messages and PR titles must be in **English** (see `AGENTS.md` and `CONTRIBUTING.md`)\n- Branch naming: `feat/`, `fix/`, `docs/` per `CONTRIBUTING.md`; for other commit types use `<type>/` prefix; never commit on `main`/`master` — create a branch first (step 2)\n- Pre-commit runs `eslint --fix` via lint-staged; if the hook modifies files, fix and create a new commit instead of amending\n\n<!-- File: .agents/skills/wechat-svg/references/core-principles.md (Tokens: ~1214 | Category: anthropic-skill) -->\n# Core Principles\n\n## 1. 绝对父子链原则\n\n真正有效的无 ID 冒泡交互，不是「看起来层很多」，而是：\n\n- 最外层到最深层之间是一条连续不间断的父子链\n- 透明触发器必须在整条链的最底部\n- 任何平级断链都会让方法论失效\n\n**错误示意：**\n\n- 很多 `<g>` 平行摆放\n- 触发器只是在视觉上「放在下面」\n- 某一层动画和触发器不是父子关系而是兄弟关系\n\n**正确目标：**\n\n- 每一层动画都在触发器的祖先链上\n\n## 2. 世界层 / 遭遇层 / 触发层三分法\n\n### 世界层\n\n- 承担大场景运动\n- 例如背景上升、地面后退、天空密度变化\n\n### 遭遇层\n\n- 承担单个事件对象\n- 例如气球、直升机、飞机、火箭、第二个 UFO\n\n### 触发层\n\n- 只负责接收事件和向上冒泡\n- 不负责视觉叙事\n\n## 3. 施加 → 抵消 → 再施加\n\n复杂变换串层时，固定采用三段式：\n\n1. 先施加外层参考系变化\n2. 在下一层抵消这段变化\n3. 再在更深层只对当前对象施加自己的局部运动\n\n好处：\n\n- 父层控制大结构\n- 子层拿回局部控制权\n- 更深层总能回到干净坐标系\n\n## 4. 遭遇物必须模块化闭环\n\n每个遭遇物最小结构：\n\n```xml\n<g> <!-- 位移施加层 -->\n  <animateTransform ... />\n  <g> <!-- 姿态层 -->\n    <animateTransform ... />\n    <!-- 对象本体、文本卡、image -->\n  </g>\n  <g> <!-- 位移抵消层 -->\n    <animateTransform ... />\n    <!-- 下一个更深层模块 -->\n  </g>\n</g>\n```\n\n这样后续对象不会继承前一个对象的轨迹、旋转、透明度或姿态残留。\n\n## 5. 交互模式必须全链统一\n\n推荐正式规范：\n\n```xml\nbegin=\"click\"\nfill=\"freeze\"\nrestart=\"never\"\n```\n\n固定要求：\n\n- 不允许主链是 `click`，补偿层还是 `touchstart/touchend`\n- 不允许提示文案、遮挡层、字幕层停留在旧交互语义\n- 交互模式一旦切换，必须全文件统一\n\n## 6. 局部效果必须就地收口\n\n以下效果只能包裹在最小局部范围里：\n\n- 红灯闪烁\n- 尾焰\n- 呼吸发光\n- 小幅摇摆\n- 局部透明度变化\n\n否则它们会误伤更深层链路。\n\n## 7. 全局收尾层也必须在链内\n\n常见误区：视觉上想让字幕固定在屏幕中央，就把它直接挂到 SVG 根部最外层。\n\n正确做法：\n\n- 把收尾字幕接在最深层内部补偿组之后\n- 让它位于「已经抵消完成的视口坐标层」中\n- 这样既能稳定居中，又不脱离方法论\n\n## 8. 固定实施顺序\n\n后续新模块一律按这个顺序实现：\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n\n<!-- File: .agents/skills/wechat-svg/references/image-integration.md (Tokens: ~1282 | Category: anthropic-skill) -->\n# Image Integration And Pitfalls\n\n## 1. `<image>` 的正确接入方式\n\n核心原则：\n\n- `<image>` 只是视觉内容，不应该自己决定时间轴\n- 时间轴、旋转、进场和冻结全部由外层 `<g>` 接管\n- `<image>` 必须属于某个对象模块，而不是脱链挂在 SVG 根部\n\n标准结构：\n\n```xml\n<g> <!-- 遭遇物位移施加层 -->\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g> <!-- 遭遇物姿态层 -->\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n    <image x=\"0\" y=\"-1900\" width=\"609\" height=\"343\" href=\"...\" />\n  </g>\n</g>\n```\n\n## 2. `<image>` 的固定约束\n\n- 不要依赖外部 CSS 调位置\n- 不要把尺寸交给响应式布局\n- 不要让 `<image>` 自己承担运动逻辑\n- 不要把 `<image>` 放到与本体平级但不在同一局部姿态组的位置\n\n推荐做法：\n\n- 位置用 `x` / `y`\n- 尺寸用 `width` / `height`\n- 序列排布用不同的 `y`\n- 组级运动用外层 `transform`\n\n## 3. 文本卡与 `<image>` 的关系\n\n如果对象既有文本卡，也有 `<image>`：\n\n- 文本卡和 `<image>` 都应该属于同一对象的局部层级\n- 但它们不一定要放在同一最小组里\n- 判断标准不是「看起来近不近」，而是「是否应该共享同一轨迹和同一姿态」\n\n## 4. 典型错误与修法\n\n### 错误 1：`<image>` 放在 SVG 根部\n\n- 结果：图片能显示，但完全脱离编组时间轴\n- 修法：挂回对应遭遇物的姿态层或其内部子组\n\n### 错误 2：`<image>` 跟在错误的补偿层下面\n\n- 结果：图片方向对，但位置始终不对，或者跟着下一个对象一起移动\n- 修法：确认它位于「当前对象的姿态层内部」，而不是「下一个对象的补偿层之后」\n\n### 错误 3：只调 `x/y`，不看外层 `transform`\n\n- 结果：怎么挪都不对，因为真正决定运动的是外层位移和旋转\n- 修法：先定外层轨迹，再微调 `x/y`\n\n### 错误 4：收尾字幕放在最外层\n\n- 结果：视觉上居中，但逻辑上不属于最深层编组体系\n- 修法：把字幕接入最深层补偿后的内部视口坐标层\n\n### 错误 5：交互模式切换不彻底\n\n- 结果：`<image>` 所在段落已经 click-only，但同一链上的遮挡层、字幕层或对象层仍保留旧回位逻辑\n- 修法：统一整条链的 `begin` / `fill` / `restart`\n\n## 5. 固定结论\n\n### 结论 1\n\n- `<image>` 是「局部视觉载荷」，不是「独立时间轴节点」\n\n### 结论 2\n\n- 居中文案虽然视觉上像 HUD，但如果它属于故事收尾的一部分，仍然应该放进最深层链内\n\n### 结论 3\n\n- 如果视觉感觉不对，优先排查时序、补偿层、父子链\n- 不要第一反应只去改 `x/y/width/height`\n\n## 6. 推荐排错顺序\n\n1. 先看 `<image>` 在不在正确对象模块里\n2. 再看它是不是放在姿态层里\n3. 再看外层位移与旋转\n4. 再看它的 `x/y/width/height`\n5. 最后再看是否被透明度或遮挡层影响\n\n<!-- File: .agents/skills/wechat-svg/SKILL.md (Tokens: ~2658 | Category: anthropic-skill) -->\n---\nname: wechat-svg\ndescription: >-\n  WeChat / 微信公众号 SVG constraints and bubbling-group interaction design.\n  Use when adapting SVG for WeChat paste, fixing missing arrows or oversized\n  diagrams, designing pure-SVG interactions without JS, or working with\n  id/class/defs/marker/foreignObject compatibility. Includes inline\n  SVG AttributeName whitelist.\n---\n\n# WeChat SVG Skill\n\n适用于微信公众号、小程序等强约束 SVG 环境。\n\n## 何时调用\n\n- 用户要把 SVG 粘贴到微信公众号，或排查粘贴后样式/交互失效\n- 需要纯 SVG、无 JS、无块级 CSS 的交互动画\n- 约束包含：无 `id` / `class` / `defs` / `href` 依赖\n- 需要深层 `<g>` 嵌套、透明触发器、事件冒泡组织动画\n- 需要接入 `<image>`、文本卡、外部素材，或排查 transform 串层、箭头消失、尺寸异常\n\n## SVG AttributeName 白名单\n\n微信生态对 SVG 动画的 **AttributeName** 有白名单。超出白名单的标签、指令或属性名，可能在保存后被平台过滤。\n\n| 元素 | Name | 说明 |\n| --- | --- | --- |\n| `animate` | `x` | 控制简单几何体 x 轴方向移动 |\n| `animate` | `y` | 控制简单几何体 y 轴方向移动 |\n| `animate` | `width` | 控制简单几何体宽度变化 |\n| `animate` | `height` | 控制简单几何体高度变化 |\n| `animate` | `opacity` | 控制透明度变化，数值通常为 0 到 1 |\n| `animate` | `d` | 控制贝塞尔曲线补间，表现可能有随机性 |\n| `animate` | `points` | 控制多边形补间，表现可能有随机性 |\n| `animate` | `stroke-width` | 控制描边宽度 |\n| `animate` | `stroke-linecap` | 控制描边端点样式 |\n| `animate` | `stroke-dashoffset` | 控制描边偏移，常用于线性遮罩/进度线 |\n| `animate` | `fill` | 控制填充色过渡变化 |\n| `set` | `visibility` | 控制可见性：`visible` / `hidden` / `collapse` / `inherit` |\n| `animateTransform` | `translate` | 控制路径和编组位移 |\n| `animateTransform` | `scale` | 控制路径和编组缩放，可用于翻转 |\n| `animateTransform` | `rotate` | 控制路径和编组旋转 |\n| `animateTransform` | `skewX` | 控制 x 轴倾斜 |\n| `animateTransform` | `skewY` | 控制 y 轴倾斜 |\n| `animateMotion` | `path` | 复杂轨迹动画，可配合 `rotate` 定义朝向 |\n\n### 禁用边界\n\n在设计或适配 SVG 时，默认遵守：\n\n- 不使用 `id`\n- 不使用 `class`\n- 不使用 `href` / `xlink:href` 作为样式与结构依赖（含 `url(#id)` 引用）\n- 不使用 `defs`\n- 不使用 `embed`\n- 不使用块级 CSS 与 JS 动画\n- 样式尽量以内联属性或 `style=\"\"` 的最小必要形式书写\n\n### 静态图表适配要点（非交互动画）\n\n第三方 SVG（如 Mermaid）粘贴到微信时，常见问题与修法：\n\n| 现象 | 原因 | 修法 |\n| --- | --- | --- |\n| 箭头消失 | `<defs>` + `<marker>` + `url(#id)` 被过滤 | 将 marker 展开为内联 `<path>` / `<polygon>`，移除 `marker-end` |\n| 图表过大 | `width=\"100%\"` 或 CSS `max-width` 被忽略，按 viewBox 1:1 渲染 | 设置显式像素 `width` / `height`（不超过正文栏可用宽度），保留 `viewBox` |\n| 文字错位 | `foreignObject` 兼容性差 | 转为 `<text>` / `<tspan>` 或外层 HTML `<section>` |\n\n## 核心使用原则\n\n1. 先判断这是不是「真正的无 ID 冒泡编组问题」\n2. 先搭结构，再写动画\n3. 区分世界层 / 遭遇层 / 触发层\n4. 最深层透明触发器放在整条父子链最底部\n5. 每个遭遇物做成闭环模块：施加层 → 姿态层 → 抵消层\n6. 先统一交互模式，再统一全链实现\n\n详细原则见 [core-principles.md](./references/core-principles.md)。\n\n## 已验证的交互写法\n\n```xml\n<animateTransform\n  begin=\"click\"\n  dur=\"30s\"\n  fill=\"freeze\"\n  restart=\"never\"\n  ... />\n```\n\n固定要求：\n\n- 所有交互动画统一 `begin=\"click\"`\n- 所有交互动画统一 `fill=\"freeze\"`\n- 所有交互动画统一 `restart=\"never\"`\n- 删除所有旧的 `touchend;mouseup` 回位链\n- 不允许一部分层保留旧长按逻辑，一部分层改成 click-only\n\n## 嵌套与变换\n\n### 嵌套规则\n\n- 必须形成连续不间断的绝对父子链，不是「很多 `<g>` 平铺」\n- 任何平级断链都会让冒泡和补偿逻辑失效\n\n### 变换规则\n\n- 标准写法：**施加 → 抵消 → 再施加**\n- 父层改变参考系，子层拿回局部控制权，更深层通过补偿层回到干净坐标基准\n\n## `<image>` 接入\n\n- `<image>` 不能直接丢到 SVG 根部\n- 必须挂在对应对象的局部姿态层或遭遇层内部\n- 位移、旋转、出场时机由外层 `<g>` 的 `animateTransform` 控制\n- 位置用 `x` / `y`，尺寸用 `width` / `height`，不依赖外部 CSS\n\n```xml\n<g>\n  <animateTransform attributeName=\"transform\" type=\"translate\"\n      begin=\"click\" dur=\"80s\"\n      values=\"...\"\n      keyTimes=\"...\"\n      fill=\"freeze\" restart=\"never\" />\n\n  <g>\n    <animateTransform attributeName=\"transform\" type=\"rotate\"\n        begin=\"click\" dur=\"80s\"\n        values=\"...\"\n        keyTimes=\"...\"\n        fill=\"freeze\" restart=\"never\" />\n\n    <image x=\"0\" y=\"-800\" width=\"609\" height=\"639\" href=\"...\" />\n    <image x=\"0\" y=\"-1500\" width=\"609\" height=\"634\" href=\"...\" />\n  </g>\n</g>\n```\n\n详细规则与排错见 [image-integration.md](./references/image-integration.md)。\n\n## 排错顺序\n\n按顺序排查，不要跳步：\n\n1. 是否还是绝对父子链\n2. 触发器是否在最深层\n3. 补偿层是否成对存在\n4. 坐标是否跑出视口\n5. `opacity` / `visibility` 是否误伤深层\n6. `keyTimes` 与出现窗口\n7. （静态 SVG）是否仍依赖 `defs` / `id` / 百分比宽度\n\n## 常见错误与固定修法\n\n| 错误 | 现象 | 修法 |\n| --- | --- | --- |\n| 平级 `<g>` 当深层结构 | 事件链断 | 回到单一路径父子链 |\n| 只施加，不抵消 | 后续对象继承前一层轨迹 | 每个遭遇物补上抵消层 |\n| 局部闪烁挂在公共父层 | 深层对象一起透明 | 把 `opacity` 动画缩到最小局部组 |\n| 文案/字幕放错逻辑层 | 视觉居中但脱离编组 | 绑对象局部层，或放最深层补偿后的视口坐标层 |\n| 交互模式半新半旧 | 部分层仍用旧长按逻辑 | 全链统一 `begin` / `fill` / `restart` |\n| marker 箭头依赖 defs | 粘贴后箭头消失 | 内联展开箭头，移除 `marker-end` |\n| SVG 使用 width 100% | 粘贴后撑满编辑器 | 写死像素宽高并保留 viewBox |\n\n## 新模块实施顺序\n\n1. 判断属于世界层还是遭遇层\n2. 先画静态本体\n3. 搭施加层 / 姿态层 / 抵消层骨架\n4. 计算时序与 `keyTimes`\n5. 再接文本卡、`<image>`、说明层\n6. 最后统一检查交互模式、补偿层、最深层触发器\n\n## 延伸阅读\n\n- [core-principles.md](./references/core-principles.md) — 洋葱式嵌套、模块化、局部效果收口\n- [image-integration.md](./references/image-integration.md) — `<image>` 接入与典型陷阱\n\n<!-- File: docs/architecture.md (Tokens: ~2342 | Category: project-spec) -->\n# 架构概览\n\n本文档简述 doocs/md 的核心模块与数据流，供贡献者快速定位代码。\n\n## Monorepo 结构\n\n| 包               | 路径                  | 职责                                                                                            |\n| ---------------- | --------------------- | ----------------------------------------------------------------------------------------------- |\n| `@md/web`        | `apps/web`            | Vue 3 主应用、WXT 浏览器扩展（Chrome/Firefox）、CF Workers 部署                                 |\n| `@md/api`        | `apps/api`            | 账户、云同步、计费、上传代理、分享链接、主题/组件市场、表情包（Cloudflare Workers + Hono + D1） |\n| `doocs-md`       | `apps/vscode`         | VS Code 扩展（webpack 构建，marketplace ID 为 `doocs.doocs-md`）                                |\n| `@md/utools`     | `apps/utools`         | uTools 插件打包壳（构建产物来自 `@md/web`）                                                     |\n| `@md/core`       | `packages/core`       | Markdown → HTML 渲染引擎                                                                        |\n| `@md/shared`     | `packages/shared`     | 配置、类型、CodeMirror 编辑器封装、主题 CSS                                                     |\n| `@md/config`     | `packages/config`     | 共享 TypeScript 配置                                                                            |\n| `@doocs/md-cli`  | `packages/md-cli`     | 已发布 npm CLI（Express 静态服务）                                                              |\n| `@md/mcp-server` | `packages/mcp-server` | MCP 服务（`render_markdown` 等工具）                                                            |\n\n独立示例（不在 pnpm workspace 内）：\n\n| 示例              | 路径                                   | 说明                    |\n| ----------------- | -------------------------------------- | ----------------------- |\n| 微信 OpenAPI 代理 | `docs/examples/wechat-openapi-worker/` | 最小 CF Worker 转发示例 |\n\n### 依赖关系\n\n```\napps/web, apps/vscode, packages/mcp-server\n  └── @md/core\n        └── @md/shared\n              └── @md/config (dev)\n```\n\n`@md/core` 与 `@md/shared` **直接导出 TypeScript 源码**，由消费方构建工具（Vite / webpack）编译。\n\n## 渲染管线\n\n```\nMarkdown 原文\n  → @md/core (marked + 自定义扩展)\n  → isomorphic-dompurify 净化\n  → 注入主题 CSS 变量 (@md/core/theme)\n  → HTML 输出（预览）\n  → juice 内联 CSS（仅复制到微信时，在 `@md/web` 导出层）\n  → 剪贴板 HTML（公众号）\n```\n\nWeb 端入口：\n\n1. `useRenderStore`（`apps/web/src/stores/render.ts`）调用 `initRenderer` / `renderMarkdown`\n2. `useThemeStore` 通过 `applyTheme` 将主题 CSS 写入 `<style>` 标签\n3. 编辑器内容变更经 debounce 后触发 `render()`\n\n扩展列表见 `packages/core/src/extensions/`（Mermaid、PlantUML、KaTeX、Ruby、alert、脚注等）。\n\n## Web 应用目录约定（`apps/web/src`）\n\n| 目录                 | 职责                                                                    |\n| -------------------- | ----------------------------------------------------------------------- |\n| `i18n/`              | vue-i18n 配置、locale 检测、按领域拆分的 message 模块                   |\n| `stores/`            | Pinia 全局状态，按领域划分                                              |\n| `composables/`       | 跨组件复用的响应式逻辑                                                  |\n| `services/`          | 外部 API 与领域服务（account / sync / share / upload / export）         |\n| `storage/`           | IndexedDB 抽象层、键前缀与安全读写                                      |\n| `lib/`               | 纯函数与浏览器辅助（bootstrap / browser / format / markdown / preview） |\n| `components/ui/`     | Shadcn-Vue 设计系统（无业务逻辑）                                       |\n| `components/editor/` | 编辑器主界面                                                            |\n| `components/ai/`     | AI 相关 UI                                                              |\n| `components/shared/` | 跨 feature 通用组件                                                     |\n| `entrypoints/`       | WXT 浏览器扩展入口                                                      |\n\n## 状态管理（Web）\n\nPinia stores 按领域划分：\n\n- `useEditorStore` — 编辑器实例与文档内容\n- `useThemeStore` — 主题与样式（含 per-theme 配置持久化）\n- `useRenderStore` — 渲染结果与目录标题\n- `useUIStore` — 布局、对话框、视图模式\n- `useLocaleStore` — 界面语言（zh-CN / zh-TW / en-US / ja-JP），同步 `document.title` 与 i18n 实例\n- `useSyncStore` / `useAuthStore` — 云同步与账户\n- `useMarketplaceStore` — 主题/组件市场目录、安装与发布\n- `useConfirmStore` — 全局确认对话框（`components/shared/confirm-dialog/`）\n\n样式变更后通过 `useEditorRefresh()`（`apps/web/src/composables/useEditorRefresh.ts`）触发预览重渲染。\n\n## 云同步\n\n- **白名单**：`apps/web/src/services/sync/settings.ts` 中的 `SYNC_SETTING_KEYS`（含 `marketplace_installed_themes` / `marketplace_installed_components`）\n- **合并策略**：LWW，元数据存于 `sync_settings_meta`\n- **热更新**：远端设置应用后由 `hydrateSyncedSettings`（`services/sync/hydrate.ts`）写入 Store（含 `locale`），无需刷新页面\n- **用户说明**：见 [cloud-sync.md](./cloud-sync.md)\n\n## 主题 / 组件市场\n\n- **API**：`/marketplace/*`（公开浏览；登录发布；`ADMIN_GITHUB_LOGINS` 审核）\n- **主题包**：安装后以 `mp:<uuid>` 作为独立主题出现在主题选择器；CSS 经 `applyTheme({ themeCSS })` 动态注入\n- **组件包**：安装后写入 `custom_components` 注册表\n- **Web UI**：`MarketplaceDialog`（文件菜单 / 右侧主题栏 / 组件对话框入口）\n\n## 本地存储\n\n- **IndexedDB**（`apps/web/src/storage/`）：文章正文、偏好设置、图床/AI 密钥、缓存分层存储\n- **StorageEngine 抽象**（`storage/manager.ts`）：`store.reactive()` / `store.getJSON()` 统一入口\n- **文章持久化**：`documentRepo` 按篇读写，避免整包 JSON 写入\n- **云同步元数据**：`services/sync/settings.ts` 通过 `store` 读写设置白名单\n- **配额提示**：`storage/quota.ts`（IndexedDB 配额远大于 localStorage，保留 toast 兜底）\n\n### 启动顺序\n\n1. `main.ts` → `bootstrap()`（`apps/web/src/bootstrap.ts`）\n2. `initComponentDarkVars()` + `setupComponents()`\n3. `await initStorage()`（迁移 localStorage、预加载 KV 缓存、加载文档）\n4. `setupI18n(detectInitialLocale())` + `setAppI18n()`，注册 vue-i18n 插件\n5. `createApp`、Pinia、`useLocaleStore()` 并挂载\n6. `App.vue` 中 `usePlatformEnv()`、`useAccountSyncBootstrap()`、`useDeepLinkImport()` 完成账户与深链引导\n\n### 国际化（i18n）\n\n- **范围**：`apps/web` 主应用 UI；扩展 popup / background 部分文案。VS Code、uTools、CLI、MCP 无 i18n。\n- **入口**：`apps/web/src/i18n/`（`detect.ts`、`translate.ts`、`messages/`）\n- **偏好**：`PreferencesDialog`（文件菜单或 `Ctrl+,`）→ General → Language\n- **动态 UI**：命令面板、快捷键列表、Slash 命令、CodeMirror placeholder 等在 `locale` 变化时重建；Store 内 toast 使用 `@/i18n/translate` 的 `t()`\n\n## 构建\n\n- Web：Vite 8，`manualChunks` 拆分 codemirror、katex、highlight 等\n- VSCode 扩展：webpack，预览渲染复用 `@md/core`（见 `apps/vscode/src/previewRenderer.ts`）\n- 浏览器扩展：WXT，`src/entrypoints/` 为入口\n- Core / Shared：**直接导出 TypeScript 源码**，由消费方构建工具编译\n\n## 静态资源\n\nWeb 应用静态资源统一放在 `apps/web/public/`（如 `mpmd/` 图标）。根目录不再有 `public/` 副本。\n\n<!-- File: .cursor/mcp.json (Tokens: ~68 | Category: mcp-config) -->\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n\n<!-- File: apps/utools/plugin.json (Tokens: ~193 | Category: plugin-manifest) -->\n{\n  \"pluginName\": \"微信 Markdown 编辑器\",\n  \"description\": \"Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用\",\n  \"version\": \"2.1.0\",\n  \"author\": \"doocs\",\n  \"homepage\": \"https://github.com/doocs/md\",\n  \"pluginType\": \"tool\",\n  \"platform\": [\n    \"win32\",\n    \"darwin\",\n    \"linux\"\n  ],\n  \"logo\": \"logo.png\",\n  \"main\": \"dist/index.html\",\n  \"preload\": \"preload.js\",\n  \"features\": [\n    {\n      \"code\": \"wechat-md\",\n      \"explain\": \"打开微信 Markdown 编辑器\",\n      \"cmds\": [\n        \"微信排版\",\n        \"Markdown 编辑器\",\n        \"doocs md\"\n      ]\n    }\n  ]\n}\n\n<!-- File: apps/utools/README.md (Tokens: ~548 | Category: plugin-manifest) -->\n# uTools 插件打包指引\n\n该目录包含将微信 Markdown 编辑器打包为 [uTools](https://u.tools) 插件所需的脚本与配置。\n\n## 快速开始\n\n```sh\npnpm utools:package\n```\n\n该命令将完成以下动作：\n\n1. 调用 `pnpm --filter @md/web run build:utools` 构建前端资源至 `apps/utools/dist`，该构建将自动使用相对路径，确保在 uTools 的 `file://` 协议下能够正常加载。MathJax 从 `node_modules` 复制到构建产物中，Mermaid 作为 npm 模块打包。\n2. 将仓库根目录的版本号写入 `apps/utools/plugin.json`，保持与主项目同步。\n3. 从 `apps/web/public/mpmd/icon-256.png` 拷贝插件图标至 `apps/utools/logo.png`。\n4. 生成形如 `apps/utools/release/md-utools-vX.Y.Z.zip` 的安装包，可直接导入到 uTools。\n\n> 注意：命令执行前请确认已安装 pnpm 10+ 与 Node.js 22+，并在仓库根目录执行 `pnpm install` 安装依赖。\n\n## 手动导入调试\n\n1. 运行 `pnpm --filter @md/web run build:utools`。\n2. 打开 uTools，进入插件面板中的「开发者工具」。\n3. 选择「载入本地插件」，指向 `apps/utools` 目录即可。\n\n## 目录说明\n\n- `plugin.json`：uTools 插件的清单文件。\n- `preload.js`：在 uTools 渲染进程和 Web 前端之间建立通信的脚本，用于处理插件唤起事件。\n- `package.json`：将此目录标记为 CommonJS 模块以兼容 uTools。\n- `dist/`：由 Vite 构建输出的静态资源目录。\n- `release/`：运行打包命令后生成的插件安装包。\n\n<!-- File: packages/core/README.md (Tokens: ~499 | Category: plugin-manifest) -->\n# @md/core\n\nMarkdown 渲染引擎：将 Markdown 转为适合微信公众号的 HTML。\n\n## 导出\n\n| 路径                  | 说明                                                      |\n| --------------------- | --------------------------------------------------------- |\n| `@md/core`            | 主入口：`initRenderer`、`renderMarkdown`、`applyTheme` 等 |\n| `@md/core/renderer`   | 渲染器实现                                                |\n| `@md/core/extensions` | marked 扩展（Mermaid、KaTeX、alert 等）                   |\n| `@md/core/utils`      | `postProcessHtml`、`renderMarkdown` 辅助                  |\n| `@md/core/theme`      | 主题注入与 CSS 变量                                       |\n\n## 基本用法\n\n```ts\nimport { initRenderer, renderMarkdown } from '@md/core'\nimport { postProcessHtml } from '@md/core/utils'\n\nconst renderer = initRenderer({\n  isMacCodeBlock: true,\n  isShowLineNumber: true,\n})\n\nconst html = postProcessHtml(renderMarkdown(renderer, markdown))\n```\n\n主题样式需配合 `@md/core/theme` 的 `applyTheme` 或 Web 端 `useThemeStore.applyCurrentTheme()` 注入 CSS。\n\n## 扩展\n\n扩展位于 `src/extensions/`，在 `renderer-impl.ts` 中注册。新增扩展时：\n\n1. 在 `src/extensions/` 实现 marked 扩展\n2. 在 `src/extensions/index.ts` 导出\n3. 在 `initRenderer` 中注册\n\n## 依赖说明\n\n- **marked** — Markdown 解析\n- **highlight.js** — 代码高亮\n- **mermaid / @antv/infographic** — 图表（按需加载仍建议在消费方做 code-splitting）\n- **isomorphic-dompurify** — HTML 净化（`sanitizeHtml`）\n- **juice** — CSS 内联（仅 Web 端复制到微信时使用，不在本包内）\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n\n<!-- File: packages/mcp-server/README.md (Tokens: ~1540 | Category: plugin-manifest) -->\n# @md/mcp-server\n\nMCP (Model Context Protocol) server for [doocs/md](https://github.com/doocs/md).\n\nExposes the `doocs/md` markdown rendering engine and AI service configuration to AI agent runtimes (Claude Desktop, Cursor, VS Code Copilot, etc.) via the standard MCP protocol over **stdio**.\n\n## Prerequisites\n\n- **Node.js** ≥ 22.22.2（与 monorepo 根目录 `.nvmrc` 一致）\n- **pnpm** ≥ 9（monorepo workspace）\n- Clone the monorepo and install dependencies:\n\n```bash\ngit clone https://github.com/doocs/md.git\ncd md\npnpm install\n```\n\n## Tools\n\n### `render_markdown`\n\nConvert Markdown text to styled HTML using the full doocs/md rendering pipeline.\n\n| Parameter          | Type                               | Default     | Description                                            |\n| ------------------ | ---------------------------------- | ----------- | ------------------------------------------------------ |\n| `markdown`         | `string`                           | —           | Markdown source text                                   |\n| `theme`            | `\"default\" \\| \"grace\" \\| \"simple\"` | `\"default\"` | Visual theme (经典 / 优雅 / 简洁)                      |\n| `primaryColor`     | `string (hex)`                     | `\"#0F4C81\"` | Primary accent color (see `list_colors`)               |\n| `fontFamily`       | `string`                           | 无衬线预设  | Font family stack (see `list_fonts`)                   |\n| `fontSize`         | `string (px)`                      | `\"16px\"`    | Base font size (see `list_font_sizes`)                 |\n| `legend`           | `string`                           | `\"alt\"`     | Image caption format (see `list_legend_formats`)       |\n| `isMacCodeBlock`   | `boolean`                          | `false`     | Render code blocks with a macOS-style title bar        |\n| `isShowLineNumber` | `boolean`                          | `false`     | Show line numbers in code blocks                       |\n| `citeStatus`       | `boolean`                          | `false`     | Convert links to footnote-style citations              |\n| `countStatus`      | `boolean`                          | `false`     | Prepend a reading-time estimate                        |\n| `themeMode`        | `\"light\" \\| \"dark\"`                | `\"light\"`   | Color mode for diagram extensions                      |\n| `isUseIndent`      | `boolean`                          | `false`     | Indent paragraph first lines                           |\n| `isUseJustify`     | `boolean`                          | `false`     | Justify paragraph text                                 |\n| `headingStyles`    | `object`                           | `{}`        | Per-level heading styles (see `list_heading_styles`)   |\n| `codeBlockTheme`   | preset URL                         | GitHub 主题 | highlight.js preset from `list_code_block_themes` only |\n| `customCSS`        | `string`                           | `\"\"`        | Additional custom CSS (highest priority)               |\n\nReturns `{ html, frontMatter, readingTime: { words, minutes } }`.\n\n### Other tools\n\n| Tool                     | Description                                                                       |\n| ------------------------ | --------------------------------------------------------------------------------- |\n| `list_themes`            | List all available visual themes with labels and authors                          |\n| `list_colors`            | List all available primary accent colors                                          |\n| `list_fonts`             | List preset font family options                                                   |\n| `list_font_sizes`        | List preset font size options                                                     |\n| `list_legend_formats`    | List image caption format options                                                 |\n| `list_heading_styles`    | List heading style presets                                                        |\n| `list_code_block_themes` | List highlight.js code block theme URLs                                           |\n| `list_ai_services`       | List all built-in AI service providers with endpoints and models                  |\n| `explain_extensions`     | Describe every Markdown extension beyond CommonMark (KaTeX, Mermaid, PlantUML, …) |\n| `get_renderer_options`   | Describe all renderer configuration options                                       |\n\n## Setup\n\n### VS Code (GitHub Copilot)\n\nAdd to `.vscode/mcp.json` in the project root (already included in this repo):\n\n```json\n{\n  \"servers\": {\n    \"md\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"--import\", \"tsx/esm\", \"${workspaceFolder}/packages/mcp-server/run.mjs\"],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open the **MCP** panel in VS Code and start the `md` server.\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"C:/path/to/md/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"C:/path/to/md/packages/mcp-server\"\n    }\n  }\n}\n```\n\nReplace `C:/path/to/md` with the absolute path to your cloned repository.\n\n### Cursor\n\nAdd to `.cursor/mcp.json` at the project root (already included in this repo):\n\n```json\n{\n  \"mcpServers\": {\n    \"md\": {\n      \"command\": \"node\",\n      \"args\": [\n        \"--import\",\n        \"tsx/esm\",\n        \"${workspaceFolder}/packages/mcp-server/run.mjs\"\n      ],\n      \"cwd\": \"${workspaceFolder}/packages/mcp-server\"\n    }\n  }\n}\n```\n\nThen open **Cursor Settings → MCP** and enable the `md` server.\n\n### Windsurf / Other MCP Clients\n\nUse the same stdio pattern:\n\n```json\n{\n  \"command\": \"node\",\n  \"args\": [\"--import\", \"tsx/esm\", \"/absolute/path/to/packages/mcp-server/run.mjs\"],\n  \"cwd\": \"/absolute/path/to/packages/mcp-server\"\n}\n```\n\n## Example Prompts\n\nOnce the server is connected, you can ask your AI assistant:\n\n```\n使用 grace 主题将下面的 Markdown 渲染为 HTML，开启代码行号：\n# Hello World\n```\n\n```\n列出所有可用主题，并解释每个主题的风格特点。\n```\n\n```\nrender_markdown 支持哪些 Markdown 扩展？给我每个扩展的示例写法。\n```\n\n```\n列出所有内置 AI 服务，帮我找一个支持 DeepSeek-V3 的接入点。\n```\n\n## Development\n\n```bash\n# Run server directly (connects to stdin/stdout — for manual testing)\npnpm --filter @md/mcp-server start\n\n# Watch mode (auto-restart on changes)\npnpm --filter @md/mcp-server dev\n```\n\nTo test manually, use [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector node --import tsx/esm run.mjs\n```\n\n<!-- File: packages/md-cli/README.md (Tokens: ~279 | Category: plugin-manifest) -->\n# md-cli\n\nA powerful yet simple tool for rendering Markdown documents locally during development.\n\n## Installation\n\nTo get started with `md-cli`, you can install it either globally or locally, depending on your needs.\n\n### Install locally\n\nIf you only need it for a specific project, you can install it locally by running:\n\n```bash\nnpm install @doocs/md-cli\n```\n\n### Install globally\n\nFor global access across all your projects, install it globally with:\n\n```bash\nnpm install -g @doocs/md-cli\n```\n\n## Usage\n\nOnce installed, running `md-cli` is a breeze. Here’s how to get started:\n\n### Default setup\n\nTo launch `md-cli` with the default settings, simply run:\n\n```bash\nmd-cli\n```\n\n### Custom port\n\nIf you prefer to run `md-cli` on a different port, say `8899`, just specify it like this:\n\n```bash\nmd-cli port=8899\n```\n\n## Maintainers\n\n- [yanglbme](https://github.com/yanglbme) – Core maintainer.\n- [YangFong](https://github.com/yangfong) – Core maintainer.\n- [xw](https://github.com/wll8) – Contributor.\n- [thinkasany](https://www.npmjs.com/~thinkerwing) – Contributor.\n\n<!-- File: packages/shared/README.md (Tokens: ~442 | Category: plugin-manifest) -->\n# @md/shared\n\n跨应用共享的配置、类型、工具与 CodeMirror 编辑器封装。\n\n## 导出\n\n| 路径                   | 说明                                   |\n| ---------------------- | -------------------------------------- |\n| `@md/shared`           | 主入口                                 |\n| `@md/shared/configs`   | 主题、字体、颜色等默认配置与选项列表   |\n| `@md/shared/constants` | 常量                                   |\n| `@md/shared/types`     | 共享 TypeScript 类型                   |\n| `@md/shared/utils`     | fetch、tokenTools 等工具               |\n| `@md/shared/editor`    | CodeMirror 6 setup、格式化命令、快捷键 |\n\n## 主要配置（`configs`）\n\n- `themeOptions` / `defaultStyleConfig` — 主题名与默认样式\n- `defaultPerThemeSettings` — 每个主题的独立配置结构\n- `fontFamilyOptions` / `fontSizeOptions` / `colorOptions` — 样式面板选项\n- `ctrlKey` / `ctrlSign` — 平台相关快捷键展示\n\n主题 CSS 源文件位于 `src/configs/theme-css/`（如 `default.css`、`grace.css`）。\n\n## 编辑器（`editor`）\n\nWeb 与 VSCode 扩展共用 CodeMirror 配置：\n\n```ts\nimport { applyHeading, formatBold, markdownSetup, theme } from '@md/shared/editor'\n```\n\n## 消费方\n\n- `apps/web` — 主编辑器 UI\n- `apps/vscode` — VSCode 预览侧边栏\n- `packages/core` — 渲染相关类型与工具\n\n## 相关文档\n\n- [架构概览](../../docs/architecture.md)\n- [AGENTS.md](../../AGENTS.md)\n</yakaai_skills>"}