adspecs 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.adspecs/feature.json +16 -16
- package/.adspecs/feature.yml +28 -28
- package/.adspecs/paths.json +17 -17
- package/.adspecs/templates/04-/345/211/215/347/253/257/345/212/237/350/203/275/350/256/276/350/256/241/346/250/241/346/235/277.md +1 -1
- package/.adspecs/templates/05-/345/220/216/347/253/257/344/273/273/345/212/241/346/270/205/345/215/225/346/250/241/346/235/277.md +613 -724
- package/.adspecs/templates/05b-/345/211/215/347/253/257/344/273/273/345/212/241/346/270/205/345/215/225/346/250/241/346/235/277.md +51 -51
- package/.claude-plugin/marketplace.json +23 -23
- package/.claude-plugin/plugin.json +18 -18
- package/.qoder-plugin/plugin.json +31 -31
- package/CLAUDE.md +1 -5
- package/INSTALL.md +3 -3
- package/README.md +395 -395
- package/bin/adspecs.js +129 -129
- package/hooks/commit-queue.js +245 -245
- package/hooks/hooks.json +63 -63
- package/hooks/session-start.js +44 -44
- package/hooks/wiki-queue.js +127 -127
- package/package.json +61 -61
- package/references/ant6-front-standard/index.md +99 -99
- package/references/antd-front-demo/public/mockServiceWorker.js +361 -361
- package/references/ecp-end-standard/index.md +63 -63
- package/references/python-end-standard/01-Python/345/220/216/347/253/257/347/274/226/347/240/201/350/247/204/350/214/203.md +372 -372
- package/references/python-end-standard/02-/346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/344/270/216/344/275/277/347/224/250/350/247/204/350/214/203.md +226 -226
- package/references/python-end-standard/03-Celery/345/274/202/346/255/245/344/273/273/345/212/241/350/247/204/350/214/203.md +237 -237
- package/references/python-end-standard/04-Redis/344/275/277/347/224/250/350/247/204/350/214/203.md +231 -231
- package/scripts/postinstall.js +107 -107
- package/scripts/sync-version.js +105 -105
- package/skills/.claude/.wiki-update-queue +26 -26
- package/skills/adspecs-constitution/SKILL.md +157 -0
- package/skills/adspecs-export-word/SKILL.md +498 -498
- package/skills/adspecs-export-word/references/md-to-docx.js +862 -862
- package/skills/adspecs-export-word/references/package-lock.json +220 -220
- package/skills/adspecs-export-word/references/package.json +10 -10
- package/skills/adspecs-front-prototype/SKILL.md +405 -405
- package/skills/adspecs-front-spec/SKILL.md +4 -4
- package/skills/adspecs-front-tasks/SKILL.md +213 -173
- package/skills/adspecs-plan/SKILL.md +59 -69
- package/skills/adspecs-prd/SKILL.md +13 -5
- package/skills/adspecs-prd-to-demo/SKILL.md +532 -0
- package/skills/adspecs-tasks/SKILL.md +175 -204
- package/skills/adspecs-update-status/SKILL.md +382 -382
- package/skills/adspecs-utest/SKILL.md +107 -116
- package/skills/grill-me/SKILL.md +7 -0
- package/skills/grill-me/agents/openai.yaml +5 -0
- package/skills/playwright-cli/SKILL.md +420 -0
- package/skills/playwright-cli/references/element-attributes.md +23 -0
- package/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/skills/playwright-cli/references/request-mocking.md +87 -0
- package/skills/playwright-cli/references/running-code.md +241 -0
- package/skills/playwright-cli/references/session-management.md +225 -0
- package/skills/playwright-cli/references/storage-state.md +275 -0
- package/skills/playwright-cli/references/test-generation.md +433 -0
- package/skills/playwright-cli/references/tracing.md +139 -0
- package/skills/playwright-cli/references/video-recording.md +143 -0
- package/skills/playwright-trace/SKILL.md +171 -0
- package/skills/project-init/SKILL.md +93 -22
- package/skills/project-init/references/front-demo/.claude/settings.local.json +9 -0
- package/skills/wiki-update/SKILL.md +232 -232
- package/src/commands/doctor.js +197 -197
- package/src/commands/init.js +83 -83
- package/src/commands/plugin.js +165 -165
- package/src/commands/update.js +87 -87
- package/src/lib/area-scanner.js +129 -129
- package/src/lib/copier.js +104 -104
- package/src/lib/dir-utils.js +161 -133
- package/src/lib/json-merge.js +114 -114
- package/src/lib/paths-defaults.js +37 -37
- package/src/lib/prompts.js +428 -347
- package/src/lib/readme-gen.js +143 -143
- package/src/lib/report.js +338 -327
- package/src/lib/scaffolder.js +551 -518
- package/src/lib/short-name.js +36 -36
- package/src/utils.js +80 -80
- package/references/antd-front-demo/.env +0 -15
|
@@ -1,498 +1,498 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "adspecs-export-word"
|
|
3
|
-
description: "将 Markdown 文档导出为 Word (.docx),自动生成封面页和目录索引页。支持单文件或批量目录转换。"
|
|
4
|
-
argument-hint: "指定 .md 文件路径或目录路径,如 docs/20-prd/xxx.md 或 docs/30-system-design/"
|
|
5
|
-
compatibility: "需要 Node.js (>= 18)"
|
|
6
|
-
metadata:
|
|
7
|
-
author: "Qingwen Chen"
|
|
8
|
-
user-invocable: true
|
|
9
|
-
disable-model-invocation: false
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Markdown 导出 Word (Export to Word)
|
|
13
|
-
|
|
14
|
-
## 用户输入
|
|
15
|
-
|
|
16
|
-
```text
|
|
17
|
-
$ARGUMENTS
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**必须** 在继续之前考虑用户输入(如果非空)。
|
|
21
|
-
|
|
22
|
-
## 路径配置加载
|
|
23
|
-
|
|
24
|
-
在开始执行之前,先确定输出目录:
|
|
25
|
-
|
|
26
|
-
1. 检查项目根目录是否存在 `.adspecs/paths.json`
|
|
27
|
-
2. 如果存在,读取其中的 `paths` 对象,提取本技能需要的配置键
|
|
28
|
-
3. 如果不存在或配置键缺失,使用下方表格中的默认值
|
|
29
|
-
|
|
30
|
-
| 配置键 | 默认值 | 用途 |
|
|
31
|
-
| ------------------ | ---------------------- | -------------------------------- |
|
|
32
|
-
| `export_dir` | `docs/90-export` | Word 导出输出目录 |
|
|
33
|
-
| `architecture_dir` | `docs/10-architecture` | 架构文档目录(读取项目模块信息) |
|
|
34
|
-
|
|
35
|
-
将解析后的路径记为 `EXPORT_DIR` 和 `ARCH_DIR`,后续步骤中引用此变量而非硬编码路径。
|
|
36
|
-
|
|
37
|
-
## 定位
|
|
38
|
-
|
|
39
|
-
本 skill 专注于 **Markdown → Word (.docx) 文档导出**,自动完成:
|
|
40
|
-
|
|
41
|
-
1. **封面页生成** — 包含项目名称、文档标题、版本号、日期、作者、审核人、批准人、公司 Logo、公司名称、文档编号、保密等级
|
|
42
|
-
2. **目录索引页生成** — 基于 Markdown heading 结构自动生成目录(深度到 H3)
|
|
43
|
-
3. **正文转换** — 将 Markdown 内容完整转换为 Word 格式,保持标题层级、表格、代码块、列表等格式
|
|
44
|
-
|
|
45
|
-
**典型使用场景**:
|
|
46
|
-
|
|
47
|
-
- 将 PRD、系统设计文档导出为 Word 供业务方/客户审阅
|
|
48
|
-
- 将需求分析文档导出为正式交付物
|
|
49
|
-
- 批量导出 `docs/` 目录下的文档供归档
|
|
50
|
-
|
|
51
|
-
**技术实现**:使用 Node.js + `docx` + `marked` 库,零系统级依赖(不需要安装 pandoc)。
|
|
52
|
-
|
|
53
|
-
## 执行前检查
|
|
54
|
-
|
|
55
|
-
### 1. Node.js 可用性检查
|
|
56
|
-
|
|
57
|
-
执行 `node --version`,确认 Node.js 已安装且版本 >= 18。
|
|
58
|
-
|
|
59
|
-
**如果 Node.js 未安装**,输出安装指引:
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
❌ 未检测到 Node.js,请先安装:
|
|
63
|
-
|
|
64
|
-
Windows:
|
|
65
|
-
winget install OpenJS.NodeJS.LTS # winget
|
|
66
|
-
choco install nodejs-lts # Chocolatey
|
|
67
|
-
scoop install nodejs-lts # Scoop
|
|
68
|
-
|
|
69
|
-
macOS:
|
|
70
|
-
brew install node@20 # Homebrew
|
|
71
|
-
|
|
72
|
-
Linux:
|
|
73
|
-
sudo apt install nodejs npm # Debian/Ubuntu
|
|
74
|
-
sudo dnf install nodejs npm # Fedora/RHEL
|
|
75
|
-
|
|
76
|
-
通用:
|
|
77
|
-
从 https://nodejs.org/ 下载安装 LTS 版本
|
|
78
|
-
|
|
79
|
-
安装后重新执行本命令。
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### 2. npm 依赖检查
|
|
83
|
-
|
|
84
|
-
检查本 skill 的 Node.js 依赖是否已安装:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
SKILL_DIR="<SKILL.md 所在目录>"
|
|
88
|
-
cd "$SKILL_DIR/references"
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
执行 `npm ls docx marked`,检查依赖是否存在。
|
|
92
|
-
|
|
93
|
-
**如果依赖未安装**(首次使用),自动执行安装:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
cd "$SKILL_DIR/references" && npm install
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
安装成功后继续。安装失败则输出错误并终止。
|
|
100
|
-
|
|
101
|
-
### 3. 检查扩展钩子(导出前)
|
|
102
|
-
|
|
103
|
-
- 检查项目根目录是否存在 `.adspecs/extensions.yml`。
|
|
104
|
-
- 如果存在,读取它并查找 `hooks.before_export_word` 下的条目。
|
|
105
|
-
- 如果 YAML 无法解析或无效,静默跳过钩子检查并继续正常执行。
|
|
106
|
-
- 过滤掉 `enabled` 明确为 `false` 的钩子。没有 `enabled` 字段的钩子默认视为启用。
|
|
107
|
-
- 对于每个剩余的钩子,**不要** 尝试解释或评估钩子的 `condition` 表达式:
|
|
108
|
-
- 如果钩子没有 `condition` 字段,或为空/null,视为可执行。
|
|
109
|
-
- 如果钩子定义了非空的 `condition`,跳过该钩子,将条件评估留给 HookExecutor 实现。
|
|
110
|
-
- 从钩子命令名构造斜杠命令时,将点号(`.`)替换为连字符(`-`)。例如:`adspecs.git.commit` → `/adspecs-git-commit`。
|
|
111
|
-
- 对于每个可执行钩子,根据其 `optional` 标志输出以下内容:
|
|
112
|
-
- **可选钩子** (`optional: true`):
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
## 扩展钩子
|
|
116
|
-
|
|
117
|
-
**可选前置钩子**: {extension}
|
|
118
|
-
命令: `/{command}`
|
|
119
|
-
描述: {description}
|
|
120
|
-
|
|
121
|
-
提示: {prompt}
|
|
122
|
-
执行: `/{command}`
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
- **必选钩子** (`optional: false`):
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
## 扩展钩子
|
|
129
|
-
|
|
130
|
-
**自动前置钩子**: {extension}
|
|
131
|
-
执行: `/{command}`
|
|
132
|
-
EXECUTE_COMMAND: {command}
|
|
133
|
-
|
|
134
|
-
等待钩子命令结果后再继续执行。
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
- 如果没有注册钩子或 `.adspecs/extensions.yml` 不存在,静默跳过。
|
|
138
|
-
|
|
139
|
-
## 参数解析
|
|
140
|
-
|
|
141
|
-
从 `$ARGUMENTS` 中解析以下参数:
|
|
142
|
-
|
|
143
|
-
### 位置参数(必选)
|
|
144
|
-
|
|
145
|
-
| 参数 | 说明 | 示例 |
|
|
146
|
-
| ------------- | ------------------------------------------ | ------------------------ |
|
|
147
|
-
| 文件/目录路径 | 要转换的 `.md` 文件或包含 `.md` 文件的目录 | `docs/20-prd/crm-prd.md` |
|
|
148
|
-
|
|
149
|
-
### 可选标志
|
|
150
|
-
|
|
151
|
-
| 标志 | 说明 | 默认值 |
|
|
152
|
-
| ----------------- | ----------------------------------- | ---------------- |
|
|
153
|
-
| `--output <路径>` | 自定义输出路径(覆盖 `EXPORT_DIR`) | `{EXPORT_DIR}/` |
|
|
154
|
-
| `--no-cover` | 跳过封面页生成 | 生成封面页 |
|
|
155
|
-
| `--no-toc` | 跳过目录索引页生成 | 生成目录 |
|
|
156
|
-
| `--recursive` | 目录模式下递归扫描子目录 | 仅扫描当前层 |
|
|
157
|
-
|
|
158
|
-
### 参数解析流程
|
|
159
|
-
|
|
160
|
-
1. 从 `$ARGUMENTS` 中分离位置参数和可选标志
|
|
161
|
-
2. 如果位置参数为空 → 使用 **AskUserQuestion** 让用户选择文件或输入路径
|
|
162
|
-
3. 判断位置参数是文件还是目录,确定工作模式
|
|
163
|
-
|
|
164
|
-
## 项目元数据提取
|
|
165
|
-
|
|
166
|
-
从以下来源提取封面页信息(优先级从高到低):
|
|
167
|
-
|
|
168
|
-
### 提取来源
|
|
169
|
-
|
|
170
|
-
| 优先级 | 来源 | 可提取字段 |
|
|
171
|
-
| ------ | ------------------------------------------- | ------------------------------------------ |
|
|
172
|
-
| 1 | `.adspecs/project.json` | 项目名称、公司名、公司 Logo 路径、保密等级 |
|
|
173
|
-
| 2 | Markdown 文件 YAML frontmatter / 头部元信息 | 文档标题、版本、模块编号、模块名称 |
|
|
174
|
-
| 3 | `CLAUDE.md` 第一行 `#` 标题 | 项目名称 |
|
|
175
|
-
| 4 | `git config user.name` | 作者 |
|
|
176
|
-
| 5 | 当前日期 | 创建日期 |
|
|
177
|
-
| 6 | **AskUserQuestion** 交互补全 | 审核人、批准人、文档编号、保密等级 |
|
|
178
|
-
|
|
179
|
-
### `.adspecs/project.json` 结构(可选)
|
|
180
|
-
|
|
181
|
-
```json
|
|
182
|
-
{
|
|
183
|
-
"project_name": "CRM 客户关系管理平台",
|
|
184
|
-
"project_short_name": "crm",
|
|
185
|
-
"company_name": "XX 科技有限公司",
|
|
186
|
-
"company_logo": "docs/assets/logo.png",
|
|
187
|
-
"confidentiality": "内部 — 机密"
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
如果 `project.json` 不存在,从 `CLAUDE.md` 和 git config 提取,缺失字段用 AskUserQuestion 补全。
|
|
192
|
-
|
|
193
|
-
### 元数据字段清单
|
|
194
|
-
|
|
195
|
-
| 字段 | 变量名 | 提取方式 | 必填 |
|
|
196
|
-
| --------- | ----------------- | ------------------------------------- | ---- |
|
|
197
|
-
| 文档标题 | `title` | Markdown H1 或文件名 | ✅ |
|
|
198
|
-
| 副标题 | `subtitle` | frontmatter 或模块名称 | — |
|
|
199
|
-
| 项目名称 | `project_name` | project.json / CLAUDE.md | ✅ |
|
|
200
|
-
| 公司名称 | `company_name` | project.json / 交互 | ✅ |
|
|
201
|
-
| 公司 Logo | `company_logo` | project.json / `docs/assets/logo.png` | — |
|
|
202
|
-
| 作者 | `author` | git config user.name | ✅ |
|
|
203
|
-
| 审核人 | `reviewer` | 交互补全 | — |
|
|
204
|
-
| 批准人 | `approver` | 交互补全 | — |
|
|
205
|
-
| 版本号 | `version` | frontmatter / 默认 "v1.0" | ✅ |
|
|
206
|
-
| 日期 | `date` | 当前日期 | ✅ |
|
|
207
|
-
| 文档编号 | `document_number` | 自动生成或交互 | — |
|
|
208
|
-
| 保密等级 | `confidentiality` | project.json / 默认 "内部使用" | ✅ |
|
|
209
|
-
|
|
210
|
-
### 文档编号自动生成规则
|
|
211
|
-
|
|
212
|
-
格式:`DOC-{MODULE_ID}-{DOC_TYPE}-{SEQ}`
|
|
213
|
-
|
|
214
|
-
- `MODULE_ID`:从文档内容或所在目录识别的模块编号(如 M03-02)
|
|
215
|
-
- `DOC_TYPE`:从文档类型推断(PRD / BRD / SDD / TR / SOW 等)
|
|
216
|
-
- `SEQ`:同类型文档序号,从 001 开始
|
|
217
|
-
|
|
218
|
-
如无法自动生成,使用 AskUserQuestion 让用户输入或留空。
|
|
219
|
-
|
|
220
|
-
### 元数据补全交互
|
|
221
|
-
|
|
222
|
-
对于必填但无法自动提取的字段,使用 **AskUserQuestion** 一次性收集:
|
|
223
|
-
|
|
224
|
-
```
|
|
225
|
-
请补全以下封面页信息:
|
|
226
|
-
- 审核人:{输入或留空}
|
|
227
|
-
- 批准人:{输入或留空}
|
|
228
|
-
- 文档编号:{自动生成值或自定义}
|
|
229
|
-
- 保密等级:[公开 / 内部使用 / 机密 / 绝密]
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## 执行步骤
|
|
233
|
-
|
|
234
|
-
### 步骤 1:确定工作模式
|
|
235
|
-
|
|
236
|
-
根据参数解析结果确定工作模式:
|
|
237
|
-
|
|
238
|
-
| 模式 | 触发条件 | 行为 |
|
|
239
|
-
| ---------- | --------------------------- | --------------------------------------------- |
|
|
240
|
-
| **单文件** | 参数是单个 `.md` 文件路径 | 转换该文件 |
|
|
241
|
-
| **多文件** | 参数包含多个 `.md` 文件路径 | 逐个转换 |
|
|
242
|
-
| **目录** | 参数是目录路径 | 扫描目录下所有 `.md` 文件(排除 `README.md`) |
|
|
243
|
-
| **交互** | 参数为空 | 使用 AskUserQuestion 选择文件或输入路径 |
|
|
244
|
-
|
|
245
|
-
**目录模式扫描规则**:
|
|
246
|
-
|
|
247
|
-
- 默认扫描当前层:`{dir}/*.md`
|
|
248
|
-
- 带 `--recursive` 标志:`{dir}/**/*.md`
|
|
249
|
-
- 排除:`README.md`、隐藏目录(`.git/`、`.claude/`、`.adspecs/`、`node_modules/`)中的文件
|
|
250
|
-
- 列出待转换文件清单,显示给用户确认
|
|
251
|
-
|
|
252
|
-
### 步骤 2:提取项目元数据
|
|
253
|
-
|
|
254
|
-
按"项目元数据提取"章节的规则,从各来源提取封面页信息:
|
|
255
|
-
|
|
256
|
-
1. 读取 `.adspecs/project.json`(如存在)
|
|
257
|
-
2. 读取目标 `.md` 文件头部元信息(frontmatter 或 `> **版本**:` 格式)
|
|
258
|
-
3. 读取 `CLAUDE.md` 提取项目名称
|
|
259
|
-
4. 执行 `git config user.name` 获取作者
|
|
260
|
-
5. 对缺失的必填字段使用 AskUserQuestion 补全
|
|
261
|
-
|
|
262
|
-
将提取结果记为元数据 JSON 对象,后续步骤使用。
|
|
263
|
-
|
|
264
|
-
### 步骤 3:执行 Node.js 转换脚本
|
|
265
|
-
|
|
266
|
-
**确定路径变量**:
|
|
267
|
-
|
|
268
|
-
```
|
|
269
|
-
SKILL_DIR = SKILL.md 所在目录
|
|
270
|
-
SCRIPT_PATH = "{SKILL_DIR}/references/md-to-docx.js"
|
|
271
|
-
OUTPUT_DIR = --output 参数值 或 EXPORT_DIR(默认 docs/90-export)
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
如果输出目录不存在,自动创建。
|
|
275
|
-
|
|
276
|
-
**构造元数据 JSON 字符串**:
|
|
277
|
-
|
|
278
|
-
```json
|
|
279
|
-
{
|
|
280
|
-
"title": "{文档标题}",
|
|
281
|
-
"subtitle": "{副标题}",
|
|
282
|
-
"project_name": "{项目名称}",
|
|
283
|
-
"company_name": "{公司名称}",
|
|
284
|
-
"company_logo": "{公司 Logo 路径}",
|
|
285
|
-
"author": "{作者}",
|
|
286
|
-
"reviewer": "{审核人}",
|
|
287
|
-
"approver": "{批准人}",
|
|
288
|
-
"version": "{版本号}",
|
|
289
|
-
"date": "{日期}",
|
|
290
|
-
"document_number": "{文档编号}",
|
|
291
|
-
"confidentiality": "{保密等级}"
|
|
292
|
-
}
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
将 JSON 对象序列化为字符串,记为 `META_JSON`。
|
|
296
|
-
|
|
297
|
-
#### 单文件模式
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
node "{SCRIPT_PATH}" \
|
|
301
|
-
--input "{INPUT_FILE}" \
|
|
302
|
-
--output "{OUTPUT_DIR}/{original_name}.docx" \
|
|
303
|
-
--meta '{META_JSON}'
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
附加标志:
|
|
307
|
-
|
|
308
|
-
| 标志 | 脚本参数 |
|
|
309
|
-
| ------------ | ------------ |
|
|
310
|
-
| 跳过封面页 | `--no-cover` |
|
|
311
|
-
| 跳过目录页 | `--no-toc` |
|
|
312
|
-
|
|
313
|
-
#### 目录批量模式
|
|
314
|
-
|
|
315
|
-
```bash
|
|
316
|
-
node "{SCRIPT_PATH}" \
|
|
317
|
-
--dir "{INPUT_DIR}" \
|
|
318
|
-
--output "{OUTPUT_DIR}/" \
|
|
319
|
-
--meta '{META_JSON}'
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
附加标志:
|
|
323
|
-
|
|
324
|
-
| 标志 | 脚本参数 |
|
|
325
|
-
| ------------ | ------------- |
|
|
326
|
-
| 跳过封面页 | `--no-cover` |
|
|
327
|
-
| 跳过目录页 | `--no-toc` |
|
|
328
|
-
| 递归扫描 | `--recursive` |
|
|
329
|
-
|
|
330
|
-
**执行方式**:使用 Bash 工具执行 Node.js 命令。
|
|
331
|
-
|
|
332
|
-
### 步骤 4:解析输出并生成报告
|
|
333
|
-
|
|
334
|
-
脚本执行后,stdout 输出 JSON 格式的结果:
|
|
335
|
-
|
|
336
|
-
```json
|
|
337
|
-
{
|
|
338
|
-
"status": "success",
|
|
339
|
-
"files": [
|
|
340
|
-
{ "input": "crm-prd.md", "output": "crm-prd.docx", "status": "ok" }
|
|
341
|
-
],
|
|
342
|
-
"cover": true,
|
|
343
|
-
"toc": true,
|
|
344
|
-
"total": 1,
|
|
345
|
-
"success": 1,
|
|
346
|
-
"failed": 0
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
根据 JSON 输出生成完成报告:
|
|
351
|
-
|
|
352
|
-
```
|
|
353
|
-
✅ Word 导出完成
|
|
354
|
-
|
|
355
|
-
转换结果:
|
|
356
|
-
| 序号 | 源文件 | 输出文件 | 状态 |
|
|
357
|
-
|------|--------|----------|------|
|
|
358
|
-
| 1 | {input} | {output} | ✅ 成功 |
|
|
359
|
-
| ... | ... | ... | ... |
|
|
360
|
-
|
|
361
|
-
封面页:{'✅ 已生成' 或 '❌ 已跳过 (--no-cover)'}
|
|
362
|
-
目录页:{'✅ 已生成' 或 '❌ 已跳过 (--no-toc)'}
|
|
363
|
-
|
|
364
|
-
输出目录:{OUTPUT_DIR}
|
|
365
|
-
共转换 {total} 个文件,成功 {success} 个,失败 {failed} 个。
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
如果目录页已生成,追加提示:
|
|
369
|
-
|
|
370
|
-
```
|
|
371
|
-
💡 提示:在 Word 中打开文档后,右键点击目录区域选择"更新域"即可刷新目录页码。
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
**错误处理**:
|
|
375
|
-
|
|
376
|
-
| 错误 | 处理 |
|
|
377
|
-
| ----------------------------- | ----------------------------------------------------------------- |
|
|
378
|
-
| 脚本输出 status = "error" | 解析 JSON 中的 message 字段,输出错误详情 |
|
|
379
|
-
| Node.js 进程退出码非 0 | 输出 stderr 内容,提示用户检查 Node.js 安装和 Markdown 文件格式 |
|
|
380
|
-
| `Cannot find module 'docx'` | 在 `references/` 目录执行 `npm install` 后重试 |
|
|
381
|
-
| 图片资源找不到 | 脚本会在文档中插入 `[Image: path]` 占位文本,输出警告 |
|
|
382
|
-
| 文件不存在 | 提示用户检查输入路径 |
|
|
383
|
-
|
|
384
|
-
## 必选执行后钩子
|
|
385
|
-
|
|
386
|
-
**必须在向用户报告完成之前完成本节。**
|
|
387
|
-
|
|
388
|
-
检查项目根目录是否存在 `.adspecs/extensions.yml`。
|
|
389
|
-
|
|
390
|
-
- 如果不存在,或 `hooks.after_export_word` 下没有注册钩子,跳到完成报告。
|
|
391
|
-
- 如果存在,读取它并查找 `hooks.after_export_word` 下的条目。
|
|
392
|
-
- 如果 YAML 无法解析或无效,静默跳过钩子检查并继续完成报告。
|
|
393
|
-
- 过滤掉 `enabled` 明确为 `false` 的钩子。没有 `enabled` 字段的钩子默认视为启用。
|
|
394
|
-
- 对于每个剩余的钩子,**不要** 尝试解释或评估钩子的 `condition` 表达式:
|
|
395
|
-
- 如果钩子没有 `condition` 字段,或为空/null,视为可执行。
|
|
396
|
-
- 如果钩子定义了非空的 `condition`,跳过该钩子,将条件评估留给 HookExecutor 实现。
|
|
397
|
-
- 从钩子命令名构造斜杠命令时,将点号(`.`)替换为连字符(`-`)。例如:`adspecs.git.commit` → `/adspecs-git-commit`。
|
|
398
|
-
- 对于每个可执行钩子,根据其 `optional` 标志输出以下内容:
|
|
399
|
-
- **必选钩子** (`optional: false`) — **必须为每个必选钩子发出 `EXECUTE_COMMAND:`**:
|
|
400
|
-
|
|
401
|
-
```
|
|
402
|
-
## 扩展钩子
|
|
403
|
-
|
|
404
|
-
**自动钩子**: {extension}
|
|
405
|
-
执行: `/{command}`
|
|
406
|
-
EXECUTE_COMMAND: {command}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
- **可选钩子** (`optional: true`):
|
|
410
|
-
|
|
411
|
-
```
|
|
412
|
-
## 扩展钩子
|
|
413
|
-
|
|
414
|
-
**可选钩子**: {extension}
|
|
415
|
-
命令: `/{command}`
|
|
416
|
-
描述: {description}
|
|
417
|
-
|
|
418
|
-
提示: {prompt}
|
|
419
|
-
执行: `/{command}`
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
## 错误处理
|
|
423
|
-
|
|
424
|
-
### 常见错误及解决方案
|
|
425
|
-
|
|
426
|
-
| 错误 | 可能原因 | 解决方案 |
|
|
427
|
-
| ------------------------------------- | ------------------------------------------- | --------------------------------------------------------- |
|
|
428
|
-
| `node: command not found` | Node.js 未安装或不在 PATH 中 | 按安装指引安装 Node.js >= 18 |
|
|
429
|
-
| `Cannot find module 'docx'` | npm 依赖未安装 | 在 `references/` 目录执行 `npm install` |
|
|
430
|
-
| `Cannot find module 'marked'` | npm 依赖未安装 | 在 `references/` 目录执行 `npm install` |
|
|
431
|
-
| `JSON 解析失败` | `--meta` 参数 JSON 格式错误 | 检查 JSON 字符串引号转义 |
|
|
432
|
-
| `文件不存在` | 输入文件路径错误 | 检查 `--input` 路径 |
|
|
433
|
-
| `目录中未找到 .md 文件` | 目录为空或扫描范围不足 | 添加 `--recursive` 标志或检查目录路径 |
|
|
434
|
-
| 图片显示为占位文本 | Markdown 中引用了不存在的图片 | 检查图片路径是否正确 |
|
|
435
|
-
| 目录页码为空 | Word TOC 域未更新 | 在 Word 中右键目录选择"更新域" |
|
|
436
|
-
| 中文乱码或方块字符 | 系统缺少中文字体 | 安装微软雅黑/宋体字体 |
|
|
437
|
-
|
|
438
|
-
## 快速指南
|
|
439
|
-
|
|
440
|
-
### 首次使用准备
|
|
441
|
-
|
|
442
|
-
首次使用前需安装 npm 依赖(仅需执行一次):
|
|
443
|
-
|
|
444
|
-
```bash
|
|
445
|
-
cd skills/adspecs-export-word/references && npm install
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
依赖包括:
|
|
449
|
-
- `docx` (^9.x) — Word 文档生成库
|
|
450
|
-
- `marked` (^15.x) — Markdown 解析器
|
|
451
|
-
|
|
452
|
-
### 基本用法
|
|
453
|
-
|
|
454
|
-
```bash
|
|
455
|
-
# 转换单个文件
|
|
456
|
-
/adspecs-export-word docs/20-prd/crm-prd.md
|
|
457
|
-
|
|
458
|
-
# 转换目录下所有文件
|
|
459
|
-
/adspecs-export-word docs/30-system-design/
|
|
460
|
-
|
|
461
|
-
# 递归转换目录及子目录
|
|
462
|
-
/adspecs-export-word docs/ --recursive
|
|
463
|
-
|
|
464
|
-
# 指定输出路径
|
|
465
|
-
/adspecs-export-word docs/20-prd/crm-prd.md --output /tmp/exports/
|
|
466
|
-
|
|
467
|
-
# 不生成封面页和目录
|
|
468
|
-
/adspecs-export-word docs/20-prd/crm-prd.md --no-cover --no-toc
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### 封面页与目录
|
|
472
|
-
|
|
473
|
-
封面页和目录由 Node.js 脚本自动生成:
|
|
474
|
-
|
|
475
|
-
- **封面页内容**:从 `.adspecs/project.json` 和 Markdown 元信息自动提取
|
|
476
|
-
- **封面页样式**:修改 `references/md-to-docx.js` 中的 `buildCoverPage()` 函数
|
|
477
|
-
- **目录深度**:默认 Heading 1-3,Word 打开后需右键更新目录域
|
|
478
|
-
|
|
479
|
-
### 与 project-init 集成
|
|
480
|
-
|
|
481
|
-
执行 `/project-init` 时会自动:
|
|
482
|
-
|
|
483
|
-
- 创建 `docs/90-export/` 输出目录
|
|
484
|
-
- 生成 `.adspecs/project.json` 提供封面页元数据
|
|
485
|
-
|
|
486
|
-
## 完成标志
|
|
487
|
-
|
|
488
|
-
- [ ] Node.js 可用性已确认(版本 >= 18)
|
|
489
|
-
- [ ] npm 依赖已安装(docx + marked)
|
|
490
|
-
- [ ] 工作模式已确定(单文件/多文件/目录/交互)
|
|
491
|
-
- [ ] 项目元数据已从配置文件和 git 提取
|
|
492
|
-
- [ ] 缺失的必填元数据字段已通过 AskUserQuestion 补全
|
|
493
|
-
- [ ] 元数据 JSON 已构造
|
|
494
|
-
- [ ] Node.js 转换脚本已执行(`md-to-docx.js`)
|
|
495
|
-
- [ ] 封面页已生成(除非 `--no-cover`)
|
|
496
|
-
- [ ] 目录索引页已生成(除非 `--no-toc`)
|
|
497
|
-
- [ ] 完成报告已输出(转换结果表 + 统计数据)
|
|
498
|
-
- [ ] 扩展钩子已根据上述必选执行后钩子规则分发或跳过
|
|
1
|
+
---
|
|
2
|
+
name: "adspecs-export-word"
|
|
3
|
+
description: "将 Markdown 文档导出为 Word (.docx),自动生成封面页和目录索引页。支持单文件或批量目录转换。"
|
|
4
|
+
argument-hint: "指定 .md 文件路径或目录路径,如 docs/20-prd/xxx.md 或 docs/30-system-design/"
|
|
5
|
+
compatibility: "需要 Node.js (>= 18)"
|
|
6
|
+
metadata:
|
|
7
|
+
author: "Qingwen Chen"
|
|
8
|
+
user-invocable: true
|
|
9
|
+
disable-model-invocation: false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Markdown 导出 Word (Export to Word)
|
|
13
|
+
|
|
14
|
+
## 用户输入
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
$ARGUMENTS
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**必须** 在继续之前考虑用户输入(如果非空)。
|
|
21
|
+
|
|
22
|
+
## 路径配置加载
|
|
23
|
+
|
|
24
|
+
在开始执行之前,先确定输出目录:
|
|
25
|
+
|
|
26
|
+
1. 检查项目根目录是否存在 `.adspecs/paths.json`
|
|
27
|
+
2. 如果存在,读取其中的 `paths` 对象,提取本技能需要的配置键
|
|
28
|
+
3. 如果不存在或配置键缺失,使用下方表格中的默认值
|
|
29
|
+
|
|
30
|
+
| 配置键 | 默认值 | 用途 |
|
|
31
|
+
| ------------------ | ---------------------- | -------------------------------- |
|
|
32
|
+
| `export_dir` | `docs/90-export` | Word 导出输出目录 |
|
|
33
|
+
| `architecture_dir` | `docs/10-architecture` | 架构文档目录(读取项目模块信息) |
|
|
34
|
+
|
|
35
|
+
将解析后的路径记为 `EXPORT_DIR` 和 `ARCH_DIR`,后续步骤中引用此变量而非硬编码路径。
|
|
36
|
+
|
|
37
|
+
## 定位
|
|
38
|
+
|
|
39
|
+
本 skill 专注于 **Markdown → Word (.docx) 文档导出**,自动完成:
|
|
40
|
+
|
|
41
|
+
1. **封面页生成** — 包含项目名称、文档标题、版本号、日期、作者、审核人、批准人、公司 Logo、公司名称、文档编号、保密等级
|
|
42
|
+
2. **目录索引页生成** — 基于 Markdown heading 结构自动生成目录(深度到 H3)
|
|
43
|
+
3. **正文转换** — 将 Markdown 内容完整转换为 Word 格式,保持标题层级、表格、代码块、列表等格式
|
|
44
|
+
|
|
45
|
+
**典型使用场景**:
|
|
46
|
+
|
|
47
|
+
- 将 PRD、系统设计文档导出为 Word 供业务方/客户审阅
|
|
48
|
+
- 将需求分析文档导出为正式交付物
|
|
49
|
+
- 批量导出 `docs/` 目录下的文档供归档
|
|
50
|
+
|
|
51
|
+
**技术实现**:使用 Node.js + `docx` + `marked` 库,零系统级依赖(不需要安装 pandoc)。
|
|
52
|
+
|
|
53
|
+
## 执行前检查
|
|
54
|
+
|
|
55
|
+
### 1. Node.js 可用性检查
|
|
56
|
+
|
|
57
|
+
执行 `node --version`,确认 Node.js 已安装且版本 >= 18。
|
|
58
|
+
|
|
59
|
+
**如果 Node.js 未安装**,输出安装指引:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
❌ 未检测到 Node.js,请先安装:
|
|
63
|
+
|
|
64
|
+
Windows:
|
|
65
|
+
winget install OpenJS.NodeJS.LTS # winget
|
|
66
|
+
choco install nodejs-lts # Chocolatey
|
|
67
|
+
scoop install nodejs-lts # Scoop
|
|
68
|
+
|
|
69
|
+
macOS:
|
|
70
|
+
brew install node@20 # Homebrew
|
|
71
|
+
|
|
72
|
+
Linux:
|
|
73
|
+
sudo apt install nodejs npm # Debian/Ubuntu
|
|
74
|
+
sudo dnf install nodejs npm # Fedora/RHEL
|
|
75
|
+
|
|
76
|
+
通用:
|
|
77
|
+
从 https://nodejs.org/ 下载安装 LTS 版本
|
|
78
|
+
|
|
79
|
+
安装后重新执行本命令。
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. npm 依赖检查
|
|
83
|
+
|
|
84
|
+
检查本 skill 的 Node.js 依赖是否已安装:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
SKILL_DIR="<SKILL.md 所在目录>"
|
|
88
|
+
cd "$SKILL_DIR/references"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
执行 `npm ls docx marked`,检查依赖是否存在。
|
|
92
|
+
|
|
93
|
+
**如果依赖未安装**(首次使用),自动执行安装:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
cd "$SKILL_DIR/references" && npm install
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
安装成功后继续。安装失败则输出错误并终止。
|
|
100
|
+
|
|
101
|
+
### 3. 检查扩展钩子(导出前)
|
|
102
|
+
|
|
103
|
+
- 检查项目根目录是否存在 `.adspecs/extensions.yml`。
|
|
104
|
+
- 如果存在,读取它并查找 `hooks.before_export_word` 下的条目。
|
|
105
|
+
- 如果 YAML 无法解析或无效,静默跳过钩子检查并继续正常执行。
|
|
106
|
+
- 过滤掉 `enabled` 明确为 `false` 的钩子。没有 `enabled` 字段的钩子默认视为启用。
|
|
107
|
+
- 对于每个剩余的钩子,**不要** 尝试解释或评估钩子的 `condition` 表达式:
|
|
108
|
+
- 如果钩子没有 `condition` 字段,或为空/null,视为可执行。
|
|
109
|
+
- 如果钩子定义了非空的 `condition`,跳过该钩子,将条件评估留给 HookExecutor 实现。
|
|
110
|
+
- 从钩子命令名构造斜杠命令时,将点号(`.`)替换为连字符(`-`)。例如:`adspecs.git.commit` → `/adspecs-git-commit`。
|
|
111
|
+
- 对于每个可执行钩子,根据其 `optional` 标志输出以下内容:
|
|
112
|
+
- **可选钩子** (`optional: true`):
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
## 扩展钩子
|
|
116
|
+
|
|
117
|
+
**可选前置钩子**: {extension}
|
|
118
|
+
命令: `/{command}`
|
|
119
|
+
描述: {description}
|
|
120
|
+
|
|
121
|
+
提示: {prompt}
|
|
122
|
+
执行: `/{command}`
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- **必选钩子** (`optional: false`):
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
## 扩展钩子
|
|
129
|
+
|
|
130
|
+
**自动前置钩子**: {extension}
|
|
131
|
+
执行: `/{command}`
|
|
132
|
+
EXECUTE_COMMAND: {command}
|
|
133
|
+
|
|
134
|
+
等待钩子命令结果后再继续执行。
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- 如果没有注册钩子或 `.adspecs/extensions.yml` 不存在,静默跳过。
|
|
138
|
+
|
|
139
|
+
## 参数解析
|
|
140
|
+
|
|
141
|
+
从 `$ARGUMENTS` 中解析以下参数:
|
|
142
|
+
|
|
143
|
+
### 位置参数(必选)
|
|
144
|
+
|
|
145
|
+
| 参数 | 说明 | 示例 |
|
|
146
|
+
| ------------- | ------------------------------------------ | ------------------------ |
|
|
147
|
+
| 文件/目录路径 | 要转换的 `.md` 文件或包含 `.md` 文件的目录 | `docs/20-prd/crm-prd.md` |
|
|
148
|
+
|
|
149
|
+
### 可选标志
|
|
150
|
+
|
|
151
|
+
| 标志 | 说明 | 默认值 |
|
|
152
|
+
| ----------------- | ----------------------------------- | ---------------- |
|
|
153
|
+
| `--output <路径>` | 自定义输出路径(覆盖 `EXPORT_DIR`) | `{EXPORT_DIR}/` |
|
|
154
|
+
| `--no-cover` | 跳过封面页生成 | 生成封面页 |
|
|
155
|
+
| `--no-toc` | 跳过目录索引页生成 | 生成目录 |
|
|
156
|
+
| `--recursive` | 目录模式下递归扫描子目录 | 仅扫描当前层 |
|
|
157
|
+
|
|
158
|
+
### 参数解析流程
|
|
159
|
+
|
|
160
|
+
1. 从 `$ARGUMENTS` 中分离位置参数和可选标志
|
|
161
|
+
2. 如果位置参数为空 → 使用 **AskUserQuestion** 让用户选择文件或输入路径
|
|
162
|
+
3. 判断位置参数是文件还是目录,确定工作模式
|
|
163
|
+
|
|
164
|
+
## 项目元数据提取
|
|
165
|
+
|
|
166
|
+
从以下来源提取封面页信息(优先级从高到低):
|
|
167
|
+
|
|
168
|
+
### 提取来源
|
|
169
|
+
|
|
170
|
+
| 优先级 | 来源 | 可提取字段 |
|
|
171
|
+
| ------ | ------------------------------------------- | ------------------------------------------ |
|
|
172
|
+
| 1 | `.adspecs/project.json` | 项目名称、公司名、公司 Logo 路径、保密等级 |
|
|
173
|
+
| 2 | Markdown 文件 YAML frontmatter / 头部元信息 | 文档标题、版本、模块编号、模块名称 |
|
|
174
|
+
| 3 | `CLAUDE.md` 第一行 `#` 标题 | 项目名称 |
|
|
175
|
+
| 4 | `git config user.name` | 作者 |
|
|
176
|
+
| 5 | 当前日期 | 创建日期 |
|
|
177
|
+
| 6 | **AskUserQuestion** 交互补全 | 审核人、批准人、文档编号、保密等级 |
|
|
178
|
+
|
|
179
|
+
### `.adspecs/project.json` 结构(可选)
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"project_name": "CRM 客户关系管理平台",
|
|
184
|
+
"project_short_name": "crm",
|
|
185
|
+
"company_name": "XX 科技有限公司",
|
|
186
|
+
"company_logo": "docs/assets/logo.png",
|
|
187
|
+
"confidentiality": "内部 — 机密"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
如果 `project.json` 不存在,从 `CLAUDE.md` 和 git config 提取,缺失字段用 AskUserQuestion 补全。
|
|
192
|
+
|
|
193
|
+
### 元数据字段清单
|
|
194
|
+
|
|
195
|
+
| 字段 | 变量名 | 提取方式 | 必填 |
|
|
196
|
+
| --------- | ----------------- | ------------------------------------- | ---- |
|
|
197
|
+
| 文档标题 | `title` | Markdown H1 或文件名 | ✅ |
|
|
198
|
+
| 副标题 | `subtitle` | frontmatter 或模块名称 | — |
|
|
199
|
+
| 项目名称 | `project_name` | project.json / CLAUDE.md | ✅ |
|
|
200
|
+
| 公司名称 | `company_name` | project.json / 交互 | ✅ |
|
|
201
|
+
| 公司 Logo | `company_logo` | project.json / `docs/assets/logo.png` | — |
|
|
202
|
+
| 作者 | `author` | git config user.name | ✅ |
|
|
203
|
+
| 审核人 | `reviewer` | 交互补全 | — |
|
|
204
|
+
| 批准人 | `approver` | 交互补全 | — |
|
|
205
|
+
| 版本号 | `version` | frontmatter / 默认 "v1.0" | ✅ |
|
|
206
|
+
| 日期 | `date` | 当前日期 | ✅ |
|
|
207
|
+
| 文档编号 | `document_number` | 自动生成或交互 | — |
|
|
208
|
+
| 保密等级 | `confidentiality` | project.json / 默认 "内部使用" | ✅ |
|
|
209
|
+
|
|
210
|
+
### 文档编号自动生成规则
|
|
211
|
+
|
|
212
|
+
格式:`DOC-{MODULE_ID}-{DOC_TYPE}-{SEQ}`
|
|
213
|
+
|
|
214
|
+
- `MODULE_ID`:从文档内容或所在目录识别的模块编号(如 M03-02)
|
|
215
|
+
- `DOC_TYPE`:从文档类型推断(PRD / BRD / SDD / TR / SOW 等)
|
|
216
|
+
- `SEQ`:同类型文档序号,从 001 开始
|
|
217
|
+
|
|
218
|
+
如无法自动生成,使用 AskUserQuestion 让用户输入或留空。
|
|
219
|
+
|
|
220
|
+
### 元数据补全交互
|
|
221
|
+
|
|
222
|
+
对于必填但无法自动提取的字段,使用 **AskUserQuestion** 一次性收集:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
请补全以下封面页信息:
|
|
226
|
+
- 审核人:{输入或留空}
|
|
227
|
+
- 批准人:{输入或留空}
|
|
228
|
+
- 文档编号:{自动生成值或自定义}
|
|
229
|
+
- 保密等级:[公开 / 内部使用 / 机密 / 绝密]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 执行步骤
|
|
233
|
+
|
|
234
|
+
### 步骤 1:确定工作模式
|
|
235
|
+
|
|
236
|
+
根据参数解析结果确定工作模式:
|
|
237
|
+
|
|
238
|
+
| 模式 | 触发条件 | 行为 |
|
|
239
|
+
| ---------- | --------------------------- | --------------------------------------------- |
|
|
240
|
+
| **单文件** | 参数是单个 `.md` 文件路径 | 转换该文件 |
|
|
241
|
+
| **多文件** | 参数包含多个 `.md` 文件路径 | 逐个转换 |
|
|
242
|
+
| **目录** | 参数是目录路径 | 扫描目录下所有 `.md` 文件(排除 `README.md`) |
|
|
243
|
+
| **交互** | 参数为空 | 使用 AskUserQuestion 选择文件或输入路径 |
|
|
244
|
+
|
|
245
|
+
**目录模式扫描规则**:
|
|
246
|
+
|
|
247
|
+
- 默认扫描当前层:`{dir}/*.md`
|
|
248
|
+
- 带 `--recursive` 标志:`{dir}/**/*.md`
|
|
249
|
+
- 排除:`README.md`、隐藏目录(`.git/`、`.claude/`、`.adspecs/`、`node_modules/`)中的文件
|
|
250
|
+
- 列出待转换文件清单,显示给用户确认
|
|
251
|
+
|
|
252
|
+
### 步骤 2:提取项目元数据
|
|
253
|
+
|
|
254
|
+
按"项目元数据提取"章节的规则,从各来源提取封面页信息:
|
|
255
|
+
|
|
256
|
+
1. 读取 `.adspecs/project.json`(如存在)
|
|
257
|
+
2. 读取目标 `.md` 文件头部元信息(frontmatter 或 `> **版本**:` 格式)
|
|
258
|
+
3. 读取 `CLAUDE.md` 提取项目名称
|
|
259
|
+
4. 执行 `git config user.name` 获取作者
|
|
260
|
+
5. 对缺失的必填字段使用 AskUserQuestion 补全
|
|
261
|
+
|
|
262
|
+
将提取结果记为元数据 JSON 对象,后续步骤使用。
|
|
263
|
+
|
|
264
|
+
### 步骤 3:执行 Node.js 转换脚本
|
|
265
|
+
|
|
266
|
+
**确定路径变量**:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
SKILL_DIR = SKILL.md 所在目录
|
|
270
|
+
SCRIPT_PATH = "{SKILL_DIR}/references/md-to-docx.js"
|
|
271
|
+
OUTPUT_DIR = --output 参数值 或 EXPORT_DIR(默认 docs/90-export)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
如果输出目录不存在,自动创建。
|
|
275
|
+
|
|
276
|
+
**构造元数据 JSON 字符串**:
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"title": "{文档标题}",
|
|
281
|
+
"subtitle": "{副标题}",
|
|
282
|
+
"project_name": "{项目名称}",
|
|
283
|
+
"company_name": "{公司名称}",
|
|
284
|
+
"company_logo": "{公司 Logo 路径}",
|
|
285
|
+
"author": "{作者}",
|
|
286
|
+
"reviewer": "{审核人}",
|
|
287
|
+
"approver": "{批准人}",
|
|
288
|
+
"version": "{版本号}",
|
|
289
|
+
"date": "{日期}",
|
|
290
|
+
"document_number": "{文档编号}",
|
|
291
|
+
"confidentiality": "{保密等级}"
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
将 JSON 对象序列化为字符串,记为 `META_JSON`。
|
|
296
|
+
|
|
297
|
+
#### 单文件模式
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
node "{SCRIPT_PATH}" \
|
|
301
|
+
--input "{INPUT_FILE}" \
|
|
302
|
+
--output "{OUTPUT_DIR}/{original_name}.docx" \
|
|
303
|
+
--meta '{META_JSON}'
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
附加标志:
|
|
307
|
+
|
|
308
|
+
| 标志 | 脚本参数 |
|
|
309
|
+
| ------------ | ------------ |
|
|
310
|
+
| 跳过封面页 | `--no-cover` |
|
|
311
|
+
| 跳过目录页 | `--no-toc` |
|
|
312
|
+
|
|
313
|
+
#### 目录批量模式
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
node "{SCRIPT_PATH}" \
|
|
317
|
+
--dir "{INPUT_DIR}" \
|
|
318
|
+
--output "{OUTPUT_DIR}/" \
|
|
319
|
+
--meta '{META_JSON}'
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
附加标志:
|
|
323
|
+
|
|
324
|
+
| 标志 | 脚本参数 |
|
|
325
|
+
| ------------ | ------------- |
|
|
326
|
+
| 跳过封面页 | `--no-cover` |
|
|
327
|
+
| 跳过目录页 | `--no-toc` |
|
|
328
|
+
| 递归扫描 | `--recursive` |
|
|
329
|
+
|
|
330
|
+
**执行方式**:使用 Bash 工具执行 Node.js 命令。
|
|
331
|
+
|
|
332
|
+
### 步骤 4:解析输出并生成报告
|
|
333
|
+
|
|
334
|
+
脚本执行后,stdout 输出 JSON 格式的结果:
|
|
335
|
+
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"status": "success",
|
|
339
|
+
"files": [
|
|
340
|
+
{ "input": "crm-prd.md", "output": "crm-prd.docx", "status": "ok" }
|
|
341
|
+
],
|
|
342
|
+
"cover": true,
|
|
343
|
+
"toc": true,
|
|
344
|
+
"total": 1,
|
|
345
|
+
"success": 1,
|
|
346
|
+
"failed": 0
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
根据 JSON 输出生成完成报告:
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
✅ Word 导出完成
|
|
354
|
+
|
|
355
|
+
转换结果:
|
|
356
|
+
| 序号 | 源文件 | 输出文件 | 状态 |
|
|
357
|
+
|------|--------|----------|------|
|
|
358
|
+
| 1 | {input} | {output} | ✅ 成功 |
|
|
359
|
+
| ... | ... | ... | ... |
|
|
360
|
+
|
|
361
|
+
封面页:{'✅ 已生成' 或 '❌ 已跳过 (--no-cover)'}
|
|
362
|
+
目录页:{'✅ 已生成' 或 '❌ 已跳过 (--no-toc)'}
|
|
363
|
+
|
|
364
|
+
输出目录:{OUTPUT_DIR}
|
|
365
|
+
共转换 {total} 个文件,成功 {success} 个,失败 {failed} 个。
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
如果目录页已生成,追加提示:
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
💡 提示:在 Word 中打开文档后,右键点击目录区域选择"更新域"即可刷新目录页码。
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**错误处理**:
|
|
375
|
+
|
|
376
|
+
| 错误 | 处理 |
|
|
377
|
+
| ----------------------------- | ----------------------------------------------------------------- |
|
|
378
|
+
| 脚本输出 status = "error" | 解析 JSON 中的 message 字段,输出错误详情 |
|
|
379
|
+
| Node.js 进程退出码非 0 | 输出 stderr 内容,提示用户检查 Node.js 安装和 Markdown 文件格式 |
|
|
380
|
+
| `Cannot find module 'docx'` | 在 `references/` 目录执行 `npm install` 后重试 |
|
|
381
|
+
| 图片资源找不到 | 脚本会在文档中插入 `[Image: path]` 占位文本,输出警告 |
|
|
382
|
+
| 文件不存在 | 提示用户检查输入路径 |
|
|
383
|
+
|
|
384
|
+
## 必选执行后钩子
|
|
385
|
+
|
|
386
|
+
**必须在向用户报告完成之前完成本节。**
|
|
387
|
+
|
|
388
|
+
检查项目根目录是否存在 `.adspecs/extensions.yml`。
|
|
389
|
+
|
|
390
|
+
- 如果不存在,或 `hooks.after_export_word` 下没有注册钩子,跳到完成报告。
|
|
391
|
+
- 如果存在,读取它并查找 `hooks.after_export_word` 下的条目。
|
|
392
|
+
- 如果 YAML 无法解析或无效,静默跳过钩子检查并继续完成报告。
|
|
393
|
+
- 过滤掉 `enabled` 明确为 `false` 的钩子。没有 `enabled` 字段的钩子默认视为启用。
|
|
394
|
+
- 对于每个剩余的钩子,**不要** 尝试解释或评估钩子的 `condition` 表达式:
|
|
395
|
+
- 如果钩子没有 `condition` 字段,或为空/null,视为可执行。
|
|
396
|
+
- 如果钩子定义了非空的 `condition`,跳过该钩子,将条件评估留给 HookExecutor 实现。
|
|
397
|
+
- 从钩子命令名构造斜杠命令时,将点号(`.`)替换为连字符(`-`)。例如:`adspecs.git.commit` → `/adspecs-git-commit`。
|
|
398
|
+
- 对于每个可执行钩子,根据其 `optional` 标志输出以下内容:
|
|
399
|
+
- **必选钩子** (`optional: false`) — **必须为每个必选钩子发出 `EXECUTE_COMMAND:`**:
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
## 扩展钩子
|
|
403
|
+
|
|
404
|
+
**自动钩子**: {extension}
|
|
405
|
+
执行: `/{command}`
|
|
406
|
+
EXECUTE_COMMAND: {command}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
- **可选钩子** (`optional: true`):
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
## 扩展钩子
|
|
413
|
+
|
|
414
|
+
**可选钩子**: {extension}
|
|
415
|
+
命令: `/{command}`
|
|
416
|
+
描述: {description}
|
|
417
|
+
|
|
418
|
+
提示: {prompt}
|
|
419
|
+
执行: `/{command}`
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 错误处理
|
|
423
|
+
|
|
424
|
+
### 常见错误及解决方案
|
|
425
|
+
|
|
426
|
+
| 错误 | 可能原因 | 解决方案 |
|
|
427
|
+
| ------------------------------------- | ------------------------------------------- | --------------------------------------------------------- |
|
|
428
|
+
| `node: command not found` | Node.js 未安装或不在 PATH 中 | 按安装指引安装 Node.js >= 18 |
|
|
429
|
+
| `Cannot find module 'docx'` | npm 依赖未安装 | 在 `references/` 目录执行 `npm install` |
|
|
430
|
+
| `Cannot find module 'marked'` | npm 依赖未安装 | 在 `references/` 目录执行 `npm install` |
|
|
431
|
+
| `JSON 解析失败` | `--meta` 参数 JSON 格式错误 | 检查 JSON 字符串引号转义 |
|
|
432
|
+
| `文件不存在` | 输入文件路径错误 | 检查 `--input` 路径 |
|
|
433
|
+
| `目录中未找到 .md 文件` | 目录为空或扫描范围不足 | 添加 `--recursive` 标志或检查目录路径 |
|
|
434
|
+
| 图片显示为占位文本 | Markdown 中引用了不存在的图片 | 检查图片路径是否正确 |
|
|
435
|
+
| 目录页码为空 | Word TOC 域未更新 | 在 Word 中右键目录选择"更新域" |
|
|
436
|
+
| 中文乱码或方块字符 | 系统缺少中文字体 | 安装微软雅黑/宋体字体 |
|
|
437
|
+
|
|
438
|
+
## 快速指南
|
|
439
|
+
|
|
440
|
+
### 首次使用准备
|
|
441
|
+
|
|
442
|
+
首次使用前需安装 npm 依赖(仅需执行一次):
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
cd skills/adspecs-export-word/references && npm install
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
依赖包括:
|
|
449
|
+
- `docx` (^9.x) — Word 文档生成库
|
|
450
|
+
- `marked` (^15.x) — Markdown 解析器
|
|
451
|
+
|
|
452
|
+
### 基本用法
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
# 转换单个文件
|
|
456
|
+
/adspecs-export-word docs/20-prd/crm-prd.md
|
|
457
|
+
|
|
458
|
+
# 转换目录下所有文件
|
|
459
|
+
/adspecs-export-word docs/30-system-design/
|
|
460
|
+
|
|
461
|
+
# 递归转换目录及子目录
|
|
462
|
+
/adspecs-export-word docs/ --recursive
|
|
463
|
+
|
|
464
|
+
# 指定输出路径
|
|
465
|
+
/adspecs-export-word docs/20-prd/crm-prd.md --output /tmp/exports/
|
|
466
|
+
|
|
467
|
+
# 不生成封面页和目录
|
|
468
|
+
/adspecs-export-word docs/20-prd/crm-prd.md --no-cover --no-toc
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### 封面页与目录
|
|
472
|
+
|
|
473
|
+
封面页和目录由 Node.js 脚本自动生成:
|
|
474
|
+
|
|
475
|
+
- **封面页内容**:从 `.adspecs/project.json` 和 Markdown 元信息自动提取
|
|
476
|
+
- **封面页样式**:修改 `references/md-to-docx.js` 中的 `buildCoverPage()` 函数
|
|
477
|
+
- **目录深度**:默认 Heading 1-3,Word 打开后需右键更新目录域
|
|
478
|
+
|
|
479
|
+
### 与 project-init 集成
|
|
480
|
+
|
|
481
|
+
执行 `/project-init` 时会自动:
|
|
482
|
+
|
|
483
|
+
- 创建 `docs/90-export/` 输出目录
|
|
484
|
+
- 生成 `.adspecs/project.json` 提供封面页元数据
|
|
485
|
+
|
|
486
|
+
## 完成标志
|
|
487
|
+
|
|
488
|
+
- [ ] Node.js 可用性已确认(版本 >= 18)
|
|
489
|
+
- [ ] npm 依赖已安装(docx + marked)
|
|
490
|
+
- [ ] 工作模式已确定(单文件/多文件/目录/交互)
|
|
491
|
+
- [ ] 项目元数据已从配置文件和 git 提取
|
|
492
|
+
- [ ] 缺失的必填元数据字段已通过 AskUserQuestion 补全
|
|
493
|
+
- [ ] 元数据 JSON 已构造
|
|
494
|
+
- [ ] Node.js 转换脚本已执行(`md-to-docx.js`)
|
|
495
|
+
- [ ] 封面页已生成(除非 `--no-cover`)
|
|
496
|
+
- [ ] 目录索引页已生成(除非 `--no-toc`)
|
|
497
|
+
- [ ] 完成报告已输出(转换结果表 + 统计数据)
|
|
498
|
+
- [ ] 扩展钩子已根据上述必选执行后钩子规则分发或跳过
|