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/commands/doctor.js
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 环境依赖检查
|
|
10
|
-
*
|
|
11
|
-
* 检查 adspecs 运行所需的各工具是否可用,输出状态报告。
|
|
12
|
-
* 不阻断 init 执行,仅作提示。
|
|
13
|
-
*/
|
|
14
|
-
module.exports = async function doctor() {
|
|
15
|
-
console.log(chalk.cyan('🩺 adspecs 环境检查'));
|
|
16
|
-
console.log('');
|
|
17
|
-
|
|
18
|
-
const checks = [
|
|
19
|
-
checkNode(),
|
|
20
|
-
checkGit(),
|
|
21
|
-
checkClaudeCli(),
|
|
22
|
-
checkPython(),
|
|
23
|
-
checkPowerShell(),
|
|
24
|
-
checkPluginIntegrity(),
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const maxNameLen = Math.max(...checks.map((c) => c.name.length));
|
|
28
|
-
|
|
29
|
-
for (const check of checks) {
|
|
30
|
-
const icon = check.ok ? chalk.green('✅') : check.required ? chalk.red('❌') : chalk.yellow('⚠');
|
|
31
|
-
const paddedName = check.name.padEnd(maxNameLen);
|
|
32
|
-
const version = check.version ? chalk.gray(`(${check.version})`) : '';
|
|
33
|
-
const status = check.ok
|
|
34
|
-
? chalk.green(check.message || '可用')
|
|
35
|
-
: check.required
|
|
36
|
-
? chalk.red(check.message || '未找到(必需)')
|
|
37
|
-
: chalk.yellow(check.message || '未找到(可选)');
|
|
38
|
-
console.log(` ${icon} ${paddedName} ${status} ${version}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
console.log('');
|
|
42
|
-
|
|
43
|
-
const failed = checks.filter((c) => !c.ok);
|
|
44
|
-
const requiredFailed = failed.filter((c) => c.required);
|
|
45
|
-
|
|
46
|
-
if (requiredFailed.length > 0) {
|
|
47
|
-
console.log(chalk.red.bold(`❌ ${requiredFailed.length} 个必需依赖缺失,部分功能不可用`));
|
|
48
|
-
console.log('');
|
|
49
|
-
console.log(' 安装指南:');
|
|
50
|
-
for (const c of requiredFailed) {
|
|
51
|
-
if (c.installHint) {
|
|
52
|
-
console.log(` - ${c.name}: ${c.installHint}`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
} else if (failed.length > 0) {
|
|
56
|
-
console.log(chalk.yellow(`⚠ ${failed.length} 个可选依赖缺失,部分功能受限`));
|
|
57
|
-
} else {
|
|
58
|
-
console.log(chalk.green.bold('✅ 所有依赖检查通过'));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
console.log('');
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// ============================================================
|
|
65
|
-
// 各项检查
|
|
66
|
-
// ============================================================
|
|
67
|
-
|
|
68
|
-
function checkNode() {
|
|
69
|
-
try {
|
|
70
|
-
const version = process.version;
|
|
71
|
-
const major = parseInt(version.slice(1).split('.')[0], 10);
|
|
72
|
-
const ok = major >= 18;
|
|
73
|
-
return {
|
|
74
|
-
name: 'Node.js',
|
|
75
|
-
ok,
|
|
76
|
-
required: true,
|
|
77
|
-
version,
|
|
78
|
-
message: ok ? '可用' : '版本过低(需要 >=18.0.0)',
|
|
79
|
-
installHint: '访问 https://nodejs.org 下载最新版本',
|
|
80
|
-
};
|
|
81
|
-
} catch {
|
|
82
|
-
return { name: 'Node.js', ok: false, required: true, message: '未找到' };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function checkGit() {
|
|
87
|
-
try {
|
|
88
|
-
const output = execSync('git --version', { stdio: 'pipe' }).toString().trim();
|
|
89
|
-
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
90
|
-
return { name: 'Git', ok: true, required: false, version, message: '可用' };
|
|
91
|
-
} catch {
|
|
92
|
-
return {
|
|
93
|
-
name: 'Git',
|
|
94
|
-
ok: false,
|
|
95
|
-
required: false,
|
|
96
|
-
message: '未找到(git 扩展功能不可用)',
|
|
97
|
-
installHint: '访问 https://git-scm.com 下载',
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function checkClaudeCli() {
|
|
103
|
-
try {
|
|
104
|
-
const output = execSync('claude --version', { stdio: 'pipe' }).toString().trim();
|
|
105
|
-
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
106
|
-
return { name: 'Claude CLI', ok: true, required: false, version, message: '可用' };
|
|
107
|
-
} catch {
|
|
108
|
-
return {
|
|
109
|
-
name: 'Claude CLI',
|
|
110
|
-
ok: false,
|
|
111
|
-
required: false,
|
|
112
|
-
message: '未找到(plugin install 命令不可用)',
|
|
113
|
-
installHint: 'npm install -g @anthropic-ai/claude-code',
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function checkPython() {
|
|
119
|
-
try {
|
|
120
|
-
const output = execSync('python3 --version 2>&1 || python --version 2>&1', {
|
|
121
|
-
stdio: 'pipe',
|
|
122
|
-
shell: true,
|
|
123
|
-
})
|
|
124
|
-
.toString()
|
|
125
|
-
.trim();
|
|
126
|
-
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
127
|
-
return { name: 'Python', ok: true, required: false, version, message: '可用' };
|
|
128
|
-
} catch {
|
|
129
|
-
return {
|
|
130
|
-
name: 'Python',
|
|
131
|
-
ok: false,
|
|
132
|
-
required: false,
|
|
133
|
-
message: '未找到(Python 脚本不可用)',
|
|
134
|
-
installHint: '访问 https://www.python.org 下载',
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function checkPowerShell() {
|
|
140
|
-
try {
|
|
141
|
-
// 尝试 PowerShell Core (pwsh)
|
|
142
|
-
const output = execSync('pwsh --version', { stdio: 'pipe' }).toString().trim();
|
|
143
|
-
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
144
|
-
return { name: 'PowerShell', ok: true, required: false, version, message: '可用 (pwsh)' };
|
|
145
|
-
} catch {
|
|
146
|
-
try {
|
|
147
|
-
// 退而尝试 Windows PowerShell
|
|
148
|
-
if (process.platform === 'win32') {
|
|
149
|
-
execSync('powershell -Command "echo ok"', { stdio: 'pipe' });
|
|
150
|
-
return {
|
|
151
|
-
name: 'PowerShell',
|
|
152
|
-
ok: true,
|
|
153
|
-
required: false,
|
|
154
|
-
version: 'Windows PowerShell',
|
|
155
|
-
message: '可用 (Windows PowerShell)',
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
} catch {
|
|
159
|
-
// ignore
|
|
160
|
-
}
|
|
161
|
-
return {
|
|
162
|
-
name: 'PowerShell',
|
|
163
|
-
ok: false,
|
|
164
|
-
required: false,
|
|
165
|
-
message: '未找到(PowerShell 脚本不可用)',
|
|
166
|
-
installHint: '访问 https://github.com/PowerShell/PowerShell 安装 pwsh',
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function checkPluginIntegrity() {
|
|
172
|
-
const pluginDir = path.resolve(__dirname, '../..');
|
|
173
|
-
const requiredPaths = [
|
|
174
|
-
'.claude-plugin/plugin.json',
|
|
175
|
-
'.adspecs/feature.json',
|
|
176
|
-
'skills/project-init/SKILL.md',
|
|
177
|
-
'hooks/hooks.json',
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
const missing = requiredPaths.filter((p) => !fs.existsSync(path.join(pluginDir, p)));
|
|
181
|
-
|
|
182
|
-
if (missing.length === 0) {
|
|
183
|
-
return {
|
|
184
|
-
name: '插件完整性',
|
|
185
|
-
ok: true,
|
|
186
|
-
required: true,
|
|
187
|
-
message: `所有核心文件存在 (${pluginDir})`,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
name: '插件完整性',
|
|
193
|
-
ok: false,
|
|
194
|
-
required: true,
|
|
195
|
-
message: `缺失文件: ${missing.join(', ')}`,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 环境依赖检查
|
|
10
|
+
*
|
|
11
|
+
* 检查 adspecs 运行所需的各工具是否可用,输出状态报告。
|
|
12
|
+
* 不阻断 init 执行,仅作提示。
|
|
13
|
+
*/
|
|
14
|
+
module.exports = async function doctor() {
|
|
15
|
+
console.log(chalk.cyan('🩺 adspecs 环境检查'));
|
|
16
|
+
console.log('');
|
|
17
|
+
|
|
18
|
+
const checks = [
|
|
19
|
+
checkNode(),
|
|
20
|
+
checkGit(),
|
|
21
|
+
checkClaudeCli(),
|
|
22
|
+
checkPython(),
|
|
23
|
+
checkPowerShell(),
|
|
24
|
+
checkPluginIntegrity(),
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const maxNameLen = Math.max(...checks.map((c) => c.name.length));
|
|
28
|
+
|
|
29
|
+
for (const check of checks) {
|
|
30
|
+
const icon = check.ok ? chalk.green('✅') : check.required ? chalk.red('❌') : chalk.yellow('⚠');
|
|
31
|
+
const paddedName = check.name.padEnd(maxNameLen);
|
|
32
|
+
const version = check.version ? chalk.gray(`(${check.version})`) : '';
|
|
33
|
+
const status = check.ok
|
|
34
|
+
? chalk.green(check.message || '可用')
|
|
35
|
+
: check.required
|
|
36
|
+
? chalk.red(check.message || '未找到(必需)')
|
|
37
|
+
: chalk.yellow(check.message || '未找到(可选)');
|
|
38
|
+
console.log(` ${icon} ${paddedName} ${status} ${version}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log('');
|
|
42
|
+
|
|
43
|
+
const failed = checks.filter((c) => !c.ok);
|
|
44
|
+
const requiredFailed = failed.filter((c) => c.required);
|
|
45
|
+
|
|
46
|
+
if (requiredFailed.length > 0) {
|
|
47
|
+
console.log(chalk.red.bold(`❌ ${requiredFailed.length} 个必需依赖缺失,部分功能不可用`));
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(' 安装指南:');
|
|
50
|
+
for (const c of requiredFailed) {
|
|
51
|
+
if (c.installHint) {
|
|
52
|
+
console.log(` - ${c.name}: ${c.installHint}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} else if (failed.length > 0) {
|
|
56
|
+
console.log(chalk.yellow(`⚠ ${failed.length} 个可选依赖缺失,部分功能受限`));
|
|
57
|
+
} else {
|
|
58
|
+
console.log(chalk.green.bold('✅ 所有依赖检查通过'));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log('');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ============================================================
|
|
65
|
+
// 各项检查
|
|
66
|
+
// ============================================================
|
|
67
|
+
|
|
68
|
+
function checkNode() {
|
|
69
|
+
try {
|
|
70
|
+
const version = process.version;
|
|
71
|
+
const major = parseInt(version.slice(1).split('.')[0], 10);
|
|
72
|
+
const ok = major >= 18;
|
|
73
|
+
return {
|
|
74
|
+
name: 'Node.js',
|
|
75
|
+
ok,
|
|
76
|
+
required: true,
|
|
77
|
+
version,
|
|
78
|
+
message: ok ? '可用' : '版本过低(需要 >=18.0.0)',
|
|
79
|
+
installHint: '访问 https://nodejs.org 下载最新版本',
|
|
80
|
+
};
|
|
81
|
+
} catch {
|
|
82
|
+
return { name: 'Node.js', ok: false, required: true, message: '未找到' };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function checkGit() {
|
|
87
|
+
try {
|
|
88
|
+
const output = execSync('git --version', { stdio: 'pipe' }).toString().trim();
|
|
89
|
+
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
90
|
+
return { name: 'Git', ok: true, required: false, version, message: '可用' };
|
|
91
|
+
} catch {
|
|
92
|
+
return {
|
|
93
|
+
name: 'Git',
|
|
94
|
+
ok: false,
|
|
95
|
+
required: false,
|
|
96
|
+
message: '未找到(git 扩展功能不可用)',
|
|
97
|
+
installHint: '访问 https://git-scm.com 下载',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function checkClaudeCli() {
|
|
103
|
+
try {
|
|
104
|
+
const output = execSync('claude --version', { stdio: 'pipe' }).toString().trim();
|
|
105
|
+
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
106
|
+
return { name: 'Claude CLI', ok: true, required: false, version, message: '可用' };
|
|
107
|
+
} catch {
|
|
108
|
+
return {
|
|
109
|
+
name: 'Claude CLI',
|
|
110
|
+
ok: false,
|
|
111
|
+
required: false,
|
|
112
|
+
message: '未找到(plugin install 命令不可用)',
|
|
113
|
+
installHint: 'npm install -g @anthropic-ai/claude-code',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function checkPython() {
|
|
119
|
+
try {
|
|
120
|
+
const output = execSync('python3 --version 2>&1 || python --version 2>&1', {
|
|
121
|
+
stdio: 'pipe',
|
|
122
|
+
shell: true,
|
|
123
|
+
})
|
|
124
|
+
.toString()
|
|
125
|
+
.trim();
|
|
126
|
+
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
127
|
+
return { name: 'Python', ok: true, required: false, version, message: '可用' };
|
|
128
|
+
} catch {
|
|
129
|
+
return {
|
|
130
|
+
name: 'Python',
|
|
131
|
+
ok: false,
|
|
132
|
+
required: false,
|
|
133
|
+
message: '未找到(Python 脚本不可用)',
|
|
134
|
+
installHint: '访问 https://www.python.org 下载',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function checkPowerShell() {
|
|
140
|
+
try {
|
|
141
|
+
// 尝试 PowerShell Core (pwsh)
|
|
142
|
+
const output = execSync('pwsh --version', { stdio: 'pipe' }).toString().trim();
|
|
143
|
+
const version = output.match(/[\d.]+/)?.[0] || '';
|
|
144
|
+
return { name: 'PowerShell', ok: true, required: false, version, message: '可用 (pwsh)' };
|
|
145
|
+
} catch {
|
|
146
|
+
try {
|
|
147
|
+
// 退而尝试 Windows PowerShell
|
|
148
|
+
if (process.platform === 'win32') {
|
|
149
|
+
execSync('powershell -Command "echo ok"', { stdio: 'pipe' });
|
|
150
|
+
return {
|
|
151
|
+
name: 'PowerShell',
|
|
152
|
+
ok: true,
|
|
153
|
+
required: false,
|
|
154
|
+
version: 'Windows PowerShell',
|
|
155
|
+
message: '可用 (Windows PowerShell)',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
} catch {
|
|
159
|
+
// ignore
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
name: 'PowerShell',
|
|
163
|
+
ok: false,
|
|
164
|
+
required: false,
|
|
165
|
+
message: '未找到(PowerShell 脚本不可用)',
|
|
166
|
+
installHint: '访问 https://github.com/PowerShell/PowerShell 安装 pwsh',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function checkPluginIntegrity() {
|
|
172
|
+
const pluginDir = path.resolve(__dirname, '../..');
|
|
173
|
+
const requiredPaths = [
|
|
174
|
+
'.claude-plugin/plugin.json',
|
|
175
|
+
'.adspecs/feature.json',
|
|
176
|
+
'skills/project-init/SKILL.md',
|
|
177
|
+
'hooks/hooks.json',
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
const missing = requiredPaths.filter((p) => !fs.existsSync(path.join(pluginDir, p)));
|
|
181
|
+
|
|
182
|
+
if (missing.length === 0) {
|
|
183
|
+
return {
|
|
184
|
+
name: '插件完整性',
|
|
185
|
+
ok: true,
|
|
186
|
+
required: true,
|
|
187
|
+
message: `所有核心文件存在 (${pluginDir})`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
name: '插件完整性',
|
|
193
|
+
ok: false,
|
|
194
|
+
required: true,
|
|
195
|
+
message: `缺失文件: ${missing.join(', ')}`,
|
|
196
|
+
};
|
|
197
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const { scaffold } = require('../lib/scaffolder');
|
|
6
|
-
const {
|
|
7
|
-
collectProjectInfo,
|
|
8
|
-
collectDecisions,
|
|
9
|
-
collectSubDecisions,
|
|
10
|
-
detectModeUpgrade,
|
|
11
|
-
confirmExecution,
|
|
12
|
-
} = require('../lib/prompts');
|
|
13
|
-
const { deriveShortName } = require('../lib/short-name');
|
|
14
|
-
const { scanAreaStates } = require('../lib/area-scanner');
|
|
15
|
-
const { printPlanSummary, printFinalReport } = require('../lib/report');
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* init 命令实现
|
|
19
|
-
*
|
|
20
|
-
* 10 步流程:
|
|
21
|
-
* 1. 收集项目信息
|
|
22
|
-
* 2. 扫描各区域存在状态
|
|
23
|
-
* 3. 收集每区域决策(3 选项:recreate/update/skip)
|
|
24
|
-
* 4. 收集子目录决策(conventions/templates)
|
|
25
|
-
* 5. 模式升级检测
|
|
26
|
-
* 6. 输出计划摘要
|
|
27
|
-
* 7. 等待用户确认
|
|
28
|
-
* 8. 执行脚手架(带实时状态输出)
|
|
29
|
-
* 9. 输出详细最终报告
|
|
30
|
-
*
|
|
31
|
-
* @param {object} options - CLI 选项(来自 commander)
|
|
32
|
-
*/
|
|
33
|
-
module.exports = async function init(options) {
|
|
34
|
-
console.log(chalk.cyan('🚀 adspecs 项目初始化'));
|
|
35
|
-
console.log('');
|
|
36
|
-
|
|
37
|
-
const pluginDir = path.resolve(__dirname, '../..');
|
|
38
|
-
|
|
39
|
-
// === Step 1: 收集项目信息 ===
|
|
40
|
-
const info = await collectProjectInfo(options);
|
|
41
|
-
info.project_short_name = deriveShortName(info.project_name, info.project_dir);
|
|
42
|
-
|
|
43
|
-
const targetDir = info.project_dir
|
|
44
|
-
? path.resolve(process.cwd(), info.project_dir)
|
|
45
|
-
: process.cwd();
|
|
46
|
-
|
|
47
|
-
// === Step 2: 扫描区域状态 ===
|
|
48
|
-
const areaStates = scanAreaStates(targetDir, info.mode);
|
|
49
|
-
|
|
50
|
-
// === Step 3: 收集每区域决策 ===
|
|
51
|
-
const decisions = await collectDecisions(areaStates, options);
|
|
52
|
-
|
|
53
|
-
// === Step 4: 收集子目录决策 ===
|
|
54
|
-
const subDecisions = await collectSubDecisions(decisions, targetDir, options);
|
|
55
|
-
|
|
56
|
-
// === Step 5: 模式升级检测 ===
|
|
57
|
-
const modeUpgrade = detectModeUpgrade(decisions, info.mode, targetDir);
|
|
58
|
-
|
|
59
|
-
// === Step 6: 输出计划摘要 ===
|
|
60
|
-
printPlanSummary(info, decisions, subDecisions, modeUpgrade, targetDir);
|
|
61
|
-
|
|
62
|
-
// === Step 7: 等待用户确认 ===
|
|
63
|
-
const confirmed = await confirmExecution(options);
|
|
64
|
-
if (!confirmed) {
|
|
65
|
-
console.log(chalk.yellow('⏹ 已取消初始化'));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
console.log('');
|
|
69
|
-
|
|
70
|
-
// === Step 8: 执行脚手架(带实时状态输出) ===
|
|
71
|
-
const report = await scaffold({
|
|
72
|
-
targetDir,
|
|
73
|
-
pluginDir,
|
|
74
|
-
...info,
|
|
75
|
-
decisions,
|
|
76
|
-
subDecisions,
|
|
77
|
-
modeUpgrade,
|
|
78
|
-
logger: (msg) => console.log(` ${msg}`),
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// === Step 9: 输出详细最终报告 ===
|
|
82
|
-
printFinalReport(report, info, decisions, subDecisions, modeUpgrade);
|
|
83
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { scaffold } = require('../lib/scaffolder');
|
|
6
|
+
const {
|
|
7
|
+
collectProjectInfo,
|
|
8
|
+
collectDecisions,
|
|
9
|
+
collectSubDecisions,
|
|
10
|
+
detectModeUpgrade,
|
|
11
|
+
confirmExecution,
|
|
12
|
+
} = require('../lib/prompts');
|
|
13
|
+
const { deriveShortName } = require('../lib/short-name');
|
|
14
|
+
const { scanAreaStates } = require('../lib/area-scanner');
|
|
15
|
+
const { printPlanSummary, printFinalReport } = require('../lib/report');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* init 命令实现
|
|
19
|
+
*
|
|
20
|
+
* 10 步流程:
|
|
21
|
+
* 1. 收集项目信息
|
|
22
|
+
* 2. 扫描各区域存在状态
|
|
23
|
+
* 3. 收集每区域决策(3 选项:recreate/update/skip)
|
|
24
|
+
* 4. 收集子目录决策(conventions/templates)
|
|
25
|
+
* 5. 模式升级检测
|
|
26
|
+
* 6. 输出计划摘要
|
|
27
|
+
* 7. 等待用户确认
|
|
28
|
+
* 8. 执行脚手架(带实时状态输出)
|
|
29
|
+
* 9. 输出详细最终报告
|
|
30
|
+
*
|
|
31
|
+
* @param {object} options - CLI 选项(来自 commander)
|
|
32
|
+
*/
|
|
33
|
+
module.exports = async function init(options) {
|
|
34
|
+
console.log(chalk.cyan('🚀 adspecs 项目初始化'));
|
|
35
|
+
console.log('');
|
|
36
|
+
|
|
37
|
+
const pluginDir = path.resolve(__dirname, '../..');
|
|
38
|
+
|
|
39
|
+
// === Step 1: 收集项目信息 ===
|
|
40
|
+
const info = await collectProjectInfo(options);
|
|
41
|
+
info.project_short_name = deriveShortName(info.project_name, info.project_dir);
|
|
42
|
+
|
|
43
|
+
const targetDir = info.project_dir
|
|
44
|
+
? path.resolve(process.cwd(), info.project_dir)
|
|
45
|
+
: process.cwd();
|
|
46
|
+
|
|
47
|
+
// === Step 2: 扫描区域状态 ===
|
|
48
|
+
const areaStates = scanAreaStates(targetDir, info.mode);
|
|
49
|
+
|
|
50
|
+
// === Step 3: 收集每区域决策 ===
|
|
51
|
+
const decisions = await collectDecisions(areaStates, options);
|
|
52
|
+
|
|
53
|
+
// === Step 4: 收集子目录决策 ===
|
|
54
|
+
const subDecisions = await collectSubDecisions(decisions, targetDir, pluginDir, options);
|
|
55
|
+
|
|
56
|
+
// === Step 5: 模式升级检测 ===
|
|
57
|
+
const modeUpgrade = detectModeUpgrade(decisions, info.mode, targetDir);
|
|
58
|
+
|
|
59
|
+
// === Step 6: 输出计划摘要 ===
|
|
60
|
+
printPlanSummary(info, decisions, subDecisions, modeUpgrade, targetDir);
|
|
61
|
+
|
|
62
|
+
// === Step 7: 等待用户确认 ===
|
|
63
|
+
const confirmed = await confirmExecution(options);
|
|
64
|
+
if (!confirmed) {
|
|
65
|
+
console.log(chalk.yellow('⏹ 已取消初始化'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log('');
|
|
69
|
+
|
|
70
|
+
// === Step 8: 执行脚手架(带实时状态输出) ===
|
|
71
|
+
const report = await scaffold({
|
|
72
|
+
targetDir,
|
|
73
|
+
pluginDir,
|
|
74
|
+
...info,
|
|
75
|
+
decisions,
|
|
76
|
+
subDecisions,
|
|
77
|
+
modeUpgrade,
|
|
78
|
+
logger: (msg) => console.log(` ${msg}`),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// === Step 9: 输出详细最终报告 ===
|
|
82
|
+
printFinalReport(report, info, decisions, subDecisions, modeUpgrade);
|
|
83
|
+
};
|