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
package/src/lib/report.js
CHANGED
|
@@ -1,327 +1,338 @@
|
|
|
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'
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
console.log(
|
|
135
|
-
console.log(chalk.bold('
|
|
136
|
-
console.log(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
console.log(chalk.bold('
|
|
143
|
-
console.log('');
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
console.log('
|
|
149
|
-
console.log('
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
console.log(
|
|
205
|
-
console.log('');
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
lines.push(' ├──
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (mode === 'demo') {
|
|
271
|
-
lines.push('');
|
|
272
|
-
lines.push('
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
} else if (mode === '
|
|
300
|
-
console.log(' 1. 执行 `git init` 初始化 Git 仓库');
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
console.log(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
console.log(`
|
|
312
|
-
console.log(
|
|
313
|
-
console.log(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
console.log('
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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') {
|
|
95
|
+
const tmplMap = subDecisions.templates || {};
|
|
96
|
+
const tmplEntries = Object.entries(tmplMap);
|
|
97
|
+
const replaceCount = tmplEntries.filter(([, v]) => v === 'replace').length;
|
|
98
|
+
const keepCount = tmplEntries.filter(([, v]) => v === 'keep').length;
|
|
99
|
+
if (replaceCount > 0 || keepCount > 0) {
|
|
100
|
+
console.log(
|
|
101
|
+
` ${chalk.gray('└')} templates/ ${chalk.gray('→')} 逐文件确认(${replaceCount} 个替换,${keepCount} 个保留)`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 模式升级提示
|
|
108
|
+
if (modeUpgrade.detected) {
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(
|
|
111
|
+
chalk.yellow(
|
|
112
|
+
` 📦 模式升级检测:检测到 40-project_conventions/ 为空目录(简易模式产物),将自动补充 frontend-standard/`
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log('');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ============================================================
|
|
121
|
+
// 最终详细报告(执行后)
|
|
122
|
+
// ============================================================
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 输出最终详细报告
|
|
126
|
+
*
|
|
127
|
+
* @param {object} report - scaffolder 返回的执行报告
|
|
128
|
+
* @param {object} info - 项目信息
|
|
129
|
+
* @param {object} decisions - 每区域决策
|
|
130
|
+
* @param {object} subDecisions - 子目录决策
|
|
131
|
+
* @param {object} modeUpgrade - 模式升级检测
|
|
132
|
+
*/
|
|
133
|
+
function printFinalReport(report, info, decisions, subDecisions, modeUpgrade) {
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log(chalk.green.bold('## 项目初始化完成 🎉'));
|
|
136
|
+
console.log('');
|
|
137
|
+
|
|
138
|
+
// 项目信息段
|
|
139
|
+
console.log(chalk.bold('项目名称:'), info.project_name);
|
|
140
|
+
console.log(chalk.bold('项目短名称:'), info.project_short_name);
|
|
141
|
+
console.log(chalk.bold('公司名称:'), info.company_name);
|
|
142
|
+
console.log(chalk.bold('文件密级:'), info.confidentiality);
|
|
143
|
+
console.log(chalk.bold('初始化模式:'), modeLabel(info.mode));
|
|
144
|
+
if (info.mode === 'classic' || info.mode === 'full' || info.mode === 'demo') {
|
|
145
|
+
const fdLabel = info.mode === 'demo' ? frontDemoLabel('antd') : frontDemoLabel(info.frontDemo);
|
|
146
|
+
console.log(chalk.bold('前端技术栈:'), fdLabel);
|
|
147
|
+
}
|
|
148
|
+
console.log(chalk.bold('目标路径:'), report.targetDir);
|
|
149
|
+
console.log('');
|
|
150
|
+
|
|
151
|
+
// 区域执行结果表格
|
|
152
|
+
console.log(chalk.bold('### 区域执行结果'));
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log(' | 区域 | 状态 | 说明 |');
|
|
155
|
+
console.log(' | --- | --- | --- |');
|
|
156
|
+
|
|
157
|
+
for (const stage of report.stages) {
|
|
158
|
+
const icon = statusIcon(stage.status);
|
|
159
|
+
const detail = stageDetail(stage);
|
|
160
|
+
console.log(` | ${stage.name} | ${icon} ${stage.status} | ${detail} |`);
|
|
161
|
+
|
|
162
|
+
// 子行:templates/(逐文件确认结果)
|
|
163
|
+
if (stage.name === '.adspecs/' && stage.subDecisions && stage.subDecisions.templates) {
|
|
164
|
+
const tmpl = stage.subDecisions.templates;
|
|
165
|
+
if (typeof tmpl === 'object' && (tmpl.replaced > 0 || tmpl.kept > 0 || tmpl.added > 0)) {
|
|
166
|
+
const parts = [];
|
|
167
|
+
if (tmpl.added > 0) parts.push(`${tmpl.added} 个新增`);
|
|
168
|
+
if (tmpl.replaced > 0) parts.push(`${tmpl.replaced} 个替换`);
|
|
169
|
+
if (tmpl.kept > 0) parts.push(`${tmpl.kept} 个保留`);
|
|
170
|
+
console.log(` | ${chalk.gray('└ templates/')} | ${chalk.green('🔄')} 部分更新 | ${parts.join(',')} |`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 子行:feature.json
|
|
175
|
+
if (stage.name === '.adspecs/' && stage.featureResult) {
|
|
176
|
+
if (stage.featureResult.addedKeys && stage.featureResult.addedKeys.length > 0) {
|
|
177
|
+
console.log(
|
|
178
|
+
` | ${chalk.gray('└ feature.json')} | ${chalk.yellow('🔧')} 已补全 | 补充缺失属性 [${stage.featureResult.addedKeys.join(', ')}] |`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 子行:40-project_conventions/
|
|
184
|
+
if (stage.name === 'docs/' && stage.subDecisions) {
|
|
185
|
+
if (stage.subDecisions.conventions === 'update') {
|
|
186
|
+
console.log(
|
|
187
|
+
` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.green('🔄')} 已更新 | 按前端技术栈覆盖更新 |`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (stage.modeUpgrade && stage.modeUpgrade.detected) {
|
|
191
|
+
console.log(
|
|
192
|
+
` | ${chalk.gray('└ 40-project_conventions/')} | ${chalk.yellow('📦')} 已补充 | 模式升级自动补充 frontend-standard/ |`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
console.log('');
|
|
199
|
+
|
|
200
|
+
// 状态说明
|
|
201
|
+
console.log(chalk.bold('状态说明:'));
|
|
202
|
+
console.log(' ✅ 已创建 — 目录原本不存在,新建完成');
|
|
203
|
+
console.log(' 🔄 已重建 — 目录原本存在,按用户选择删除后重新创建');
|
|
204
|
+
console.log(' 🔄 已更新 — 父目录跳过,但子目录按用户选择使用最新文件覆盖(templates/ 支持逐文件确认,部分替换部分保留)');
|
|
205
|
+
console.log(' 🔧 已补全 — 已有文件属性与 references 对比后,补充缺失属性');
|
|
206
|
+
console.log(' ⏭ 已跳过 — 目录原本存在,按用户选择保留未动');
|
|
207
|
+
console.log('');
|
|
208
|
+
|
|
209
|
+
// 目录树总览
|
|
210
|
+
console.log(chalk.bold('### 目录树总览'));
|
|
211
|
+
console.log('');
|
|
212
|
+
printDirectoryTree(info.mode, info.frontDemo);
|
|
213
|
+
|
|
214
|
+
// 后续步骤
|
|
215
|
+
console.log(chalk.bold('### 后续步骤'));
|
|
216
|
+
console.log('');
|
|
217
|
+
printNextSteps(info.mode, report.targetDir, info.frontDemo);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 状态图标
|
|
222
|
+
*/
|
|
223
|
+
function statusIcon(status) {
|
|
224
|
+
const icons = {
|
|
225
|
+
created: '✅',
|
|
226
|
+
recreated: '🔄',
|
|
227
|
+
updated: '🔄',
|
|
228
|
+
skipped: '⏭',
|
|
229
|
+
exists: '⏭',
|
|
230
|
+
};
|
|
231
|
+
return icons[status] || '❓';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 阶段详情
|
|
236
|
+
*/
|
|
237
|
+
function stageDetail(stage) {
|
|
238
|
+
if (stage.fileCount !== undefined) {
|
|
239
|
+
return `${stage.fileCount} 个文件`;
|
|
240
|
+
}
|
|
241
|
+
if (stage.reason) {
|
|
242
|
+
return stage.reason;
|
|
243
|
+
}
|
|
244
|
+
if (stage.detail && stage.detail.created) {
|
|
245
|
+
return '已创建';
|
|
246
|
+
}
|
|
247
|
+
return '';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 按模式输出 ASCII 目录树
|
|
252
|
+
*/
|
|
253
|
+
function printDirectoryTree(mode, frontDemo) {
|
|
254
|
+
const lines = [];
|
|
255
|
+
lines.push(' {targetDir}/');
|
|
256
|
+
lines.push(' ├── .adspecs/ (插件配置、脚本、模板 + project.json)');
|
|
257
|
+
lines.push(' ├── docs/ (11 个子目录)');
|
|
258
|
+
if (mode === 'classic' || mode === 'full' || mode === 'demo') {
|
|
259
|
+
lines.push(' │ └── 40-project_conventions/');
|
|
260
|
+
if (mode === 'demo') {
|
|
261
|
+
lines.push(' │ ├── frontend-standard/ (Ant Design React 前端规范)');
|
|
262
|
+
lines.push(' │ └── end-standard/ (Python 后端规范)');
|
|
263
|
+
} else {
|
|
264
|
+
const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
|
|
265
|
+
lines.push(` │ └── frontend-standard/ (${fdLabel} 前端规范)`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
lines.push(' ├── wiki/ (基线文件目录)');
|
|
269
|
+
|
|
270
|
+
if (mode === 'full' || mode === 'demo') {
|
|
271
|
+
lines.push(' ├── web-ui/ (前端生产项目)');
|
|
272
|
+
lines.push(' ├── service/ (后端服务模块)');
|
|
273
|
+
}
|
|
274
|
+
if (mode === 'classic' || mode === 'full' || mode === 'demo') {
|
|
275
|
+
if (frontDemo !== 'skip') {
|
|
276
|
+
const fdLabel = frontDemo === 'antd' ? 'Ant Design React' : 'Vue';
|
|
277
|
+
lines.push(` └── front-demo/ (${fdLabel} 前端演示项目)`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (mode === 'demo') {
|
|
282
|
+
lines.push('');
|
|
283
|
+
lines.push(' 技术栈:Python + SQLite + React + Ant Design 6 全栈 demo');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log(lines.join('\n'));
|
|
287
|
+
console.log('');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 按模式输出后续步骤
|
|
292
|
+
*/
|
|
293
|
+
function printNextSteps(mode, targetDir, frontDemo = 'vue') {
|
|
294
|
+
if (mode === 'simple') {
|
|
295
|
+
console.log(' 1. 执行 `git init` 初始化 Git 仓库');
|
|
296
|
+
console.log(' 2. 根据需要调整 .adspecs/templates/ 下的文档模板');
|
|
297
|
+
console.log(' 3. 根据需要编辑 .adspecs/project.json 补充公司 Logo 路径等信息');
|
|
298
|
+
console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
|
|
299
|
+
} else if (mode === 'classic') {
|
|
300
|
+
console.log(' 1. 执行 `git init` 初始化 Git 仓库');
|
|
301
|
+
if (frontDemo !== 'skip') {
|
|
302
|
+
console.log(' 2. 在前端演示目录执行 `npm install` 安装依赖:');
|
|
303
|
+
console.log(` cd ${targetDir}/front-demo && npm install`);
|
|
304
|
+
console.log(' 3. 根据需要调整文档模板和编码规范');
|
|
305
|
+
console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
|
|
306
|
+
} else {
|
|
307
|
+
console.log(' 2. 根据需要调整文档模板和编码规范');
|
|
308
|
+
console.log(' 3. 执行 `adspecs plugin install` 注册 Claude Code 插件');
|
|
309
|
+
}
|
|
310
|
+
} else if (mode === 'full') {
|
|
311
|
+
console.log(' 1. 执行 `git init` 初始化 Git 仓库');
|
|
312
|
+
console.log(' 2. 安装前端依赖:');
|
|
313
|
+
console.log(` cd ${targetDir}/web-ui && npm install`);
|
|
314
|
+
if (frontDemo !== 'skip') {
|
|
315
|
+
console.log(` cd ${targetDir}/front-demo && npm install`);
|
|
316
|
+
}
|
|
317
|
+
console.log(' 3. 根据需要调整文档模板和编码规范');
|
|
318
|
+
console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
|
|
319
|
+
} else if (mode === 'demo') {
|
|
320
|
+
console.log(' 1. 执行 `git init` 初始化 Git 仓库');
|
|
321
|
+
console.log(' 2. 安装前端依赖:');
|
|
322
|
+
console.log(` cd ${targetDir}/web-ui && npm install`);
|
|
323
|
+
console.log(` cd ${targetDir}/front-demo && npm install`);
|
|
324
|
+
console.log(' 3. 安装后端依赖(Python 环境):');
|
|
325
|
+
console.log(` cd ${targetDir}/service`);
|
|
326
|
+
console.log(' python -m venv venv && source venv/bin/activate # Windows: venv\\Scripts\\activate');
|
|
327
|
+
console.log(' pip install -r requirements.txt');
|
|
328
|
+
console.log(' 4. 执行 `adspecs plugin install` 注册 Claude Code 插件');
|
|
329
|
+
}
|
|
330
|
+
console.log('');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
module.exports = {
|
|
334
|
+
printPlanSummary,
|
|
335
|
+
printFinalReport,
|
|
336
|
+
modeLabel,
|
|
337
|
+
frontDemoLabel,
|
|
338
|
+
};
|