adspecs 0.1.29 → 0.1.30

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 (45) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.qoder-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/plugin.json +24 -0
  5. package/CHANGELOG.md +13 -0
  6. package/CLAUDE.md +14 -8
  7. package/INSTALL.md +57 -4
  8. package/README.md +5 -4
  9. package/bin/adspecs.js +8 -7
  10. package/hooks/hooks.json +2 -2
  11. package/hooks/platform.js +22 -11
  12. package/package.json +4 -2
  13. package/scripts/postinstall.js +79 -36
  14. package/scripts/sync-version.js +11 -1
  15. package/skills/adspecs-adversarial-review/SKILL.md +1 -0
  16. package/skills/adspecs-analyze/SKILL.md +1 -0
  17. package/skills/adspecs-architecture-planning/SKILL.md +1 -0
  18. package/skills/adspecs-biz-blueprint/SKILL.md +555 -554
  19. package/skills/adspecs-clarify/SKILL.md +1 -0
  20. package/skills/adspecs-constitution/SKILL.md +1 -0
  21. package/skills/adspecs-export-word/SKILL.md +499 -498
  22. package/skills/adspecs-front-prototype/SKILL.md +1 -0
  23. package/skills/adspecs-front-spec/SKILL.md +1 -0
  24. package/skills/adspecs-front-tasks/SKILL.md +1 -0
  25. package/skills/adspecs-git-commit/SKILL.md +1 -0
  26. package/skills/adspecs-git-initialize/SKILL.md +1 -0
  27. package/skills/adspecs-new-requirement/SKILL.md +1 -0
  28. package/skills/adspecs-plan/SKILL.md +1 -0
  29. package/skills/adspecs-prd/SKILL.md +1 -0
  30. package/skills/adspecs-prd-to-demo/SKILL.md +1 -0
  31. package/skills/adspecs-save-session/SKILL.md +179 -178
  32. package/skills/adspecs-tasks/SKILL.md +1 -0
  33. package/skills/adspecs-update-status/SKILL.md +1 -0
  34. package/skills/adspecs-utest/SKILL.md +1 -0
  35. package/skills/adspecs-write-planning-report/SKILL.md +1 -0
  36. package/skills/adspecs-write-roadmap/SKILL.md +1 -0
  37. package/skills/adspecs-write-sow/SKILL.md +1 -0
  38. package/skills/grill-me/SKILL.md +1 -0
  39. package/skills/playwright-cli/SKILL.md +1 -0
  40. package/skills/playwright-trace/SKILL.md +1 -0
  41. package/skills/project-init/SKILL.md +1 -0
  42. package/skills/sie-front-code-review/SKILL.md +1 -0
  43. package/skills/wiki-update/SKILL.md +233 -232
  44. package/src/commands/plugin.js +145 -7
  45. package/src/commands/update.js +5 -1
