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.
Files changed (74) hide show
  1. package/.adspecs/feature.json +16 -16
  2. package/.adspecs/feature.yml +28 -28
  3. package/.adspecs/paths.json +17 -17
  4. 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
  5. 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
  6. 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
  7. package/.claude-plugin/marketplace.json +23 -23
  8. package/.claude-plugin/plugin.json +18 -18
  9. package/.qoder-plugin/plugin.json +31 -31
  10. package/CLAUDE.md +1 -5
  11. package/INSTALL.md +3 -3
  12. package/README.md +395 -395
  13. package/bin/adspecs.js +129 -129
  14. package/hooks/commit-queue.js +245 -245
  15. package/hooks/hooks.json +63 -63
  16. package/hooks/session-start.js +44 -44
  17. package/hooks/wiki-queue.js +127 -127
  18. package/package.json +61 -61
  19. package/references/ant6-front-standard/index.md +99 -99
  20. package/references/antd-front-demo/public/mockServiceWorker.js +361 -361
  21. package/references/ecp-end-standard/index.md +63 -63
  22. 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
  23. 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
  24. 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
  25. package/references/python-end-standard/04-Redis/344/275/277/347/224/250/350/247/204/350/214/203.md +231 -231
  26. package/scripts/postinstall.js +107 -107
  27. package/scripts/sync-version.js +105 -105
  28. package/skills/.claude/.wiki-update-queue +26 -26
  29. package/skills/adspecs-constitution/SKILL.md +157 -0
  30. package/skills/adspecs-export-word/SKILL.md +498 -498
  31. package/skills/adspecs-export-word/references/md-to-docx.js +862 -862
  32. package/skills/adspecs-export-word/references/package-lock.json +220 -220
  33. package/skills/adspecs-export-word/references/package.json +10 -10
  34. package/skills/adspecs-front-prototype/SKILL.md +405 -405
  35. package/skills/adspecs-front-spec/SKILL.md +4 -4
  36. package/skills/adspecs-front-tasks/SKILL.md +213 -173
  37. package/skills/adspecs-plan/SKILL.md +59 -69
  38. package/skills/adspecs-prd/SKILL.md +13 -5
  39. package/skills/adspecs-prd-to-demo/SKILL.md +532 -0
  40. package/skills/adspecs-tasks/SKILL.md +175 -204
  41. package/skills/adspecs-update-status/SKILL.md +382 -382
  42. package/skills/adspecs-utest/SKILL.md +107 -116
  43. package/skills/grill-me/SKILL.md +7 -0
  44. package/skills/grill-me/agents/openai.yaml +5 -0
  45. package/skills/playwright-cli/SKILL.md +420 -0
  46. package/skills/playwright-cli/references/element-attributes.md +23 -0
  47. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  48. package/skills/playwright-cli/references/request-mocking.md +87 -0
  49. package/skills/playwright-cli/references/running-code.md +241 -0
  50. package/skills/playwright-cli/references/session-management.md +225 -0
  51. package/skills/playwright-cli/references/storage-state.md +275 -0
  52. package/skills/playwright-cli/references/test-generation.md +433 -0
  53. package/skills/playwright-cli/references/tracing.md +139 -0
  54. package/skills/playwright-cli/references/video-recording.md +143 -0
  55. package/skills/playwright-trace/SKILL.md +171 -0
  56. package/skills/project-init/SKILL.md +93 -22
  57. package/skills/project-init/references/front-demo/.claude/settings.local.json +9 -0
  58. package/skills/wiki-update/SKILL.md +232 -232
  59. package/src/commands/doctor.js +197 -197
  60. package/src/commands/init.js +83 -83
  61. package/src/commands/plugin.js +165 -165
  62. package/src/commands/update.js +87 -87
  63. package/src/lib/area-scanner.js +129 -129
  64. package/src/lib/copier.js +104 -104
  65. package/src/lib/dir-utils.js +161 -133
  66. package/src/lib/json-merge.js +114 -114
  67. package/src/lib/paths-defaults.js +37 -37
  68. package/src/lib/prompts.js +428 -347
  69. package/src/lib/readme-gen.js +143 -143
  70. package/src/lib/report.js +338 -327
  71. package/src/lib/scaffolder.js +551 -518
  72. package/src/lib/short-name.js +36 -36
  73. package/src/utils.js +80 -80
  74. package/references/antd-front-demo/.env +0 -15
