adspecs 0.1.18 → 0.1.20

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.
Files changed (88) hide show
  1. package/.adspecs/extensions/git/commands/adspecs.git.initialize.md +4 -4
  2. package/.adspecs/extensions/git/extension.yml +1 -1
  3. package/.adspecs/extensions/git/git-config.yml +17 -2
  4. package/.adspecs/extensions.yml +32 -0
  5. package/.adspecs/feature.json +16 -16
  6. package/.adspecs/feature.yml +28 -28
  7. package/.adspecs/paths.json +17 -0
  8. package/.adspecs/templates/02-/344/272/247/345/223/201/351/234/200/346/261/202/350/257/264/346/230/216/344/271/246/346/250/241/346/235/277.md +4 -0
  9. package/.adspecs/workflows/adspecs/workflow.yml +5 -4
  10. package/.claude-plugin/marketplace.json +23 -23
  11. package/.claude-plugin/plugin.json +18 -18
  12. package/.qoder-plugin/plugin.json +31 -31
  13. package/CLAUDE.md +1 -5
  14. package/README.md +395 -395
  15. package/bin/adspecs.js +129 -129
  16. package/hooks/commit-queue.js +245 -245
  17. package/hooks/hooks.json +63 -63
  18. package/hooks/session-start.js +44 -44
  19. package/hooks/wiki-queue.js +127 -127
  20. package/package.json +61 -61
  21. package/references/ant6-front-standard/index.md +99 -99
  22. package/references/antd-front-demo/.env.develop +12 -0
  23. package/references/antd-front-demo/.env.production +5 -0
  24. package/references/antd-front-demo/package-lock.json +2 -2
  25. package/references/antd-front-demo/package.json +1 -1
  26. package/references/antd-front-demo/public/mockServiceWorker.js +361 -361
  27. package/references/ecp-end-standard/index.md +63 -63
  28. 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
  29. 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
  30. 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
  31. package/references/python-end-standard/04-Redis/344/275/277/347/224/250/350/247/204/350/214/203.md +231 -231
  32. package/scripts/postinstall.js +107 -107
  33. package/scripts/sync-version.js +105 -105
  34. package/skills/.claude/.wiki-update-queue +26 -26
  35. package/skills/adspecs-constitution/SKILL.md +157 -0
  36. package/skills/adspecs-export-word/SKILL.md +498 -498
  37. package/skills/adspecs-export-word/references/md-to-docx.js +862 -862
  38. package/skills/adspecs-export-word/references/package-lock.json +220 -220
  39. package/skills/adspecs-export-word/references/package.json +10 -10
  40. package/skills/adspecs-front-prototype/SKILL.md +405 -0
  41. package/skills/adspecs-git-commit/SKILL.md +23 -8
  42. package/skills/adspecs-git-initialize/SKILL.md +54 -0
  43. package/skills/adspecs-plan/SKILL.md +59 -69
  44. package/skills/adspecs-prd/SKILL.md +13 -5
  45. package/skills/adspecs-prd-to-demo/SKILL.md +532 -0
  46. package/skills/adspecs-tasks/SKILL.md +175 -204
  47. package/skills/adspecs-update-status/SKILL.md +382 -382
  48. package/skills/adspecs-utest/SKILL.md +107 -116
  49. package/skills/grill-me/SKILL.md +7 -0
  50. package/skills/grill-me/agents/openai.yaml +5 -0
  51. package/skills/playwright-cli/SKILL.md +420 -0
  52. package/skills/playwright-cli/references/element-attributes.md +23 -0
  53. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  54. package/skills/playwright-cli/references/request-mocking.md +87 -0
  55. package/skills/playwright-cli/references/running-code.md +241 -0
  56. package/skills/playwright-cli/references/session-management.md +225 -0
  57. package/skills/playwright-cli/references/storage-state.md +275 -0
  58. package/skills/playwright-cli/references/test-generation.md +433 -0
  59. package/skills/playwright-cli/references/tracing.md +139 -0
  60. package/skills/playwright-cli/references/video-recording.md +143 -0
  61. package/skills/playwright-trace/SKILL.md +171 -0
  62. package/skills/project-init/references/front-demo/.claude/settings.local.json +9 -0
  63. package/skills/wiki-update/SKILL.md +232 -232
  64. package/src/commands/doctor.js +197 -197
  65. package/src/commands/init.js +83 -83
  66. package/src/commands/plugin.js +165 -165
  67. package/src/commands/update.js +87 -87
  68. package/src/lib/area-scanner.js +129 -129
  69. package/src/lib/copier.js +104 -104
  70. package/src/lib/dir-utils.js +133 -133
  71. package/src/lib/json-merge.js +114 -114
  72. package/src/lib/paths-defaults.js +37 -37
  73. package/src/lib/prompts.js +347 -345
  74. package/src/lib/readme-gen.js +143 -143
  75. package/src/lib/report.js +327 -327
  76. package/src/lib/scaffolder.js +518 -518
  77. package/src/lib/short-name.js +36 -36
  78. package/src/utils.js +80 -80
  79. package/references/antd-front-demo/.env +0 -15
  80. package/references/antd-front-demo/src/pages/aps/coil/components/CoilDrawer.tsx +0 -141
  81. package/references/antd-front-demo/src/pages/aps/coil/index.tsx +0 -209
  82. package/references/antd-front-demo/src/pages/aps/optimization/index.tsx +0 -192
  83. package/references/antd-front-demo/src/pages/aps/order/components/OrderDrawer.tsx +0 -251
  84. package/references/antd-front-demo/src/pages/aps/order/index.tsx +0 -273
  85. package/references/antd-front-demo/src/pages/aps/param/index.tsx +0 -153
  86. package/references/antd-front-demo/src/pages/aps/plan/components/CuttingPlanVisualization.tsx +0 -821
  87. package/references/antd-front-demo/src/pages/aps/plan/index.tsx +0 -254
  88. package/references/antd-front-demo/src/pages/aps/task/index.tsx +0 -190
