@jspg-ai/coding-bb 0.0.3-beta.23 → 0.0.3-beta.25
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 +3 -3
- package/cbb/lib/install/init.js +23 -21
- package/cbb/lib/install/workspaces.js +15 -15
- package/cbb/lib/utils/githook.js +9 -7
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/_shared/scripts/install-git-hook.js +1 -1
- package/cbb/worktrees/_shared/scripts/start-local.js +4 -4
- package/cbb/worktrees/skills/cbb-local-mode/SKILL.md +1 -1
- package/cbb/worktrees/skills/cbb-local-mode/scripts/install-git-hook.js +1 -1
- package/cbb/worktrees/skills/cbb-local-mode/scripts/start-local.js +4 -4
- package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +11 -11
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-env.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/delete-branches.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/discover-apps.js +14 -5
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/remove-worktrees.js +11 -2
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/safety-check.js +11 -2
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +25 -25
- 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 +3 -3
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-worktrees.js +23 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/install-git-hook.js +1 -1
- 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/sync-repos.js +6 -6
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +7 -7
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/commit-worktrees.js +30 -8
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-worktrees.js +30 -8
- package/config/{workspace-config.sample.json → CBB-WORKSPACE.sample.json} +1 -1
- package/config/workspace-agents.sample.md +4 -44
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ require('./silence-popup');
|
|
|
8
8
|
*
|
|
9
9
|
* 行为:
|
|
10
10
|
* 1. 按需求名发现参与仓库(ADR 0002 双布局):
|
|
11
|
-
* - worktree 布局:.worktrees/worktree-<branch>/
|
|
11
|
+
* - worktree 布局:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内各 app worktree(镜像主布局,ADR 0003)
|
|
12
12
|
* - 本地布局:根 / .codespace/<app>/ 检出恰在 <branch> 分支上
|
|
13
13
|
* 2. 对每个仓库:
|
|
14
14
|
* a. git status --porcelain 检测 dirty
|
|
@@ -97,6 +97,16 @@ function isGitRepo(p) {
|
|
|
97
97
|
return fs.existsSync(path.join(p, '.git'));
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/** 读取 CBB-WORKSPACE.json 的 app 名列表(旧布局兼容判定用;缺失返回 []) */
|
|
101
|
+
function loadAppNames(wsRoot) {
|
|
102
|
+
try {
|
|
103
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(wsRoot, 'CBB-WORKSPACE.json'), 'utf-8'));
|
|
104
|
+
return Array.isArray(cfg.apps) ? cfg.apps.map(a => a.name).filter(Boolean) : [];
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
100
110
|
function currentBranch(p) {
|
|
101
111
|
try {
|
|
102
112
|
return execSync('git branch --show-current', { cwd: p, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
@@ -105,7 +115,7 @@ function currentBranch(p) {
|
|
|
105
115
|
|
|
106
116
|
/**
|
|
107
117
|
* 按需求名发现参与仓库(ADR 0002 双布局):
|
|
108
|
-
* 布局一 worktree:.worktrees/worktree-<branch>/
|
|
118
|
+
* 布局一 worktree:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内 app worktree(ADR 0003 镜像主布局;≤beta.23 旧平铺顶层布局按配置 app 名兼容)
|
|
109
119
|
* 布局二 本地模式:根 / .codespace/<app>/ 的检出恰在 <branch> 分支上(同名仓库以 worktree 布局优先)
|
|
110
120
|
* 两者皆空 → error。
|
|
111
121
|
*/
|
|
@@ -118,12 +128,24 @@ function scanWorktreeRepos(wsRoot, branch) {
|
|
|
118
128
|
if (isGitRepo(wtRoot)) {
|
|
119
129
|
repos.push({ name: 'workspace', wt: wtRoot, repo: wsRoot, layout: 'worktree' });
|
|
120
130
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
// app worktree 收拢在 .codespace/ 容器内(镜像主布局,ADR 0003)
|
|
132
|
+
const appContainer = path.join(wtRoot, '.codespace');
|
|
133
|
+
if (fs.existsSync(appContainer)) {
|
|
134
|
+
for (const e of fs.readdirSync(appContainer, { withFileTypes: true })) {
|
|
135
|
+
if (!e.isDirectory()) continue;
|
|
136
|
+
const appWt = path.join(appContainer, e.name);
|
|
137
|
+
if (!isGitRepo(appWt)) continue;
|
|
138
|
+
repos.push({ name: e.name, wt: appWt, repo: path.join(wsRoot, '.codespace', e.name), layout: 'worktree' });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 兼容 ≤beta.23 旧平铺布局:按配置 app 名精确匹配(避免把根仓库自带的嵌套 git 目录误判为 app)
|
|
142
|
+
for (const name of loadAppNames(wsRoot)) {
|
|
143
|
+
if (repos.some(r => r.name === name)) continue;
|
|
144
|
+
const legacyWt = path.join(wtRoot, name);
|
|
145
|
+
if (fs.existsSync(path.join(legacyWt, '.git'))) {
|
|
146
|
+
console.error('⚠️ ' + name + ' 仍是旧平铺布局(' + legacyWt + '),建议重跑 cbb-worktree-init 迁移到 .codespace/ 容器');
|
|
147
|
+
repos.push({ name, wt: legacyWt, repo: path.join(wsRoot, '.codespace', name), layout: 'worktree' });
|
|
148
|
+
}
|
|
127
149
|
}
|
|
128
150
|
}
|
|
129
151
|
|
|
@@ -5,8 +5,8 @@ require('./silence-popup');
|
|
|
5
5
|
* 唯一真源:cbb/worktrees/_shared/scripts/find-workspace-root.js
|
|
6
6
|
* 由 scripts/sync-shared.js 展开到各 skill 的 scripts/ 下(init / extend / close / push)。
|
|
7
7
|
*
|
|
8
|
-
* 优先:git worktree list 第一行(主仓库根目录,不受 worktree 内
|
|
9
|
-
* 兜底:当前目录含
|
|
8
|
+
* 优先:git worktree list 第一行(主仓库根目录,不受 worktree 内 CBB-WORKSPACE.json 副本干扰)
|
|
9
|
+
* 兜底:当前目录含 CBB-WORKSPACE.json
|
|
10
10
|
*
|
|
11
11
|
* 退出码:
|
|
12
12
|
* 0 - 定位成功,输出 WS_ROOT 绝对路径
|
|
@@ -44,19 +44,19 @@ if (worktreeList.ok) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// 兜底:当前目录含
|
|
47
|
+
// 兜底:当前目录含 CBB-WORKSPACE.json
|
|
48
48
|
if (!wsRoot) {
|
|
49
49
|
const cwd = process.cwd();
|
|
50
|
-
if (fs.existsSync(path.join(cwd, '
|
|
50
|
+
if (fs.existsSync(path.join(cwd, 'CBB-WORKSPACE.json'))) {
|
|
51
51
|
wsRoot = cwd;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// 校验
|
|
56
|
-
if (!wsRoot || !fs.existsSync(path.join(wsRoot, '
|
|
56
|
+
if (!wsRoot || !fs.existsSync(path.join(wsRoot, 'CBB-WORKSPACE.json'))) {
|
|
57
57
|
console.error('❌ 未找到工作空间根目录');
|
|
58
|
-
console.error(' 原因:git worktree list 失败且当前目录无
|
|
59
|
-
console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含
|
|
58
|
+
console.error(' 原因:git worktree list 失败且当前目录无 CBB-WORKSPACE.json');
|
|
59
|
+
console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含 CBB-WORKSPACE.json)下执行本技能');
|
|
60
60
|
process.exit(1);
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -8,7 +8,7 @@ require('./silence-popup');
|
|
|
8
8
|
*
|
|
9
9
|
* 行为:
|
|
10
10
|
* 1. 按需求名发现参与仓库(ADR 0002 双布局):
|
|
11
|
-
* - worktree 布局:.worktrees/worktree-<branch>/
|
|
11
|
+
* - worktree 布局:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内各 app worktree(镜像主布局,ADR 0003)
|
|
12
12
|
* - 本地布局:根 / .codespace/<app>/ 检出恰在 <branch> 分支上
|
|
13
13
|
* 2. 对每个仓库调 push-core.pushSingle(已建立 upstream 时直接 push -u;否则建立 upstream)
|
|
14
14
|
* 3. 逐个报告状态,输出末行 PUSH_RESULT
|
|
@@ -59,6 +59,16 @@ function isGitRepo(p) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** 读取 CBB-WORKSPACE.json 的 app 名列表(旧布局兼容判定用;缺失返回 []) */
|
|
63
|
+
function loadAppNames(wsRoot) {
|
|
64
|
+
try {
|
|
65
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(wsRoot, 'CBB-WORKSPACE.json'), 'utf-8'));
|
|
66
|
+
return Array.isArray(cfg.apps) ? cfg.apps.map(a => a.name).filter(Boolean) : [];
|
|
67
|
+
} catch (e) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
function currentBranch(p) {
|
|
63
73
|
try {
|
|
64
74
|
return execSync('git branch --show-current', { cwd: p, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
@@ -67,7 +77,7 @@ function currentBranch(p) {
|
|
|
67
77
|
|
|
68
78
|
/**
|
|
69
79
|
* 按需求名发现参与仓库(ADR 0002 双布局):
|
|
70
|
-
* 布局一 worktree:.worktrees/worktree-<branch>/
|
|
80
|
+
* 布局一 worktree:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内 app worktree(ADR 0003 镜像主布局;≤beta.23 旧平铺顶层布局按配置 app 名兼容)
|
|
71
81
|
* 布局二 本地模式:根 / .codespace/<app>/ 的检出恰在 <branch> 分支上(同名仓库以 worktree 布局优先)
|
|
72
82
|
* 两者皆空 → error。
|
|
73
83
|
*/
|
|
@@ -80,12 +90,24 @@ function scanWorktreeRepos(wsRoot, branch) {
|
|
|
80
90
|
if (isGitRepo(wtRoot)) {
|
|
81
91
|
repos.push({ name: 'workspace', wt: wtRoot, repo: wsRoot, layout: 'worktree' });
|
|
82
92
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
// app worktree 收拢在 .codespace/ 容器内(镜像主布局,ADR 0003)
|
|
94
|
+
const appContainer = path.join(wtRoot, '.codespace');
|
|
95
|
+
if (fs.existsSync(appContainer)) {
|
|
96
|
+
for (const e of fs.readdirSync(appContainer, { withFileTypes: true })) {
|
|
97
|
+
if (!e.isDirectory()) continue;
|
|
98
|
+
const appWt = path.join(appContainer, e.name);
|
|
99
|
+
if (!isGitRepo(appWt)) continue;
|
|
100
|
+
repos.push({ name: e.name, wt: appWt, repo: path.join(wsRoot, '.codespace', e.name), layout: 'worktree' });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 兼容 ≤beta.23 旧平铺布局:按配置 app 名精确匹配(避免把根仓库自带的嵌套 git 目录误判为 app)
|
|
104
|
+
for (const name of loadAppNames(wsRoot)) {
|
|
105
|
+
if (repos.some(r => r.name === name)) continue;
|
|
106
|
+
const legacyWt = path.join(wtRoot, name);
|
|
107
|
+
if (fs.existsSync(path.join(legacyWt, '.git'))) {
|
|
108
|
+
console.error('⚠️ ' + name + ' 仍是旧平铺布局(' + legacyWt + '),建议重跑 cbb-worktree-init 迁移到 .codespace/ 容器');
|
|
109
|
+
repos.push({ name, wt: legacyWt, repo: path.join(wsRoot, '.codespace', name), layout: 'worktree' });
|
|
110
|
+
}
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "AI 开发工作空间配置样例(请勿修改本文件,复制为工作空间根目录的
|
|
2
|
+
"_comment": "AI 开发工作空间配置样例(请勿修改本文件,复制为工作空间根目录的 CBB-WORKSPACE.json 后编辑使用)。apps 数组中每个对象需包含:name(应用名,同时作为 .codespace/ 子目录名)、repo(Git 仓库地址,支持 SSH 或 HTTPS)、side(仓库类型,'front' 表示前端工程,'back' 表示后端工程,'mixed' 表示前后端混合工程);可选 desc(该应用的职责描述,便于人与 AI 理解应用分工)。",
|
|
3
3
|
"apps":
|
|
4
4
|
[
|
|
5
5
|
{
|
|
@@ -1,50 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
进入本目录工作时,请先按本文件理解目录职责与协作约定,再动手。
|
|
3
|
+
本空间由 `@jspg-ai/coding-bb` 初始化(升级用 `cbb update`)。
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
1. **双模式开发,用户选择制**:接到需求先问"要不要隔离/并行"——要 → **worktree 模式**(`/cbb-worktree-init <需求名>`,隔离目录、可多需求并行);不要 → **本地模式**(`/cbb-local-mode`,根与 `.codespace/<app>/` 就地切同名分支、当前会话直接干)。两模式能力对称(都能改 workspace 内容与应用代码、都强制分支隔离、交付都走 MR),agent 只给推荐,用户拍板。模式选错零代价:本地模式中途重跑 `/cbb-worktree-init` 即升级隔离(分支复用,提交随身带走)。
|
|
9
|
-
2. **基准 = `origin/main`(唯一真相源)**:`.codespace/<app>/` 是各应用的**标准本地检出(视图)**——main 检出是基准快照,本地模式下可 checkout 到需求分支暂态占用(收尾恢复)。读"main 现状"先看检出分支或用 `git show main:<path>`,不要默认工作区即基准。
|
|
10
|
-
3. **严禁直接在 main 检出上提交载荷**:分支感知 pre-commit hook 会机械拦截(workspace 仓库仅放行控制面白名单:`workspace-config.json` / `.gitignore` / `AGENTS.md` / `openspec/config.yaml` / `openspec/schemas/**`;应用仓库 main 全拦)——被拦是防线生效,不是故障;`--no-verify` 仅限用户显式要求。
|
|
11
|
-
4. **开发会话开在开发目录**:本地模式 = 当前会话原地(根检出分支后);worktree 模式 = 新会话开进 `.worktrees/worktree-<需求名>/`(AI 配置已 junction,`/opsx:*` 等命令可用)——相对路径原样生效。空间根会话保留作**控制面**(模式调度、worktree 生灭、`cbb update`)。
|
|
12
|
-
5. **远端推送唯一出口 = "提交并推送"**(`/cbb-worktree-push`,dry-run 预览 → 确认 commit 信息 → push → MR 预填链接)。worktree 创建流程零远端操作(lazy push)。
|
|
13
|
-
6. **开工前必做状态自检**:对 `cbb-local-mode` 说开工(或跑其状态自检)——干净态零交互;**遗留态(上一需求没收尾)必须先由用户决策**(继续 / 收尾 / 升级 / 丢弃)。本地模式一次只承载一个需求;并行需求走 worktree 模式(互不干扰)。
|
|
14
|
-
7. **关联应用增减只改配置**:编辑 `workspace-config.json` 的 `apps` 数组(`name` / `repo` / `side` / `desc`),然后重跑对应模式技能即幂等补齐;不要手工 `git clone` 应用仓库。
|
|
15
|
-
|
|
16
|
-
## 目录结构与职责
|
|
17
|
-
|
|
18
|
-
| 路径 | 职责 | 维护方式 |
|
|
19
|
-
|------|----------|----------|
|
|
20
|
-
| `workspace-config.json` | 关联应用清单,所有应用联动的唯一数据源 | 人工编辑(控制面白名单,可直接提交 main) |
|
|
21
|
-
| `.codespace/` | 各应用的**标准本地检出**(基准 = `origin/main`) | `cbb setup` 与技能自动 clone / fetch;本地模式可在其中**切需求分支开发**(main 检出禁改);已 gitignore,不提交 |
|
|
22
|
-
| `.worktrees/` | 需求隔离开发区(每个需求一个 `worktree-<需求名>/`,内含 AI 配置 junction) | worktree 技能自动创建 / 清理;已 gitignore,不提交 |
|
|
23
|
-
| `openspec/` | OpenSpec 工作流配置(`config.yaml` + `schemas/`) | `config.yaml`/`schemas/` 为控制面白名单(`cbb update` 部署,可直改);变更产物(`openspec/changes/`)落需求分支随 MR 合入 |
|
|
24
|
-
| `.claude/` `.qoder/` `.opencode/` `.workbuddy/` `.trae/` | AI 工具适配目录:编码规范规则、OpenSpec 命令、技能 | 由 cbb 按 setup 时选择的工具安装(**唯一物理副本在此**);worktree 内经 junction 引用同一份;已 gitignore,不提交,勿手动改 |
|
|
25
|
-
| `.cbb/` | cbb 安装清单与状态(`.managed-by-cbb`、`.last-tools`) | 由 cbb 管理;**勿手动编辑** |
|
|
26
|
-
|
|
27
|
-
## 典型流程
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
需求进来 → 选模式(agent 推荐 + 用户拍板)
|
|
31
|
-
├─ 本地模式(单线程快改):
|
|
32
|
-
│ /cbb-local-mode(自检 → 确认布局 → 根+涉及 app 就地切分支)
|
|
33
|
-
│ → 当前会话直接开发:/opsx:propose → apply → verify
|
|
34
|
-
│ → 说"提交并推送"(push 技能自动发现本地布局)→ MR 预填链接
|
|
35
|
-
│ → 验收通过 → /opsx:archive → MR 合并 → 收尾(各仓库回 main + 删分支)
|
|
36
|
-
└─ worktree 模式(并行 / 隔离):
|
|
37
|
-
/cbb-worktree-init <需求名>(建分支+worktree+AI 配置 junction,不推远端)
|
|
38
|
-
→ 开发会话开进 .worktrees/worktree-<需求名>/ → opsx 全流程
|
|
39
|
-
→ 说"提交并推送" → MR 预填链接(测试分支)
|
|
40
|
-
→ 测试环境验收 → /opsx:archive → 正式合并走公司流程
|
|
41
|
-
→ 说"关闭工作空间"(/cbb-worktree-close)
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
> worktree 管理技能(init / close / push)与本地模式技能(cbb-local-mode)均以 **skill 形态**分发:既能被 AI 在对话中按意图**自动触发**(如"为 xxx 创建工作空间"、"本地模式开发"、"提交并推送"、"关闭工作空间"),也能用斜杠命令手动指定(各工具一致)。OpenSpec 命令为 `/opsx:propose`(opencode 扁平化为 `/opsx-propose`)。
|
|
5
|
+
- **行为准则与开发纪律**(双模式、基准 = `origin/main`、提交防线、推送出口):见你所用 AI 工具规则目录中的 `cbb-ai-behavior.md`——各工具自动加载;未适配的工具可任选一处直接读,如 `.claude/rules/cbb-ai-behavior.md` 或 `.qoder/rules/` 下同名文件。
|
|
6
|
+
- **空间事实**:关联应用清单(增减应用即编辑它)见 `CBB-WORKSPACE.json`;目录职责建议维护在你自己的 `README.md`。
|
|
45
7
|
|
|
46
8
|
---
|
|
47
9
|
|
|
48
10
|
本文件由 `@jspg-ai/coding-bb` 生成(仅缺失时写入,之后不会覆盖或删除,可自由增补团队约定)。
|
|
49
|
-
|
|
50
|
-
> ⓘ 本文件仅供导航;开发模式纪律以 cbb 安装的编码规范规则(`cbb-ai-behavior.md` 第 8 条)为准,该规则随 `cbb update` 更新。
|