@@ -1,165 +1,165 @@
1
- 'use strict';
2
-
3
- const { execSync } = require('child_process');
4
- const path = require('path');
5
- const fs = require('fs');
6
- const chalk = require('chalk');
7
-
8
- /**
9
- * 插件根目录(即 adspecs/ 目录)
10
- * bin/adspecs.js 在 bin/ 下,src/commands/ 在 src/commands/ 下
11
- * 所以 __dirname/../../ 指向插件根目录
12
- */
13
- const PLUGIN_DIR = path.resolve(__dirname, '../..');
14
-
15
- /**
16
- * 检查 claude CLI 是否可用
17
- */
18
- function checkClaudeCli() {
19
- try {
20
- execSync('claude --version', { stdio: 'ignore' });
21
- return true;
22
- } catch {
23
- return false;
24
- }
25
- }
26
-
27
- /**
28
- * 读取 plugin.json 获取插件名
29
- */
30
- function getPluginName() {
31
- const pluginJsonPath = path.join(PLUGIN_DIR, '.claude-plugin', 'plugin.json');
32
- if (!fs.existsSync(pluginJsonPath)) {
33
- throw new Error(`未找到插件清单文件: ${pluginJsonPath}`);
34
- }
35
- const pluginJson = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
36
- return pluginJson.name || 'adspecs';
37
- }
38
-
39
- /**
40
- * 安装(注册)插件到 Claude Code
41
- *
42
- * Claude Code 的 marketplace 命令期望路径指向包含 `.claude-plugin/marketplace.json`
43
- * 的目录,因此传入 PLUGIN_DIR(而非 PLUGIN_DIR/.claude-plugin)。
44
- *
45
- * @param {object} options
46
- * @param {string} options.scope - 安装范围: user|project
47
- */
48
- exports.install = async function install(options) {
49
- const scope = options.scope || 'user';
50
- const pluginName = getPluginName();
51
-
52
- // marketplace.json 必须存在,否则无法注册
53
- const marketplaceJson = path.join(PLUGIN_DIR, '.claude-plugin', 'marketplace.json');
54
- if (!fs.existsSync(marketplaceJson)) {
55
- throw new Error(`未找到 marketplace 清单: ${marketplaceJson}`);
56
- }
57
-
58
- console.log(chalk.cyan('🔌 adspecs 插件注册'));
59
- console.log('');
60
- console.log(` 插件目录: ${PLUGIN_DIR}`);
61
- console.log(` 插件名称: ${pluginName}`);
62
- console.log(` 安装范围: ${scope}`);
63
- console.log('');
64
-
65
- // 1. 检查 claude CLI
66
- if (!checkClaudeCli()) {
67
- console.error(chalk.red('❌ 未检测到 claude CLI'));
68
- console.error('');
69
- console.error(' 请先安装 Claude Code:');
70
- console.error(' npm install -g @anthropic-ai/claude-code');
71
- console.error('');
72
- console.error(' 或访问: https://claude.ai/code');
73
- process.exit(1);
74
- }
75
-
76
- // 2. 注册 marketplace
77
- // 注意:传入 PLUGIN_DIR,claude 会去找 <PLUGIN_DIR>/.claude-plugin/marketplace.json
78
- console.log(chalk.gray(' → 注册 marketplace...'));
79
- let marketplaceRegistered = false;
80
- try {
81
- execSync(
82
- `claude plugins marketplace add "${PLUGIN_DIR}" --scope ${scope}`,
83
- { stdio: 'pipe' }
84
- );
85
- console.log(chalk.green(' ✅ marketplace 注册成功'));
86
- marketplaceRegistered = true;
87
- } catch (err) {
88
- const stderr = err.stderr ? err.stderr.toString() : '';
89
- const stdout = err.stdout ? err.stdout.toString() : '';
90
- const combined = stderr + stdout;
91
- if (combined.includes('already exists') || combined.includes('already registered')) {
92
- console.log(chalk.yellow(' ⏭ marketplace 已存在,跳过'));
93
- marketplaceRegistered = true; // 已存在也视为可用
94
- } else {
95
- // 把真实错误输出,方便排查,不再静默吞掉
96
- console.log(chalk.red(` ❌ marketplace 注册失败: ${combined.trim() || err.message}`));
97
- }
98
- }
99
-
100
- // 3. 安装插件
101
- // 只有 marketplace 注册成功(或已存在)时,才能按名称安装
102
- console.log(chalk.gray(' → 安装插件...'));
103
- if (!marketplaceRegistered) {
104
- throw new Error('marketplace 未注册成功,无法按名称安装插件,请检查上方错误');
105
- }
106
- try {
107
- execSync(`claude plugins install ${pluginName} --scope ${scope}`, {
108
- stdio: 'pipe',
109
- });
110
- console.log(chalk.green(` ✅ ${pluginName} 插件安装成功`));
111
- } catch (err) {
112
- const stderr = err.stderr ? err.stderr.toString() : '';
113
- const stdout = err.stdout ? err.stdout.toString() : '';
114
- const combined = stderr + stdout;
115
- if (combined.includes('already installed')) {
116
- console.log(chalk.yellow(` ⏭ ${pluginName} 已安装,跳过`));
117
- } else {
118
- throw new Error(`插件安装失败: ${combined.trim() || err.message}`);
119
- }
120
- }
121
-
122
- console.log('');
123
- console.log(chalk.green.bold(`✅ adspecs 插件已注册到 Claude Code (scope=${scope})`));
124
- console.log('');
125
- console.log(' 现在可以在 Claude Code 中使用以下技能:');
126
- console.log(' /adspecs-prd — 生成 PRD');
127
- console.log(' /adspecs-plan — 后端系统设计');
128
- console.log(' /adspecs-tasks — TDD 任务清单');
129
- console.log(' /adspecs-utest — 生成单元测试');
130
- console.log(' ...(共 19 个技能)');
131
- console.log('');
132
- };
133
-
134
- /**
135
- * 卸载插件
136
- *
137
- * @param {object} options
138
- * @param {string} options.scope - 卸载范围: user|project
139
- */
140
- exports.uninstall = async function uninstall(options) {
141
- const scope = options.scope || 'user';
142
- const pluginName = getPluginName();
143
-
144
- console.log(chalk.cyan('🔌 adspecs 插件卸载'));
145
- console.log('');
146
-
147
- if (!checkClaudeCli()) {
148
- console.error(chalk.red('❌ 未检测到 claude CLI'));
149
- process.exit(1);
150
- }
151
-
152
- try {
153
- execSync(`claude plugins uninstall ${pluginName} --scope ${scope}`, {
154
- stdio: 'pipe',
155
- });
156
- console.log(chalk.green(`✅ ${pluginName} 插件已卸载 (scope=${scope})`));
157
- } catch (err) {
158
- const stderr = err.stderr ? err.stderr.toString() : '';
159
- if (stderr.includes('not installed') || stderr.includes('not found')) {
160
- console.log(chalk.yellow(`⏭ ${pluginName} 未安装,无需卸载`));
161
- } else {
162
- throw new Error(`插件卸载失败: ${stderr || err.message}`);
163
- }
164
- }
165
- };
1
+ 'use strict';
2
+
3
+ const { execSync } = require('child_process');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const chalk = require('chalk');
7
+
8
+ /**
9
+ * 插件根目录(即 adspecs/ 目录)
10
+ * bin/adspecs.js 在 bin/ 下,src/commands/ 在 src/commands/ 下
11
+ * 所以 __dirname/../../ 指向插件根目录
12
+ */
13
+ const PLUGIN_DIR = path.resolve(__dirname, '../..');
14
+
15
+ /**
16
+ * 检查 claude CLI 是否可用
17
+ */
18
+ function checkClaudeCli() {
19
+ try {
20
+ execSync('claude --version', { stdio: 'ignore' });
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * 读取 plugin.json 获取插件名
29
+ */
30
+ function getPluginName() {
31
+ const pluginJsonPath = path.join(PLUGIN_DIR, '.claude-plugin', 'plugin.json');
32
+ if (!fs.existsSync(pluginJsonPath)) {
33
+ throw new Error(`未找到插件清单文件: ${pluginJsonPath}`);
34
+ }
35
+ const pluginJson = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
36
+ return pluginJson.name || 'adspecs';
37
+ }
38
+
39
+ /**
40
+ * 安装(注册)插件到 Claude Code
41
+ *
42
+ * Claude Code 的 marketplace 命令期望路径指向包含 `.claude-plugin/marketplace.json`
43
+ * 的目录,因此传入 PLUGIN_DIR(而非 PLUGIN_DIR/.claude-plugin)。
44
+ *
45
+ * @param {object} options
46
+ * @param {string} options.scope - 安装范围: user|project
47
+ */
48
+ exports.install = async function install(options) {
49
+ const scope = options.scope || 'user';
50
+ const pluginName = getPluginName();
51
+
52
+ // marketplace.json 必须存在,否则无法注册
53
+ const marketplaceJson = path.join(PLUGIN_DIR, '.claude-plugin', 'marketplace.json');
54
+ if (!fs.existsSync(marketplaceJson)) {
55
+ throw new Error(`未找到 marketplace 清单: ${marketplaceJson}`);
56
+ }
57
+
58
+ console.log(chalk.cyan('🔌 adspecs 插件注册'));
59
+ console.log('');
60
+ console.log(` 插件目录: ${PLUGIN_DIR}`);
61
+ console.log(` 插件名称: ${pluginName}`);
62
+ console.log(` 安装范围: ${scope}`);
63
+ console.log('');
64
+
65
+ // 1. 检查 claude CLI
66
+ if (!checkClaudeCli()) {
67
+ console.error(chalk.red('❌ 未检测到 claude CLI'));
68
+ console.error('');
69
+ console.error(' 请先安装 Claude Code:');
70
+ console.error(' npm install -g @anthropic-ai/claude-code');
71
+ console.error('');
72
+ console.error(' 或访问: https://claude.ai/code');
73
+ process.exit(1);
74
+ }
75
+
76
+ // 2. 注册 marketplace
77
+ // 注意:传入 PLUGIN_DIR,claude 会去找 <PLUGIN_DIR>/.claude-plugin/marketplace.json
78
+ console.log(chalk.gray(' → 注册 marketplace...'));
79
+ let marketplaceRegistered = false;
80
+ try {
81
+ execSync(
82
+ `claude plugins marketplace add "${PLUGIN_DIR}" --scope ${scope}`,
83
+ { stdio: 'pipe' }
84
+ );
85
+ console.log(chalk.green(' ✅ marketplace 注册成功'));
86
+ marketplaceRegistered = true;
87
+ } catch (err) {
88
+ const stderr = err.stderr ? err.stderr.toString() : '';
89
+ const stdout = err.stdout ? err.stdout.toString() : '';
90
+ const combined = stderr + stdout;
91
+ if (combined.includes('already exists') || combined.includes('already registered')) {
92
+ console.log(chalk.yellow(' ⏭ marketplace 已存在,跳过'));
93
+ marketplaceRegistered = true; // 已存在也视为可用
94
+ } else {
95
+ // 把真实错误输出,方便排查,不再静默吞掉
96
+ console.log(chalk.red(` ❌ marketplace 注册失败: ${combined.trim() || err.message}`));
97
+ }
98
+ }
99
+
100
+ // 3. 安装插件
101
+ // 只有 marketplace 注册成功(或已存在)时,才能按名称安装
102
+ console.log(chalk.gray(' → 安装插件...'));
103
+ if (!marketplaceRegistered) {
104
+ throw new Error('marketplace 未注册成功,无法按名称安装插件,请检查上方错误');
105
+ }
106
+ try {
107
+ execSync(`claude plugins install ${pluginName} --scope ${scope}`, {
108
+ stdio: 'pipe',
109
+ });
110
+ console.log(chalk.green(` ✅ ${pluginName} 插件安装成功`));
111
+ } catch (err) {
112
+ const stderr = err.stderr ? err.stderr.toString() : '';
113
+ const stdout = err.stdout ? err.stdout.toString() : '';
114
+ const combined = stderr + stdout;
115
+ if (combined.includes('already installed')) {
116
+ console.log(chalk.yellow(` ⏭ ${pluginName} 已安装,跳过`));
117
+ } else {
118
+ throw new Error(`插件安装失败: ${combined.trim() || err.message}`);
119
+ }
120
+ }
121
+
122
+ console.log('');
123
+ console.log(chalk.green.bold(`✅ adspecs 插件已注册到 Claude Code (scope=${scope})`));
124
+ console.log('');
125
+ console.log(' 现在可以在 Claude Code 中使用以下技能:');
126
+ console.log(' /adspecs-prd — 生成 PRD');
127
+ console.log(' /adspecs-plan — 后端系统设计');
128
+ console.log(' /adspecs-tasks — TDD 任务清单');
129
+ console.log(' /adspecs-utest — 生成单元测试');
130
+ console.log(' ...(共 19 个技能)');
131
+ console.log('');
132
+ };
133
+
134
+ /**
135
+ * 卸载插件
136
+ *
137
+ * @param {object} options
138
+ * @param {string} options.scope - 卸载范围: user|project
139
+ */
140
+ exports.uninstall = async function uninstall(options) {
141
+ const scope = options.scope || 'user';
142
+ const pluginName = getPluginName();
143
+
144
+ console.log(chalk.cyan('🔌 adspecs 插件卸载'));
145
+ console.log('');
146
+
147
+ if (!checkClaudeCli()) {
148
+ console.error(chalk.red('❌ 未检测到 claude CLI'));
149
+ process.exit(1);
150
+ }
151
+
152
+ try {
153
+ execSync(`claude plugins uninstall ${pluginName} --scope ${scope}`, {
154
+ stdio: 'pipe',
155
+ });
156
+ console.log(chalk.green(`✅ ${pluginName} 插件已卸载 (scope=${scope})`));
157
+ } catch (err) {
158
+ const stderr = err.stderr ? err.stderr.toString() : '';
159
+ if (stderr.includes('not installed') || stderr.includes('not found')) {
160
+ console.log(chalk.yellow(`⏭ ${pluginName} 未安装,无需卸载`));
161
+ } else {
162
+ throw new Error(`插件卸载失败: ${stderr || err.message}`);
163
+ }
164
+ }
165
+ };
@@ -1,87 +1,87 @@
1
- 'use strict';
2
-
3
- const { execSync, spawn } = require('child_process');
4
- const chalk = require('chalk');
5
- const path = require('path');
6
- const fs = require('fs');
7
-
8
- /**
9
- * adspecs update 命令
10
- *
11
- * 便捷命令:一条命令完成 adspecs 升级 + Claude Code 插件刷新。
12
- *
13
- * 流程:
14
- * 1. 检查当前版本
15
- * 2. 执行 `npm install -g adspecs@latest`(或 `npm update -g adspecs`)
16
- * 3. postinstall 钩子会自动刷新 Claude Code 插件注册
17
- * 4. 显示升级前后版本
18
- */
19
- module.exports = async function update(options) {
20
- const pluginDir = path.resolve(__dirname, '../..');
21
- const pkgPath = path.join(pluginDir, 'package.json');
22
-
23
- // 读取升级前版本
24
- let oldVersion = 'unknown';
25
- try {
26
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
27
- oldVersion = pkg.version;
28
- } catch {
29
- // ignore
30
- }
31
-
32
- console.log(chalk.cyan('🔄 adspecs 升级'));
33
- console.log('');
34
- console.log(` 当前版本: ${chalk.yellow(oldVersion)}`);
35
- console.log(` 目标版本: ${options.version || 'latest'}`);
36
- console.log('');
37
-
38
- // 确定要安装的版本
39
- const targetVersion = options.version ? `adspecs@${options.version}` : 'adspecs@latest';
40
-
41
- // 执行 npm install -g
42
- console.log(chalk.gray(` → 执行: npm install -g ${targetVersion}`));
43
- console.log('');
44
-
45
- try {
46
- // 使用 spawn 以实时显示 npm 输出
47
- await new Promise((resolve, reject) => {
48
- const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
49
- const child = spawn(npmCmd, ['install', '-g', targetVersion], {
50
- stdio: 'inherit',
51
- shell: true,
52
- });
53
- child.on('close', (code) => {
54
- if (code === 0) resolve();
55
- else reject(new Error(`npm install 退出码: ${code}`));
56
- });
57
- child.on('error', reject);
58
- });
59
- } catch (err) {
60
- console.error('');
61
- console.error(chalk.red(`❌ 升级失败: ${err.message}`));
62
- console.error('');
63
- console.error(' 请检查网络连接或手动执行:');
64
- console.error(' npm install -g adspecs@latest');
65
- process.exit(1);
66
- }
67
-
68
- // 读取升级后版本
69
- let newVersion = 'unknown';
70
- try {
71
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
72
- newVersion = pkg.version;
73
- } catch {
74
- // ignore
75
- }
76
-
77
- console.log('');
78
- if (oldVersion === newVersion) {
79
- console.log(chalk.green(`✅ 已是最新版本 (${newVersion})`));
80
- } else {
81
- console.log(chalk.green.bold(`✅ 升级完成: ${oldVersion} → ${newVersion}`));
82
- }
83
- console.log('');
84
- console.log(' Claude Code 插件注册已通过 postinstall 钩子自动刷新。');
85
- console.log(` 验证: ${chalk.gray('adspecs --version')}`);
86
- console.log('');
87
- };
1
+ 'use strict';
2
+
3
+ const { execSync, spawn } = require('child_process');
4
+ const chalk = require('chalk');
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+
8
+ /**
9
+ * adspecs update 命令
10
+ *
11
+ * 便捷命令:一条命令完成 adspecs 升级 + Claude Code 插件刷新。
12
+ *
13
+ * 流程:
14
+ * 1. 检查当前版本
15
+ * 2. 执行 `npm install -g adspecs@latest`(或 `npm update -g adspecs`)
16
+ * 3. postinstall 钩子会自动刷新 Claude Code 插件注册
17
+ * 4. 显示升级前后版本
18
+ */
19
+ module.exports = async function update(options) {
20
+ const pluginDir = path.resolve(__dirname, '../..');
21
+ const pkgPath = path.join(pluginDir, 'package.json');
22
+
23
+ // 读取升级前版本
24
+ let oldVersion = 'unknown';
25
+ try {
26
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
27
+ oldVersion = pkg.version;
28
+ } catch {
29
+ // ignore
30
+ }
31
+
32
+ console.log(chalk.cyan('🔄 adspecs 升级'));
33
+ console.log('');
34
+ console.log(` 当前版本: ${chalk.yellow(oldVersion)}`);
35
+ console.log(` 目标版本: ${options.version || 'latest'}`);
36
+ console.log('');
37
+
38
+ // 确定要安装的版本
39
+ const targetVersion = options.version ? `adspecs@${options.version}` : 'adspecs@latest';
40
+
41
+ // 执行 npm install -g
42
+ console.log(chalk.gray(` → 执行: npm install -g ${targetVersion}`));
43
+ console.log('');
44
+
45
+ try {
46
+ // 使用 spawn 以实时显示 npm 输出
47
+ await new Promise((resolve, reject) => {
48
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
49
+ const child = spawn(npmCmd, ['install', '-g', targetVersion], {
50
+ stdio: 'inherit',
51
+ shell: true,
52
+ });
53
+ child.on('close', (code) => {
54
+ if (code === 0) resolve();
55
+ else reject(new Error(`npm install 退出码: ${code}`));
56
+ });
57
+ child.on('error', reject);
58
+ });
59
+ } catch (err) {
60
+ console.error('');
61
+ console.error(chalk.red(`❌ 升级失败: ${err.message}`));
62
+ console.error('');
63
+ console.error(' 请检查网络连接或手动执行:');
64
+ console.error(' npm install -g adspecs@latest');
65
+ process.exit(1);
66
+ }
67
+
68
+ // 读取升级后版本
69
+ let newVersion = 'unknown';
70
+ try {
71
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
72
+ newVersion = pkg.version;
73
+ } catch {
74
+ // ignore
75
+ }
76
+
77
+ console.log('');
78
+ if (oldVersion === newVersion) {
79
+ console.log(chalk.green(`✅ 已是最新版本 (${newVersion})`));
80
+ } else {
81
+ console.log(chalk.green.bold(`✅ 升级完成: ${oldVersion} → ${newVersion}`));
82
+ }
83
+ console.log('');
84
+ console.log(' Claude Code 插件注册已通过 postinstall 钩子自动刷新。');
85
+ console.log(` 验证: ${chalk.gray('adspecs --version')}`);
86
+ console.log('');
87
+ };