@house365/comate 0.9.24 → 0.9.26

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Jian Liang
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jian Liang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,110 +1,110 @@
1
- <div align="center">
2
- <img src="comate.png" alt="comate" width="600">
3
- </div>
4
-
5
- # comate
6
-
7
- **SDD (规约驱动开发)** 的 AI 开发编排器。
8
-
9
- comate 践行 **Specification-Driven Development (SDD)** 理念,通过五阶段工作流(gate → open → design → build → verify → archive)确保每个变更都有完整的规约与设计(fix 预设除外)。底层集成 **OpenSpec**(提案、规约生命周期、归档)和 **Superpowers**(技术设计、规划、执行、收尾),并提供 PRD 门禁、决策澄清、知识库对接等编排能力。
10
-
11
- ## 五阶段
12
-
13
- ```
14
- [原始 PRD] ─→ /comate-gate ─┐ (阶段 0:门禁+拆分)
15
- ▼
16
- /comate ──自动探测阶段──────→ open → design → build → verify → archive
17
- ```
18
-
19
- | 阶段 | skill | 职责 |
20
- |------|-------|------|
21
- | gate | `/comate-gate` | (阶段 0,可选)对原始 PRD 做质量门禁 + 拆分成 N 个 change |
22
- | open | `/comate-open` | 探索想法,创建 change 结构并初始化 `.comate.yaml` |
23
- | design | `/comate-design` | 技术设计与方案 brainstorming |
24
- | build | `/comate-build` | 按任务实现并提交 |
25
- | verify | `/comate-verify` | 验证、出报告、处理分支 |
26
- | archive | `/comate-archive` | 同步增量规约并归档 |
27
-
28
- 预设路径:`/comate-fix`(快速小改动,覆盖 bug 修复与文案/配置小调整两种模式)。
29
-
30
- 工具 skill:
31
- - `/comate-grill`(决策点穷追式澄清)——对计划/设计/PRD 的模糊点逐个深挖,每问附推荐答案、一次一问,直到歧义清零。comate-gate 在阻断问题多、有依赖链时会自动提供「深度澄清」选项调用它;也可单独 `/comate-grill <话题>` 挑战自己的计划草稿。
32
- - `/comate-kb-integration`(第三方对接档案生成)——从官方文档 URL 抓取并按 `docs/knowledge-base/integrations/_TEMPLATE/` 规范产出对接档案(`<service-id>/README.md` + `api-snapshot.md`),自动追加根索引一行。是知识库 integrations scaffold 的配套建档工具;遇 JS 动态渲染文档站自动降级 Playwright 无头抓取。
33
-
34
- **阶段 0(PRD 门禁与拆分)**:需求若来自一份**原始 PRD**,先过 `/comate-gate`——它审阅 PRD 质量、百分制评分、建阻断台账,门禁通过前禁止建任何 change;通过后按依赖/独立性判定把 PRD 拆成 1 或 N 个 change(粒度由用户定),逐个交给 `/comate-open`。门禁状态钉在 PRD 同级 `<PRD>.gate.yaml`,PRD 通过后被改会自动失效需重跑。需求来自对话时无需此阶段,直接从 open 起步。
35
-
36
- ## 安装
37
-
38
- ```bash
39
- npm install -g @house365/comate
40
- ```
41
-
42
- 到项目目录初始化:
43
-
44
- ```bash
45
- cd your-project
46
- comate init
47
- ```
48
-
49
- `init` 会装好 comate 及其依赖(OpenSpec CLI、Superpowers),创建 `openspec/` 项目结构,并铺出 `docs/` 知识库骨架(`docs/knowledge-base/requirements/` 放 PRD + PRD 模板、`docs/architecture/` 架构规范占位、integrations 对接模板)——`/comate-gate` 从这里读 PRD。支持 Claude Code、Codex、Cursor 等 70+ agent。可重复执行,已装的自动跳过,已有的 docs 文件不覆盖。
50
-
51
- skills 装到用户级(`~/.agents/skills`),装一次所有项目共用;`openspec/` 是项目自己的规约,建在当前目录,所以 `init` 需要在项目目录下运行。
52
-
53
- 装完输入 `/comate` 开始使用,`comate doctor` 可自检。
54
-
55
- ## 更新
56
-
57
- ```bash
58
- npm install -g @house365/comate@latest
59
- cd your-project && comate init
60
- ```
61
-
62
- 两步都要跑:`npm` 只换 CLI 本身,skills 是 `comate init` 铺到 `~/.agents/skills` 的,npm 不管。这里的 `@latest` 不能省——本地已装时,不带 tag 的 `npm install -g` 可能认为已满足而不去 registry 取新版。
63
-
64
- ## 用法
65
-
66
- 输入 `/comate` 自动探测当前阶段并分派,或直接调用某个阶段 skill。状态记录在每个 change 的 `openspec/changes/<name>/.comate.yaml` 中,支持上下文压缩后断点恢复。
67
-
68
- ## Token 用量:`comate usage`
69
-
70
- 查看**当前项目**的 token 消耗与估算成本(封装 [ccusage](https://github.com/ryoppippi/ccusage),随 comate 一起装):
71
-
72
- ```bash
73
- comate usage # 本项目按会话(session)统计
74
- comate usage daily # 本项目按天
75
- comate usage --global # 全部项目(不做项目隔离)
76
- comate usage --json -s 2026-08-01 # 其余参数原样透传给 ccusage
77
- ```
78
-
79
- 默认只统计当前工作目录这一个项目:Claude Code 数据按 `~/.claude/projects/<项目>/` 隔离,Codex 数据按会话记录里的 `cwd` 过滤,两者都不会混入其它项目的用量。加 `--global` 看全量,或用 `comate usage codex ...` 单看某个 agent。
80
-
81
- > 粒度到项目/会话级;不做 open/design/build 阶段级归因(那需要在状态机打时间戳,属后续增强)。
82
-
83
- ## 目录结构
84
-
85
- ```
86
- skills/
87
- comate/ 主编排器:SKILL.md + 脚本 + 参考文档 + 测试
88
- scripts/ comate.sh(CLI)、comate-lib.sh(共享库)
89
- reference/ 决策点、脏工作树协议、前置条件
90
- tests/ bats 测试
91
- comate-open/ design/ build/ verify/ archive/ 各阶段 skill
92
- comate-gate/ 阶段 0:PRD 门禁与拆分
93
- comate-fix/ 预设路径 skill(bug + 小调整)
94
- comate-grill/ 决策点穷追式澄清工具
95
- comate-kb-integration/ 第三方对接档案生成工具(知识库配套)
1
+ <div align="center">
2
+ <img src="comate.png" alt="comate" width="600">
3
+ </div>
4
+
5
+ # comate
6
+
7
+ **SDD (规约驱动开发)** 的 AI 开发编排器。
8
+
9
+ comate 践行 **Specification-Driven Development (SDD)** 理念,通过五阶段工作流(gate → open → design → build → verify → archive)确保每个变更都有完整的规约与设计(fix 预设除外)。底层集成 **OpenSpec**(提案、规约生命周期、归档)和 **Superpowers**(技术设计、规划、执行、收尾),并提供 PRD 门禁、决策澄清、知识库对接等编排能力。
10
+
11
+ ## 五阶段
12
+
13
+ ```
14
+ [原始 PRD] ─→ /comate-gate ─┐ (阶段 0:门禁+拆分)
15
+ ▼
16
+ /comate ──自动探测阶段──────→ open → design → build → verify → archive
17
+ ```
18
+
19
+ | 阶段 | skill | 职责 |
20
+ |------|-------|------|
21
+ | gate | `/comate-gate` | (阶段 0,可选)对原始 PRD 做质量门禁 + 拆分成 N 个 change |
22
+ | open | `/comate-open` | 探索想法,创建 change 结构并初始化 `.comate.yaml` |
23
+ | design | `/comate-design` | 技术设计与方案 brainstorming |
24
+ | build | `/comate-build` | 按任务实现并提交 |
25
+ | verify | `/comate-verify` | 验证、出报告、处理分支 |
26
+ | archive | `/comate-archive` | 同步增量规约并归档 |
27
+
28
+ 预设路径:`/comate-fix`(快速小改动,覆盖 bug 修复与文案/配置小调整两种模式)。
29
+
30
+ 工具 skill:
31
+ - `/comate-grill`(决策点穷追式澄清)——对计划/设计/PRD 的模糊点逐个深挖,每问附推荐答案、一次一问,直到歧义清零。comate-gate 在阻断问题多、有依赖链时会自动提供「深度澄清」选项调用它;也可单独 `/comate-grill <话题>` 挑战自己的计划草稿。
32
+ - `/comate-kb-integration`(第三方对接档案生成)——从官方文档 URL 抓取并按 `docs/knowledge-base/integrations/_TEMPLATE/` 规范产出对接档案(`<service-id>/README.md` + `api-snapshot.md`),自动追加根索引一行。是知识库 integrations scaffold 的配套建档工具;遇 JS 动态渲染文档站自动降级 Playwright 无头抓取。
33
+
34
+ **阶段 0(PRD 门禁与拆分)**:需求若来自一份**原始 PRD**,先过 `/comate-gate`——它审阅 PRD 质量、百分制评分、建阻断台账,门禁通过前禁止建任何 change;通过后按依赖/独立性判定把 PRD 拆成 1 或 N 个 change(粒度由用户定),逐个交给 `/comate-open`。门禁状态钉在 PRD 同级 `<PRD>.gate.yaml`,PRD 通过后被改会自动失效需重跑。需求来自对话时无需此阶段,直接从 open 起步。
35
+
36
+ ## 安装
37
+
38
+ ```bash
39
+ npm install -g @house365/comate
40
+ ```
41
+
42
+ 到项目目录初始化:
43
+
44
+ ```bash
45
+ cd your-project
46
+ comate init
47
+ ```
48
+
49
+ `init` 会装好 comate 及其依赖(OpenSpec CLI、Superpowers),创建 `openspec/` 项目结构,并铺出 `docs/` 知识库骨架(`docs/knowledge-base/requirements/` 放 PRD + PRD 模板、`docs/architecture/` 架构规范占位、integrations 对接模板)——`/comate-gate` 从这里读 PRD。支持 Claude Code、Codex、Cursor 等 70+ agent。可重复执行,已装的自动跳过,已有的 docs 文件不覆盖。
50
+
51
+ skills 装到用户级(`~/.agents/skills`),装一次所有项目共用;`openspec/` 是项目自己的规约,建在当前目录,所以 `init` 需要在项目目录下运行。
52
+
53
+ 装完输入 `/comate` 开始使用,`comate doctor` 可自检。
54
+
55
+ ## 更新
56
+
57
+ ```bash
58
+ npm install -g @house365/comate@latest
59
+ cd your-project && comate init
60
+ ```
61
+
62
+ 两步都要跑:`npm` 只换 CLI 本身,skills 是 `comate init` 铺到 `~/.agents/skills` 的,npm 不管。这里的 `@latest` 不能省——本地已装时,不带 tag 的 `npm install -g` 可能认为已满足而不去 registry 取新版。
63
+
64
+ ## 用法
65
+
66
+ 输入 `/comate` 自动探测当前阶段并分派,或直接调用某个阶段 skill。状态记录在每个 change 的 `openspec/changes/<name>/.comate.yaml` 中,支持上下文压缩后断点恢复。
67
+
68
+ ## Token 用量:`comate usage`
69
+
70
+ 查看**当前项目**的 token 消耗与估算成本(封装 [ccusage](https://github.com/ryoppippi/ccusage),随 comate 一起装):
71
+
72
+ ```bash
73
+ comate usage # 本项目按会话(session)统计
74
+ comate usage daily # 本项目按天
75
+ comate usage --global # 全部项目(不做项目隔离)
76
+ comate usage --json -s 2026-08-01 # 其余参数原样透传给 ccusage
77
+ ```
78
+
79
+ 默认只统计当前工作目录这一个项目:Claude Code 数据按 `~/.claude/projects/<项目>/` 隔离,Codex 数据按会话记录里的 `cwd` 过滤,两者都不会混入其它项目的用量。加 `--global` 看全量,或用 `comate usage codex ...` 单看某个 agent。
80
+
81
+ > 粒度到项目/会话级;不做 open/design/build 阶段级归因(那需要在状态机打时间戳,属后续增强)。
82
+
83
+ ## 目录结构
84
+
85
+ ```
86
+ skills/
87
+ comate/ 主编排器:SKILL.md + 脚本 + 参考文档 + 测试
88
+ scripts/ comate.sh(CLI)、comate-lib.sh(共享库)
89
+ reference/ 决策点、脏工作树协议、前置条件
90
+ tests/ bats 测试
91
+ comate-open/ design/ build/ verify/ archive/ 各阶段 skill
92
+ comate-gate/ 阶段 0:PRD 门禁与拆分
93
+ comate-fix/ 预设路径 skill(bug + 小调整)
94
+ comate-grill/ 决策点穷追式澄清工具
95
+ comate-kb-integration/ 第三方对接档案生成工具(知识库配套)
96
96
  docs/
97
97
  COMATE_BEGINNER_GUIDE.md 面向新手的安装与使用手册
98
98
  COMATE_MANUAL.md 完整操作手册
99
99
  ```
100
-
101
- ## 文档
102
-
100
+
101
+ ## 文档
102
+
103
103
  文档:
104
104
 
105
105
  - [入门操作手册](docs/COMATE_BEGINNER_GUIDE.md):面向第一次使用 comate 的同学,覆盖安装、`init`、目录、PRD、Skill 流程和常见问题。
106
106
  - [完整技术手册](docs/COMATE_MANUAL.md):安装前置、命令参考、阶段详解、状态文件字段、决策阻塞点、故障排除。
107
-
108
- ## License
109
-
110
- [MIT](LICENSE)
107
+
108
+ ## License
109
+
110
+ [MIT](LICENSE)
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ // 清理重复的 superpowers 安装(当 plugin 版本已存在时)
3
+ import { existsSync, readFileSync, rmSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+
6
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
7
+
8
+ // 检查是否有 Claude Code plugin 安装
9
+ function hasPluginInstall() {
10
+ const pluginRegistry = join(home, '.claude', 'plugins', 'installed_plugins.json');
11
+ if (!existsSync(pluginRegistry)) return false;
12
+
13
+ try {
14
+ const registry = JSON.parse(readFileSync(pluginRegistry, 'utf8'));
15
+ return Object.keys(registry.plugins || {}).some((key) =>
16
+ key.startsWith('superpowers@') &&
17
+ Array.isArray(registry.plugins[key]) &&
18
+ registry.plugins[key].length > 0
19
+ );
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ // 检查并清理 skills CLI 安装的 superpowers
26
+ function cleanupSkillsCliInstall() {
27
+ const skillsRoots = [
28
+ join(home, '.agents', 'skills'),
29
+ join(home, '.claude', 'skills'),
30
+ join(home, '.config', 'skills'),
31
+ join(home, '.cursor', 'skills'),
32
+ ];
33
+
34
+ const superpowersSkills = ['using-superpowers', 'brainstorming'];
35
+ const removed = [];
36
+
37
+ for (const root of skillsRoots) {
38
+ for (const skill of superpowersSkills) {
39
+ const skillPath = join(root, skill);
40
+ if (existsSync(skillPath)) {
41
+ try {
42
+ rmSync(skillPath, { recursive: true, force: true });
43
+ removed.push(skillPath);
44
+ } catch (err) {
45
+ console.error(`✗ 删除失败: ${skillPath}`);
46
+ console.error(` 错误: ${err.message}`);
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ return removed;
53
+ }
54
+
55
+ // 主函数
56
+ export function cleanup() {
57
+ console.log('=== Superpowers 重复安装清理工具 ===\n');
58
+
59
+ // 1. 检查 plugin 安装
60
+ console.log('1. 检查 Claude Code plugin 安装...');
61
+ if (!hasPluginInstall()) {
62
+ console.log(' ✗ 未检测到 Claude Code plugin 版本的 superpowers');
63
+ console.log(' ⚠️ 不建议清理 skills CLI 版本,因为没有其他可用版本\n');
64
+ return 1;
65
+ }
66
+ console.log(' ✓ 检测到 Claude Code plugin 版本\n');
67
+
68
+ // 2. 列出将要删除的目录
69
+ console.log('2. 扫描 skills CLI 安装...');
70
+ const skillsRoots = [
71
+ join(home, '.agents', 'skills'),
72
+ join(home, '.claude', 'skills'),
73
+ join(home, '.config', 'skills'),
74
+ join(home, '.cursor', 'skills'),
75
+ ];
76
+
77
+ const superpowersSkills = ['using-superpowers', 'brainstorming'];
78
+ const toRemove = [];
79
+
80
+ for (const root of skillsRoots) {
81
+ for (const skill of superpowersSkills) {
82
+ const skillPath = join(root, skill);
83
+ if (existsSync(skillPath)) {
84
+ toRemove.push(skillPath);
85
+ console.log(` 发现: ${skillPath}`);
86
+ }
87
+ }
88
+ }
89
+
90
+ if (toRemove.length === 0) {
91
+ console.log(' ✓ 未发现 skills CLI 版本的 superpowers\n');
92
+ console.log('无需清理,已经是最优状态!');
93
+ return 0;
94
+ }
95
+
96
+ console.log(`\n 共找到 ${toRemove.length} 个目录需要清理\n`);
97
+
98
+ // 3. 确认清理
99
+ console.log('3. 执行清理...');
100
+ const removed = cleanupSkillsCliInstall();
101
+
102
+ if (removed.length > 0) {
103
+ console.log(` ✓ 已删除 ${removed.length} 个目录:`);
104
+ for (const path of removed) {
105
+ console.log(` - ${path}`);
106
+ }
107
+ }
108
+
109
+ console.log('\n=== 清理完成 ===');
110
+ console.log('现在只使用 Claude Code plugin 版本的 superpowers');
111
+ console.log('相关 skill 在 Claude 中仍然可用\n');
112
+
113
+ return 0;
114
+ }
115
+
116
+ // 当作为脚本直接运行时
117
+ if (import.meta.url === `file:///${process.argv[1].replace(/\\/g, '/')}`) {
118
+ process.exit(cleanup());
119
+ }
package/bin/cli.mjs CHANGED
@@ -52,7 +52,7 @@ async function checkForUpdates(currentVersion) {
52
52
  }
53
53
 
54
54
  // comate 自身的子命令(在下方被先取处理,不会透传给 skills CLI)。
55
- const COMATE_COMMANDS = ['init', 'doctor', 'update', 'usage'];
55
+ const COMATE_COMMANDS = ['init', 'doctor', 'update', 'usage', 'cleanup'];
56
56
 
57
57
  // 允许透传给 skills CLI 的子命令(含别名)。留在这里的都是 skills CLI 真实存在
58
58
  // 的命令,未列入的一律视为未知命令并命中 --help。init/update 已被 comate 先取,
@@ -93,6 +93,7 @@ const HELP_TEXT = `comate — SDD (规约驱动开发) 的 AI 开发编排器
93
93
  comate doctor 健康检查
94
94
  comate update 更新 comate 到最新版本
95
95
  comate usage 查看本项目 token 用量(--global 看全部;参数透传给 ccusage)
96
+ comate cleanup 清理重复的 superpowers 安装(当 plugin 版本已存在时)
96
97
  comate --help, -h 显示本帮助
97
98
  comate --version, -v 显示版本号
98
99
 
@@ -144,6 +145,11 @@ if (args[0] === 'usage') {
144
145
  process.exit(await usage(args.slice(1), { pkgRoot }));
145
146
  }
146
147
 
148
+ if (args[0] === 'cleanup') {
149
+ const { cleanup } = await import('./cleanup-duplicate-superpowers.mjs');
150
+ process.exit(cleanup());
151
+ }
152
+
147
153
  if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
148
154
  printHelp();
149
155
  process.exit(0);
package/bin/init.mjs CHANGED
@@ -9,7 +9,7 @@
9
9
  // ponytail: no SKILLS_AGENT_MAP here. The skills CLI detects the running agent
10
10
  // on its own, so translating platform ids to agent names would be dead code.
11
11
  import { spawnSync } from 'node:child_process';
12
- import { existsSync, mkdirSync, readdirSync, copyFileSync, statSync, lstatSync, rmSync } from 'node:fs';
12
+ import { existsSync, mkdirSync, readdirSync, copyFileSync, statSync, lstatSync, rmSync, readFileSync } from 'node:fs';
13
13
  import { createRequire } from 'node:module';
14
14
  import { dirname, join } from 'node:path';
15
15
 
@@ -149,9 +149,8 @@ function openSpecState() {
149
149
  return { status: atLeast(version, MIN_OPENSPEC) ? 'ready' : 'outdated', version };
150
150
  }
151
151
 
152
- // Only detect skills CLI installation (flattens obra/superpowers into one dir
153
- // per skill). Claude Code plugin cache (plugins/{cache,data}/) is not a real
154
- // user-level install and should not count.
152
+ // Detect skills CLI installation (flattens obra/superpowers into one dir per
153
+ // skill) and Claude Code plugin installation (installed_plugins.json registry).
155
154
  const SUPERPOWERS_MARKERS = [
156
155
  ['using-superpowers'],
157
156
  ['brainstorming'],
@@ -164,7 +163,28 @@ function superpowersInstalled(scope) {
164
163
  ? ['.agents/skills', '.claude/skills', '.config/skills', '.cursor/skills']
165
164
  .map((r) => join(home, r))
166
165
  : ['.agents/skills', '.claude/skills', '.cursor/skills', '.codex/skills'];
167
- return roots.some((root) => SUPERPOWERS_MARKERS.some((m) => existsSync(join(root, ...m))));
166
+
167
+ // Check skills CLI installation
168
+ if (roots.some((root) => SUPERPOWERS_MARKERS.some((m) => existsSync(join(root, ...m))))) {
169
+ return true;
170
+ }
171
+
172
+ // Check Claude Code plugin installation (only for global scope - plugins are user-level)
173
+ if (scope === 'global') {
174
+ const pluginRegistry = join(home, '.claude', 'plugins', 'installed_plugins.json');
175
+ try {
176
+ const registry = JSON.parse(readFileSync(pluginRegistry, 'utf8'));
177
+ // Check if superpowers plugin is installed (any marketplace)
178
+ return Object.keys(registry.plugins || {}).some((key) =>
179
+ key.startsWith('superpowers@') && Array.isArray(registry.plugins[key]) && registry.plugins[key].length > 0
180
+ );
181
+ } catch {
182
+ // File doesn't exist or parse failed - not a plugin install
183
+ return false;
184
+ }
185
+ }
186
+
187
+ return false;
168
188
  }
169
189
 
170
190
  // The docs scaffold ships inside the comate skill, so it is present both in dev
package/bin/update.mjs CHANGED
@@ -2,6 +2,8 @@
2
2
  import { get } from 'node:https';
3
3
  import { spawn } from 'node:child_process';
4
4
 
5
+ import { npmInvocation } from './init.mjs';
6
+
5
7
  // Fetch the latest version from npm registry
6
8
  function fetchLatestVersion() {
7
9
  return new Promise((resolve, reject) => {
@@ -30,16 +32,15 @@ function fetchLatestVersion() {
30
32
  }
31
33
 
32
34
  // Run npm install -g with live output
33
- function runNpmInstall(packageName) {
35
+ export function runNpmInstall(packageName, { spawnFn = spawn, invocation = npmInvocation } = {}) {
34
36
  return new Promise((resolve) => {
35
37
  console.log(`\n正在更新 ${packageName}...\n`);
36
38
 
37
- const isWindows = process.platform === 'win32';
38
- const npmCmd = isWindows ? 'npm.cmd' : 'npm';
39
+ const { command, args, shell } = invocation(['install', '-g', packageName]);
39
40
 
40
- const child = spawn(npmCmd, ['install', '-g', packageName], {
41
+ const child = spawnFn(command, args, {
41
42
  stdio: 'inherit',
42
- shell: isWindows,
43
+ ...(shell ? { shell: true } : {}),
43
44
  });
44
45
 
45
46
  child.on('close', (code) => {