@jspg-ai/coding-bb 0.0.3-beta.1 → 0.0.3-beta.13
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/cbb/dev-standards/rules/cbb-ai-behavior.md +118 -116
- package/cbb/lib/install/claude-code.js +1 -3
- package/cbb/lib/install/codebuddy.js +30 -0
- package/cbb/lib/install/init.js +295 -119
- package/cbb/lib/install/opencode.js +35 -31
- package/cbb/lib/install/qoder.js +1 -3
- package/cbb/lib/install/rule-rewrite.js +27 -0
- package/cbb/lib/install/trae.js +33 -0
- package/cbb/lib/openspec/index.js +337 -554
- package/cbb/lib/superpowers/index.js +246 -265
- package/cbb/lib/utils/check-update.js +8 -1
- package/cbb/lib/utils/gitignore.js +2 -0
- package/cbb/lib/utils/settings.js +17 -4
- package/cbb/lib/utils/tar.js +92 -0
- package/cbb/lib/utils/upstream.js +90 -0
- package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +32 -23
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/remove-worktrees.js +2 -2
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +36 -28
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-worktrees.js +15 -37
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/update-gitignore.js +25 -9
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +108 -31
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/make-mr-urls.js +211 -0
- package/config/openspec/schemas/spec-driven/schema.yaml +38 -30
- package/config/openspec/schemas/spec-driven/templates/design.md +0 -18
- package/config/openspec/schemas/spec-driven/templates/proposal.md +4 -3
- package/config/upstream-mirrors.json +12 -0
- package/config/workspace-agents.sample.md +43 -39
- package/openspec/.version +2 -3
- package/openspec/commands/apply.md +189 -175
- package/openspec/commands/archive.md +237 -216
- package/openspec/commands/bulk-archive.md +355 -327
- package/openspec/commands/continue.md +116 -105
- package/openspec/commands/explore.md +230 -199
- package/openspec/commands/ff.md +115 -104
- package/openspec/commands/new.md +74 -63
- package/openspec/commands/onboard.md +557 -548
- package/openspec/commands/propose.md +161 -150
- package/openspec/commands/sync.md +277 -249
- package/openspec/commands/update.md +92 -80
- package/openspec/commands/verify.md +175 -162
- package/openspec/skills/openspec-apply-change/SKILL.md +20 -5
- package/openspec/skills/openspec-archive-change/SKILL.md +30 -8
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +36 -6
- package/openspec/skills/openspec-continue-change/SKILL.md +14 -2
- package/openspec/skills/openspec-explore/SKILL.md +21 -9
- package/openspec/skills/openspec-ff-change/SKILL.md +14 -2
- package/openspec/skills/openspec-new-change/SKILL.md +13 -1
- package/openspec/skills/openspec-onboard/SKILL.md +49 -39
- package/openspec/skills/openspec-propose/SKILL.md +15 -3
- package/openspec/skills/openspec-sync-specs/SKILL.md +31 -2
- package/openspec/skills/openspec-update-change/SKILL.md +27 -14
- package/openspec/skills/openspec-verify-change/SKILL.md +17 -3
- package/package.json +2 -2
- package/superpowers/.version +4 -4
- package/superpowers/skills/brainstorming/SKILL.md +47 -12
- package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -213
- package/superpowers/skills/brainstorming/scripts/server.cjs +723 -723
- package/superpowers/skills/brainstorming/visual-companion.md +6 -6
- package/superpowers/skills/diagnosing-superpowers/SKILL.md +120 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/analyst-common.md +38 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/cost-and-time.md +28 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/plan-adherence.md +29 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/quality-evidence.md +26 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/repeated-work.md +30 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/request-conflicts.md +20 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/scrub-audit.md +33 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/scrub.md +29 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/similar-session.md +38 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/skill-timeline.md +30 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/stumbles.md +28 -0
- package/superpowers/skills/diagnosing-superpowers/references/context-safety.md +22 -0
- package/superpowers/skills/diagnosing-superpowers/references/github-issues.md +47 -0
- package/superpowers/skills/diagnosing-superpowers/references/redaction-policy.md +34 -0
- package/superpowers/skills/diagnosing-superpowers/references/session-discovery.md +31 -0
- package/superpowers/skills/diagnosing-superpowers/templates/bundle-README.md +77 -0
- package/superpowers/skills/diagnosing-superpowers/templates/case.md +64 -0
- package/superpowers/skills/diagnosing-superpowers/templates/issue.md +51 -0
- package/superpowers/skills/diagnosing-superpowers/templates/report.md +82 -0
- package/superpowers/skills/executing-plans/SKILL.md +350 -41
- package/superpowers/skills/executing-plans/scripts/task-done +52 -0
- package/superpowers/skills/executing-plans/scripts/task-start +28 -0
- package/superpowers/skills/requesting-code-review/SKILL.md +1 -1
- package/superpowers/skills/requesting-code-review/code-reviewer.md +17 -0
- package/superpowers/skills/subagent-driven-development/SKILL.md +18 -18
- package/superpowers/skills/subagent-driven-development/re-review-prompt.md +1 -1
- package/superpowers/skills/subagent-driven-development/scripts/review-package +53 -46
- package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +82 -40
- package/superpowers/skills/subagent-driven-development/scripts/task-brief +43 -41
- package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +2 -2
- package/superpowers/skills/systematic-debugging/root-cause-tracing.md +1 -1
- package/superpowers/skills/test-driven-development/SKILL.md +10 -0
- package/superpowers/skills/using-superpowers/SKILL.md +2 -0
- package/superpowers/skills/using-superpowers/references/claude-code-tools.md +29 -0
- package/superpowers/skills/using-superpowers/references/muse-tools.md +35 -0
- package/superpowers/skills/writing-plans/SKILL.md +30 -9
- package/superpowers/skills/writing-skills/SKILL.md +4 -2
- package/superpowers/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/cbb/worktrees/commands/worktree-close.md +0 -64
- package/cbb/worktrees/commands/worktree-init.md +0 -51
- package/cbb/worktrees/commands/worktree-push.md +0 -42
|
@@ -1,265 +1,246 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Superpowers Skills 管理模块
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 提供 cbbm update --upstream-superpowers 选项,以及 init 时的自动部署能力。
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
await
|
|
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
|
-
|
|
205
|
-
|
|
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
|
-
module.exports = {
|
|
252
|
-
// 常量
|
|
253
|
-
SUPERPOWERS_DIR,
|
|
254
|
-
SUPERPOWERS_SKILLS_DIR,
|
|
255
|
-
VERSION_FILE,
|
|
256
|
-
EXPECTED_SKILLS,
|
|
257
|
-
GITHUB_REPO,
|
|
258
|
-
GITHUB_BRANCH,
|
|
259
|
-
|
|
260
|
-
// 核心函数
|
|
261
|
-
fetchLatestSkills,
|
|
262
|
-
getLocalVersion,
|
|
263
|
-
validateSkills,
|
|
264
|
-
getSkillCount,
|
|
265
|
-
};
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Superpowers Skills 管理模块
|
|
5
|
+
*
|
|
6
|
+
* 负责按 pin 的 release tag 从 GitHub 下载 obra/superpowers 的 skills 并部署到本项目。
|
|
7
|
+
* 提供 cbbm update --upstream-superpowers 选项,以及 init 时的自动部署能力。
|
|
8
|
+
*
|
|
9
|
+
* 网络:GitHub 直连可能被墙,走 config/upstream-mirrors.json 的镜像前缀列表
|
|
10
|
+
* (按顺序尝试,首个成功即用;空字符串 = 直连)。
|
|
11
|
+
*
|
|
12
|
+
* 升级方式:cbbm update --upstream-superpowers(按 .version 的 tag 幂等重拉)
|
|
13
|
+
* 版本检查:cbbm check-upstream
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
|
|
20
|
+
const SHARED_STANDARDS_DIR = path.join(__dirname, '..', '..', '..');
|
|
21
|
+
|
|
22
|
+
// Superpowers 本地存储目录
|
|
23
|
+
const SUPERPOWERS_DIR = path.join(SHARED_STANDARDS_DIR, 'superpowers');
|
|
24
|
+
const SUPERPOWERS_SKILLS_DIR = path.join(SUPERPOWERS_DIR, 'skills');
|
|
25
|
+
const VERSION_FILE = path.join(SUPERPOWERS_DIR, '.version');
|
|
26
|
+
|
|
27
|
+
// GitHub 配置
|
|
28
|
+
const GITHUB_REPO = 'obra/superpowers';
|
|
29
|
+
|
|
30
|
+
// 预期的 skill 列表(15 个)
|
|
31
|
+
const EXPECTED_SKILLS = [
|
|
32
|
+
'brainstorming',
|
|
33
|
+
'diagnosing-superpowers',
|
|
34
|
+
'dispatching-parallel-agents',
|
|
35
|
+
'executing-plans',
|
|
36
|
+
'finishing-a-development-branch',
|
|
37
|
+
'receiving-code-review',
|
|
38
|
+
'requesting-code-review',
|
|
39
|
+
'subagent-driven-development',
|
|
40
|
+
'systematic-debugging',
|
|
41
|
+
'test-driven-development',
|
|
42
|
+
'using-git-worktrees',
|
|
43
|
+
'using-superpowers',
|
|
44
|
+
'verification-before-completion',
|
|
45
|
+
'writing-plans',
|
|
46
|
+
'writing-skills',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const { log } = require('../utils/output');
|
|
50
|
+
const { extractTarGz } = require('../utils/tar');
|
|
51
|
+
const { loadMirrors, fetchWithMirrors } = require('../utils/upstream');
|
|
52
|
+
|
|
53
|
+
// ── 版本管理(pin)────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 读取本地 pin(.version 的 tag 字段)。
|
|
57
|
+
* 兼容旧格式:无 tag 时回退 sha。
|
|
58
|
+
* @returns {string|null}
|
|
59
|
+
*/
|
|
60
|
+
function getLocalVersion() {
|
|
61
|
+
if (!fs.existsSync(VERSION_FILE)) return null;
|
|
62
|
+
try {
|
|
63
|
+
const content = fs.readFileSync(VERSION_FILE, 'utf-8').trim();
|
|
64
|
+
if (content.startsWith('{')) {
|
|
65
|
+
const data = JSON.parse(content);
|
|
66
|
+
return data.tag || data.sha || null;
|
|
67
|
+
}
|
|
68
|
+
return content || null;
|
|
69
|
+
} catch (_) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 写入版本信息到 .version 文件。
|
|
76
|
+
* @param {string} tag
|
|
77
|
+
* @param {string} sha
|
|
78
|
+
*/
|
|
79
|
+
function writeVersion(tag, sha) {
|
|
80
|
+
const data = {
|
|
81
|
+
tag,
|
|
82
|
+
sha,
|
|
83
|
+
repo: GITHUB_REPO,
|
|
84
|
+
updatedAt: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
fs.writeFileSync(VERSION_FILE, JSON.stringify(data, null, 2) + '\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── 上游拉取 ──────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/** tarball 下载地址(按镜像前缀拼接) */
|
|
92
|
+
function tarballUrl(mirror, tag) {
|
|
93
|
+
return `${mirror}https://api.github.com/repos/${GITHUB_REPO}/tarball/${tag}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** tag → commit sha(走镜像) */
|
|
97
|
+
async function fetchTagSha(tag) {
|
|
98
|
+
const mirrors = loadMirrors('superpowers');
|
|
99
|
+
const { buffer } = await fetchWithMirrors(
|
|
100
|
+
mirrors,
|
|
101
|
+
m => `${m}https://api.github.com/repos/${GITHUB_REPO}/git/ref/tags/${tag}`
|
|
102
|
+
);
|
|
103
|
+
const data = JSON.parse(buffer.toString('utf-8'));
|
|
104
|
+
// annotated tag 指向 tag 对象(需再解一层);lightweight tag 直接是 commit
|
|
105
|
+
return (data.object && data.object.sha) || null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** 最新 release tag(走镜像,用于 check-upstream) */
|
|
109
|
+
async function fetchLatestTag() {
|
|
110
|
+
const mirrors = loadMirrors('superpowers');
|
|
111
|
+
const { buffer } = await fetchWithMirrors(
|
|
112
|
+
mirrors,
|
|
113
|
+
m => `${m}https://api.github.com/repos/${GITHUB_REPO}/releases/latest`
|
|
114
|
+
);
|
|
115
|
+
const data = JSON.parse(buffer.toString('utf-8'));
|
|
116
|
+
return data.tag_name || null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── 下载与部署 ────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 按 pin 的 tag 下载 tarball,解压出 skills/ 覆盖到 superpowers/skills/。
|
|
123
|
+
* 幂等:重复执行结果一致。
|
|
124
|
+
* @returns {Promise<{tag: string, skillCount: number, skipped: boolean}>}
|
|
125
|
+
*/
|
|
126
|
+
async function fetchLatestSkills() {
|
|
127
|
+
const pin = getLocalVersion();
|
|
128
|
+
if (!pin) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`未找到 superpowers 版本 pin(${path.relative(SHARED_STANDARDS_DIR, VERSION_FILE)} 缺失或损坏)。\n` +
|
|
131
|
+
`请先写入 { "tag": "vX.Y.Z" } 再执行。`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// pin 一致且 skills 齐全 → 幂等跳过
|
|
136
|
+
const validation = validateSkills();
|
|
137
|
+
if (validation.valid) {
|
|
138
|
+
log(`superpowers 内容已按 pin ${pin} 就位,跳过重拉`, 'success');
|
|
139
|
+
return { tag: pin, skillCount: getSkillCount(), skipped: true };
|
|
140
|
+
}
|
|
141
|
+
log(`检测到 skills 不完整,按 pin ${pin} 重新拉取...`, 'info');
|
|
142
|
+
|
|
143
|
+
const mirrors = loadMirrors('superpowers');
|
|
144
|
+
log(`正在获取 superpowers ${pin}(${mirrors.map(m => m || '直连').join(' → ')})...`, 'info');
|
|
145
|
+
const { buffer, mirror } = await fetchWithMirrors(mirrors, m => tarballUrl(m, pin));
|
|
146
|
+
log(`已从 ${mirror || '(直连)'} 下载 ${(buffer.length / 1024).toFixed(0)} KB`, 'info');
|
|
147
|
+
|
|
148
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cbb-sp-'));
|
|
149
|
+
try {
|
|
150
|
+
log('正在解压...', 'info');
|
|
151
|
+
extractTarGz(buffer, tmpDir);
|
|
152
|
+
|
|
153
|
+
// GitHub tarball 顶层目录名格式:obra-superpowers-<short-sha>
|
|
154
|
+
const entries = fs.readdirSync(tmpDir).filter(f => {
|
|
155
|
+
const p = path.join(tmpDir, f);
|
|
156
|
+
return fs.statSync(p).isDirectory() && f.startsWith('obra-superpowers');
|
|
157
|
+
});
|
|
158
|
+
if (entries.length === 0) throw new Error('解压后未找到 superpowers 目录');
|
|
159
|
+
|
|
160
|
+
const extractedSkills = path.join(tmpDir, entries[0], 'skills');
|
|
161
|
+
if (!fs.existsSync(extractedSkills)) throw new Error('解压后未找到 skills 目录');
|
|
162
|
+
|
|
163
|
+
// 覆盖 skills/
|
|
164
|
+
fs.rmSync(SUPERPOWERS_SKILLS_DIR, { recursive: true, force: true });
|
|
165
|
+
fs.mkdirSync(SUPERPOWERS_SKILLS_DIR, { recursive: true });
|
|
166
|
+
fs.cpSync(extractedSkills, SUPERPOWERS_SKILLS_DIR, { recursive: true });
|
|
167
|
+
|
|
168
|
+
// 记录版本(tag + 其指向的 sha)
|
|
169
|
+
let sha = null;
|
|
170
|
+
try { sha = await fetchTagSha(pin); } catch (_) { /* sha 记录失败不阻塞 */ }
|
|
171
|
+
writeVersion(pin, sha);
|
|
172
|
+
|
|
173
|
+
const skillCount = getSkillCount();
|
|
174
|
+
log(`superpowers skills 已更新: ${pin}(${skillCount} 个)`, 'success');
|
|
175
|
+
return { tag: pin, skillCount, skipped: false };
|
|
176
|
+
} finally {
|
|
177
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_) { /* ignore */ }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 检查上游是否有新版本(不改动任何文件)。
|
|
183
|
+
* @returns {Promise<{current: string|null, latest: string|null, outdated: boolean}>}
|
|
184
|
+
*/
|
|
185
|
+
async function checkUpstream() {
|
|
186
|
+
const current = getLocalVersion();
|
|
187
|
+
const latest = await fetchLatestTag();
|
|
188
|
+
const outdated = Boolean(current && latest && current !== latest);
|
|
189
|
+
return { current, latest, outdated };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── Skills 校验 ───────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 获取本地 skills 目录中的 skill 数量。
|
|
196
|
+
*/
|
|
197
|
+
function getSkillCount() {
|
|
198
|
+
if (!fs.existsSync(SUPERPOWERS_SKILLS_DIR)) return 0;
|
|
199
|
+
return fs.readdirSync(SUPERPOWERS_SKILLS_DIR)
|
|
200
|
+
.filter(f => {
|
|
201
|
+
const p = path.join(SUPERPOWERS_SKILLS_DIR, f);
|
|
202
|
+
return fs.statSync(p).isDirectory();
|
|
203
|
+
}).length;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 校验本地 skills 完整性:所有预期的 skill 目录存在且包含 SKILL.md。
|
|
208
|
+
* @returns {{valid: boolean, missing: string[], incomplete: string[]}}
|
|
209
|
+
*/
|
|
210
|
+
function validateSkills() {
|
|
211
|
+
const missing = [];
|
|
212
|
+
const incomplete = [];
|
|
213
|
+
|
|
214
|
+
for (const skill of EXPECTED_SKILLS) {
|
|
215
|
+
const skillDir = path.join(SUPERPOWERS_SKILLS_DIR, skill);
|
|
216
|
+
if (!fs.existsSync(skillDir)) {
|
|
217
|
+
missing.push(skill);
|
|
218
|
+
} else if (!fs.existsSync(path.join(skillDir, 'SKILL.md'))) {
|
|
219
|
+
incomplete.push(skill);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
valid: missing.length === 0 && incomplete.length === 0,
|
|
225
|
+
missing,
|
|
226
|
+
incomplete,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ── 导出 ──────────────────────────────────────────────────────
|
|
231
|
+
|
|
232
|
+
module.exports = {
|
|
233
|
+
// 常量
|
|
234
|
+
SUPERPOWERS_DIR,
|
|
235
|
+
SUPERPOWERS_SKILLS_DIR,
|
|
236
|
+
VERSION_FILE,
|
|
237
|
+
EXPECTED_SKILLS,
|
|
238
|
+
GITHUB_REPO,
|
|
239
|
+
|
|
240
|
+
// 核心函数
|
|
241
|
+
fetchLatestSkills,
|
|
242
|
+
checkUpstream,
|
|
243
|
+
getLocalVersion,
|
|
244
|
+
validateSkills,
|
|
245
|
+
getSkillCount,
|
|
246
|
+
};
|
|
@@ -23,11 +23,18 @@ const CACHE_FILE = path.join(os.homedir(), '.cbb', '.update-check-cache.json');
|
|
|
23
23
|
const CACHE_TTL = 24 * 60 * 60 * 1000;
|
|
24
24
|
|
|
25
25
|
function getProjectDir() {
|
|
26
|
-
return process.env.
|
|
26
|
+
return process.env.CODEBUDDY_PROJECT_DIR
|
|
27
|
+
|| process.env.TRAE_PROJECT_DIR
|
|
28
|
+
|| process.env.QODER_PROJECT_DIR
|
|
29
|
+
|| process.env.CLAUDE_PROJECT_DIR
|
|
30
|
+
|| process.cwd();
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/** 通过环境变量检测当前调用方对应的适配器名称 */
|
|
30
34
|
function detectAdapterName() {
|
|
35
|
+
// 兼容变量(CLAUDE_PROJECT_DIR)由 Trae / CodeBuddy 一并注入,故优先判定各自专属变量
|
|
36
|
+
if (process.env.CODEBUDDY_PROJECT_DIR) return 'codebuddy';
|
|
37
|
+
if (process.env.TRAE_PROJECT_DIR) return 'trae';
|
|
31
38
|
if (process.env.QODER_PROJECT_DIR) return 'qoder';
|
|
32
39
|
if (process.env.CLAUDE_PROJECT_DIR) return 'claude-code';
|
|
33
40
|
return null;
|
|
@@ -19,6 +19,8 @@ const GITIGNORE_RULES = [
|
|
|
19
19
|
{ add: '.cbb/', accept: ['.cbb/'] },
|
|
20
20
|
{ add: '.codespace/', accept: ['.codespace/', '.codespace'] },
|
|
21
21
|
{ add: '.opencode', accept: ['.opencode', '.opencode/'] },
|
|
22
|
+
{ add: '.codebuddy', accept: ['.codebuddy', '.codebuddy/'] },
|
|
23
|
+
{ add: '.trae', accept: ['.trae', '.trae/'] },
|
|
22
24
|
];
|
|
23
25
|
|
|
24
26
|
/** 将 .gitignore 文本拆为行数组。 */
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* removeLegacyHooks 负责清理旧版本曾写入、现已弃用的 SessionStart hook:
|
|
12
12
|
* 当前仅安装 UserPromptSubmit,但升级自旧版本的用户 settings.json 中可能仍残留
|
|
13
13
|
* SessionStart 条目,升级 / 卸载时需主动移除,否则会永久残留。
|
|
14
|
+
*
|
|
15
|
+
* 方言:Trae 的 hooks.json 需顶层 `version: 1` 且非 Claude 的 settings.json,
|
|
16
|
+
* 由 opts.dialect === 'trae' 处理(写入时补 version,清理干净后移除)。
|
|
14
17
|
*/
|
|
15
18
|
|
|
16
19
|
const fs = require('fs');
|
|
@@ -53,12 +56,16 @@ function stripManaged(arr) {
|
|
|
53
56
|
* @param {string} settingsPath settings.json 路径
|
|
54
57
|
* @param {string} command 要执行的命令
|
|
55
58
|
* @param {string[]} events 要写入的事件名数组,如 ['UserPromptSubmit']
|
|
59
|
+
* @param {{dialect?: string}} [opts] 方言:'trae' 时补顶层 version: 1(Trae hooks.json 要求)
|
|
56
60
|
* 已存在本包标记的条目会先移除再添加(保证命令为最新路径),不重复。
|
|
57
61
|
*/
|
|
58
|
-
function addHooks(settingsPath, command, events) {
|
|
62
|
+
function addHooks(settingsPath, command, events, opts = {}) {
|
|
59
63
|
const settings = readSettings(settingsPath);
|
|
60
64
|
if (!settings.hooks || typeof settings.hooks !== 'object') settings.hooks = {};
|
|
61
65
|
|
|
66
|
+
// Trae hooks.json 需要顶层 version 字段(当前仅支持 1)
|
|
67
|
+
if (opts.dialect === 'trae' && settings.version === undefined) settings.version = 1;
|
|
68
|
+
|
|
62
69
|
events.forEach(event => {
|
|
63
70
|
settings.hooks[event] = stripManaged(settings.hooks[event]);
|
|
64
71
|
const entry = { _managedBy: MANAGED_BY, hooks: [{ type: 'command', command }] };
|
|
@@ -74,9 +81,10 @@ function addHooks(settingsPath, command, events) {
|
|
|
74
81
|
* 清理变空的事件数组 / hooks。
|
|
75
82
|
* @param {string} settingsPath settings.json 路径
|
|
76
83
|
* @param {string[]} events 要清理的事件名数组
|
|
84
|
+
* @param {{dialect?: string}} [opts] 方言:'trae' 时把 version 一并视为可清理字段
|
|
77
85
|
* 返回 true 表示有改动。
|
|
78
86
|
*/
|
|
79
|
-
function removeHooks(settingsPath, events) {
|
|
87
|
+
function removeHooks(settingsPath, events, opts = {}) {
|
|
80
88
|
if (!fs.existsSync(settingsPath)) return false;
|
|
81
89
|
const settings = readSettings(settingsPath);
|
|
82
90
|
if (!settings.hooks || typeof settings.hooks !== 'object') return false;
|
|
@@ -94,6 +102,11 @@ function removeHooks(settingsPath, events) {
|
|
|
94
102
|
|
|
95
103
|
if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
|
|
96
104
|
|
|
105
|
+
// Trae:hooks 清空后 version 只是本包写入的脚手架,一并移除
|
|
106
|
+
if (opts.dialect === 'trae' && settings.version !== undefined && !settings.hooks) {
|
|
107
|
+
delete settings.version;
|
|
108
|
+
}
|
|
109
|
+
|
|
97
110
|
// 文件变成空对象则删除,否则写回
|
|
98
111
|
if (Object.keys(settings).length === 0) {
|
|
99
112
|
fs.unlinkSync(settingsPath);
|
|
@@ -107,8 +120,8 @@ function removeHooks(settingsPath, events) {
|
|
|
107
120
|
* 清理遗留事件下本包标记的 hook 条目(旧版本写入的 SessionStart 等)。
|
|
108
121
|
* 复用 removeHooks 的清理逻辑;返回 true 表示有改动。
|
|
109
122
|
*/
|
|
110
|
-
function removeLegacyHooks(settingsPath) {
|
|
111
|
-
return removeHooks(settingsPath, LEGACY_HOOK_EVENTS);
|
|
123
|
+
function removeLegacyHooks(settingsPath, opts = {}) {
|
|
124
|
+
return removeHooks(settingsPath, LEGACY_HOOK_EVENTS, opts);
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
module.exports = {
|