@jspg-ai/coding-bb 0.0.3-beta.8 → 0.0.4
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 +0 -15
- package/cbb/dev-standards/rules/cbb-workspace-discipline.md +38 -0
- package/cbb/lib/external/index.js +228 -0
- package/cbb/lib/install/agents-nav.js +92 -0
- package/cbb/lib/install/claude-code.js +8 -1
- package/cbb/lib/install/command-skill.js +105 -0
- package/cbb/lib/install/init.js +399 -129
- package/cbb/lib/install/minimax.js +60 -0
- package/cbb/lib/install/rule-rewrite.js +1 -1
- package/cbb/lib/install/setup-decision.js +92 -0
- package/cbb/lib/install/tool-selection.js +23 -0
- package/cbb/lib/install/trae.js +18 -8
- package/cbb/lib/install/workbuddy.js +36 -0
- package/cbb/lib/install/workspaces.js +15 -61
- package/cbb/lib/utils/check-update.js +13 -5
- package/cbb/lib/utils/githook.js +230 -0
- package/cbb/lib/utils/gitignore.js +17 -4
- package/cbb/lib/utils/plugin-hook.js +92 -0
- package/cbb/worktrees/_shared/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/_shared/scripts/check-unarchived.js +77 -0
- package/cbb/worktrees/_shared/scripts/delete-branches.js +147 -0
- package/cbb/worktrees/_shared/scripts/deprecate-branches.js +119 -0
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +8 -8
- package/cbb/worktrees/_shared/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/_shared/scripts/junction-ai-config.js +192 -0
- package/cbb/worktrees/_shared/scripts/merge-branches.js +469 -0
- package/cbb/worktrees/_shared/scripts/push-core.js +1 -1
- package/cbb/worktrees/_shared/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/_shared/scripts/start-local.js +180 -0
- package/cbb/worktrees/skills/cbb-local-mode/SKILL.md +194 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/delete-branches.js +147 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/deprecate-branches.js +119 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/merge-branches.js +469 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/start-local.js +180 -0
- package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +133 -81
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-env.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-unarchived.js +77 -48
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/delete-branches.js +147 -136
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/deprecate-branches.js +119 -0
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/discover-apps.js +14 -5
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/find-workspace-root.js +8 -8
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/junction-ai-config.js +192 -0
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/merge-branches.js +469 -0
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/remove-worktrees.js +44 -9
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/safety-check.js +15 -4
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +136 -123
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-env.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-repos.js +2 -2
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-branches.js +33 -8
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-worktrees.js +60 -46
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/junction-ai-config.js +192 -0
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/parse-config.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/push-branches.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/push-core.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/sync-repos.js +11 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/update-gitignore.js +37 -9
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +212 -56
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/check-unarchived.js +77 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/commit-worktrees.js +70 -12
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-workspace-root.js +8 -8
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/make-mr-urls.js +211 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/merge-branches.js +469 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-core.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-worktrees.js +67 -20
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/silence-popup.js +1 -1
- package/config/{workspace-config.sample.json → CBB-WORKSPACE.sample.json} +1 -1
- package/config/openspec/schemas/spec-driven/schema.yaml +20 -0
- package/config/upstream-mirrors.json +5 -0
- package/external/frontend-design/.version +6 -0
- package/external/frontend-design/LICENSE.txt +177 -0
- package/external/frontend-design/SKILL.md +71 -0
- package/openspec/.version +2 -2
- package/openspec/commands/archive.md +15 -8
- package/openspec/commands/bulk-archive.md +13 -6
- package/openspec/commands/continue.md +0 -1
- package/openspec/commands/explore.md +1 -1
- package/openspec/commands/ff.md +1 -1
- package/openspec/commands/onboard.md +9 -4
- package/openspec/commands/update.md +11 -5
- package/openspec/commands/verify.md +57 -26
- package/openspec/skills/openspec-apply-change/SKILL.md +1 -1
- package/openspec/skills/openspec-archive-change/SKILL.md +16 -9
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +14 -7
- package/openspec/skills/openspec-continue-change/SKILL.md +1 -2
- package/openspec/skills/openspec-explore/SKILL.md +2 -2
- package/openspec/skills/openspec-ff-change/SKILL.md +2 -2
- package/openspec/skills/openspec-new-change/SKILL.md +1 -1
- package/openspec/skills/openspec-onboard/SKILL.md +10 -5
- package/openspec/skills/openspec-propose/SKILL.md +1 -1
- package/openspec/skills/openspec-sync-specs/SKILL.md +1 -1
- package/openspec/skills/openspec-update-change/SKILL.md +12 -6
- package/openspec/skills/openspec-verify-change/SKILL.md +59 -27
- package/package.json +3 -2
- package/superpowers/.version +3 -3
- package/superpowers/skills/writing-plans/SKILL.md +32 -20
- package/cbb/lib/install/codebuddy.js +0 -30
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/find-workspace-root.js +0 -67
- package/config/workspace-agents.sample.md +0 -41
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MiniMax Code(mcode CLI)适配器
|
|
3
|
+
*
|
|
4
|
+
* 官方源码考证结论(agent.minimaxi.com 文档站 + 源码浅克隆):
|
|
5
|
+
* - rules:MiniMax 无原生 rules 自动读取逻辑(源码无 .minimax/rules 读取),
|
|
6
|
+
* 规则照常分发到 .minimax/rules/,靠 AGENTS.md 托管导航块(agentsNav)引导
|
|
7
|
+
* AI 主动读取——AGENTS.md 是 MiniMax 唯一的项目级规则注入通道
|
|
8
|
+
* (local-runtime/src/project/instructions.ts,32KB 预算)。
|
|
9
|
+
* - skills:.minimax/skills 为原生 workspace skill 根(skills/roots.ts),
|
|
10
|
+
* 标准 Agent Skills 格式(目录名 = frontmatter name)零改写。
|
|
11
|
+
* - commands:MiniMax 无项目级 commands 目录,openspec 命令转 skill 形态分发
|
|
12
|
+
* (skill 即其命令形态,/opsx-propose 斜杠照常可用),commandsAsSkills: true。
|
|
13
|
+
* - hooks:无 Claude 式 settings.json hooks(hooks 仅插件作用域),版本检查改用
|
|
14
|
+
* 用户级本地插件(<data-dir>/plugins/cbb-check-update,声明 UserPromptSubmit)。
|
|
15
|
+
*
|
|
16
|
+
* 数据目录:MINIMAX_DATA_DIR(优先)> MAVIS_DATA_DIR > ~/.minimax,与 mcode
|
|
17
|
+
* 运行时一致;用户若改过数据目录,需重跑 cbb update 以重装插件到新位置。
|
|
18
|
+
*
|
|
19
|
+
* 退市(selectable: false):实测 MiniMax Code 不支持目录级 skill 与 command
|
|
20
|
+
* (无项目级 commands 目录,skill 亦需插件形态承载),当前分发形态不可用。
|
|
21
|
+
* 适配器代码与全部能力保留(备将来改走插件形态),但不在安装面板提供;
|
|
22
|
+
* 旧记录中的遗留内容不在勾选范围时随清单差集与用户级差集清理移除(ADR 0006)。
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const os = require('os');
|
|
27
|
+
|
|
28
|
+
/** 解析 mcode 数据目录(调用时求值,便于环境变量覆盖与测试) */
|
|
29
|
+
function resolveDataDir() {
|
|
30
|
+
return process.env.MINIMAX_DATA_DIR
|
|
31
|
+
|| process.env.MAVIS_DATA_DIR
|
|
32
|
+
|| path.join(os.homedir(), '.minimax');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
name: 'minimax',
|
|
37
|
+
displayName: 'MiniMax Code',
|
|
38
|
+
rulesDir: '.minimax/rules',
|
|
39
|
+
skillsDir: '.minimax/skills',
|
|
40
|
+
// 无项目级 commands 目录:openspec 命令转 <skillsDir>/<prefix><name>/SKILL.md
|
|
41
|
+
commandsAsSkills: true,
|
|
42
|
+
commandPrefix: 'opsx-',
|
|
43
|
+
// 部署副本中把 /opsx: 与 /cbb: 引用改写为 skill 斜杠风格(/opsx-propose)
|
|
44
|
+
contentRewrites: [['/opsx:', '/opsx-'], ['/cbb:', '/cbb-']],
|
|
45
|
+
// AGENTS.md 托管导航块(幂等注入 / 卸载精确摘除,不触碰块外用户内容)
|
|
46
|
+
agentsNav: {
|
|
47
|
+
file: 'AGENTS.md',
|
|
48
|
+
text: '⚠️ 规则优先:在当前目录下执行的任何任务(不限于编码任务)开始前,必须先读取并遵循 `.minimax/rules/` 中的相关规则文件。',
|
|
49
|
+
},
|
|
50
|
+
// 版本检查 hook:用户级本地插件(<dataDir>/plugins/<dirName>,自动发现热加载、默认启用)
|
|
51
|
+
pluginHook: {
|
|
52
|
+
dirName: 'cbb-check-update',
|
|
53
|
+
events: ['UserPromptSubmit'],
|
|
54
|
+
// 解析上限:MiniMax timeout 单位为秒,1–10(超出视为非法回落 5s)
|
|
55
|
+
timeout: 10,
|
|
56
|
+
},
|
|
57
|
+
resolveDataDir,
|
|
58
|
+
// 退市:不在安装面板提供(代码保留;旧记录遗留随清单/用户级差集清理,ADR 0006)
|
|
59
|
+
selectable: false,
|
|
60
|
+
};
|
|
@@ -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 的适配器原样返回。
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* cbb setup 空间级安装的跳过判定 + 工具记录归一与多空间预选(纯逻辑,可单测)。
|
|
5
|
+
*
|
|
6
|
+
* 背景 bug(0.0.3-beta.15 修复):旧版 decideUpgradeIfInstalled 只比较
|
|
7
|
+
* 「已装版本 vs 当前包版本」,版本一致即 skip——导致「空间已是当前版本 +
|
|
8
|
+
* 本次新选了工具(如 WorkBuddy)」被整体跳过,新工具的空间级目录
|
|
9
|
+
* (.workbuddy/ 等)永不生成,.last-tools 也不更新。
|
|
10
|
+
*
|
|
11
|
+
* 背景 bug(0.0.3-beta.39 修复):多空间 `cbb setup` 工具面板预选曾硬编码
|
|
12
|
+
* 「只预选 opencode」,未读所选空间的 .last-tools——直接回车会把已装工具
|
|
13
|
+
* 当作「未勾选」由清单差集清理移除。现由 preselectIndexes 计算并集预选。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 读取 <targetDir>/.cbb/.last-tools 的已装工具集合。
|
|
21
|
+
* @param {string} targetDir 业务空间根
|
|
22
|
+
* @returns {Set<string>|null} 工具名集合;无文件或解析失败返回 null
|
|
23
|
+
*/
|
|
24
|
+
function readLastToolsFrom(targetDir) {
|
|
25
|
+
const filePath = path.join(targetDir, '.cbb', '.last-tools');
|
|
26
|
+
if (!fs.existsSync(filePath)) return null;
|
|
27
|
+
try {
|
|
28
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
29
|
+
return new Set(data.tools || []);
|
|
30
|
+
} catch (_) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 判定已安装空间本次 setup 应跳过还是继续安装。
|
|
37
|
+
* @param {object} p
|
|
38
|
+
* @param {boolean} p.sameVersion 已装版本 == 当前包版本
|
|
39
|
+
* @param {Set<string>|null} p.lastTools .last-tools 记录(null = 无记录)
|
|
40
|
+
* @param {string[]} p.selectedNames 本次选中的工具名
|
|
41
|
+
* @returns {{action:'skip'|'install', newTools:string[], reason:string}}
|
|
42
|
+
* reason: 'version-changed' | 'no-tools-record' | 'new-tools' | 'up-to-date'
|
|
43
|
+
*/
|
|
44
|
+
function decideSetupAction({ sameVersion, lastTools, selectedNames }) {
|
|
45
|
+
if (!sameVersion) return { action: 'install', newTools: [], reason: 'version-changed' };
|
|
46
|
+
if (lastTools === null) return { action: 'install', newTools: [], reason: 'no-tools-record' };
|
|
47
|
+
const newTools = (selectedNames || []).filter(n => !lastTools.has(n));
|
|
48
|
+
if (newTools.length > 0) return { action: 'install', newTools, reason: 'new-tools' };
|
|
49
|
+
return { action: 'skip', newTools: [], reason: 'up-to-date' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── 工具记录归一与多空间预选 ─────────────────────────────────
|
|
53
|
+
|
|
54
|
+
// 工具历史名迁移:beta.16 及以前为 'codebuddy'(CodeBuddy 目录模型),
|
|
55
|
+
// beta.17 起统一为 'workbuddy'。存量 .last-tools / 清单里的旧名读取时归一,
|
|
56
|
+
// 下次安装由 saveLastTools 以新名落盘。
|
|
57
|
+
const LEGACY_TOOL_NAMES = { codebuddy: 'workbuddy' };
|
|
58
|
+
|
|
59
|
+
/** 工具名集合归一(旧名 → 新名);null 透传 */
|
|
60
|
+
function normalizeToolSet(set) {
|
|
61
|
+
if (!set) return set;
|
|
62
|
+
return new Set([...set].map(t => LEGACY_TOOL_NAMES[t] || t));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 由多个空间 .last-tools 记录计算多空间 setup 面板的预选索引。
|
|
67
|
+
*
|
|
68
|
+
* 并集语义:任一所选空间装过的工具都预勾(延续既有工具面,批量升级一次回车);
|
|
69
|
+
* 退市工具不并回(ADR 0006);并集过滤后为空时回退预选 fallbackName(首次引导行为)。
|
|
70
|
+
*
|
|
71
|
+
* @param {Array<Set<string>|null>} records 各空间记录(null = 无记录)
|
|
72
|
+
* @param {Array<{name:string}>} selectable 面板可选项(未退市适配器,顺序即索引)
|
|
73
|
+
* @param {string} [fallbackName='opencode'] 并集为空时的回退预选工具名
|
|
74
|
+
* @returns {number[]} 预选索引(升序)
|
|
75
|
+
*/
|
|
76
|
+
function preselectIndexes(records, selectable, fallbackName = 'opencode') {
|
|
77
|
+
const union = new Set();
|
|
78
|
+
(records || []).forEach(r => {
|
|
79
|
+
if (!r) return;
|
|
80
|
+
normalizeToolSet(r).forEach(t => union.add(t));
|
|
81
|
+
});
|
|
82
|
+
const valid = new Set(selectable.map(a => a.name));
|
|
83
|
+
const kept = [...union].filter(t => valid.has(t));
|
|
84
|
+
if (kept.length > 0) {
|
|
85
|
+
const target = new Set(kept);
|
|
86
|
+
return selectable.map((a, i) => (target.has(a.name) ? i : -1)).filter(i => i >= 0);
|
|
87
|
+
}
|
|
88
|
+
const idx = selectable.findIndex(a => a.name === fallbackName);
|
|
89
|
+
return idx >= 0 ? [idx] : [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = { decideSetupAction, readLastToolsFrom, LEGACY_TOOL_NAMES, normalizeToolSet, preselectIndexes };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 工具选择策略:安装面板的可见集合(未退市适配器)。
|
|
5
|
+
*
|
|
6
|
+
* 背景(2026-09-28 决策):MiniMax Code 实测不支持目录级 skill 与 command、
|
|
7
|
+
* Claude Code 团队当前未用,两者**退市**——适配器与全部能力保留(见各适配器
|
|
8
|
+
* 文件头),仅不在 `cbb setup` / `cbb update` 的安装面板提供。
|
|
9
|
+
*
|
|
10
|
+
* 退市工具的取舍(ADR 0006,反转 beta.30 的粘性保留决策):
|
|
11
|
+
* - 退市工具**不进**选择集:面板、非交互沿用、setup 预设、用户级组件,
|
|
12
|
+
* 一律只用未退市适配器(`selectable !== false`);
|
|
13
|
+
* - 勾选范围即权威:`.last-tools` 只如实记录本次实际选择,不在范围内的
|
|
14
|
+
* 工具内容(含用户级 hook / 插件)由清单差集与用户级差集清理移除;
|
|
15
|
+
* - 恢复入口:删掉适配器的 `selectable: false` 即回到面板。
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** 面板/默认可选适配器(未标 selectable: false 的全部) */
|
|
19
|
+
function selectableAdapters(adapters) {
|
|
20
|
+
return adapters.filter(a => a.selectable !== false);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = { selectableAdapters };
|
package/cbb/lib/install/trae.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TraeWork / TraeCode
|
|
2
|
+
* TraeWork / TraeCode 适配器(中国版)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 中国版 TraeCode IDE 与 TraeWork 的项目级配置目录为 `.trae/`
|
|
5
|
+
* (官方文档 docs.trae.cn:项目规则 `.trae/rules/`、项目命令 `.trae/commands`),
|
|
6
|
+
* `.trae-cn/` 仅是中国版**用户级**目录(~/.trae-cn/hooks.json、user_rules、commands),
|
|
7
|
+
* 与国际版共用项目级 `.trae/` 命名。cbb 仅支持中国版(我司均用中国版)。
|
|
6
8
|
*
|
|
7
9
|
* 与 Claude Code / Qoder 的映射差异:
|
|
8
10
|
* - rules:`.trae/rules/*.md`(扁平文件、支持子目录,最多 3 层),frontmatter 用
|
|
9
11
|
* `alwaysApply: true`(Qoder 的 `trigger: always_on` 需改写,见 ruleRewrites)
|
|
10
12
|
* - skills:`.trae/skills/<name>/SKILL.md`,结构与 Claude 同构
|
|
11
|
-
* - commands
|
|
12
|
-
*
|
|
13
|
+
* - commands:命令名 = 文件名,无 Claude 式"目录:命令"命名空间(实测嵌套目录 +
|
|
14
|
+
* `name: "OPSX: Apply"` 不出现在斜杠列表),故与 opencode 同款扁平化为
|
|
15
|
+
* `.trae/commands/opsx-<name>.md`(/opsx-propose),frontmatter name 同步 kebab 化
|
|
16
|
+
* - hooks:`~/.trae-cn/hooks.json`(用户级),格式与 Claude 相近但需顶层 `version: 1`
|
|
13
17
|
* (由 settingsManager 的 hookDialect 处理),事件名/输出字段一致
|
|
18
|
+
*
|
|
19
|
+
* 注意:不设 legacyDirs —— `.trae/` 本就是正确的项目级目录,无需清理。
|
|
14
20
|
*/
|
|
15
21
|
|
|
16
22
|
const path = require('path');
|
|
@@ -18,13 +24,17 @@ const os = require('os');
|
|
|
18
24
|
|
|
19
25
|
module.exports = {
|
|
20
26
|
name: 'trae',
|
|
21
|
-
displayName: 'TraeWork(TraeCode
|
|
27
|
+
displayName: 'TraeWork(TraeCode·中国版)',
|
|
22
28
|
rulesDir: '.trae/rules',
|
|
23
29
|
skillsDir: '.trae/skills',
|
|
24
|
-
commandsDir: '.trae/commands
|
|
30
|
+
commandsDir: '.trae/commands',
|
|
31
|
+
// 命令扁平化(同 opencode):中国版命令名 = 文件名,不支持 "目录:命令" 命名空间
|
|
32
|
+
commandPrefix: 'opsx-',
|
|
33
|
+
contentRewrites: [['/opsx:', '/opsx-'], ['/cbb:', '/cbb-']],
|
|
34
|
+
commandNameKebab: true,
|
|
25
35
|
// 规则 frontmatter 改写:Qoder 风格 → Trae 风格
|
|
26
36
|
ruleRewrites: [['trigger: always_on', 'alwaysApply: true']],
|
|
27
|
-
// 用户级 hooks
|
|
37
|
+
// 用户级 hooks 配置(中国版目录为 ~/.trae-cn/,项目级才是 .trae/)
|
|
28
38
|
settingsFile: path.join(os.homedir(), '.trae-cn', 'hooks.json'),
|
|
29
39
|
settingsFileIsUserLevel: true,
|
|
30
40
|
hookEvents: ['UserPromptSubmit'],
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkBuddy 适配器
|
|
3
|
+
*
|
|
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` 仅作为
|
|
8
|
+
* legacy 由安装流程迁移清理(legacyDirs / legacySettingsFile)。
|
|
9
|
+
*
|
|
10
|
+
* 与 Claude Code / Qoder 的映射差异:
|
|
11
|
+
* - rules:`.workbuddy/rules/*.md`(扁平文件、递归加载),frontmatter 用
|
|
12
|
+
* `alwaysApply: true`(Qoder 的 `trigger: always_on` 需改写,见 ruleRewrites)
|
|
13
|
+
* - skills:`.workbuddy/skills/<name>/SKILL.md`,结构与 Claude 同构
|
|
14
|
+
* - commands:`.workbuddy/commands/`,支持目录嵌套(`/group:command`),与 Claude 同风格
|
|
15
|
+
* - hooks:兼容 Claude Code Hooks 规范,settings 结构一致,直接复用 settingsManager
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
name: 'workbuddy',
|
|
23
|
+
displayName: 'WorkBuddy',
|
|
24
|
+
rulesDir: '.workbuddy/rules',
|
|
25
|
+
skillsDir: '.workbuddy/skills',
|
|
26
|
+
commandsDir: '.workbuddy/commands/opsx',
|
|
27
|
+
// 规则 frontmatter 改写:Qoder 风格 → WorkBuddy 风格
|
|
28
|
+
ruleRewrites: [['trigger: always_on', 'alwaysApply: true']],
|
|
29
|
+
// 用户级 settings,写入全局生效,不污染项目目录
|
|
30
|
+
settingsFile: path.join(os.homedir(), '.workbuddy', 'settings.json'),
|
|
31
|
+
settingsFileIsUserLevel: true,
|
|
32
|
+
hookEvents: ['UserPromptSubmit'],
|
|
33
|
+
// 旧版(beta.15 及以前按 CodeBuddy 装的 .codebuddy):安装时迁移清理
|
|
34
|
+
legacyDirs: ['.codebuddy'],
|
|
35
|
+
legacySettingsFile: path.join(os.homedir(), '.codebuddy', 'settings.json'),
|
|
36
|
+
};
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* - 加载 + 校验
|
|
9
9
|
* - 归一化 remote URL(兼容 SSH / HTTPS 两种写法)
|
|
10
10
|
* - 检测当前目录是否已拉取指定 workspace 的仓库
|
|
11
|
-
* - 空间种子文件生成(AGENTS.md 空间导航,仅缺失时)
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
13
|
const fs = require('fs');
|
|
@@ -16,8 +15,7 @@ const path = require('path');
|
|
|
16
15
|
const { execSync } = require('child_process');
|
|
17
16
|
|
|
18
17
|
const DEFAULT_CONFIG = 'config/workspaces.json';
|
|
19
|
-
const SAMPLE_CONFIG = 'config/
|
|
20
|
-
const SAMPLE_AGENTS_MD = 'config/workspace-agents.sample.md';
|
|
18
|
+
const SAMPLE_CONFIG = 'config/CBB-WORKSPACE.sample.json';
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
21
|
* 归一化 git remote URL:提取 "namespace/repo" 形式(去掉 .git 后缀)。
|
|
@@ -104,7 +102,7 @@ function loadWorkspaces(configPath = DEFAULT_CONFIG) {
|
|
|
104
102
|
}
|
|
105
103
|
|
|
106
104
|
/**
|
|
107
|
-
* 校验业务工作空间
|
|
105
|
+
* 校验业务工作空间 CBB-WORKSPACE.json 的格式是否合法。
|
|
108
106
|
*
|
|
109
107
|
* 校验项:
|
|
110
108
|
* - 文件存在且为合法 JSON
|
|
@@ -113,31 +111,31 @@ function loadWorkspaces(configPath = DEFAULT_CONFIG) {
|
|
|
113
111
|
* - name、repo 为非空字符串;side 必须为 'front'、'back' 或 'mixed'
|
|
114
112
|
* - desc 为可选字段;一旦出现必须是非空字符串(应用职责描述)
|
|
115
113
|
*
|
|
116
|
-
* @param {string} configPath
|
|
114
|
+
* @param {string} configPath CBB-WORKSPACE.json 的绝对路径
|
|
117
115
|
* @returns {{ valid: boolean, message?: string, config?: object }}
|
|
118
116
|
*/
|
|
119
117
|
function validateWorkspaceConfig(configPath) {
|
|
120
118
|
if (!fs.existsSync(configPath)) {
|
|
121
|
-
return { valid: false, message: `
|
|
119
|
+
return { valid: false, message: `CBB-WORKSPACE.json 不存在:${configPath}` };
|
|
122
120
|
}
|
|
123
121
|
|
|
124
122
|
let raw;
|
|
125
123
|
try {
|
|
126
124
|
raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
127
125
|
} catch (e) {
|
|
128
|
-
return { valid: false, message: `
|
|
126
|
+
return { valid: false, message: `CBB-WORKSPACE.json 不是合法 JSON:${e.message}` };
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
if (!raw || typeof raw !== 'object') {
|
|
132
|
-
return { valid: false, message: '
|
|
130
|
+
return { valid: false, message: 'CBB-WORKSPACE.json 内容应为 JSON 对象' };
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
if (!Array.isArray(raw.apps)) {
|
|
136
|
-
return { valid: false, message: '
|
|
134
|
+
return { valid: false, message: 'CBB-WORKSPACE.json 缺少 apps 数组' };
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
if (raw.apps.length === 0) {
|
|
140
|
-
return { valid: false, message: '
|
|
138
|
+
return { valid: false, message: 'CBB-WORKSPACE.json 中 apps 数组为空,请至少配置一个关联应用' };
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
const VALID_SIDES = ['front', 'back', 'mixed'];
|
|
@@ -146,69 +144,28 @@ function validateWorkspaceConfig(configPath) {
|
|
|
146
144
|
const label = `第 ${i + 1} 项`;
|
|
147
145
|
|
|
148
146
|
if (!app || typeof app !== 'object') {
|
|
149
|
-
return { valid: false, message: `
|
|
147
|
+
return { valid: false, message: `CBB-WORKSPACE.json ${label}不是对象` };
|
|
150
148
|
}
|
|
151
149
|
if (typeof app.name !== 'string' || !app.name.trim()) {
|
|
152
|
-
return { valid: false, message: `
|
|
150
|
+
return { valid: false, message: `CBB-WORKSPACE.json ${label}缺少 name(应用名)` };
|
|
153
151
|
}
|
|
154
152
|
if (typeof app.repo !== 'string' || !app.repo.trim()) {
|
|
155
|
-
return { valid: false, message: `
|
|
153
|
+
return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 缺少 repo(Git 仓库地址)` };
|
|
156
154
|
}
|
|
157
155
|
if (typeof app.side !== 'string' || !app.side.trim()) {
|
|
158
|
-
return { valid: false, message: `
|
|
156
|
+
return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 缺少 side(仓库类型,可选值:front / back / mixed)` };
|
|
159
157
|
}
|
|
160
158
|
if (!VALID_SIDES.includes(app.side.trim())) {
|
|
161
|
-
return { valid: false, message: `
|
|
159
|
+
return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 的 side 字段值无效:"${app.side}"(可选值:front / back / mixed)` };
|
|
162
160
|
}
|
|
163
161
|
if (app.desc !== undefined && (typeof app.desc !== 'string' || !app.desc.trim())) {
|
|
164
|
-
return { valid: false, message: `
|
|
162
|
+
return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 的 desc 字段应为非空字符串(该应用的职责描述),不需要可整条删除` };
|
|
165
163
|
}
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
return { valid: true, config: raw };
|
|
169
167
|
}
|
|
170
168
|
|
|
171
|
-
/**
|
|
172
|
-
* 确保业务空间根目录存在 AGENTS.md(空间导航文件,讲清目录职责与协作约定)。
|
|
173
|
-
*
|
|
174
|
-
* 仅缺失时从包内模板复制;已存在(可能含团队自维护内容)一律不覆盖。
|
|
175
|
-
* 该文件不登记安装清单,升级 / 卸载均不触碰。
|
|
176
|
-
*
|
|
177
|
-
* @param {string} targetDir 业务空间根目录
|
|
178
|
-
* @returns {'exists' | 'created'}
|
|
179
|
-
*/
|
|
180
|
-
function ensureWorkspaceAgentsMd(targetDir) {
|
|
181
|
-
const agentsPath = path.join(targetDir, 'AGENTS.md');
|
|
182
|
-
if (fs.existsSync(agentsPath)) return 'exists';
|
|
183
|
-
|
|
184
|
-
const samplePath = path.resolve(__dirname, '..', '..', '..', SAMPLE_AGENTS_MD);
|
|
185
|
-
fs.copyFileSync(samplePath, agentsPath);
|
|
186
|
-
return 'created';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// 旧版空间导航模板(0.0.3 单层安装改造前)的特征语句。
|
|
190
|
-
// 该文件归用户所有、永不覆盖,故只能提示用户删除后重跑 cbb update 重新生成。
|
|
191
|
-
const LEGACY_AGENTS_MD_MARKERS = [
|
|
192
|
-
'故意不含编码规范',
|
|
193
|
-
'自动安装沙箱内的编码规范',
|
|
194
|
-
];
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* 检测空间根 AGENTS.md 是否仍为旧版导航文案(命中任一特征语句即为旧版)。
|
|
198
|
-
* 仅用于安装时打印提示,不修改文件。
|
|
199
|
-
* @returns {boolean}
|
|
200
|
-
*/
|
|
201
|
-
function detectLegacyAgentsMd(targetDir) {
|
|
202
|
-
const agentsPath = path.join(targetDir, 'AGENTS.md');
|
|
203
|
-
if (!fs.existsSync(agentsPath)) return false;
|
|
204
|
-
try {
|
|
205
|
-
const content = fs.readFileSync(agentsPath, 'utf-8');
|
|
206
|
-
return LEGACY_AGENTS_MD_MARKERS.some(m => content.includes(m));
|
|
207
|
-
} catch (_) {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
169
|
/**
|
|
213
170
|
* 在指定目录执行 `git remote -v`,解析出 [{ name, url }] 列表。
|
|
214
171
|
* 任何异常静默返回空数组,便于上层用 state 机判定。
|
|
@@ -268,7 +225,7 @@ function extractRepoBasename(url) {
|
|
|
268
225
|
|
|
269
226
|
/**
|
|
270
227
|
* 判断 repo 是否为样例占位地址(RFC 2606 保留域名)。
|
|
271
|
-
* 样例
|
|
228
|
+
* 样例 CBB-WORKSPACE.json 的 repo 用 example.com 等占位,clone 必然失败;
|
|
272
229
|
* setup 据此逐条跳过空跑并给出明确编辑提示。
|
|
273
230
|
* 支持 SSH(git@host:path)与 URL(ssh://、https://、git://)两种形式的 host 提取。
|
|
274
231
|
*
|
|
@@ -302,13 +259,10 @@ function findSampleApps(apps) {
|
|
|
302
259
|
module.exports = {
|
|
303
260
|
DEFAULT_CONFIG,
|
|
304
261
|
SAMPLE_CONFIG,
|
|
305
|
-
SAMPLE_AGENTS_MD,
|
|
306
262
|
normalizeRepoUrl,
|
|
307
263
|
matchesConfiguredRepo,
|
|
308
264
|
loadWorkspaces,
|
|
309
265
|
validateWorkspaceConfig,
|
|
310
|
-
ensureWorkspaceAgentsMd,
|
|
311
|
-
detectLegacyAgentsMd,
|
|
312
266
|
readGitRemotes,
|
|
313
267
|
detectRepo,
|
|
314
268
|
extractRepoBasename,
|
|
@@ -23,19 +23,27 @@ 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
|
|
28
|
+
|| process.env.TRAE_CN_PROJECT_DIR
|
|
27
29
|
|| process.env.TRAE_PROJECT_DIR
|
|
28
30
|
|| process.env.QODER_PROJECT_DIR
|
|
31
|
+
// MiniMax 同时注入 MINIMAX_PROJECT_DIR 与 CLAUDE_PROJECT_DIR,专属变量优先
|
|
32
|
+
|| process.env.MINIMAX_PROJECT_DIR
|
|
29
33
|
|| process.env.CLAUDE_PROJECT_DIR
|
|
30
34
|
|| process.cwd();
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
/** 通过环境变量检测当前调用方对应的适配器名称 */
|
|
34
38
|
function detectAdapterName() {
|
|
35
|
-
// 兼容变量(CLAUDE_PROJECT_DIR)由 Trae /
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
// 兼容变量(CLAUDE_PROJECT_DIR)由 Trae / WorkBuddy / MiniMax 一并注入,故优先判定各自专属变量;
|
|
40
|
+
// CODEBUDDY_PROJECT_DIR 为 WorkBuddy 沿用的历史变量名,一并识别为 workbuddy;
|
|
41
|
+
// TRAE_CN_PROJECT_DIR / TRAE_PROJECT_DIR 为中国版 Trae 的变量名(不同版本注入不一),均识别为 trae;
|
|
42
|
+
// MINIMAX_PROJECT_DIR 为 MiniMax Code 专属变量(插件 hook 注入,与 CLAUDE_PROJECT_DIR 同时存在)
|
|
43
|
+
if (process.env.WORKBUDDY_PROJECT_DIR || process.env.CODEBUDDY_PROJECT_DIR) return 'workbuddy';
|
|
44
|
+
if (process.env.TRAE_CN_PROJECT_DIR || process.env.TRAE_PROJECT_DIR) return 'trae';
|
|
38
45
|
if (process.env.QODER_PROJECT_DIR) return 'qoder';
|
|
46
|
+
if (process.env.MINIMAX_PROJECT_DIR) return 'minimax';
|
|
39
47
|
if (process.env.CLAUDE_PROJECT_DIR) return 'claude-code';
|
|
40
48
|
return null;
|
|
41
49
|
}
|
|
@@ -141,7 +149,7 @@ async function main() {
|
|
|
141
149
|
process.stdout.write(Buffer.from(JSON.stringify({
|
|
142
150
|
hookSpecificOutput: {
|
|
143
151
|
hookEventName: 'UserPromptSubmit',
|
|
144
|
-
additionalContext: `[系统提示] 检测到 ${message}\n
|
|
152
|
+
additionalContext: `[系统提示] 检测到 ${message}\n请用一句话友好地提醒用户,且必须以「你正在使用的团队AI开发规范CBB有新版本可升级」开头,并给出上面的升级命令。`,
|
|
145
153
|
},
|
|
146
154
|
}) + '\n', 'utf8'));
|
|
147
155
|
cache.notifiedSessions[notifiedKey] = sessionId;
|