@jspg-ai/coding-bb 0.0.3-beta.16 → 0.0.3-beta.18
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/lib/install/init.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 将AI 编码规范与工作流套件安装到目标项目中。
|
|
7
7
|
* 支持工具:Claude Code (.claude/rules/)、Qoder (.qoder/rules/)、opencode (.opencode/rules/)、
|
|
8
|
-
* WorkBuddy
|
|
8
|
+
* WorkBuddy (.workbuddy/rules/)、TraeWork/TraeCode (.trae/rules/)
|
|
9
9
|
*
|
|
10
10
|
* 使用方式:
|
|
11
11
|
* npm install -g @jspg-ai/coding-bb # 首次使用
|
|
@@ -56,7 +56,7 @@ const LAST_TOOLS_FILE = path.join(MANIFEST_DIR, '.last-tools');
|
|
|
56
56
|
// 适配器(数组顺序 = 工具选择面板的显示顺序)
|
|
57
57
|
const adapters = [
|
|
58
58
|
require('./opencode'),
|
|
59
|
-
require('./
|
|
59
|
+
require('./workbuddy'),
|
|
60
60
|
require('./trae'),
|
|
61
61
|
require('./qoder'),
|
|
62
62
|
require('./claude-code'),
|
|
@@ -94,6 +94,17 @@ function hookOpts(adapter) {
|
|
|
94
94
|
return adapter.hookDialect ? { dialect: adapter.hookDialect } : {};
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// 工具历史名迁移:beta.16 及以前为 'codebuddy'(CodeBuddy 目录模型),
|
|
98
|
+
// beta.17 起统一为 'workbuddy'。存量 .last-tools / 清单里的旧名读取时归一,
|
|
99
|
+
// 下次安装由 saveLastTools 以新名落盘。
|
|
100
|
+
const LEGACY_TOOL_NAMES = { codebuddy: 'workbuddy' };
|
|
101
|
+
|
|
102
|
+
/** 工具名集合归一(旧名 → 新名);null 透传 */
|
|
103
|
+
function normalizeToolSet(set) {
|
|
104
|
+
if (!set) return set;
|
|
105
|
+
return new Set([...set].map(t => LEGACY_TOOL_NAMES[t] || t));
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
/**
|
|
98
109
|
* 迁移清理:移除本包写在旧用户级 settings 里的 hook(如 WorkBuddy 适配修正:
|
|
99
110
|
* ~/.codebuddy/settings.json → ~/.workbuddy/settings.json)。
|
|
@@ -107,7 +118,7 @@ function cleanLegacySettings(adapter) {
|
|
|
107
118
|
// 清单驱动的文件清理决策(保护用户文档 CLAUDE.md / AGENTS.md 等)
|
|
108
119
|
const { pathsToDelete, protectedKeptPaths } = require('./cleanup');
|
|
109
120
|
|
|
110
|
-
// 规则 frontmatter 改写(Trae/
|
|
121
|
+
// 规则 frontmatter 改写(Trae/WorkBuddy 需 alwaysApply: true)
|
|
111
122
|
const { applyRuleRewrites } = require('./rule-rewrite');
|
|
112
123
|
|
|
113
124
|
// .gitignore 条目决策(纯函数:检测/写入/卸载移除)
|
|
@@ -208,7 +219,7 @@ function readLastTools() {
|
|
|
208
219
|
if (!fs.existsSync(filePath)) return null;
|
|
209
220
|
try {
|
|
210
221
|
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
211
|
-
return new Set(data.tools || []);
|
|
222
|
+
return normalizeToolSet(new Set(data.tools || []));
|
|
212
223
|
} catch (_) {
|
|
213
224
|
return null;
|
|
214
225
|
}
|
|
@@ -995,12 +1006,15 @@ async function init(targetDir, options = {}) {
|
|
|
995
1006
|
// 选择优先级:调用方预设(cbb setup)> .last-tools(非交互沿用)> 交互选择;无记录才回退全选
|
|
996
1007
|
const isNonInteractive = yes || !process.stdin.isTTY;
|
|
997
1008
|
let selectedAdapters;
|
|
1009
|
+
let fromRecord = false; // 选择来自预设或 .last-tools 记录(需落盘归一化后的新工具名)
|
|
998
1010
|
if (presetAdapters && presetAdapters.length > 0) {
|
|
999
1011
|
selectedAdapters = presetAdapters;
|
|
1012
|
+
fromRecord = true;
|
|
1000
1013
|
} else if (isNonInteractive) {
|
|
1001
1014
|
const lastTools = readLastTools();
|
|
1002
1015
|
const reused = lastTools ? adapters.filter(a => lastTools.has(a.name)) : [];
|
|
1003
1016
|
selectedAdapters = reused.length > 0 ? reused : adapters;
|
|
1017
|
+
fromRecord = reused.length > 0;
|
|
1004
1018
|
if (yes && process.stdin.isTTY) {
|
|
1005
1019
|
log(reused.length > 0
|
|
1006
1020
|
? `--yes 非交互模式,沿用上次工具选择:${reused.map(a => a.displayName).join('、')}`
|
|
@@ -1009,8 +1023,9 @@ async function init(targetDir, options = {}) {
|
|
|
1009
1023
|
} else {
|
|
1010
1024
|
selectedAdapters = await selectTools(isUpgrade);
|
|
1011
1025
|
}
|
|
1012
|
-
// 业务空间根记录本次选择,供 cbb update
|
|
1013
|
-
|
|
1026
|
+
// 业务空间根记录本次选择,供 cbb update 等非交互场景沿用;
|
|
1027
|
+
// 沿用旧记录时同样落盘,使历史工具名(codebuddy → workbuddy)归一化自愈
|
|
1028
|
+
if (isWorkspaceRoot && fromRecord) {
|
|
1014
1029
|
saveLastTools(selectedAdapters);
|
|
1015
1030
|
}
|
|
1016
1031
|
|
|
@@ -1281,7 +1296,7 @@ function decideUpgradeIfInstalled(targetDir, selectedAdapters) {
|
|
|
1281
1296
|
const pkg = require(path.join(SHARED_STANDARDS_DIR, 'package.json'));
|
|
1282
1297
|
const decision = setupDecision.decideSetupAction({
|
|
1283
1298
|
sameVersion: version.compareVersions(installed, pkg.version) === 0,
|
|
1284
|
-
lastTools: setupDecision.readLastToolsFrom(targetDir),
|
|
1299
|
+
lastTools: normalizeToolSet(setupDecision.readLastToolsFrom(targetDir)),
|
|
1285
1300
|
selectedNames: (selectedAdapters || []).map(a => a.name),
|
|
1286
1301
|
});
|
|
1287
1302
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `trigger: always_on`。各工具对"始终生效"的字段名不同:
|
|
8
8
|
* - Qoder:trigger: always_on(源格式)
|
|
9
9
|
* - Claude Code / opencode:无该字段,靠各自机制加载
|
|
10
|
-
* - WorkBuddy
|
|
10
|
+
* - WorkBuddy、Trae:alwaysApply: true
|
|
11
11
|
*
|
|
12
12
|
* 适配器通过 ruleRewrites([[from, to], ...])声明改写规则,部署时套用;
|
|
13
13
|
* 无 ruleRewrites 的适配器原样返回。
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WorkBuddy
|
|
2
|
+
* WorkBuddy 适配器
|
|
3
3
|
*
|
|
4
|
-
* 腾讯 WorkBuddy 桌面工作台的项目级配置目录为 `.workbuddy
|
|
5
|
-
*
|
|
6
|
-
* 0.0.3-beta.16 起目录与用户级 settings
|
|
4
|
+
* 腾讯 WorkBuddy 桌面工作台的项目级配置目录为 `.workbuddy/`(业务空间实测:
|
|
5
|
+
* skill 只有放在 `.workbuddy/skills/` 才生效;旧版假设「与 CodeBuddy 共用
|
|
6
|
+
* .codebuddy/」不成立)。0.0.3-beta.16 起目录与用户级 settings 切到
|
|
7
|
+
* `.workbuddy`;0.0.3-beta.17 起不再支持 CodeBuddy,`.codebuddy` 仅作为
|
|
7
8
|
* legacy 由安装流程迁移清理(legacyDirs / legacySettingsFile)。
|
|
8
9
|
*
|
|
9
10
|
* 与 Claude Code / Qoder 的映射差异:
|
|
@@ -18,18 +19,18 @@ const path = require('path');
|
|
|
18
19
|
const os = require('os');
|
|
19
20
|
|
|
20
21
|
module.exports = {
|
|
21
|
-
name: '
|
|
22
|
-
displayName: 'WorkBuddy
|
|
22
|
+
name: 'workbuddy',
|
|
23
|
+
displayName: 'WorkBuddy',
|
|
23
24
|
rulesDir: '.workbuddy/rules',
|
|
24
25
|
skillsDir: '.workbuddy/skills',
|
|
25
26
|
commandsDir: '.workbuddy/commands/opsx',
|
|
26
|
-
// 规则 frontmatter 改写:Qoder 风格 →
|
|
27
|
+
// 规则 frontmatter 改写:Qoder 风格 → WorkBuddy 风格
|
|
27
28
|
ruleRewrites: [['trigger: always_on', 'alwaysApply: true']],
|
|
28
29
|
// 用户级 settings,写入全局生效,不污染项目目录
|
|
29
30
|
settingsFile: path.join(os.homedir(), '.workbuddy', 'settings.json'),
|
|
30
31
|
settingsFileIsUserLevel: true,
|
|
31
32
|
hookEvents: ['UserPromptSubmit'],
|
|
32
|
-
//
|
|
33
|
+
// 旧版(beta.15 及以前按 CodeBuddy 装的 .codebuddy):安装时迁移清理
|
|
33
34
|
legacyDirs: ['.codebuddy'],
|
|
34
35
|
legacySettingsFile: path.join(os.homedir(), '.codebuddy', 'settings.json'),
|
|
35
36
|
};
|
|
@@ -23,7 +23,8 @@ 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.WORKBUDDY_PROJECT_DIR
|
|
27
|
+
|| process.env.CODEBUDDY_PROJECT_DIR
|
|
27
28
|
|| process.env.TRAE_PROJECT_DIR
|
|
28
29
|
|| process.env.QODER_PROJECT_DIR
|
|
29
30
|
|| process.env.CLAUDE_PROJECT_DIR
|
|
@@ -32,8 +33,9 @@ function getProjectDir() {
|
|
|
32
33
|
|
|
33
34
|
/** 通过环境变量检测当前调用方对应的适配器名称 */
|
|
34
35
|
function detectAdapterName() {
|
|
35
|
-
// 兼容变量(CLAUDE_PROJECT_DIR)由 Trae /
|
|
36
|
-
|
|
36
|
+
// 兼容变量(CLAUDE_PROJECT_DIR)由 Trae / WorkBuddy 一并注入,故优先判定各自专属变量;
|
|
37
|
+
// CODEBUDDY_PROJECT_DIR 为 WorkBuddy 沿用的历史变量名,一并识别为 workbuddy
|
|
38
|
+
if (process.env.WORKBUDDY_PROJECT_DIR || process.env.CODEBUDDY_PROJECT_DIR) return 'workbuddy';
|
|
37
39
|
if (process.env.TRAE_PROJECT_DIR) return 'trae';
|
|
38
40
|
if (process.env.QODER_PROJECT_DIR) return 'qoder';
|
|
39
41
|
if (process.env.CLAUDE_PROJECT_DIR) return 'claude-code';
|
|
@@ -19,7 +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
|
-
|
|
22
|
+
// .codebuddy:beta.15 及以前写入的旧目录,不再新增(add: null),但卸载/清理时仍移除其行
|
|
23
|
+
{ add: null, accept: ['.codebuddy', '.codebuddy/'] },
|
|
23
24
|
{ add: '.workbuddy', accept: ['.workbuddy', '.workbuddy/'] },
|
|
24
25
|
{ add: '.trae', accept: ['.trae', '.trae/'] },
|
|
25
26
|
];
|
|
@@ -32,12 +33,12 @@ function toLines(content) {
|
|
|
32
33
|
/**
|
|
33
34
|
* 给定 .gitignore 内容,返回需要新增的条目。
|
|
34
35
|
* 已含任一可接受形式(带/不带尾斜杠)的目录会被跳过;全部已存在时返回空数组。
|
|
35
|
-
* 返回的是写入形式(.claude / .qoder 无尾斜杠,.cbb/
|
|
36
|
+
* 返回的是写入形式(.claude / .qoder 无尾斜杠,.cbb/ 带尾斜杠;add 为 null 的纯遗留规则不新增)。
|
|
36
37
|
*/
|
|
37
38
|
function entriesToAdd(content) {
|
|
38
39
|
const lines = toLines(content).map(l => l.trim());
|
|
39
40
|
return GITIGNORE_RULES
|
|
40
|
-
.filter(r => !r.accept.some(a => lines.includes(a)))
|
|
41
|
+
.filter(r => r.add && !r.accept.some(a => lines.includes(a)))
|
|
41
42
|
.map(r => r.add);
|
|
42
43
|
}
|
|
43
44
|
|