package/src/lib/report.js CHANGED
@@ -1,327 +1,327 @@
1
- 'use strict';
2
-
3
- const chalk = require('chalk');
4
- const { areaDisplayName, decisionLabel, decisionIcon } = require('./area-scanner');
5
-
6
- /**
7
- * 报告生成
8
- *
9
- * 提供两种报告:
10
- * 1. 计划摘要(执行前)— 让用户确认即将执行的操作
11
- * 2. 最终详细报告(执行后)— 含表格、目录树、状态说明、后续步骤
12
- */
13
-
14
- // ============================================================
15
- // 模式标签
16
- // ============================================================
17
-
18
- function modeLabel(mode) {
19
- const labels = {
20
- simple: '简易模式',
21
- classic: '经典模式',
22
- full: '完整模式',
23
- demo: '轻量模式',
24
- };
25
- return labels[mode] || mode;
26
- }
27
-
28
- function frontDemoLabel(frontDemo) {
29
- if (frontDemo === 'antd') return 'Ant Design React';
30
- if (frontDemo === 'vue') return 'Vue';
31
- if (frontDemo === 'skip') return '跳过';
32
- return frontDemo;
33
- }
34
-
35
- // ============================================================
36
- // 计划摘要(执行前)
37
- // ============================================================
38
-
39
- /**
40
- * 输出计划摘要
41
- *
42
- * @param {object} info - 项目信息
43
- * @param {object} decisions - 每区域决策
44
- * @param {object} subDecisions - 子目录决策
45
- * @param {object} modeUpgrade - 模式升级检测
46
- * @param {string} targetDir - 目标路径
47
- */
48
- function printPlanSummary(info, decisions, subDecisions, modeUpgrade, targetDir) {
49
- console.log('');
50
- console.log(chalk.bold('📋 初始化计划:'));
51
- console.log('');
52
- console.log(chalk.gray(' 项目信息'));
53
- console.log(` 项目名称: ${chalk.green(info.project_name)}`);
54
- console.log(` 项目短名称: ${chalk.green(info.project_short_name)}`);
55
- console.log(` 公司名称: ${info.company_name}`);
56
- console.log(` 文件密级: ${info.confidentiality}`);
57
- console.log(` 初始化模式: ${chalk.yellow(modeLabel(info.mode))}`);
58
-
59
- if (info.mode === 'classic' || info.mode === 'full') {
60
- console.log(` 前端技术栈: ${frontDemoLabel(info.frontDemo)}`);
61
- }
62
- if (info.mode === 'demo') {
63
- console.log(` 前端技术栈: ${frontDemoLabel('antd')} (固定)`);
64
- }
65
-
66
- console.log(` 目标路径: ${chalk.blue(targetDir)}`);
67
- console.log('');
68
-
69
- // 区域操作预览
70
- console.log(chalk.gray(' 区域操作'));
71
- const areaEntries = Object.entries(decisions);
72
- const maxNameLen = Math.max(...areaEntries.map(([k]) => areaDisplayName(k).length));
73
-
74
- for (const [areaKey, decision] of areaEntries) {
75
- // frontDemo='skip' 覆盖决策显示
76
- let displayDecision = decision;
77
- let displayIcon = decisionIcon(decision);
78
- let displayLabel = decisionLabel(decision);
79
-
80
- if (areaKey === 'frontDemo' && info.frontDemo === 'skip') {
81
- displayIcon = '⏭';
82
- displayLabel = '跳过(用户选择不创建)';
83
- }
84
-
85
- const name = areaDisplayName(areaKey).padEnd(maxNameLen);
86
- console.log(` ${displayIcon} ${name}/ ${chalk.gray('→')} ${displayLabel}`);
87
-
88
- // 子决策预览
89
- if (areaKey === 'docs' && decision === 'skip' && subDecisions.conventions !== 'skip') {
90
- console.log(
91
- ` ${chalk.gray('└')} 40-project_conventions/ ${chalk.gray('→')} ${decisionLabel(subDecisions.conventions)}`
92
- );
93
- }
94
- if (areaKey === 'adspecs' && decision === 'skip' && subDecisions.templates !== 'skip') {
95
- console.log(
96
- ` ${chalk.gray('└')} templates/ ${chalk.gray('→')} ${decisionLabel(subDecisions.templates)}`
97
- );
98
- }
99
- }
100
-
101
- // 模式升级提示
102
- if (modeUpgrade.detected) {
103
- console.log('');
104
- console.log(
105
- chalk.yellow(
106
- ` 📦 模式升级检测:检测到 40-project_conventions/ 为空目录(简易模式产物),将自动补充 frontend-standard/`
107
- )
108
- );
109
- }
110
-
111
- console.log('');
112
- }
113
-
114
- // ============================================================
115
- // 最终详细报告(执行后)
116
- // ============================================================
117
-
118
- /**
119
- * 输出最终详细报告
120
- *
121
- * @param {object} report - scaffolder 返回的执行报告
122
- * @param {object} info - 项目信息
123
- * @param {object} decisions - 每区域决策
124
- * @param {object} subDecisions - 子目录决策
125
- * @param {object} modeUpgrade - 模式升级检测
126
- */
127
- function printFinalReport(report, info, decisions, subDecisions, modeUpgrade) {
128
- console.log('');
129
- console.log(chalk.green.bold('## 项目初始化完成 🎉'));
130
- console.log('');
131
-
132
- // 项目信息段
133
- console.log(chalk.bold('项目名称:'), info.project_name);
134
- console.log(chalk.bold('项目短名称:'), info.project_short_name);
135
- console.log(chalk.bold('公司名称:'), info.company_name);
136
- console.log(chalk.bold('文件密级:'), info.confidentiality);
137
- console.log(chalk.bold('初始化模式:'), modeLabel(info.mode));
138
- if (info.mode === 'classic' || info.mode === 'full' || info.mode === 'demo') {
139
- const fdLabel = info.mode === 'demo' ? frontDemoLabel('antd') : frontDemoLabel(info.frontDemo);
140
- console.log(chalk.bold('前端技术栈:'), fdLabel);
141
- }
142
- console.log(chalk.bold('目标路径:'), report.targetDir);
143
- console.log('');
144
-
145
- // 区域执行结果表格
146
- console.log(chalk.bold('### 区域执行结果'));
147
- console.log('');
148
- console.log(' | 区域 | 状态 | 说明 |');
149
- console.log(' | --- | --- | --- |');
150
-
151
- for (const stage of report.stages) {
152
- const icon = statusIcon(stage.status);
153
- const detail = stageDetail(stage);
154
- console.log(` | ${stage.name} | ${icon} ${stage.status} | ${detail} |`);
155
-
156
- // 子行:templates/
157
- if (stage.name === '.adspecs/' && stage.subDecisions) {
158
- if (stage.subDecisions.templates === 'update') {
159
- console.log(` | ${chalk.gray('└ templates/')} | ${chalk.green('🔄')} 已更新 | 从插件根目录覆盖更新 |`);
160
- }
161
- }
162
-
163
- // 子行:feature.json
164
- if (stage.name === '.adspecs/' && stage.featureResult) {
165
- if (stage.featureResult.addedKeys && stage.featureResult.addedKeys.length > 0) {
166
- console.log(
167
- ` | ${chalk.gray('└ feature.json')} | ${chalk.yellow('🔧')} 已补全 | 补充缺失属性 [${stage.featureResult.addedKeys.join(', ')}] |`
168
- );
169
- }
170
- }
171
-
172
- // 子行:40-project_conventions/
173
- if (stage.name === 'docs/' && stage.subDecisions) {
174
- if (stage.subDecisions.conventions === 'update') {
175
- console.log(
176
- ` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.green('🔄')} 已更新 | 按前端技术栈覆盖更新 |`
177
- );
178
- }
179
- if (stage.modeUpgrade && stage.modeUpgrade.detected) {
180
- console.log(
181
- ` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.yellow('📦')} 已补充 | 模式升级自动补充 frontend-standard/ |`
182
- );
183
- }
184
- }
185
- }
186
-
187
- console.log('');
188
-
189
- // 状态说明
190
- console.log(chalk.bold('状态说明:'));
191
- console.log(' ✅ 已创建 — 目录原本不存在,新建完成');
192
- console.log(' 🔄 已重建 — 目录原本存在,按用户选择删除后重新创建');
193
- console.log(' 🔄 已更新 — 父目录跳过,但子目录按用户选择使用最新文件覆盖');
194
- console.log(' 🔧 已补全 — 已有文件属性与 references 对比后,补充缺失属性');
195
- console.log(' ⏭ 已跳过 — 目录原本存在,按用户选择保留未动');
196
- console.log('');
197
-
198
- // 目录树总览
199
- console.log(chalk.bold('### 目录树总览'));
200
- console.log('');
201
- printDirectoryTree(info.mode, info.frontDemo);
202
-
203
- // 后续步骤
204
- console.log(chalk.bold('### 后续步骤'));
205
- console.log('');
206
- printNextSteps(info.mode, report.targetDir, info.frontDemo);
207
- }
208
-
209
- /**
210
- * 状态图标
211
- */
212
- function statusIcon(status) {
213
- const icons = {
214
- created: '✅',
215
- recreated: '🔄',
216
- updated: '🔄',
217
- skipped: '⏭',
218
- exists: '⏭',
219
- };
220
- return icons[status] || '❓';
221
- }
222
-
223
- /**
224
- * 阶段详情
225
- */
226
- function stageDetail(stage) {
227
- if (stage.fileCount !== undefined) {
228
- return `${stage.fileCount} 个文件`;
229
- }
230
- if (stage.reason) {
231
- return stage.reason;
232
- }
233
- if (stage.detail && stage.detail.created) {
234
- return '已创建';
235
- }
236
- return '';
237
- }
238
-
239
- /**
240
- * 按模式输出 ASCII 目录树
241
- */
242
- function printDirectoryTree(mode, frontDemo) {
243
- const lines = [];
244
- lines.push(' {targetDir}/');
245
- lines.push(' ├── .adspecs/ (插件配置、脚本、模板 + project.json)');
246
- lines.push(' ├── docs/ (11 个子目录)');
247
- if (mode === 'classic' || mode === 'full' || mode === 'demo') {
248
- lines.push(' │ └── 40-project_conventions/');
249
- if (mode === 'demo') {
250
- lines.push(' │ ├── frontend-standard/ (Ant Design React 前端规范)');
251
- lines.push(' │ └── end-standard/ (Python 后端规范)');
252
- } else {
253
- const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
254
- lines.push(` │ └── frontend-standard/ (${fdLabel} 前端规范)`);
255
- }
256
- }
257
- lines.push(' ├── wiki/ (基线文件目录)');
258
-
259
- if (mode === 'full' || mode === 'demo') {
260
- lines.push(' ├── web-ui/ (前端生产项目)');
261
- lines.push(' ├── service/ (后端服务模块)');
262
- }
263
- if (mode === 'classic' || mode === 'full' || mode === 'demo') {
264
- if (frontDemo !== 'skip') {
265
- const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
266
- lines.push(` └── front-demo/ (${fdLabel} 前端演示项目)`);
267
- }
268
- }
269
-
270
- if (mode === 'demo') {
271
- lines.push('');
272
- lines.push(' 技术栈:Python + SQLite + React + Ant Design 6 全栈 demo');
273
- }
274
-
275
- console.log(lines.join('\n'));
276
- console.log('');
277
- }
278
-
279
- /**
280
- * 按模式输出后续步骤
281
- */
282
- function printNextSteps(mode, targetDir, frontDemo = 'vue') {
283
- if (mode === 'simple') {
284
- console.log(' 1. 执行 `git init` 初始化 Git 仓库');
285
- console.log(' 2. 根据需要调整 .adspecs/templates/ 下的文档模板');
286
- console.log(' 3. 根据需要编辑 .adspecs/project.json 补充公司 Logo 路径等信息');
287
- console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
288
- } else if (mode === 'classic') {
289
- console.log(' 1. 执行 `git init` 初始化 Git 仓库');
290
- if (frontDemo !== 'skip') {
291
- console.log(' 2. 在前端演示目录执行 `npm install` 安装依赖:');
292
- console.log(` cd ${targetDir}/front-demo && npm install`);
293
- console.log(' 3. 根据需要调整文档模板和编码规范');
294
- console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
295
- } else {
296
- console.log(' 2. 根据需要调整文档模板和编码规范');
297
- console.log(' 3. 执行 `adspecs plugin install` 注册 Claude Code 插件');
298
- }
299
- } else if (mode === 'full') {
300
- console.log(' 1. 执行 `git init` 初始化 Git 仓库');
301
- console.log(' 2. 安装前端依赖:');
302
- console.log(` cd ${targetDir}/web-ui && npm install`);
303
- if (frontDemo !== 'skip') {
304
- console.log(` cd ${targetDir}/front-demo && npm install`);
305
- }
306
- console.log(' 3. 根据需要调整文档模板和编码规范');
307
- console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
308
- } else if (mode === 'demo') {
309
- console.log(' 1. 执行 `git init` 初始化 Git 仓库');
310
- console.log(' 2. 安装前端依赖:');
311
- console.log(` cd ${targetDir}/web-ui && npm install`);
312
- console.log(` cd ${targetDir}/front-demo && npm install`);
313
- console.log(' 3. 安装后端依赖(Python 环境):');
314
- console.log(` cd ${targetDir}/service`);
315
- console.log(' python -m venv venv && source venv/bin/activate # Windows: venv\\Scripts\\activate');
316
- console.log(' pip install -r requirements.txt');
317
- console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
318
- }
319
- console.log('');
320
- }
321
-
322
- module.exports = {
323
- printPlanSummary,
324
- printFinalReport,
325
- modeLabel,
326
- frontDemoLabel,
327
- };
1
+ 'use strict';
2
+
3
+ const chalk = require('chalk');
4
+ const { areaDisplayName, decisionLabel, decisionIcon } = require('./area-scanner');
5
+
6
+ /**
7
+ * 报告生成
8
+ *
9
+ * 提供两种报告:
10
+ * 1. 计划摘要(执行前)— 让用户确认即将执行的操作
11
+ * 2. 最终详细报告(执行后)— 含表格、目录树、状态说明、后续步骤
12
+ */
13
+
14
+ // ============================================================
15
+ // 模式标签
16
+ // ============================================================
17
+
18
+ function modeLabel(mode) {
19
+ const labels = {
20
+ simple: '简易模式',
21
+ classic: '经典模式',
22
+ full: '完整模式',
23
+ demo: '轻量模式',
24
+ };
25
+ return labels[mode] || mode;
26
+ }
27
+
28
+ function frontDemoLabel(frontDemo) {
29
+ if (frontDemo === 'antd') return 'Ant Design React';
30
+ if (frontDemo === 'vue') return 'Vue';
31
+ if (frontDemo === 'skip') return '跳过';
32
+ return frontDemo;
33
+ }
34
+
35
+ // ============================================================
36
+ // 计划摘要(执行前)
37
+ // ============================================================
38
+
39
+ /**
40
+ * 输出计划摘要
41
+ *
42
+ * @param {object} info - 项目信息
43
+ * @param {object} decisions - 每区域决策
44
+ * @param {object} subDecisions - 子目录决策
45
+ * @param {object} modeUpgrade - 模式升级检测
46
+ * @param {string} targetDir - 目标路径
47
+ */
48
+ function printPlanSummary(info, decisions, subDecisions, modeUpgrade, targetDir) {
49
+ console.log('');
50
+ console.log(chalk.bold('📋 初始化计划:'));
51
+ console.log('');
52
+ console.log(chalk.gray(' 项目信息'));
53
+ console.log(` 项目名称: ${chalk.green(info.project_name)}`);
54
+ console.log(` 项目短名称: ${chalk.green(info.project_short_name)}`);
55
+ console.log(` 公司名称: ${info.company_name}`);
56
+ console.log(` 文件密级: ${info.confidentiality}`);
57
+ console.log(` 初始化模式: ${chalk.yellow(modeLabel(info.mode))}`);
58
+
59
+ if (info.mode === 'classic' || info.mode === 'full') {
60
+ console.log(` 前端技术栈: ${frontDemoLabel(info.frontDemo)}`);
61
+ }
62
+ if (info.mode === 'demo') {
63
+ console.log(` 前端技术栈: ${frontDemoLabel('antd')} (固定)`);
64
+ }
65
+
66
+ console.log(` 目标路径: ${chalk.blue(targetDir)}`);
67
+ console.log('');
68
+
69
+ // 区域操作预览
70
+ console.log(chalk.gray(' 区域操作'));
71
+ const areaEntries = Object.entries(decisions);
72
+ const maxNameLen = Math.max(...areaEntries.map(([k]) => areaDisplayName(k).length));
73
+
74
+ for (const [areaKey, decision] of areaEntries) {
75
+ // frontDemo='skip' 覆盖决策显示
76
+ let displayDecision = decision;
77
+ let displayIcon = decisionIcon(decision);
78
+ let displayLabel = decisionLabel(decision);
79
+
80
+ if (areaKey === 'frontDemo' && info.frontDemo === 'skip') {
81
+ displayIcon = '⏭';
82
+ displayLabel = '跳过(用户选择不创建)';
83
+ }
84
+
85
+ const name = areaDisplayName(areaKey).padEnd(maxNameLen);
86
+ console.log(` ${displayIcon} ${name}/ ${chalk.gray('→')} ${displayLabel}`);
87
+
88
+ // 子决策预览
89
+ if (areaKey === 'docs' && decision === 'skip' && subDecisions.conventions !== 'skip') {
90
+ console.log(
91
+ ` ${chalk.gray('└')} 40-project_conventions/ ${chalk.gray('→')} ${decisionLabel(subDecisions.conventions)}`
92
+ );
93
+ }
94
+ if (areaKey === 'adspecs' && decision === 'skip' && subDecisions.templates !== 'skip') {
95
+ console.log(
96
+ ` ${chalk.gray('└')} templates/ ${chalk.gray('→')} ${decisionLabel(subDecisions.templates)}`
97
+ );
98
+ }
99
+ }
100
+
101
+ // 模式升级提示
102
+ if (modeUpgrade.detected) {
103
+ console.log('');
104
+ console.log(
105
+ chalk.yellow(
106
+ ` 📦 模式升级检测:检测到 40-project_conventions/ 为空目录(简易模式产物),将自动补充 frontend-standard/`
107
+ )
108
+ );
109
+ }
110
+
111
+ console.log('');
112
+ }
113
+
114
+ // ============================================================
115
+ // 最终详细报告(执行后)
116
+ // ============================================================
117
+
118
+ /**
119
+ * 输出最终详细报告
120
+ *
121
+ * @param {object} report - scaffolder 返回的执行报告
122
+ * @param {object} info - 项目信息
123
+ * @param {object} decisions - 每区域决策
124
+ * @param {object} subDecisions - 子目录决策
125
+ * @param {object} modeUpgrade - 模式升级检测
126
+ */
127
+ function printFinalReport(report, info, decisions, subDecisions, modeUpgrade) {
128
+ console.log('');
129
+ console.log(chalk.green.bold('## 项目初始化完成 🎉'));
130
+ console.log('');
131
+
132
+ // 项目信息段
133
+ console.log(chalk.bold('项目名称:'), info.project_name);
134
+ console.log(chalk.bold('项目短名称:'), info.project_short_name);
135
+ console.log(chalk.bold('公司名称:'), info.company_name);
136
+ console.log(chalk.bold('文件密级:'), info.confidentiality);
137
+ console.log(chalk.bold('初始化模式:'), modeLabel(info.mode));
138
+ if (info.mode === 'classic' || info.mode === 'full' || info.mode === 'demo') {
139
+ const fdLabel = info.mode === 'demo' ? frontDemoLabel('antd') : frontDemoLabel(info.frontDemo);
140
+ console.log(chalk.bold('前端技术栈:'), fdLabel);
141
+ }
142
+ console.log(chalk.bold('目标路径:'), report.targetDir);
143
+ console.log('');
144
+
145
+ // 区域执行结果表格
146
+ console.log(chalk.bold('### 区域执行结果'));
147
+ console.log('');
148
+ console.log(' | 区域 | 状态 | 说明 |');
149
+ console.log(' | --- | --- | --- |');
150
+
151
+ for (const stage of report.stages) {
152
+ const icon = statusIcon(stage.status);
153
+ const detail = stageDetail(stage);
154
+ console.log(` | ${stage.name} | ${icon} ${stage.status} | ${detail} |`);
155
+
156
+ // 子行:templates/
157
+ if (stage.name === '.adspecs/' && stage.subDecisions) {
158
+ if (stage.subDecisions.templates === 'update') {
159
+ console.log(` | ${chalk.gray('└ templates/')} | ${chalk.green('🔄')} 已更新 | 从插件根目录覆盖更新 |`);
160
+ }
161
+ }
162
+
163
+ // 子行:feature.json
164
+ if (stage.name === '.adspecs/' && stage.featureResult) {
165
+ if (stage.featureResult.addedKeys && stage.featureResult.addedKeys.length > 0) {
166
+ console.log(
167
+ ` | ${chalk.gray('└ feature.json')} | ${chalk.yellow('🔧')} 已补全 | 补充缺失属性 [${stage.featureResult.addedKeys.join(', ')}] |`
168
+ );
169
+ }
170
+ }
171
+
172
+ // 子行:40-project_conventions/
173
+ if (stage.name === 'docs/' && stage.subDecisions) {
174
+ if (stage.subDecisions.conventions === 'update') {
175
+ console.log(
176
+ ` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.green('🔄')} 已更新 | 按前端技术栈覆盖更新 |`
177
+ );
178
+ }
179
+ if (stage.modeUpgrade && stage.modeUpgrade.detected) {
180
+ console.log(
181
+ ` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.yellow('📦')} 已补充 | 模式升级自动补充 frontend-standard/ |`
182
+ );
183
+ }
184
+ }
185
+ }
186
+
187
+ console.log('');
188
+
189
+ // 状态说明
190
+ console.log(chalk.bold('状态说明:'));
191
+ console.log(' ✅ 已创建 — 目录原本不存在,新建完成');
192
+ console.log(' 🔄 已重建 — 目录原本存在,按用户选择删除后重新创建');
193
+ console.log(' 🔄 已更新 — 父目录跳过,但子目录按用户选择使用最新文件覆盖');
194
+ console.log(' 🔧 已补全 — 已有文件属性与 references 对比后,补充缺失属性');
195
+ console.log(' ⏭ 已跳过 — 目录原本存在,按用户选择保留未动');
196
+ console.log('');
197
+
198
+ // 目录树总览
199
+ console.log(chalk.bold('### 目录树总览'));
200
+ console.log('');
201
+ printDirectoryTree(info.mode, info.frontDemo);
202
+
203
+ // 后续步骤
204
+ console.log(chalk.bold('### 后续步骤'));
205
+ console.log('');
206
+ printNextSteps(info.mode, report.targetDir, info.frontDemo);
207
+ }
208
+
209
+ /**
210
+ * 状态图标
211
+ */
212
+ function statusIcon(status) {
213
+ const icons = {
214
+ created: '✅',
215
+ recreated: '🔄',
216
+ updated: '🔄',
217
+ skipped: '⏭',
218
+ exists: '⏭',
219
+ };
220
+ return icons[status] || '❓';
221
+ }
222
+
223
+ /**
224
+ * 阶段详情
225
+ */
226
+ function stageDetail(stage) {
227
+ if (stage.fileCount !== undefined) {
228
+ return `${stage.fileCount} 个文件`;
229
+ }
230
+ if (stage.reason) {
231
+ return stage.reason;
232
+ }
233
+ if (stage.detail && stage.detail.created) {
234
+ return '已创建';
235
+ }
236
+ return '';
237
+ }
238
+
239
+ /**
240
+ * 按模式输出 ASCII 目录树
241
+ */
242
+ function printDirectoryTree(mode, frontDemo) {
243
+ const lines = [];
244
+ lines.push(' {targetDir}/');
245
+ lines.push(' ├── .adspecs/ (插件配置、脚本、模板 + project.json)');
246
+ lines.push(' ├── docs/ (11 个子目录)');
247
+ if (mode === 'classic' || mode === 'full' || mode === 'demo') {
248
+ lines.push(' │ └── 40-project_conventions/');
249
+ if (mode === 'demo') {
250
+ lines.push(' │ ├── frontend-standard/ (Ant Design React 前端规范)');
251
+ lines.push(' │ └── end-standard/ (Python 后端规范)');
252
+ } else {
253
+ const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
254
+ lines.push(` │ └── frontend-standard/ (${fdLabel} 前端规范)`);
255
+ }
256
+ }
257
+ lines.push(' ├── wiki/ (基线文件目录)');
258
+
259
+ if (mode === 'full' || mode === 'demo') {
260
+ lines.push(' ├── web-ui/ (前端生产项目)');
261
+ lines.push(' ├── service/ (后端服务模块)');
262
+ }
263
+ if (mode === 'classic' || mode === 'full' || mode === 'demo') {
264
+ if (frontDemo !== 'skip') {
265
+ const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
266
+ lines.push(` └── front-demo/ (${fdLabel} 前端演示项目)`);
267
+ }
268
+ }
269
+
270
+ if (mode === 'demo') {
271
+ lines.push('');
272
+ lines.push(' 技术栈:Python + SQLite + React + Ant Design 6 全栈 demo');
273
+ }
274
+
275
+ console.log(lines.join('\n'));
276
+ console.log('');
277
+ }
278
+
279
+ /**
280
+ * 按模式输出后续步骤
281
+ */
282
+ function printNextSteps(mode, targetDir, frontDemo = 'vue') {
283
+ if (mode === 'simple') {
284
+ console.log(' 1. 执行 `git init` 初始化 Git 仓库');
285
+ console.log(' 2. 根据需要调整 .adspecs/templates/ 下的文档模板');
286
+ console.log(' 3. 根据需要编辑 .adspecs/project.json 补充公司 Logo 路径等信息');
287
+ console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
288
+ } else if (mode === 'classic') {
289
+ console.log(' 1. 执行 `git init` 初始化 Git 仓库');
290
+ if (frontDemo !== 'skip') {
291
+ console.log(' 2. 在前端演示目录执行 `npm install` 安装依赖:');
292
+ console.log(` cd ${targetDir}/front-demo && npm install`);
293
+ console.log(' 3. 根据需要调整文档模板和编码规范');
294
+ console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
295
+ } else {
296
+ console.log(' 2. 根据需要调整文档模板和编码规范');
297
+ console.log(' 3. 执行 `adspecs plugin install` 注册 Claude Code 插件');
298
+ }
299
+ } else if (mode === 'full') {
300
+ console.log(' 1. 执行 `git init` 初始化 Git 仓库');
301
+ console.log(' 2. 安装前端依赖:');
302
+ console.log(` cd ${targetDir}/web-ui && npm install`);
303
+ if (frontDemo !== 'skip') {
304
+ console.log(` cd ${targetDir}/front-demo && npm install`);
305
+ }
306
+ console.log(' 3. 根据需要调整文档模板和编码规范');
307
+ console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
308
+ } else if (mode === 'demo') {
309
+ console.log(' 1. 执行 `git init` 初始化 Git 仓库');
310
+ console.log(' 2. 安装前端依赖:');
311
+ console.log(` cd ${targetDir}/web-ui && npm install`);
312
+ console.log(` cd ${targetDir}/front-demo && npm install`);
313
+ console.log(' 3. 安装后端依赖(Python 环境):');
314
+ console.log(` cd ${targetDir}/service`);
315
+ console.log(' python -m venv venv && source venv/bin/activate # Windows: venv\\Scripts\\activate');
316
+ console.log(' pip install -r requirements.txt');
317
+ console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
318
+ }
319
+ console.log('');
320
+ }
321
+
322
+ module.exports = {
323
+ printPlanSummary,
324
+ printFinalReport,
325
+ modeLabel,
326
+ frontDemoLabel,
327
+ };