@jspg-ai/coding-bb 0.0.3-beta.3 → 0.0.3-beta.6
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/codebuddy.js +32 -0
- package/cbb/lib/install/init.js +81 -27
- package/cbb/lib/install/opencode.js +2 -0
- package/cbb/lib/install/rule-rewrite.js +27 -0
- package/cbb/lib/install/trae.js +35 -0
- 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/worktrees/commands/worktree-close.md +4 -5
- package/cbb/worktrees/commands/worktree-init.md +4 -5
- package/cbb/worktrees/commands/worktree-push.md +1 -1
- package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +7 -7
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +12 -12
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +6 -6
- package/config/workspace-agents.sample.md +41 -39
- package/package.json +2 -2
|
@@ -1,117 +1,119 @@
|
|
|
1
|
-
---
|
|
2
|
-
trigger: always_on
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# AI 行为准则
|
|
6
|
-
|
|
7
|
-
七条行为准则,减少 AI 编码常见错误。源自 [Andrej Karpathy 对 LLM 编码缺陷的观察](https://x.com/karpathy/status/2015883857489522876)。
|
|
8
|
-
|
|
9
|
-
**权衡:** 这些准则倾向于谨慎而非速度。对于简单任务(如修 typo、改文案),按常识判断即可。
|
|
10
|
-
|
|
11
|
-
## 1. 先想后写
|
|
12
|
-
|
|
13
|
-
**不假设,不隐藏困惑,主动呈现权衡。**
|
|
14
|
-
|
|
15
|
-
实现前:
|
|
16
|
-
- 明确声明假设,不确定时主动询问
|
|
17
|
-
- 若存在多种解释,呈现出来而非自己默默选一种
|
|
18
|
-
- 若有更简单的方案,说出来,必要时 push back
|
|
19
|
-
- 若有不明确的地方,停下来,说出困惑,请求澄清
|
|
20
|
-
|
|
21
|
-
## 2. 简洁至上
|
|
22
|
-
|
|
23
|
-
**用最少代码解决问题,不加推测性内容。**
|
|
24
|
-
|
|
25
|
-
- 不实现用户未要求的功能
|
|
26
|
-
- 不为单次使用的代码创建抽象
|
|
27
|
-
- 不添加用户未要求的"灵活性"或"可配置性"
|
|
28
|
-
- 不为不可能发生的场景写错误处理
|
|
29
|
-
- 写了 200 行却发现 50 行就能搞定 → 重写
|
|
30
|
-
|
|
31
|
-
自问:"资深工程师会说过度设计吗?"如果会,简化。
|
|
32
|
-
|
|
33
|
-
## 3. 外科手术式修改
|
|
34
|
-
|
|
35
|
-
**只改必须改的,只清理自己造成的烂摊子。**
|
|
36
|
-
|
|
37
|
-
编辑已有代码时:
|
|
38
|
-
- 不顺手"改进"相邻代码、注释或格式
|
|
39
|
-
- 不重构没坏的东西
|
|
40
|
-
- 匹配现有风格,即使你更习惯另一种写法
|
|
41
|
-
- 发现无关的死代码,口头提及即可,不要删除
|
|
42
|
-
|
|
43
|
-
当你的改动产生孤儿代码时:
|
|
44
|
-
- 删除因你的改动而不再使用的 import / 变量 / 函数
|
|
45
|
-
- 不删除已有的死代码,除非用户要求
|
|
46
|
-
|
|
47
|
-
**检验标准:** 每一行改动都应该能追溯到用户的需求。
|
|
48
|
-
|
|
49
|
-
## 4. 目标驱动执行
|
|
50
|
-
|
|
51
|
-
**定义成功标准,循环直到验证通过。**
|
|
52
|
-
|
|
53
|
-
将命令式任务转换为可验证的目标:
|
|
54
|
-
|
|
55
|
-
| 而非… | 转换为… |
|
|
56
|
-
|--------|---------|
|
|
57
|
-
| "加个校验" | "先写无效输入的测试,再让测试通过" |
|
|
58
|
-
| "修这个 bug" | "先写能复现的测试,再修到测试通过" |
|
|
59
|
-
| "重构 X" | "确保重构前后测试全部通过" |
|
|
60
|
-
|
|
61
|
-
多步任务先给简短计划:
|
|
62
|
-
```
|
|
63
|
-
1. [步骤] → 验证: [检查项]
|
|
64
|
-
2. [步骤] → 验证: [检查项]
|
|
65
|
-
3. [步骤] → 验证: [检查项]
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
清晰的成功标准让 AI 可以独立循环验证,模糊的标准("搞一下")需要反复澄清。
|
|
69
|
-
|
|
70
|
-
## 5. 失败要大声说出来
|
|
71
|
-
|
|
72
|
-
**悄悄绕过失败比直接失败更糟糕。**
|
|
73
|
-
|
|
74
|
-
- 有步骤被跳过,"完成"就是错的——说出来
|
|
75
|
-
- 有测试被跳过,"测试通过"就是错的——说出来
|
|
76
|
-
- 不确定就直接说不确定,不假装确认
|
|
77
|
-
- 默认暴露不确定性,不掩盖
|
|
78
|
-
|
|
79
|
-
**检验标准:** 任何跳过的步骤、不确定的结论、未验证的结果,都以标记形式呈现,不悄悄带过。
|
|
80
|
-
|
|
81
|
-
## 6. 不认同也要说出来
|
|
82
|
-
|
|
83
|
-
当项目现有约定明显有问题时:
|
|
84
|
-
|
|
85
|
-
- 照样遵循,保持一致——不悄悄另起炉灶
|
|
86
|
-
- 明确提出来——指出风险,给出替代方案
|
|
87
|
-
- 让用户做决策,不要替用户做选择
|
|
88
|
-
|
|
89
|
-
**检验标准:** 你的代码放进现有代码中,读不出"换了一个人写的"。发现的问题以建议形式呈现,而非悄悄用另一种方式实现。
|
|
90
|
-
|
|
91
|
-
## 7. 先批准,后动工
|
|
92
|
-
|
|
93
|
-
**任何实现动作前,先陈述方案并获得用户批准。**
|
|
94
|
-
|
|
95
|
-
- 动手前说出打算怎么做(方案、涉及文件、验证方式),等用户确认
|
|
96
|
-
- 仪式随任务缩放:小改动两三句话说清即可;大改动走 openspec 工作流(propose → specs → design)
|
|
97
|
-
- "太简单不需要方案"是最危险的念头——简单意味着方案短,而不是没有方案
|
|
98
|
-
- 中途发现复杂度超出预期:停下来重新说明,不要闷头扩大改动范围
|
|
99
|
-
|
|
100
|
-
**检验标准:** 用户从未因"AI 直接改了代码没打招呼"而感到意外。
|
|
101
|
-
|
|
102
|
-
## 8. 业务空间目录纪律
|
|
103
|
-
|
|
104
|
-
**仅当工作目录是业务空间根(存在 `workspace-config.json`)时生效:写操作命令必须落在需求工作树内。**
|
|
105
|
-
|
|
106
|
-
业务空间根(主分支)只负责组织与调度,不做需求开发。接到需求先建工作树(`/cbb:worktree-init` 或 `/cbb-worktree-init`),之后:
|
|
107
|
-
|
|
108
|
-
- 一切产生写操作的命令(git commit / openspec / 构建 / 测试 / 文件修改)必须以 `.worktrees/worktree-<需求名>/`(或其应用子目录)为工作目录:显式 `cd` 或绝对路径
|
|
109
|
-
- 禁止在空间根执行写操作:不在主分支提交代码、不在空间根创建 openspec 变更产物、不改 `.codespace/` 基准代码
|
|
110
|
-
- 只读命令(git status / log、查看文件)在空间根执行无妨
|
|
111
|
-
- 会话开始时确认本次需求对应的工作树路径;存在多个未完成工作树时,先与用户确认目标,不要猜
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# AI 行为准则
|
|
6
|
+
|
|
7
|
+
七条行为准则,减少 AI 编码常见错误。源自 [Andrej Karpathy 对 LLM 编码缺陷的观察](https://x.com/karpathy/status/2015883857489522876)。
|
|
8
|
+
|
|
9
|
+
**权衡:** 这些准则倾向于谨慎而非速度。对于简单任务(如修 typo、改文案),按常识判断即可。
|
|
10
|
+
|
|
11
|
+
## 1. 先想后写
|
|
12
|
+
|
|
13
|
+
**不假设,不隐藏困惑,主动呈现权衡。**
|
|
14
|
+
|
|
15
|
+
实现前:
|
|
16
|
+
- 明确声明假设,不确定时主动询问
|
|
17
|
+
- 若存在多种解释,呈现出来而非自己默默选一种
|
|
18
|
+
- 若有更简单的方案,说出来,必要时 push back
|
|
19
|
+
- 若有不明确的地方,停下来,说出困惑,请求澄清
|
|
20
|
+
|
|
21
|
+
## 2. 简洁至上
|
|
22
|
+
|
|
23
|
+
**用最少代码解决问题,不加推测性内容。**
|
|
24
|
+
|
|
25
|
+
- 不实现用户未要求的功能
|
|
26
|
+
- 不为单次使用的代码创建抽象
|
|
27
|
+
- 不添加用户未要求的"灵活性"或"可配置性"
|
|
28
|
+
- 不为不可能发生的场景写错误处理
|
|
29
|
+
- 写了 200 行却发现 50 行就能搞定 → 重写
|
|
30
|
+
|
|
31
|
+
自问:"资深工程师会说过度设计吗?"如果会,简化。
|
|
32
|
+
|
|
33
|
+
## 3. 外科手术式修改
|
|
34
|
+
|
|
35
|
+
**只改必须改的,只清理自己造成的烂摊子。**
|
|
36
|
+
|
|
37
|
+
编辑已有代码时:
|
|
38
|
+
- 不顺手"改进"相邻代码、注释或格式
|
|
39
|
+
- 不重构没坏的东西
|
|
40
|
+
- 匹配现有风格,即使你更习惯另一种写法
|
|
41
|
+
- 发现无关的死代码,口头提及即可,不要删除
|
|
42
|
+
|
|
43
|
+
当你的改动产生孤儿代码时:
|
|
44
|
+
- 删除因你的改动而不再使用的 import / 变量 / 函数
|
|
45
|
+
- 不删除已有的死代码,除非用户要求
|
|
46
|
+
|
|
47
|
+
**检验标准:** 每一行改动都应该能追溯到用户的需求。
|
|
48
|
+
|
|
49
|
+
## 4. 目标驱动执行
|
|
50
|
+
|
|
51
|
+
**定义成功标准,循环直到验证通过。**
|
|
52
|
+
|
|
53
|
+
将命令式任务转换为可验证的目标:
|
|
54
|
+
|
|
55
|
+
| 而非… | 转换为… |
|
|
56
|
+
|--------|---------|
|
|
57
|
+
| "加个校验" | "先写无效输入的测试,再让测试通过" |
|
|
58
|
+
| "修这个 bug" | "先写能复现的测试,再修到测试通过" |
|
|
59
|
+
| "重构 X" | "确保重构前后测试全部通过" |
|
|
60
|
+
|
|
61
|
+
多步任务先给简短计划:
|
|
62
|
+
```
|
|
63
|
+
1. [步骤] → 验证: [检查项]
|
|
64
|
+
2. [步骤] → 验证: [检查项]
|
|
65
|
+
3. [步骤] → 验证: [检查项]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
清晰的成功标准让 AI 可以独立循环验证,模糊的标准("搞一下")需要反复澄清。
|
|
69
|
+
|
|
70
|
+
## 5. 失败要大声说出来
|
|
71
|
+
|
|
72
|
+
**悄悄绕过失败比直接失败更糟糕。**
|
|
73
|
+
|
|
74
|
+
- 有步骤被跳过,"完成"就是错的——说出来
|
|
75
|
+
- 有测试被跳过,"测试通过"就是错的——说出来
|
|
76
|
+
- 不确定就直接说不确定,不假装确认
|
|
77
|
+
- 默认暴露不确定性,不掩盖
|
|
78
|
+
|
|
79
|
+
**检验标准:** 任何跳过的步骤、不确定的结论、未验证的结果,都以标记形式呈现,不悄悄带过。
|
|
80
|
+
|
|
81
|
+
## 6. 不认同也要说出来
|
|
82
|
+
|
|
83
|
+
当项目现有约定明显有问题时:
|
|
84
|
+
|
|
85
|
+
- 照样遵循,保持一致——不悄悄另起炉灶
|
|
86
|
+
- 明确提出来——指出风险,给出替代方案
|
|
87
|
+
- 让用户做决策,不要替用户做选择
|
|
88
|
+
|
|
89
|
+
**检验标准:** 你的代码放进现有代码中,读不出"换了一个人写的"。发现的问题以建议形式呈现,而非悄悄用另一种方式实现。
|
|
90
|
+
|
|
91
|
+
## 7. 先批准,后动工
|
|
92
|
+
|
|
93
|
+
**任何实现动作前,先陈述方案并获得用户批准。**
|
|
94
|
+
|
|
95
|
+
- 动手前说出打算怎么做(方案、涉及文件、验证方式),等用户确认
|
|
96
|
+
- 仪式随任务缩放:小改动两三句话说清即可;大改动走 openspec 工作流(propose → specs → design)
|
|
97
|
+
- "太简单不需要方案"是最危险的念头——简单意味着方案短,而不是没有方案
|
|
98
|
+
- 中途发现复杂度超出预期:停下来重新说明,不要闷头扩大改动范围
|
|
99
|
+
|
|
100
|
+
**检验标准:** 用户从未因"AI 直接改了代码没打招呼"而感到意外。
|
|
101
|
+
|
|
102
|
+
## 8. 业务空间目录纪律
|
|
103
|
+
|
|
104
|
+
**仅当工作目录是业务空间根(存在 `workspace-config.json`)时生效:写操作命令必须落在需求工作树内。**
|
|
105
|
+
|
|
106
|
+
业务空间根(主分支)只负责组织与调度,不做需求开发。接到需求先建工作树(`/cbb:worktree-init` 或 `/cbb-worktree-init`),之后:
|
|
107
|
+
|
|
108
|
+
- 一切产生写操作的命令(git commit / openspec / 构建 / 测试 / 文件修改)必须以 `.worktrees/worktree-<需求名>/`(或其应用子目录)为工作目录:显式 `cd` 或绝对路径
|
|
109
|
+
- 禁止在空间根执行写操作:不在主分支提交代码、不在空间根创建 openspec 变更产物、不改 `.codespace/` 基准代码
|
|
110
|
+
- 只读命令(git status / log、查看文件)在空间根执行无妨
|
|
111
|
+
- 会话开始时确认本次需求对应的工作树路径;存在多个未完成工作树时,先与用户确认目标,不要猜
|
|
112
|
+
|
|
113
|
+
**会话与工作目录是两回事:** AI 会话窗口始终停在**空间根**(worktree 内不装 AI 配置,无工作流命令),`/opsx:*` 等命令仍在空间根会话发起;只是**产生写操作的工作目录**指向需求工作树(显式 `cd` 或绝对路径)。不要把会话切到 worktree 内,也不要因「在 worktree 内开发」就在空间根直接动手。
|
|
114
|
+
|
|
115
|
+
**检验标准:** 空间根主分支的 `git status` 永远干净(除工具维护的配置文件外),openspec 变更产物只出现在需求工作树内。
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
117
119
|
**这些准则生效的标志:** diff 中不必要的改动减少、不会因过度设计而重写、澄清问题在实现前而非出错后提出。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkBuddy / CodeBuddy 适配器
|
|
3
|
+
*
|
|
4
|
+
* 腾讯 WorkBuddy 桌面工作台与 CodeBuddy IDE / CLI 共用项目级配置目录 `.codebuddy/`,
|
|
5
|
+
* 故一个适配器同时覆盖两者。
|
|
6
|
+
*
|
|
7
|
+
* 与 Claude Code / Qoder 的映射差异:
|
|
8
|
+
* - rules:`.codebuddy/rules/*.md`(扁平文件、递归加载),frontmatter 用
|
|
9
|
+
* `alwaysApply: true`(Qoder 的 `trigger: always_on` 需改写,见 ruleRewrites)
|
|
10
|
+
* - skills:`.codebuddy/skills/<name>/SKILL.md`,结构与 Claude 同构
|
|
11
|
+
* - commands:`.codebuddy/commands/`,支持目录嵌套(`/group:command`),与 Claude 同风格
|
|
12
|
+
* - hooks:完全兼容 Claude Code Hooks 规范,settings 结构一致,直接复用 settingsManager
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
name: 'codebuddy',
|
|
20
|
+
displayName: 'WorkBuddy(CodeBuddy)',
|
|
21
|
+
rulesDir: '.codebuddy/rules',
|
|
22
|
+
skillsDir: '.codebuddy/skills',
|
|
23
|
+
commandsDir: '.codebuddy/commands/opsx',
|
|
24
|
+
// worktree 管理命令(非 openspec 上游):独立命名空间 /cbb:worktree-*
|
|
25
|
+
worktreeCommandsDir: '.codebuddy/commands/cbb',
|
|
26
|
+
// 规则 frontmatter 改写:Qoder 风格 → CodeBuddy 风格
|
|
27
|
+
ruleRewrites: [['trigger: always_on', 'alwaysApply: true']],
|
|
28
|
+
// 用户级 settings,写入全局生效,不污染项目目录
|
|
29
|
+
settingsFile: path.join(os.homedir(), '.codebuddy', 'settings.json'),
|
|
30
|
+
settingsFileIsUserLevel: true,
|
|
31
|
+
hookEvents: ['UserPromptSubmit'],
|
|
32
|
+
};
|
package/cbb/lib/install/init.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* OpenSpec Shared Standards 安装脚本
|
|
5
5
|
*
|
|
6
6
|
* 将AI 编码规范与工作流套件安装到目标项目中。
|
|
7
|
-
* 支持工具:Claude Code (.claude/rules/)、Qoder (.qoder/rules/)、opencode (.opencode/rules/)
|
|
7
|
+
* 支持工具:Claude Code (.claude/rules/)、Qoder (.qoder/rules/)、opencode (.opencode/rules/)、
|
|
8
|
+
* WorkBuddy/CodeBuddy (.codebuddy/rules/)、TraeWork/TraeCode (.trae/rules/)
|
|
8
9
|
*
|
|
9
10
|
* 使用方式:
|
|
10
11
|
* npm install -g @jspg-ai/coding-bb # 首次使用
|
|
@@ -51,10 +52,13 @@ const MANIFEST_FILE = path.join(MANIFEST_DIR, '.managed-by-cbb');
|
|
|
51
52
|
const LAST_TOOLS_FILE = path.join(MANIFEST_DIR, '.last-tools');
|
|
52
53
|
|
|
53
54
|
// 适配器
|
|
55
|
+
// 适配器(数组顺序 = 工具选择面板的显示顺序)
|
|
54
56
|
const adapters = [
|
|
55
|
-
require('./claude-code'),
|
|
56
|
-
require('./qoder'),
|
|
57
57
|
require('./opencode'),
|
|
58
|
+
require('./codebuddy'),
|
|
59
|
+
require('./trae'),
|
|
60
|
+
require('./qoder'),
|
|
61
|
+
require('./claude-code'),
|
|
58
62
|
];
|
|
59
63
|
|
|
60
64
|
// superpowers 部署白名单:仅装 openspec 工作流硬依赖 + 方法论基底(源仓库仍保留全量 14 个,
|
|
@@ -68,8 +72,8 @@ const SUPERPOWERS_WHITELIST = [
|
|
|
68
72
|
'test-driven-development', // TDD 计划结构 + TDD Evidence 方法论基底
|
|
69
73
|
];
|
|
70
74
|
|
|
71
|
-
// worktree
|
|
72
|
-
//
|
|
75
|
+
// worktree 运行时部署清单:init / close / push 三件套(SKILL.md + scripts),
|
|
76
|
+
// 部署到 .cbb/skills/<name>/(每空间一份,不分工具;命令文件统一指向此处)
|
|
73
77
|
const WORKTREE_SKILLS = ['cbb-worktree-init', 'cbb-worktree-close', 'cbb-worktree-push'];
|
|
74
78
|
|
|
75
79
|
// 装到空间的 tools skills:当前不分发。
|
|
@@ -83,9 +87,17 @@ const OPENSPEC_COMMANDS_EXCLUDE = ['onboard.md'];
|
|
|
83
87
|
// settings.json hook 工具
|
|
84
88
|
const settingsManager = require('../utils/settings');
|
|
85
89
|
|
|
90
|
+
/** 适配器的 hook 方言参数(Trae 需顶层 version 字段等差异) */
|
|
91
|
+
function hookOpts(adapter) {
|
|
92
|
+
return adapter.hookDialect ? { dialect: adapter.hookDialect } : {};
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
// 清单驱动的文件清理决策(保护用户文档 CLAUDE.md / AGENTS.md 等)
|
|
87
96
|
const { pathsToDelete, protectedKeptPaths } = require('./cleanup');
|
|
88
97
|
|
|
98
|
+
// 规则 frontmatter 改写(Trae/CodeBuddy 需 alwaysApply: true)
|
|
99
|
+
const { applyRuleRewrites } = require('./rule-rewrite');
|
|
100
|
+
|
|
89
101
|
// .gitignore 条目决策(纯函数:检测/写入/卸载移除)
|
|
90
102
|
const gitignore = require('../utils/gitignore');
|
|
91
103
|
|
|
@@ -306,7 +318,8 @@ function deployCoreRules(adapter, isUpgrade, managedPaths) {
|
|
|
306
318
|
// 同名文件存在时直接覆盖
|
|
307
319
|
removePath(destPath);
|
|
308
320
|
|
|
309
|
-
|
|
321
|
+
const content = applyRuleRewrites(adapter, fs.readFileSync(srcPath, 'utf-8'));
|
|
322
|
+
fs.writeFileSync(destPath, content);
|
|
310
323
|
}
|
|
311
324
|
});
|
|
312
325
|
|
|
@@ -560,18 +573,41 @@ function deployCommandFiles(adapter, srcDir, destDir, prefix, filter) {
|
|
|
560
573
|
const srcPath = path.join(srcDir, f);
|
|
561
574
|
const destPath = path.join(destDir, prefix + f);
|
|
562
575
|
removePath(destPath);
|
|
563
|
-
const content = sanitizeCommandFrontmatter(applyContentRewrites(adapter, fs.readFileSync(srcPath, 'utf-8')));
|
|
576
|
+
const content = rewriteCommandName(adapter, sanitizeCommandFrontmatter(applyContentRewrites(adapter, fs.readFileSync(srcPath, 'utf-8'))));
|
|
564
577
|
fs.writeFileSync(destPath, content);
|
|
565
578
|
});
|
|
566
579
|
|
|
567
580
|
return { count: commandFiles.length, names: commandFiles.map(f => prefix + f) };
|
|
568
581
|
}
|
|
569
582
|
|
|
583
|
+
/**
|
|
584
|
+
* worktree 运行时部署:SKILL.md + scripts 复制到 .cbb/skills/<name>/(每空间一份,不分工具)。
|
|
585
|
+
* 单形态 command 收敛后,worktree 不进各工具的 skills 目录——新版工具会把 skills 暴露成
|
|
586
|
+
* 斜杠命令,与命令文件在面板里重复;脚本与流程文档统一放 .cbb/skills/,命令文件指向此处。
|
|
587
|
+
*/
|
|
588
|
+
function deployWorktreeRuntime(newPaths) {
|
|
589
|
+
const srcDir = path.join(SHARED_STANDARDS_DIR, 'cbb', 'worktrees', 'skills');
|
|
590
|
+
if (!fs.existsSync(srcDir)) return 0;
|
|
591
|
+
const runtimeDir = path.join(TARGET_DIR, '.cbb', 'skills');
|
|
592
|
+
fs.mkdirSync(runtimeDir, { recursive: true });
|
|
593
|
+
let count = 0;
|
|
594
|
+
WORKTREE_SKILLS.forEach(name => {
|
|
595
|
+
const src = path.join(srcDir, name);
|
|
596
|
+
if (!fs.existsSync(src)) return;
|
|
597
|
+
const destDir = path.join(runtimeDir, name);
|
|
598
|
+
removePath(destDir);
|
|
599
|
+
fs.cpSync(src, destDir, { recursive: true });
|
|
600
|
+
newPaths.add(`.cbb/skills/${name}`);
|
|
601
|
+
count++;
|
|
602
|
+
});
|
|
603
|
+
return count;
|
|
604
|
+
}
|
|
605
|
+
|
|
570
606
|
/**
|
|
571
607
|
* 命令 frontmatter 消毒:opencode 新版校验命令配置(description 必须为 string | undefined),
|
|
572
608
|
* 上游个别命令(openspec/commands/update.md)的 description 为空值(YAML 解析为 null),
|
|
573
|
-
* 会导致 opencode
|
|
574
|
-
*
|
|
609
|
+
* 会导致 opencode 拒绝加载整个项目配置。此处对部署副本回填正文首句作为描述
|
|
610
|
+
* (超过 120 字截断),上游源文件不动(CLI 接管区)。
|
|
575
611
|
*/
|
|
576
612
|
function sanitizeCommandFrontmatter(content) {
|
|
577
613
|
const lines = content.split('\n');
|
|
@@ -581,16 +617,38 @@ function sanitizeCommandFrontmatter(content) {
|
|
|
581
617
|
if ((lines[i] || '').trim() === '---') { end = i; break; }
|
|
582
618
|
}
|
|
583
619
|
if (end === -1) return content;
|
|
620
|
+
let sentence = '';
|
|
621
|
+
for (let i = end + 1; i < lines.length; i++) {
|
|
622
|
+
const t = (lines[i] || '').trim();
|
|
623
|
+
if (t) { sentence = t; break; }
|
|
624
|
+
}
|
|
584
625
|
let changed = false;
|
|
585
626
|
for (let i = 1; i < end; i++) {
|
|
586
627
|
if (/^description:\s*(null|~)?\s*\r?$/.test(lines[i])) {
|
|
587
|
-
|
|
628
|
+
if (sentence) {
|
|
629
|
+
if (sentence.length > 120) sentence = sentence.slice(0, 117) + '...';
|
|
630
|
+
lines[i] = 'description: ' + JSON.stringify(sentence) + (lines[i].endsWith('\r') ? '\r' : '');
|
|
631
|
+
} else {
|
|
632
|
+
lines[i] = null; // 无正文可回填则移除(undefined 同样合法)
|
|
633
|
+
}
|
|
588
634
|
changed = true;
|
|
589
635
|
}
|
|
590
636
|
}
|
|
591
637
|
return changed ? lines.filter(l => l !== null).join('\n') : content;
|
|
592
638
|
}
|
|
593
639
|
|
|
640
|
+
/**
|
|
641
|
+
* opencode 命令显示名取自 frontmatter name,上游为大写空格风格("OPSX: Propose"),
|
|
642
|
+
* 与文档写法(/opsx-propose)不一致;部署副本统一重写为 kebab-case。
|
|
643
|
+
*/
|
|
644
|
+
function rewriteCommandName(adapter, content) {
|
|
645
|
+
if (!adapter.commandNameKebab) return content;
|
|
646
|
+
return content.replace(/^name:\s*"?([A-Za-z]+):\s*([^"\r\n]+?)"?\s*\r?$/m, (m0, ns, rest) => {
|
|
647
|
+
const kebab = (ns + '-' + rest).toLowerCase().replace(/\s+/g, '-');
|
|
648
|
+
return `name: "${kebab}"`;
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
|
|
594
652
|
/** 官方 OpenSpec 命令(openspec/commands/ → adapter.commandsDir) */
|
|
595
653
|
function deployCommands(adapter, isUpgrade, managedPaths, srcDir, filter) {
|
|
596
654
|
if (!adapter.commandsDir) return { count: 0, names: [] };
|
|
@@ -969,11 +1027,10 @@ async function init(targetDir, options = {}) {
|
|
|
969
1027
|
if (skillsAdapters.length > 0) {
|
|
970
1028
|
console.log(`\n 🔧 ${action}按需加载 Skills...`);
|
|
971
1029
|
const standardsSkillsSrc = path.join(SHARED_STANDARDS_DIR, 'cbb', 'dev-standards', 'skills');
|
|
972
|
-
const openspecExtendsSkillsSrc = path.join(SHARED_STANDARDS_DIR, 'cbb', 'worktrees', 'skills');
|
|
973
1030
|
const extendsSkillsSrc = path.join(SHARED_STANDARDS_DIR, 'cbb', 'tools');
|
|
974
1031
|
|
|
975
1032
|
const skillsDests = skillsAdapters.map(a => a.skillsDir);
|
|
976
|
-
let stdCount = 0,
|
|
1033
|
+
let stdCount = 0, extCount = 0;
|
|
977
1034
|
skillsAdapters.forEach(adapter => {
|
|
978
1035
|
// 通用编码规范 Skills(cbb/dev-standards/skills)
|
|
979
1036
|
const stdResult = deploySkills(adapter, isUpgrade, managedPaths, standardsSkillsSrc);
|
|
@@ -983,12 +1040,6 @@ async function init(targetDir, options = {}) {
|
|
|
983
1040
|
}
|
|
984
1041
|
// 官方 OpenSpec Skills(openspec/skills/)不部署——工作流入口统一为 /opsx:* 斜杠命令
|
|
985
1042
|
//(openspec/commands/ 在下方 Commands 段部署),避免双形态重复
|
|
986
|
-
// worktree 扩展 Skills:init / close / push 三件套(单层安装,空间根是唯一安装点)
|
|
987
|
-
const osExtResult = deploySkills(adapter, isUpgrade, managedPaths, openspecExtendsSkillsSrc, WORKTREE_SKILLS);
|
|
988
|
-
if (osExtResult.count > 0) {
|
|
989
|
-
osCount = osExtResult.count;
|
|
990
|
-
osExtResult.names.forEach(name => newPaths.add(`${adapter.skillsDir}/${name}`));
|
|
991
|
-
}
|
|
992
1043
|
// 工具 Skills:当前不分发(恢复方式见 TOOLS_SKILLS 注释)
|
|
993
1044
|
const extResult = deploySkills(adapter, isUpgrade, managedPaths, extendsSkillsSrc, TOOLS_SKILLS);
|
|
994
1045
|
if (extResult.count > 0) {
|
|
@@ -997,7 +1048,6 @@ async function init(targetDir, options = {}) {
|
|
|
997
1048
|
}
|
|
998
1049
|
});
|
|
999
1050
|
if (stdCount > 0) log(`规范 Skills → ${skillsDests.join(', ')} (${stdCount} 个)`, 'success');
|
|
1000
|
-
if (osCount > 0) log(`worktree Skills → ${skillsDests.join(', ')} (${osCount} 个)`, 'success');
|
|
1001
1051
|
if (extCount > 0) log(`扩展 Skills → ${skillsDests.join(', ')} (${extCount} 个)`, 'success');
|
|
1002
1052
|
|
|
1003
1053
|
// 部署 Superpowers Skills(白名单:openspec 工作流依赖 + 方法论基底)
|
|
@@ -1021,6 +1071,10 @@ async function init(targetDir, options = {}) {
|
|
|
1021
1071
|
await detectUserLevelSuperpowers(selectedAdapters, yes);
|
|
1022
1072
|
}
|
|
1023
1073
|
|
|
1074
|
+
// worktree 运行时(SKILL.md + scripts)→ .cbb/skills/(每空间一份,不分工具)
|
|
1075
|
+
const runtimeCount = deployWorktreeRuntime(newPaths);
|
|
1076
|
+
if (runtimeCount > 0) log(`worktree 运行时 → .cbb/skills (${runtimeCount} 个)`, 'success');
|
|
1077
|
+
|
|
1024
1078
|
// 安装 Commands(官方 11 个 → /opsx:*,onboard 不分发;worktree 管理 → /cbb:worktree-*,init/close/push 三件套)
|
|
1025
1079
|
const commandsAdapters = selectedAdapters.filter(a => a.commandsDir);
|
|
1026
1080
|
if (commandsAdapters.length > 0) {
|
|
@@ -1087,9 +1141,9 @@ async function init(targetDir, options = {}) {
|
|
|
1087
1141
|
const settingsPath = adapter.settingsFileIsUserLevel
|
|
1088
1142
|
? adapter.settingsFile
|
|
1089
1143
|
: path.join(TARGET_DIR, adapter.settingsFile);
|
|
1090
|
-
settingsManager.addHooks(settingsPath, command, adapter.hookEvents);
|
|
1144
|
+
settingsManager.addHooks(settingsPath, command, adapter.hookEvents, hookOpts(adapter));
|
|
1091
1145
|
// 清理旧版本遗留的 SessionStart hook(现已仅安装 UserPromptSubmit)
|
|
1092
|
-
if (settingsManager.removeLegacyHooks(settingsPath)) {
|
|
1146
|
+
if (settingsManager.removeLegacyHooks(settingsPath, hookOpts(adapter))) {
|
|
1093
1147
|
log(`清理 ${adapter.displayName} 遗留的 SessionStart hook`, 'success');
|
|
1094
1148
|
}
|
|
1095
1149
|
if (!adapter.settingsFileIsUserLevel) newPaths.add(adapter.settingsFile);
|
|
@@ -1698,8 +1752,8 @@ async function setupUserLevelComponents(targetAdapters = adapters) {
|
|
|
1698
1752
|
if (hookAdapters.length > 0) {
|
|
1699
1753
|
const command = settingsManager.getCheckUpdateCommand();
|
|
1700
1754
|
hookAdapters.forEach(adapter => {
|
|
1701
|
-
settingsManager.addHooks(adapter.settingsFile, command, adapter.hookEvents);
|
|
1702
|
-
settingsManager.removeLegacyHooks(adapter.settingsFile);
|
|
1755
|
+
settingsManager.addHooks(adapter.settingsFile, command, adapter.hookEvents, hookOpts(adapter));
|
|
1756
|
+
settingsManager.removeLegacyHooks(adapter.settingsFile, hookOpts(adapter));
|
|
1703
1757
|
});
|
|
1704
1758
|
summaryParts.push(`版本检查 hook → ${hookAdapters.map(a => a.displayName).join('、')}`);
|
|
1705
1759
|
}
|
|
@@ -1815,7 +1869,7 @@ async function uninstallUserLevelComponents() {
|
|
|
1815
1869
|
// 移除版本检查 hook(保留用户其余配置)
|
|
1816
1870
|
adapters.forEach(adapter => {
|
|
1817
1871
|
if (!adapter.settingsFile || !adapter.hookEvents) return;
|
|
1818
|
-
if (settingsManager.removeHooks(adapter.settingsFile, adapter.hookEvents)) {
|
|
1872
|
+
if (settingsManager.removeHooks(adapter.settingsFile, adapter.hookEvents, hookOpts(adapter))) {
|
|
1819
1873
|
log(`${adapter.settingsFile}: 移除版本检查 hook,保留用户配置`, 'success');
|
|
1820
1874
|
}
|
|
1821
1875
|
});
|
|
@@ -1846,7 +1900,7 @@ async function uninstall() {
|
|
|
1846
1900
|
// 是否同时卸载用户级组件(工具 skills + 版本检查 hook,作用于 ~/.claude 等用户目录)
|
|
1847
1901
|
let removeUserLevel = false;
|
|
1848
1902
|
if (fs.existsSync(USER_MANIFEST_FILE)) {
|
|
1849
|
-
const answerUser = await ask('是否同时卸载用户级组件(~/.claude、~/.qoder 的版本检查 hook)?(y/N): ');
|
|
1903
|
+
const answerUser = await ask('是否同时卸载用户级组件(~/.claude、~/.qoder、~/.codebuddy、~/.trae-cn 的版本检查 hook)?(y/N): ');
|
|
1850
1904
|
removeUserLevel = answerUser.toLowerCase() === 'y' || answerUser.toLowerCase() === 'yes';
|
|
1851
1905
|
}
|
|
1852
1906
|
|
|
@@ -1865,11 +1919,11 @@ async function uninstall() {
|
|
|
1865
1919
|
: path.join(TARGET_DIR, adapter.settingsFile);
|
|
1866
1920
|
// 项目级:需在清单中才处理
|
|
1867
1921
|
if (!adapter.settingsFileIsUserLevel && !managedPaths.has(adapter.settingsFile)) return;
|
|
1868
|
-
if (removeUserLevel && settingsManager.removeHooks(settingsPath, adapter.hookEvents)) {
|
|
1922
|
+
if (removeUserLevel && settingsManager.removeHooks(settingsPath, adapter.hookEvents, hookOpts(adapter))) {
|
|
1869
1923
|
log(`${adapter.settingsFile}: 移除版本检查 hook,保留用户配置`, 'success');
|
|
1870
1924
|
}
|
|
1871
1925
|
// 清理旧版本遗留的 SessionStart hook(无版本差异,无条件清理)
|
|
1872
|
-
if (settingsManager.removeLegacyHooks(settingsPath)) {
|
|
1926
|
+
if (settingsManager.removeLegacyHooks(settingsPath, hookOpts(adapter))) {
|
|
1873
1927
|
log(`${adapter.settingsFile}: 清理遗留 SessionStart hook`, 'success');
|
|
1874
1928
|
}
|
|
1875
1929
|
skippedPaths.add(adapter.settingsFile);
|
|
@@ -27,6 +27,8 @@ module.exports = {
|
|
|
27
27
|
worktreeCommandPrefix: 'cbb-',
|
|
28
28
|
// 部署副本中将该引用串改写为 opencode 的命令风格(配合 commandPrefix)
|
|
29
29
|
contentRewrites: [['/opsx:', '/opsx-'], ['/cbb:', '/cbb-']],
|
|
30
|
+
// 命令显示名取自 frontmatter name,部署副本重写为 kebab-case(/opsx-propose,与文档一致)
|
|
31
|
+
commandNameKebab: true,
|
|
30
32
|
// rules 加载登记:写入 .opencode/opencode.json 的 instructions。
|
|
31
33
|
// instructions 相对路径的解析基准(配置文件目录 vs 项目根)文档未写死,
|
|
32
34
|
// 登记双 glob 对冲:任一基准下恰有一个命中,另一个空匹配。
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 规则 frontmatter 改写(纯函数,无副作用,便于单测)。
|
|
5
|
+
*
|
|
6
|
+
* 源规则(cbb/dev-standards/rules/*.md)用 Qoder 的 frontmatter 约定
|
|
7
|
+
* `trigger: always_on`。各工具对"始终生效"的字段名不同:
|
|
8
|
+
* - Qoder:trigger: always_on(源格式)
|
|
9
|
+
* - Claude Code / opencode:无该字段,靠各自机制加载
|
|
10
|
+
* - WorkBuddy/CodeBuddy、Trae:alwaysApply: true
|
|
11
|
+
*
|
|
12
|
+
* 适配器通过 ruleRewrites([[from, to], ...])声明改写规则,部署时套用;
|
|
13
|
+
* 无 ruleRewrites 的适配器原样返回。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 按适配器的 ruleRewrites 改写规则文本。
|
|
18
|
+
* @param {object} adapter 适配器配置
|
|
19
|
+
* @param {string} text 规则文件原文
|
|
20
|
+
* @returns {string} 改写后的文本(无 ruleRewrites 时原样返回)
|
|
21
|
+
*/
|
|
22
|
+
function applyRuleRewrites(adapter, text) {
|
|
23
|
+
if (!adapter || !adapter.ruleRewrites) return text;
|
|
24
|
+
return adapter.ruleRewrites.reduce((t, [from, to]) => t.split(from).join(to), text);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { applyRuleRewrites };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraeWork / TraeCode 适配器
|
|
3
|
+
*
|
|
4
|
+
* 字节 TraeWork 桌面工作台与 TraeCode IDE 共用项目级配置目录 `.trae/`,
|
|
5
|
+
* 故一个适配器同时覆盖两者。
|
|
6
|
+
*
|
|
7
|
+
* 与 Claude Code / Qoder 的映射差异:
|
|
8
|
+
* - rules:`.trae/rules/*.md`(扁平文件、支持子目录,最多 3 层),frontmatter 用
|
|
9
|
+
* `alwaysApply: true`(Qoder 的 `trigger: always_on` 需改写,见 ruleRewrites)
|
|
10
|
+
* - skills:`.trae/skills/<name>/SKILL.md`,结构与 Claude 同构
|
|
11
|
+
* - commands:`.trae/commands/`,支持目录嵌套(最多 3 层),与 Claude 同风格
|
|
12
|
+
* - hooks:`~/.trae-cn/hooks.json`,格式与 Claude 相近但需顶层 `version: 1`
|
|
13
|
+
* (由 settingsManager 的 hookDialect 处理),事件名/输出字段一致
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
name: 'trae',
|
|
21
|
+
displayName: 'TraeWork(TraeCode)',
|
|
22
|
+
rulesDir: '.trae/rules',
|
|
23
|
+
skillsDir: '.trae/skills',
|
|
24
|
+
commandsDir: '.trae/commands/opsx',
|
|
25
|
+
// worktree 管理命令(非 openspec 上游):独立命名空间 /cbb:worktree-*
|
|
26
|
+
worktreeCommandsDir: '.trae/commands/cbb',
|
|
27
|
+
// 规则 frontmatter 改写:Qoder 风格 → Trae 风格
|
|
28
|
+
ruleRewrites: [['trigger: always_on', 'alwaysApply: true']],
|
|
29
|
+
// 用户级 hooks 配置(Trae 用 hooks.json,国内版目录为 ~/.trae-cn/)
|
|
30
|
+
settingsFile: path.join(os.homedir(), '.trae-cn', 'hooks.json'),
|
|
31
|
+
settingsFileIsUserLevel: true,
|
|
32
|
+
hookEvents: ['UserPromptSubmit'],
|
|
33
|
+
// Trae 的 hooks.json 需顶层 version: 1(Claude 风格 settings.json 无此字段)
|
|
34
|
+
hookDialect: 'trae',
|
|
35
|
+
};
|
|
@@ -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 = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "CBB: Worktree Close"
|
|
3
|
-
description: 关闭/清理由 init
|
|
3
|
+
description: 关闭/清理由 worktree-init 创建的多仓库联动 worktree 工作空间,移除 worktree 并按用户选择处理特性分支
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [worktree, cleanup, worktree, git-worktree]
|
|
6
6
|
---
|
|
@@ -11,12 +11,11 @@ tags: [worktree, cleanup, worktree, git-worktree]
|
|
|
11
11
|
|
|
12
12
|
**禁止**用 `ls` / `find` / `cat` / `head` / `grep` 等 bash 命令搜索 SKILL.md。这些命令在 Agent 运行环境(Qoder Windows PowerShell 等)中经常失败。
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
- Claude Code 适配器:`.claude/skills/cbb-worktree-close/SKILL.md`
|
|
14
|
+
**直接路径**(各工具统一,worktree 运行时部署在空间根 `.cbb/skills/`):
|
|
15
|
+
- `.cbb/skills/cbb-worktree-close/SKILL.md`
|
|
17
16
|
|
|
18
17
|
**第一步**:
|
|
19
|
-
1. 用 Read 工具直接打开 SKILL.md
|
|
18
|
+
1. 用 Read 工具直接打开 `.cbb/skills/cbb-worktree-close/SKILL.md`
|
|
20
19
|
2. 按 SKILL.md 的 Step 0 → 1 → 2 → 3 → 4 → 5 → 6 顺序执行
|
|
21
20
|
3. 每次调用 Node.js 脚本时使用**绝对路径**
|
|
22
21
|
|
|
@@ -11,16 +11,15 @@ tags: [worktree, isolation, worktree, git-worktree]
|
|
|
11
11
|
|
|
12
12
|
**禁止**用 `ls` / `find` / `cat` / `head` / `grep` 等 bash 命令搜索 SKILL.md 是否存在。**这些命令在 Agent 运行环境(Qoder Windows PowerShell 等)中经常失败**(如 `head` 不存在、stderr 重定向无效等)。
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
- Claude Code 适配器:`.claude/skills/cbb-worktree-init/SKILL.md`
|
|
14
|
+
**直接路径**(各工具统一,worktree 运行时部署在空间根 `.cbb/skills/`):
|
|
15
|
+
- `.cbb/skills/cbb-worktree-init/SKILL.md`
|
|
17
16
|
|
|
18
17
|
**第一步**:
|
|
19
|
-
1. 用 Read 工具直接打开 `.
|
|
18
|
+
1. 用 Read 工具直接打开 `.cbb/skills/cbb-worktree-init/SKILL.md`
|
|
20
19
|
2. 按 SKILL.md 的 Step 0 → 1 → 2 → 3 → 4 顺序执行
|
|
21
20
|
3. 每次调用 Node.js 脚本时,使用**绝对路径**(避免依赖相对路径):
|
|
22
21
|
```
|
|
23
|
-
node "D:\workspace\<用户工作空间>\.
|
|
22
|
+
node "D:\workspace\<用户工作空间>\.cbb\skills\cbb-worktree-init\scripts\<name>.js" <参数>
|
|
24
23
|
```
|
|
25
24
|
- 参数形式:
|
|
26
25
|
- `check-env.js`:无参数
|
|
@@ -16,7 +16,7 @@ tags: [workflow, push, commit, worktree, experimental]
|
|
|
16
16
|
- 开发过程中想保存中间进度
|
|
17
17
|
- 用户口语化说"提交并push" / "推一下"
|
|
18
18
|
|
|
19
|
-
**Steps
|
|
19
|
+
**Steps 摘要**(详细流程见空间根 `.cbb/skills/cbb-worktree-push/SKILL.md`):
|
|
20
20
|
|
|
21
21
|
1. **Step 0**:定位工作空间根(find-workspace-root.js)
|
|
22
22
|
2. **Step 1**:识别目标 worktree(find-target-worktree.js)
|
|
@@ -34,7 +34,7 @@ metadata:
|
|
|
34
34
|
### 0.1 环境健康探活
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
node "D:/workspace/<ws_root>/.
|
|
37
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/check-env.js"
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
**解读输出**:
|
|
@@ -45,7 +45,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-close/scripts/check-env.
|
|
|
45
45
|
### 0.2 定位工作空间根目录
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
node "D:/workspace/<ws_root>/.
|
|
48
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/find-workspace-root.js"
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
**解读输出**:
|
|
@@ -69,7 +69,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-close/scripts/find-works
|
|
|
69
69
|
3. AI agent 列出 `.worktrees/` 下的所有 worktree:
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
|
-
node "D:/workspace/<ws_root>/.
|
|
72
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/find-target-worktree.js "<ws_root>"
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
> 注:本技能支持工作空间根目录或 worktree 内执行,find-target-worktree 自动从 cwd 反推或列出。
|
|
@@ -84,7 +84,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-close/scripts/find-targe
|
|
|
84
84
|
### 1.2 发现关联应用 worktree
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
-
node "D:/workspace/<ws_root>/.
|
|
87
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/discover-apps.js "<ws_root>" "<branch>"
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
脚本自动从 `workspace-config.json` 读取应用列表,扫描 `.worktrees/worktree-<branch>/<应用名>/` 实际存在的子目录。
|
|
@@ -98,7 +98,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-close/scripts/discover-a
|
|
|
98
98
|
### 1.3 检查未归档 change
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
node "D:/workspace/<ws_root>/.
|
|
101
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/check-unarchived.js "<ws_root>"
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
脚本扫描 `openspec/changes/` 目录,筛选出非 `archive/` 子目录的 change 名称列表。
|
|
@@ -117,7 +117,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-close/scripts/check-unar
|
|
|
117
117
|
对 workspace worktree 和每个关联应用 worktree,依次执行三项检查并汇总成安全状态表。**这是破坏性操作前的必经环节,结果将驱动 Step 3 的用户决策。**
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
node "D:/workspace/<ws_root>/.
|
|
120
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/safety-check.js "<ws_root>" "<branch>"
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
脚本内部对每个仓库自动执行:
|
|
@@ -289,7 +289,7 @@ node "<skill>/scripts/delete-branches.js" "<ws_root>" "<branch>" local_remote
|
|
|
289
289
|
**顺序:先移除各应用 worktree,再移除 workspace worktree**(逆序于创建;也为后续删分支扫清"分支仍被检出"的障碍)。
|
|
290
290
|
|
|
291
291
|
```bash
|
|
292
|
-
node "D:/workspace/<ws_root>/.
|
|
292
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-close/scripts/remove-worktrees.js "<ws_root>" "<branch>" "<force>"
|
|
293
293
|
```
|
|
294
294
|
|
|
295
295
|
**三层降级策略**:`git worktree remove` 实际包含两个动作——①清理 git 元数据(`.git/worktrees/`)②删除物理目录。当 IDE 占用目录时 ② 会被 Windows 文件锁阻塞,但 ① 永远不受影响。脚本将这两个动作解耦:
|
|
@@ -28,11 +28,11 @@ metadata:
|
|
|
28
28
|
|
|
29
29
|
## 调用脚本的统一方式
|
|
30
30
|
|
|
31
|
-
**重要**:所有脚本必须用**绝对路径**调用。`./scripts/...` 相对路径在 Agent 运行环境中不适用(AI agent 的 cwd 不一定是技能目录)。
|
|
31
|
+
**重要**:所有脚本必须用**绝对路径**调用。`./scripts/...` 相对路径在 Agent 运行环境中不适用(AI agent 的 cwd 不一定是技能目录)。worktree 运行时统一部署在空间根 `.cbb/skills/` 下,各工具一致。
|
|
32
32
|
|
|
33
33
|
调用方式(推荐用绝对路径):
|
|
34
34
|
```
|
|
35
|
-
node "D:\workspace\<用户工作空间>\.
|
|
35
|
+
node "D:\workspace\<用户工作空间>\.cbb\skills\cbb-worktree-init\scripts\<name>.js" <参数>
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
脚本输出:
|
|
@@ -54,7 +54,7 @@ node "D:\workspace\<用户工作空间>\.qoder\skills\cbb-worktree-init\scripts\
|
|
|
54
54
|
### 0.1 环境健康探活
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
node "D:/workspace/<ws_root>/.
|
|
57
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/check-env.js"
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
**解读输出**:
|
|
@@ -67,7 +67,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/check-env.j
|
|
|
67
67
|
提前检测权限/版本问题,把可能在后续步骤暴露的失败前移到流程最开始:
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
node "D:/workspace/<ws_root>/.
|
|
70
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/check-env-deep.js"
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
**解读输出**:
|
|
@@ -81,7 +81,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/check-env-d
|
|
|
81
81
|
### 0.2 读取并校验 workspace-config.json
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
node "D:/workspace/<ws_root>/.
|
|
84
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/parse-config.js"
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
**解读输出**:
|
|
@@ -148,7 +148,7 @@ worktree 需要知道要关联哪些应用仓库。
|
|
|
148
148
|
|
|
149
149
|
```bash
|
|
150
150
|
# ws_root 来自 AI agent 维护的状态
|
|
151
|
-
node "D:/workspace/<ws_root>/.
|
|
151
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/sync-repos.js" "<ws_root>"
|
|
152
152
|
```
|
|
153
153
|
|
|
154
154
|
**用法**:
|
|
@@ -192,7 +192,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/sync-repos.
|
|
|
192
192
|
| 当前在主分支上 | ✅ | ❌ |
|
|
193
193
|
|
|
194
194
|
```bash
|
|
195
|
-
node "D:/workspace/<ws_root>/.
|
|
195
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/check-repos.js" "<ws_root>"
|
|
196
196
|
```
|
|
197
197
|
|
|
198
198
|
**解读输出**:
|
|
@@ -220,7 +220,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/check-repos
|
|
|
220
220
|
### 3.2 安全更新 .gitignore(前置)
|
|
221
221
|
|
|
222
222
|
```bash
|
|
223
|
-
node "D:/workspace/<ws_root>/.
|
|
223
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/update-gitignore.js "<ws_root>" "<branch>"
|
|
224
224
|
```
|
|
225
225
|
|
|
226
226
|
脚本内部自动完成:stash 保护 → 切分支 → 添加 `.worktrees/` 和 `.codespace/` → 提交 → 切回 → pop stash
|
|
@@ -234,7 +234,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/update-giti
|
|
|
234
234
|
### 3.3 创建分支
|
|
235
235
|
|
|
236
236
|
```bash
|
|
237
|
-
node "D:/workspace/<ws_root>/.
|
|
237
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/create-branches.js" "<ws_root>" "<branch>"
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
**解读输出**:
|
|
@@ -259,7 +259,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/create-bran
|
|
|
259
259
|
### 3.4 推送并建立 upstream
|
|
260
260
|
|
|
261
261
|
```bash
|
|
262
|
-
node "D:/workspace/<ws_root>/.
|
|
262
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/push-branches.js" "<ws_root>" "<branch>"
|
|
263
263
|
```
|
|
264
264
|
|
|
265
265
|
脚本内部自动完成:
|
|
@@ -287,7 +287,7 @@ node "D:/workspace/<ws_root>/.qoder/skills/cbb-worktree-init/scripts/push-branch
|
|
|
287
287
|
### 3.5 创建 Worktree(含自愈清理)
|
|
288
288
|
|
|
289
289
|
```bash
|
|
290
|
-
node "D:/workspace/<ws_root>/.
|
|
290
|
+
node "D:/workspace/<ws_root>/.cbb/skills/cbb-worktree-init/scripts/create-worktrees.js" "<ws_root>" "<branch>"
|
|
291
291
|
```
|
|
292
292
|
|
|
293
293
|
脚本内部自动完成:
|
|
@@ -467,7 +467,7 @@ WT_PATH d:\workspace\xxx\.worktrees\worktree-feature-login
|
|
|
467
467
|
- workspace 仓库标准检查(当前在主分支等),app 仓库轻量检查(fetch + `origin/main` 可用即可)
|
|
468
468
|
- app 仓库分支从 `origin/main` 创建(`git branch <需求名> ${REMOTE}/${MAIN}`),不依赖本地主分支状态
|
|
469
469
|
- 严格 Step 3.3 → Step 3.4 顺序(先统一创建分支,再统一创建 worktree;workspace 工作树先建,各应用按序补建)
|
|
470
|
-
- 所有脚本调用以 `node "<WS_ROOT>\.
|
|
470
|
+
- 所有脚本调用以 `node "<WS_ROOT>\.cbb\skills\cbb-worktree-init\scripts\<name>.js" "<绝对路径>" "<branch>"` 形式发起(apps 由脚本内部从 workspace-config.json 读取),**不依赖跨调用的 cwd**
|
|
471
471
|
- **Step 3.4 push 步骤必须执行且插入在 create-branches.js (3.3) 之后、create-worktrees.js (3.5) 之前** — 失败时阻塞整个 init-worktree 流程
|
|
472
472
|
- **Step 3.4 仅覆盖创建 worktree 时的空 commit** — 开发过程中产生的本地 commit(如 apply 任务实现)必须由用户在 worktree 中手动提交并调 `cbb-worktree-push` 推送;不允许依赖 Step 3.4 之后的自动推送(不存在)
|
|
473
473
|
|
|
@@ -33,7 +33,7 @@ metadata:
|
|
|
33
33
|
**所有脚本必须用绝对路径调用**(Agent 运行环境中 AI agent 的 cwd 不一定是技能目录)。
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
node "<ws_root>/.
|
|
36
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/<name>.js" <参数>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
脚本输出:
|
|
@@ -46,7 +46,7 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/<name>.js" <参数>
|
|
|
46
46
|
## Step 0:定位工作空间
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
node "<ws_root>/.
|
|
49
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/find-workspace-root.js"
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
**解读末行**:
|
|
@@ -58,7 +58,7 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/find-workspace-root.js"
|
|
|
58
58
|
## Step 1:识别目标 worktree
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
node "<ws_root>/.
|
|
61
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/find-target-worktree.js" "<ws_root>"
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
**解读末行**:
|
|
@@ -72,7 +72,7 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/find-target-worktree.js"
|
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
# 仅 commit 阶段先做 dry-run 预览
|
|
75
|
-
node "<ws_root>/.
|
|
75
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "preview" --dry-run
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
**解读末行 `COMMIT_RESULT`**:每项仓库的状态
|
|
@@ -119,7 +119,7 @@ AI agent 在执行真实 commit 前**必须**在对话中向用户确认 commit
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
# 统一信息
|
|
122
|
-
node "<ws_root>/.
|
|
122
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "feat(<branch>): 实现客户运费逻辑"
|
|
123
123
|
|
|
124
124
|
# 多仓库分别
|
|
125
125
|
node "..." "<ws_root>" "<branch>" --per-repo "ep-foo-app:feat(<branch>): 实现 saveClientExpectFreight;ep-bar-app:refactor(<branch>): 拆分 PlanService"
|
|
@@ -155,7 +155,7 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>" --message "..."
|
|
|
155
155
|
## Step 5:批量 push
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
|
-
node "<ws_root>/.
|
|
158
|
+
node "<ws_root>/.cbb/skills/cbb-worktree-push/scripts/push-worktrees.js" "<ws_root>" "<branch>"
|
|
159
159
|
|
|
160
160
|
# 或 wt_path 形式
|
|
161
161
|
node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
@@ -1,39 +1,41 @@
|
|
|
1
|
-
# 业务空间使用说明(AI Agent 导航)
|
|
2
|
-
|
|
3
|
-
本目录是由 `@jspg-ai/coding-bb` 初始化的**多仓库联动开发业务空间**。
|
|
4
|
-
进入本目录工作时,请先按本文件理解目录职责与协作约定,再动手。
|
|
5
|
-
|
|
6
|
-
## 核心约定
|
|
7
|
-
|
|
8
|
-
1.
|
|
9
|
-
2. **AI 配置安装在空间根**:编码规范、OpenSpec 命令、worktree 管理技能都装在本目录(`cbb setup` / `cbb update` 安装);worktree 内**不安装** AI 配置,AI 会话始终以空间根为基础。
|
|
10
|
-
3. **接到新需求先建 worktree**:在本目录执行 `/cbb:worktree-init <需求名>`(opencode 写法:`/cbb-worktree-init`)。它会为 `workspace-config.json` 中的全量关联应用同步创建同名 worktree。
|
|
11
|
-
4. **开发命令在本会话执行,写操作指向 worktree**:需求提案 / 实现 / 验证 / 归档(`/opsx:propose` → `/opsx:apply` → `/opsx:verify` → `/opsx:archive`)在空间根会话执行;但所有产生写操作的命令(git commit / openspec / 构建 / 测试 / 文件修改)必须以 `.worktrees/worktree-<需求名>/`(或其应用子目录)为工作目录(显式 `cd` 或绝对路径);**禁止在空间根(主分支)执行写操作**。
|
|
12
|
-
5. **关联应用增减只改配置**:编辑 `workspace-config.json` 的 `apps` 数组(`name` / `repo` / `side` / `desc`),然后用同一需求名重跑 worktree 初始化即幂等补齐;不要手工 `git clone` 应用仓库。
|
|
13
|
-
6. **不要绕过 worktree 直接修改 `.codespace/` 或本目录的代码**。`.codespace/` 是工具维护的基准代码,不是开发区。
|
|
14
|
-
|
|
15
|
-
## 目录结构与职责
|
|
16
|
-
|
|
17
|
-
| 路径 | 职责 | 维护方式 |
|
|
18
|
-
|------|----------|----------|
|
|
19
|
-
| `workspace-config.json` | 关联应用清单,所有应用联动的唯一数据源 | 人工编辑 |
|
|
20
|
-
| `.codespace/` | 各关联应用的基准代码(每个应用一个子目录) | `cbb setup` 与 worktree 流程自动 clone / fetch;**勿手动编辑**;已 gitignore,不提交 |
|
|
21
|
-
| `.worktrees/` | 需求隔离开发区(每个需求一个 `worktree-<需求名>/` 目录) | worktree 命令自动创建 / 清理;不提交(首次执行 worktree 流程时自动加入 .gitignore) |
|
|
22
|
-
| `openspec/` | OpenSpec 工作流配置(`config.yaml` + `schemas/`) | 由 cbb 安装;需求变更产物(`openspec/changes/` 等)在**需求工作树内**生成,随需求分支提交 |
|
|
23
|
-
| `.claude/` `.qoder/` `.opencode/` | AI 工具适配目录:编码规范规则、OpenSpec 命令、worktree
|
|
24
|
-
| `.cbb/` | cbb
|
|
25
|
-
|
|
26
|
-
## 典型流程
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
本目录:/cbb:worktree-init <需求名>
|
|
30
|
-
→ 继续在当前会话开发:写操作命令以 .worktrees/worktree-<需求名>/ 为工作目录
|
|
31
|
-
(/opsx:propose → /opsx:apply → /opsx:verify → /opsx:archive)
|
|
32
|
-
→ /cbb:worktree-push 推送 → 合并后 /cbb:worktree-close 关闭
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
> 命令写法因 AI 工具而异:Claude Code / Qoder 为 `/cbb:worktree-init
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
本文件由 `@jspg-ai/coding-bb` 生成(仅缺失时写入,之后不会覆盖或删除,可自由增补团队约定)。
|
|
1
|
+
# 业务空间使用说明(AI Agent 导航)
|
|
2
|
+
|
|
3
|
+
本目录是由 `@jspg-ai/coding-bb` 初始化的**多仓库联动开发业务空间**。
|
|
4
|
+
进入本目录工作时,请先按本文件理解目录职责与协作约定,再动手。
|
|
5
|
+
|
|
6
|
+
## 核心约定
|
|
7
|
+
|
|
8
|
+
1. **本目录不做需求开发**。本目录(业务空间主分支)只负责组织与调度;需求开发的**写操作**都在 `.worktrees/worktree-<需求名>/` 隔离目录内进行,**AI 会话仍停在空间根**(worktree 内不装 AI 配置)。
|
|
9
|
+
2. **AI 配置安装在空间根**:编码规范、OpenSpec 命令、worktree 管理技能都装在本目录(`cbb setup` / `cbb update` 安装);worktree 内**不安装** AI 配置,AI 会话始终以空间根为基础。
|
|
10
|
+
3. **接到新需求先建 worktree**:在本目录执行 `/cbb:worktree-init <需求名>`(opencode 写法:`/cbb-worktree-init`)。它会为 `workspace-config.json` 中的全量关联应用同步创建同名 worktree。
|
|
11
|
+
4. **开发命令在本会话执行,写操作指向 worktree**:需求提案 / 实现 / 验证 / 归档(`/opsx:propose` → `/opsx:apply` → `/opsx:verify` → `/opsx:archive`)在空间根会话执行;但所有产生写操作的命令(git commit / openspec / 构建 / 测试 / 文件修改)必须以 `.worktrees/worktree-<需求名>/`(或其应用子目录)为工作目录(显式 `cd` 或绝对路径);**禁止在空间根(主分支)执行写操作**。
|
|
12
|
+
5. **关联应用增减只改配置**:编辑 `workspace-config.json` 的 `apps` 数组(`name` / `repo` / `side` / `desc`),然后用同一需求名重跑 worktree 初始化即幂等补齐;不要手工 `git clone` 应用仓库。
|
|
13
|
+
6. **不要绕过 worktree 直接修改 `.codespace/` 或本目录的代码**。`.codespace/` 是工具维护的基准代码,不是开发区。
|
|
14
|
+
|
|
15
|
+
## 目录结构与职责
|
|
16
|
+
|
|
17
|
+
| 路径 | 职责 | 维护方式 |
|
|
18
|
+
|------|----------|----------|
|
|
19
|
+
| `workspace-config.json` | 关联应用清单,所有应用联动的唯一数据源 | 人工编辑 |
|
|
20
|
+
| `.codespace/` | 各关联应用的基准代码(每个应用一个子目录) | `cbb setup` 与 worktree 流程自动 clone / fetch;**勿手动编辑**;已 gitignore,不提交 |
|
|
21
|
+
| `.worktrees/` | 需求隔离开发区(每个需求一个 `worktree-<需求名>/` 目录) | worktree 命令自动创建 / 清理;不提交(首次执行 worktree 流程时自动加入 .gitignore) |
|
|
22
|
+
| `openspec/` | OpenSpec 工作流配置(`config.yaml` + `schemas/`) | 由 cbb 安装;需求变更产物(`openspec/changes/` 等)在**需求工作树内**生成,随需求分支提交 |
|
|
23
|
+
| `.claude/` `.qoder/` `.opencode/` `.codebuddy/` `.trae/` | AI 工具适配目录:编码规范规则、OpenSpec 命令、worktree 管理命令 | 由 cbb 按 setup 时选择的工具安装;已 gitignore,不提交,勿手动改 |
|
|
24
|
+
| `.cbb/` | cbb 安装清单 + worktree 运行时(`.cbb/skills/`:流程文档与脚本,各工具命令共用) | 由 cbb 管理;**勿手动编辑** |
|
|
25
|
+
|
|
26
|
+
## 典型流程
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
本目录:/cbb:worktree-init <需求名>
|
|
30
|
+
→ 继续在当前会话开发:写操作命令以 .worktrees/worktree-<需求名>/ 为工作目录
|
|
31
|
+
(/opsx:propose → /opsx:apply → /opsx:verify → /opsx:archive)
|
|
32
|
+
→ /cbb:worktree-push 推送 → 合并后 /cbb:worktree-close 关闭
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> 命令写法因 AI 工具而异:Claude Code / Qoder / WorkBuddy / Trae 为 `/cbb:worktree-init`、`/opsx:propose`;opencode 因「文件名即命令名」且 Windows 文件名不允许 `:`,扁平化为 `/cbb-worktree-init`、`/opsx-propose`。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
本文件由 `@jspg-ai/coding-bb` 生成(仅缺失时写入,之后不会覆盖或删除,可自由增补团队约定)。
|
|
40
|
+
|
|
41
|
+
> ⓘ 本文件仅供导航;目录纪律以 cbb 安装的编码规范规则(`cbb-ai-behavior.md` 第 8 条)为准,该规则随 `cbb update` 更新。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jspg-ai/coding-bb",
|
|
3
|
-
"version": "0.0.3-beta.
|
|
3
|
+
"version": "0.0.3-beta.6",
|
|
4
4
|
"description": "整合业界热门且高价值的工具、框架与技能,为 AI CODING AGENT 提供统一的行为准则与工作流,辅助开发者将需求高效落地为符合规范的代码",
|
|
5
5
|
"main": "cbb/lib/install/init.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"sync:shared": "node scripts/sync-shared.js",
|
|
21
21
|
"pretest": "node scripts/sync-shared.js --check",
|
|
22
|
-
"test": "node test/lib/install/cleanup.test.js && node test/lib/utils/settings.test.js && node test/lib/utils/gitignore.test.js && node test/lib/utils/version.test.js && node test/lib/install/workspaces.test.js && node test/lib/utils/checkbox.test.js && node test/lib/utils/output.test.js && node test/lib/install/cli-help.test.js && node test/lib/wiki/wiki-publish.test.js && node test/lib/wiki/wiki-parse-args.test.js && node test/lib/wiki/wiki-split.test.js && node test/lib/superpowers/superpowers.test.js && node test/worktrees/push-branches.test.js && node test/worktrees/commit-worktrees.test.js && node test/worktrees/push-worktrees.test.js && node test/worktrees/check-env-deep.test.js && node test/lib/openspec/
|
|
22
|
+
"test": "node test/lib/install/cleanup.test.js && node test/lib/utils/settings.test.js && node test/lib/utils/gitignore.test.js && node test/lib/utils/version.test.js && node test/lib/install/workspaces.test.js && node test/lib/utils/checkbox.test.js && node test/lib/utils/output.test.js && node test/lib/install/cli-help.test.js && node test/lib/install/adapters.test.js && node test/lib/wiki/wiki-publish.test.js && node test/lib/wiki/wiki-parse-args.test.js && node test/lib/wiki/wiki-split.test.js && node test/lib/superpowers/superpowers.test.js && node test/worktrees/push-branches.test.js && node test/worktrees/commit-worktrees.test.js && node test/worktrees/push-worktrees.test.js && node test/worktrees/check-env-deep.test.js && node test/lib/openspec/protected-paths.test.js"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"cbb",
|