@@ -30,7 +30,14 @@ function checkClaudeCli() {
30
30
  * @param {string} platform - 'claude' | 'qoder'
31
31
  */
32
32
  function getPluginName(platform) {
33
- var manifestDir = platform === 'qoder' ? '.qoder-plugin' : '.claude-plugin';
33
+ var manifestDir;
34
+ if (platform === 'qoder') {
35
+ manifestDir = '.qoder-plugin';
36
+ } else if (platform === 'workbuddy') {
37
+ manifestDir = '.workbuddy-plugin';
38
+ } else {
39
+ manifestDir = '.claude-plugin';
40
+ }
34
41
  const pluginJsonPath = path.join(PLUGIN_DIR, manifestDir, 'plugin.json');
35
42
  if (!fs.existsSync(pluginJsonPath)) {
36
43
  // 回退到 .claude-plugin
@@ -47,18 +54,22 @@ function getPluginName(platform) {
47
54
 
48
55
  /**
49
56
  * 检测当前可用的 AI 平台
50
- * @returns {'claude'|'qoder'}
57
+ * @returns {'claude'|'qoder'|'workbuddy'}
51
58
  */
52
59
  function detectInstalledPlatform() {
53
60
  // 显式环境变量优先
54
61
  var explicit = (process.env.ADSPECS_PLATFORM || '').toLowerCase();
55
- if (explicit === 'qoder' || explicit === 'claude') {
62
+ if (['qoder', 'claude', 'workbuddy'].includes(explicit)) {
56
63
  return explicit;
57
64
  }
58
65
  // 检测 claude CLI
59
66
  if (checkClaudeCli()) {
60
67
  return 'claude';
61
68
  }
69
+ // WorkBuddy 运行环境检测(HOME 下有 ~/.workbuddy)
70
+ if (fs.existsSync(path.join(os.homedir(), '.workbuddy'))) {
71
+ return 'workbuddy';
72
+ }
62
73
  // 默认回退 qoder(当前运行环境)
63
74
  return 'qoder';
64
75
  }
@@ -68,7 +79,7 @@ function detectInstalledPlatform() {
68
79
  *
69
80
  * @param {object} options
70
81
  * @param {string} options.scope - 安装范围: user|project
71
- * @param {string} options.platform - 目标平台: claude|qoder(可选,自动检测)
82
+ * @param {string} options.platform - 目标平台: claude|qoder|workbuddy(可选,自动检测)
72
83
  */
73
84
  exports.install = async function install(options) {
74
85
  const scope = options.scope || 'user';
@@ -83,13 +94,91 @@ exports.install = async function install(options) {
83
94
  console.log(` 目标平台: ${platform}`);
84
95
  console.log('');
85
96
 
86
- if (platform === 'qoder') {
97
+ if (platform === 'workbuddy') {
98
+ await installForWorkBuddy(pluginName, scope);
99
+ } else if (platform === 'qoder') {
87
100
  await installForQoder(pluginName, scope);
88
101
  } else {
89
102
  await installForClaude(pluginName, scope);
90
103
  }
91
104
  };
92
105
 
106
+ /**
107
+ * 检查 codebuddy CLI 是否可用(WorkBuddy 共享 CodeBuddy CLI)
108
+ */
109
+ function checkCodebuddyCli() {
110
+ try {
111
+ execSync('codebuddy --version', { stdio: 'ignore' });
112
+ return true;
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * WorkBuddy 平台安装
120
+ * 通过 CodeBuddy 插件系统安装,自动处理 skills/hooks 加载和 enabledPlugins
121
+ * 若 CLI 不可用则回退为手工配置 enabledPlugins
122
+ */
123
+ async function installForWorkBuddy(pluginName, scope) {
124
+ const workbuddyManifest = path.join(PLUGIN_DIR, '.workbuddy-plugin', 'plugin.json');
125
+ if (!fs.existsSync(workbuddyManifest)) {
126
+ throw new Error(`未找到 WorkBuddy 插件清单: ${workbuddyManifest}`);
127
+ }
128
+
129
+ if (checkCodebuddyCli()) {
130
+ // 方式 A:通过 CodeBuddy CLI 安装(自动处理一切)
131
+ const scopeFlag = scope === 'project' ? '--scope project' : '--scope user';
132
+ console.log(chalk.gray(' 通过 CodeBuddy CLI 安装 adspecs 插件...'));
133
+ try {
134
+ execSync(`codebuddy plugin install "${PLUGIN_DIR}" ${scopeFlag}`, {
135
+ encoding: 'utf8',
136
+ stdio: 'pipe'
137
+ });
138
+ console.log(chalk.green(' ✅ adspecs 插件安装成功'));
139
+ console.log(chalk.gray(' 请重启 WorkBuddy 使 skills 与 hooks 生效。'));
140
+ } catch (err) {
141
+ const stderr = err.stderr ? err.stderr.toString() : '';
142
+ const combined = stderr + (err.stdout ? err.stdout.toString() : '');
143
+ if (combined.includes('already exists') || combined.includes('already installed')) {
144
+ console.log(chalk.yellow(' ⏭ 插件已安装,跳过'));
145
+ } else {
146
+ throw new Error(`WorkBuddy 插件安装失败: ${combined.trim() || err.message}`);
147
+ }
148
+ }
149
+ } else {
150
+ // 方式 B:回退为手工配置 enabledPlugins(无 CLI 时)
151
+ console.log(chalk.yellow(' ⚠ 未检测到 codebuddy CLI,使用手工配置方式'));
152
+ const workbuddyHome = path.join(os.homedir(), '.workbuddy');
153
+ const settingsPath = path.join(workbuddyHome, 'settings.json');
154
+
155
+ // 确保 .workbuddy 目录存在
156
+ fs.mkdirSync(workbuddyHome, { recursive: true });
157
+
158
+ // 读取或创建 settings.json
159
+ let settings = {};
160
+ if (fs.existsSync(settingsPath)) {
161
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (_e) { /* use default */ }
162
+ }
163
+ if (!settings.enabledPlugins) settings.enabledPlugins = {};
164
+
165
+ var registryKey;
166
+ if (scope === 'project') {
167
+ registryKey = `${pluginName}@${PLUGIN_DIR.replace(/\\/g, '/')}`;
168
+ } else {
169
+ registryKey = `${pluginName}@local`;
170
+ }
171
+
172
+ settings.enabledPlugins[registryKey] = true;
173
+
174
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
175
+ console.log(chalk.green(` ✅ 已在 settings.json 中启用插件 (${registryKey})`));
176
+ console.log(chalk.gray(' 📁 请确保 WorkBuddy 可访问以下目录:'));
177
+ console.log(chalk.gray(` ${PLUGIN_DIR}`));
178
+ console.log(chalk.gray(' 请重启 WorkBuddy 使 skills 与 hooks 生效。'));
179
+ }
180
+ }
181
+
93
182
  /**
94
183
  * Qoder 平台安装
95
184
  * 自动注册到 Qoder 插件系统:
@@ -420,12 +509,59 @@ function printSkillList() {
420
509
  console.log('');
421
510
  }
422
511
 
512
+ /**
513
+ * WorkBuddy 平台卸载
514
+ * 通过 CodeBuddy CLI 卸载,或手工清除 settings.json 中的 enabledPlugins 条目
515
+ */
516
+ async function uninstallWorkBuddy(pluginName, scope) {
517
+ if (checkCodebuddyCli()) {
518
+ const scopeFlag = scope === 'project' ? '--scope project' : '--scope user';
519
+ try {
520
+ execSync(`codebuddy plugin uninstall ${pluginName} ${scopeFlag}`, {
521
+ stdio: 'pipe',
522
+ });
523
+ console.log(chalk.green(` ✅ ${pluginName} 插件已卸载`));
524
+ } catch (err) {
525
+ const stderr = err.stderr ? err.stderr.toString() : '';
526
+ if (stderr.includes('not installed') || stderr.includes('not found')) {
527
+ console.log(chalk.yellow(` ⏭ ${pluginName} 未安装,无需卸载`));
528
+ } else {
529
+ throw new Error(`WorkBuddy 插件卸载失败: ${stderr || err.message}`);
530
+ }
531
+ }
532
+ } else {
533
+ // 回退:手工清除 enabledPlugins 条目
534
+ const settingsPath = path.join(os.homedir(), '.workbuddy', 'settings.json');
535
+ if (fs.existsSync(settingsPath)) {
536
+ let settings = {};
537
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (_e) { /* use default */ }
538
+ if (settings.enabledPlugins) {
539
+ // 移除所有 adspecs 相关条目
540
+ const keysBefore = Object.keys(settings.enabledPlugins).length;
541
+ for (var key in settings.enabledPlugins) {
542
+ if (key.startsWith(pluginName + '@')) {
543
+ delete settings.enabledPlugins[key];
544
+ }
545
+ }
546
+ const keysAfter = Object.keys(settings.enabledPlugins).length;
547
+ if (keysBefore > keysAfter) {
548
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
549
+ console.log(chalk.green(` ✅ 已从 settings.json 移除插件配置`));
550
+ } else {
551
+ console.log(chalk.yellow(` ⏭ 未在 settings.json 中找到插件配置`));
552
+ }
553
+ }
554
+ }
555
+ }
556
+ console.log(chalk.gray(' 请重启 WorkBuddy 使变更生效。'));
557
+ }
558
+
423
559
  /**
424
560
  * 卸载插件
425
561
  *
426
562
  * @param {object} options
427
563
  * @param {string} options.scope - 卸载范围: user|project
428
- * @param {string} options.platform - 目标平台: claude|qoder(可选,自动检测)
564
+ * @param {string} options.platform - 目标平台: claude|qoder|workbuddy(可选,自动检测)
429
565
  */
430
566
  exports.uninstall = async function uninstall(options) {
431
567
  const scope = options.scope || 'user';
@@ -437,7 +573,9 @@ exports.uninstall = async function uninstall(options) {
437
573
  console.log(` 目标平台: ${platform}`);
438
574
  console.log('');
439
575
 
440
- if (platform === 'qoder') {
576
+ if (platform === 'workbuddy') {
577
+ await uninstallWorkBuddy(pluginName, scope);
578
+ } else if (platform === 'qoder') {
441
579
  if (scope === 'project') {
442
580
  // Qoder 项目级卸载:移除项目链接
443
581
  const targetDir = path.join(process.cwd(), '.qoder-plugin');
@@ -81,7 +81,11 @@ module.exports = async function update(options) {
81
81
  console.log(chalk.green.bold(`✅ 升级完成: ${oldVersion} → ${newVersion}`));
82
82
  }
83
83
  console.log('');
84
- console.log(' Claude Code 插件注册已通过 postinstall 钩子自动刷新。');
84
+ console.log(' 🔄 插件注册刷新:');
85
+ console.log(' Claude Code — postinstall 钩子已自动刷新命令行插件注册');
86
+ console.log(' Qoder — 通过 .qoder-plugin/ 清单自动发现,无需手动刷新');
87
+ console.log(' WorkBuddy — 通过 .workbuddy-plugin/ 清单自动发现,无需手动刷新');
88
+ console.log('');
85
89
  console.log(` 验证: ${chalk.gray('adspecs --version')}`);
86
90
  console.log('');
87
91
  };