@jspg-ai/coding-bb 0.0.3-beta.24 → 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.
Files changed (33) hide show
  1. package/cbb/dev-standards/rules/cbb-ai-behavior.md +2 -2
  2. package/cbb/lib/install/init.js +23 -21
  3. package/cbb/lib/install/workspaces.js +15 -15
  4. package/cbb/lib/utils/githook.js +9 -7
  5. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
  6. package/cbb/worktrees/_shared/scripts/install-git-hook.js +1 -1
  7. package/cbb/worktrees/_shared/scripts/start-local.js +4 -4
  8. package/cbb/worktrees/skills/cbb-local-mode/scripts/install-git-hook.js +1 -1
  9. package/cbb/worktrees/skills/cbb-local-mode/scripts/start-local.js +4 -4
  10. package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +7 -7
  11. package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-env.js +3 -3
  12. package/cbb/worktrees/skills/cbb-worktree-close/scripts/delete-branches.js +1 -1
  13. package/cbb/worktrees/skills/cbb-worktree-close/scripts/discover-apps.js +4 -4
  14. package/cbb/worktrees/skills/cbb-worktree-close/scripts/find-workspace-root.js +7 -7
  15. package/cbb/worktrees/skills/cbb-worktree-close/scripts/remove-worktrees.js +1 -1
  16. package/cbb/worktrees/skills/cbb-worktree-close/scripts/safety-check.js +1 -1
  17. package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +22 -22
  18. package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-env.js +1 -1
  19. package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-repos.js +2 -2
  20. package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-branches.js +3 -3
  21. package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-worktrees.js +4 -4
  22. package/cbb/worktrees/skills/cbb-worktree-init/scripts/find-workspace-root.js +7 -7
  23. package/cbb/worktrees/skills/cbb-worktree-init/scripts/install-git-hook.js +1 -1
  24. package/cbb/worktrees/skills/cbb-worktree-init/scripts/parse-config.js +7 -7
  25. package/cbb/worktrees/skills/cbb-worktree-init/scripts/push-branches.js +3 -3
  26. package/cbb/worktrees/skills/cbb-worktree-init/scripts/sync-repos.js +6 -6
  27. package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +7 -7
  28. package/cbb/worktrees/skills/cbb-worktree-push/scripts/commit-worktrees.js +2 -2
  29. package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-workspace-root.js +7 -7
  30. package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-worktrees.js +2 -2
  31. package/config/{workspace-config.sample.json → CBB-WORKSPACE.sample.json} +1 -1
  32. package/config/workspace-agents.sample.md +4 -44
  33. package/package.json +1 -1
@@ -101,7 +101,7 @@ trigger: always_on
101
101
 
102
102
  ## 8. 业务空间开发模式(双模式,用户选择制)
103
103
 
104
- **仅当工作目录是业务空间根(存在 `workspace-config.json` 且 `.git` 为目录)时生效。空间支持两种开发模式,能力对称(都能修改 workspace 内容与应用代码、都强制分支隔离、交付都走 MR),由用户显式选择,agent 只给推荐不代决。**
104
+ **仅当工作目录是业务空间根(存在 `CBB-WORKSPACE.json` 且 `.git` 为目录)时生效。空间支持两种开发模式,能力对称(都能修改 workspace 内容与应用代码、都强制分支隔离、交付都走 MR),由用户显式选择,agent 只给推荐不代决。**
105
105
 
106
106
  **模式一 · 本地模式(单线程快改,当前会话就地干):**
107
107
 
@@ -117,7 +117,7 @@ trigger: always_on
117
117
  **基准与防线(两模式共同,ADR 0002):**
118
118
 
119
119
  - **基准 = `origin/main`(唯一真相源);`.codespace/<app>/` 的检出 = 视图**——本地模式可暂态被需求分支占用,收尾恢复
120
- - **严禁直接在任何 main 检出上提交载荷**:分支感知 pre-commit hook 机械拦截(workspace 仓库仅放行控制面白名单:`workspace-config.json` / `.gitignore` / `AGENTS.md` / `openspec/config.yaml` / `openspec/schemas/**`;应用仓库 main 全拦)——**被拦是防线生效,不是故障**;`--no-verify` 绕过仅限用户显式要求
120
+ - **严禁直接在任何 main 检出上提交载荷**:分支感知 pre-commit hook 机械拦截(workspace 仓库仅放行控制面白名单:`CBB-WORKSPACE.json` / `.gitignore` / `AGENTS.md` / `openspec/config.yaml` / `openspec/schemas/**`;应用仓库 main 全拦)——**被拦是防线生效,不是故障**;`--no-verify` 绕过仅限用户显式要求
121
121
  - 远端推送唯一出口 = `cbb-worktree-push`(init 创建流程零远端操作,lazy push;空分支尸体不存在)
122
122
  - **模式误判零代价**:本地模式中途要并行/隔离 → 重跑 `cbb-worktree-init`(分支已存在自动复用,提交随身带走)
123
123
 
@@ -152,13 +152,15 @@ function detectExistingInstall() {
152
152
  }
153
153
 
154
154
  /**
155
- * 判定目标目录是否为业务空间根:workspace-config.json 存在且 .git 是目录。
156
- * 需求工作树内也有 workspace-config.json(tracked 副本),但其 .git 是文件(gitdir 指针),
155
+ * 判定目标目录是否为业务空间根:CBB-WORKSPACE.json(或旧名 workspace-config.json)存在且 .git 是目录。
156
+ * 需求工作树内也有该文件(tracked 副本),但其 .git 是文件(gitdir 指针),
157
157
  * 必须以 .git 形态排除——避免「在 worktree 里误跑 cbb update」被当作空间根
158
158
  * (误装 worktree 管理入口、在错误位置报旧导航提示)。
159
+ * 双名识别用于改名过渡期:存量空间(旧名)跑 update 时仍能识别并装上新版 hook。
159
160
  */
160
161
  function detectWorkspaceRoot() {
161
- if (!fs.existsSync(path.join(TARGET_DIR, 'workspace-config.json'))) return false;
162
+ if (!fs.existsSync(path.join(TARGET_DIR, 'CBB-WORKSPACE.json'))
163
+ && !fs.existsSync(path.join(TARGET_DIR, 'workspace-config.json'))) return false;
162
164
  const gitPath = path.join(TARGET_DIR, '.git');
163
165
  return fs.existsSync(gitPath) && fs.statSync(gitPath).isDirectory();
164
166
  }
@@ -1332,12 +1334,12 @@ function decideUpgradeIfInstalled(targetDir, selectedAdapters) {
1332
1334
  }
1333
1335
 
1334
1336
  /**
1335
- * 检查业务空间根目录下是否有 workspace-config.json(init-worktree 技能依赖)。
1336
- * 不存在时,将包内样例文件复制为 workspace-config.json。
1337
+ * 检查业务空间根目录下是否有 CBB-WORKSPACE.json(init-worktree 技能依赖)。
1338
+ * 不存在时,将包内样例文件复制为 CBB-WORKSPACE.json。
1337
1339
  * 返回 'exists' | 'created'(不打印,由调用方汇总输出)。
1338
1340
  */
1339
1341
  function ensureWorkspaceConfig(targetDir) {
1340
- const configPath = path.join(targetDir, 'workspace-config.json');
1342
+ const configPath = path.join(targetDir, 'CBB-WORKSPACE.json');
1341
1343
  if (fs.existsSync(configPath)) return 'exists';
1342
1344
 
1343
1345
  const samplePath = path.join(SHARED_STANDARDS_DIR, workspaces.SAMPLE_CONFIG);
@@ -1346,12 +1348,12 @@ function ensureWorkspaceConfig(targetDir) {
1346
1348
  }
1347
1349
 
1348
1350
  /**
1349
- * 读取 workspace-config.json 中的应用列表,将关联应用代码 clone/fetch 到 .codespace/ 目录。
1351
+ * 读取 CBB-WORKSPACE.json 中的应用列表,将关联应用代码 clone/fetch 到 .codespace/ 目录。
1350
1352
  * 首次 clone(耗时较长),后续 fetch --all(秒级更新)。
1351
1353
  * 这是基准代码,init-worktree 技能后续只做轻量 fetch 检查。
1352
1354
  */
1353
1355
  /**
1354
- * 读取 workspace-config.json,将关联应用代码 clone/fetch 到 .codespace/ 目录。
1356
+ * 读取 CBB-WORKSPACE.json,将关联应用代码 clone/fetch 到 .codespace/ 目录。
1355
1357
  * 不打印逐条日志,返回汇总对象由调用方渲染:
1356
1358
  * { ok, fail, updated[], cloned[], fetchFailed[], sampleApps[], invalid[] }
1357
1359
  * 长耗时(首次 clone),通过 onProgress 回调实时提示当前正在处理哪个应用。
@@ -1360,7 +1362,7 @@ function ensureWorkspaceConfig(targetDir) {
1360
1362
  */
1361
1363
  async function syncAppRepos(targetDir, onProgress = () => {}) {
1362
1364
  const summary = { ok: 0, fail: 0, updated: [], cloned: [], fetchFailed: [], sampleApps: [], invalid: [] };
1363
- const configPath = path.join(targetDir, 'workspace-config.json');
1365
+ const configPath = path.join(targetDir, 'CBB-WORKSPACE.json');
1364
1366
  if (!fs.existsSync(configPath)) return summary;
1365
1367
 
1366
1368
  let config;
@@ -1514,7 +1516,7 @@ async function syncWorkspaceRepo(targetDir, onProgress = () => {}) {
1514
1516
  }
1515
1517
 
1516
1518
  /**
1517
- * 处理单个业务空间:计算子目录 → 检测/克隆 → workspace-config.json → 拉取应用代码 → 升级询问 → 安装 AI 配置。
1519
+ * 处理单个业务空间:计算子目录 → 检测/克隆 → CBB-WORKSPACE.json → 拉取应用代码 → 升级询问 → 安装 AI 配置。
1518
1520
  * 输出为紧凑步进行(✓ 标签 值),失败时不抛出也不退出,返回结果对象供调用方汇总。
1519
1521
  * @param {object} [opts] - { selectedAdapters } cbb setup 上层选定的适配器(透传给空间级安装)
1520
1522
  * @returns {Promise<{ok: boolean, error?: string, message?: string, subdir?: string, skipped?: boolean}>}
@@ -1576,28 +1578,28 @@ async function initSingleWorkspace(w, opts = {}) {
1576
1578
  step('✓', '仓库', `已克隆 ${subdirName}/`);
1577
1579
  }
1578
1580
 
1579
- // 3. workspace-config.json:缺失则从样例生成,随后校验格式
1581
+ // 3. CBB-WORKSPACE.json:缺失则从样例生成,随后校验格式
1580
1582
  const cfgState = ensureWorkspaceConfig(targetDir);
1581
- const configPath = path.join(targetDir, 'workspace-config.json');
1583
+ const configPath = path.join(targetDir, 'CBB-WORKSPACE.json');
1582
1584
  const configValidation = workspaces.validateWorkspaceConfig(configPath);
1583
1585
  if (!configValidation.valid) {
1584
- step('✗', '配置', `workspace-config.json 校验失败:${configValidation.message}`,
1586
+ step('✗', '配置', `CBB-WORKSPACE.json 校验失败:${configValidation.message}`,
1585
1587
  { iconColor: 'red', labelColor: 'red', valueColor: 'red' });
1586
- // 撤销本次克隆,使工作空间回到初始状态,用户配好 workspace-config.json 后可重新执行
1588
+ // 撤销本次克隆,使工作空间回到初始状态,用户配好 CBB-WORKSPACE.json 后可重新执行
1587
1589
  if (wasCloned && fs.existsSync(targetDir)) {
1588
1590
  removePath(targetDir);
1589
- log(`已撤销本次克隆(${subdirName}/),请配好 workspace-config.json 后重新执行 cbb setup`, 'warn');
1591
+ log(`已撤销本次克隆(${subdirName}/),请配好 CBB-WORKSPACE.json 后重新执行 cbb setup`, 'warn');
1590
1592
  } else {
1591
- log('请修正 workspace-config.json 后重新执行 cbb setup', 'warn');
1593
+ log('请修正 CBB-WORKSPACE.json 后重新执行 cbb setup', 'warn');
1592
1594
  }
1593
1595
  log(`参考格式:${path.join(SHARED_STANDARDS_DIR, workspaces.SAMPLE_CONFIG)}`, 'info');
1594
1596
  return { ok: false, error: 'CONFIG_INVALID', message: configValidation.message };
1595
1597
  }
1596
1598
  if (cfgState === 'created') {
1597
- step('!', '配置', 'workspace-config.json 已从样例生成,请编辑 apps 后重跑 cbb setup',
1599
+ step('!', '配置', 'CBB-WORKSPACE.json 已从样例生成,请编辑 apps 后重跑 cbb setup',
1598
1600
  { iconColor: 'yellow', valueColor: 'yellow' });
1599
1601
  } else {
1600
- step('✓', '配置', `workspace-config.json(${configValidation.config.apps.length} 个应用)`);
1602
+ step('✓', '配置', `CBB-WORKSPACE.json(${configValidation.config.apps.length} 个应用)`);
1601
1603
  }
1602
1604
 
1603
1605
  // 4. 拉取关联应用代码到 .codespace/(基准代码,首次 clone 较慢,实时提示当前应用)
@@ -1615,7 +1617,7 @@ async function initSingleWorkspace(w, opts = {}) {
1615
1617
  step(appWarn ? '!' : '✓', '应用', appParts.join(' · '), { iconColor: appWarn ? 'yellow' : 'green' });
1616
1618
  if (apps.sampleApps.length > 0) {
1617
1619
  const names = apps.sampleApps.map(a => a.name).join('、');
1618
- console.log(` ${c('gray', `${names} → 编辑 workspace-config.json 填入真实仓库地址`)}`);
1620
+ console.log(` ${c('gray', `${names} → 编辑 CBB-WORKSPACE.json 填入真实仓库地址`)}`);
1619
1621
  }
1620
1622
 
1621
1623
  // 5. 若已安装:版本一致且无新增工具才跳过;否则继续安装/升级(setup 已整体确认过,不再二次询问)
@@ -1641,7 +1643,7 @@ function describeBatchError(r) {
1641
1643
  case 'DIR_MISMATCH': return '子目录已存在但不是该业务空间的仓库';
1642
1644
  case 'CLONE_FAILED': return `git clone 失败:${r.message || ''}`.trim();
1643
1645
  case 'PULL_FAILED': return `工作空间仓库同步失败:${r.message || ''}`.trim();
1644
- case 'CONFIG_INVALID': return `workspace-config.json 不合法:${r.message || ''}`.trim();
1646
+ case 'CONFIG_INVALID': return `CBB-WORKSPACE.json 不合法:${r.message || ''}`.trim();
1645
1647
  case 'INIT_FAILED': return `初始化失败:${r.message || ''}`.trim();
1646
1648
  default: return r.error || '未知错误';
1647
1649
  }
@@ -1839,7 +1841,7 @@ async function setupUserLevelComponents(targetAdapters = adapters) {
1839
1841
  /**
1840
1842
  * cbb update:就地升级当前目录内容 + 用户级组件。
1841
1843
  *
1842
- * 单层安装:统一安装器按空间根判定(workspace-config.json + .git 目录)补齐
1844
+ * 单层安装:统一安装器按空间根判定(CBB-WORKSPACE.json + .git 目录)补齐
1843
1845
  * worktree 管理入口与空间导航;旧子集清单升级时由清单差集机制自动补齐全量内容。
1844
1846
  */
1845
1847
  async function updateInstalled() {
@@ -16,7 +16,7 @@ const path = require('path');
16
16
  const { execSync } = require('child_process');
17
17
 
18
18
  const DEFAULT_CONFIG = 'config/workspaces.json';
19
- const SAMPLE_CONFIG = 'config/workspace-config.sample.json';
19
+ const SAMPLE_CONFIG = 'config/CBB-WORKSPACE.sample.json';
20
20
  const SAMPLE_AGENTS_MD = 'config/workspace-agents.sample.md';
21
21
 
22
22
  /**
@@ -104,7 +104,7 @@ function loadWorkspaces(configPath = DEFAULT_CONFIG) {
104
104
  }
105
105
 
106
106
  /**
107
- * 校验业务工作空间 workspace-config.json 的格式是否合法。
107
+ * 校验业务工作空间 CBB-WORKSPACE.json 的格式是否合法。
108
108
  *
109
109
  * 校验项:
110
110
  * - 文件存在且为合法 JSON
@@ -113,31 +113,31 @@ function loadWorkspaces(configPath = DEFAULT_CONFIG) {
113
113
  * - name、repo 为非空字符串;side 必须为 'front'、'back' 或 'mixed'
114
114
  * - desc 为可选字段;一旦出现必须是非空字符串(应用职责描述)
115
115
  *
116
- * @param {string} configPath workspace-config.json 的绝对路径
116
+ * @param {string} configPath CBB-WORKSPACE.json 的绝对路径
117
117
  * @returns {{ valid: boolean, message?: string, config?: object }}
118
118
  */
119
119
  function validateWorkspaceConfig(configPath) {
120
120
  if (!fs.existsSync(configPath)) {
121
- return { valid: false, message: `workspace-config.json 不存在:${configPath}` };
121
+ return { valid: false, message: `CBB-WORKSPACE.json 不存在:${configPath}` };
122
122
  }
123
123
 
124
124
  let raw;
125
125
  try {
126
126
  raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
127
127
  } catch (e) {
128
- return { valid: false, message: `workspace-config.json 不是合法 JSON:${e.message}` };
128
+ return { valid: false, message: `CBB-WORKSPACE.json 不是合法 JSON:${e.message}` };
129
129
  }
130
130
 
131
131
  if (!raw || typeof raw !== 'object') {
132
- return { valid: false, message: 'workspace-config.json 内容应为 JSON 对象' };
132
+ return { valid: false, message: 'CBB-WORKSPACE.json 内容应为 JSON 对象' };
133
133
  }
134
134
 
135
135
  if (!Array.isArray(raw.apps)) {
136
- return { valid: false, message: 'workspace-config.json 缺少 apps 数组' };
136
+ return { valid: false, message: 'CBB-WORKSPACE.json 缺少 apps 数组' };
137
137
  }
138
138
 
139
139
  if (raw.apps.length === 0) {
140
- return { valid: false, message: 'workspace-config.json 中 apps 数组为空,请至少配置一个关联应用' };
140
+ return { valid: false, message: 'CBB-WORKSPACE.json 中 apps 数组为空,请至少配置一个关联应用' };
141
141
  }
142
142
 
143
143
  const VALID_SIDES = ['front', 'back', 'mixed'];
@@ -146,22 +146,22 @@ function validateWorkspaceConfig(configPath) {
146
146
  const label = `第 ${i + 1} 项`;
147
147
 
148
148
  if (!app || typeof app !== 'object') {
149
- return { valid: false, message: `workspace-config.json ${label}不是对象` };
149
+ return { valid: false, message: `CBB-WORKSPACE.json ${label}不是对象` };
150
150
  }
151
151
  if (typeof app.name !== 'string' || !app.name.trim()) {
152
- return { valid: false, message: `workspace-config.json ${label}缺少 name(应用名)` };
152
+ return { valid: false, message: `CBB-WORKSPACE.json ${label}缺少 name(应用名)` };
153
153
  }
154
154
  if (typeof app.repo !== 'string' || !app.repo.trim()) {
155
- return { valid: false, message: `workspace-config.json "${app.name}" 缺少 repo(Git 仓库地址)` };
155
+ return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 缺少 repo(Git 仓库地址)` };
156
156
  }
157
157
  if (typeof app.side !== 'string' || !app.side.trim()) {
158
- return { valid: false, message: `workspace-config.json "${app.name}" 缺少 side(仓库类型,可选值:front / back / mixed)` };
158
+ return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 缺少 side(仓库类型,可选值:front / back / mixed)` };
159
159
  }
160
160
  if (!VALID_SIDES.includes(app.side.trim())) {
161
- return { valid: false, message: `workspace-config.json "${app.name}" 的 side 字段值无效:"${app.side}"(可选值:front / back / mixed)` };
161
+ return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 的 side 字段值无效:"${app.side}"(可选值:front / back / mixed)` };
162
162
  }
163
163
  if (app.desc !== undefined && (typeof app.desc !== 'string' || !app.desc.trim())) {
164
- return { valid: false, message: `workspace-config.json "${app.name}" 的 desc 字段应为非空字符串(该应用的职责描述),不需要可整条删除` };
164
+ return { valid: false, message: `CBB-WORKSPACE.json "${app.name}" 的 desc 字段应为非空字符串(该应用的职责描述),不需要可整条删除` };
165
165
  }
166
166
  }
167
167
 
@@ -272,7 +272,7 @@ function extractRepoBasename(url) {
272
272
 
273
273
  /**
274
274
  * 判断 repo 是否为样例占位地址(RFC 2606 保留域名)。
275
- * 样例 workspace-config.json 的 repo 用 example.com 等占位,clone 必然失败;
275
+ * 样例 CBB-WORKSPACE.json 的 repo 用 example.com 等占位,clone 必然失败;
276
276
  * setup 据此逐条跳过空跑并给出明确编辑提示。
277
277
  * 支持 SSH(git@host:path)与 URL(ssh://、https://、git://)两种形式的 host 提取。
278
278
  *
@@ -5,9 +5,10 @@
5
5
  *
6
6
  * 策略(对当前仓库生效,worktree 与主仓库共享 .git/hooks 故一并覆盖):
7
7
  * - 当前分支非主干(含 detached HEAD)→ 一律放行(两模式开发态都在需求分支上)
8
- * - workspace 仓库(检出含 workspace-config.json)在主干上 → 只放行控制面白名单路径:
9
- * workspace-config.json / .gitignore / AGENTS.md / openspec/config.yaml /
10
- * openspec/schemas/** / .cbb/**(配置变更与 cbb update 部署物,直改即推)
8
+ * - workspace 仓库(检出含 CBB-WORKSPACE.json)在主干上 → 只放行控制面白名单路径:
9
+ * CBB-WORKSPACE.json / .gitignore / AGENTS.md / openspec/config.yaml /
10
+ * openspec/schemas/** / .cbb/**(配置变更与 cbb update 部署物,直改即推);
11
+ * 另放行旧名 workspace-config.json 的删除条目(仅用于一次性更名迁移)
11
12
  * - 应用仓库在主干上 → 全拦(交付只走 MR)
12
13
  * - 逃生口:用户显式 git commit --no-verify(AI 侧纪律禁止自动绕过)
13
14
  *
@@ -60,20 +61,21 @@ const PRE_COMMIT_SOURCE = [
60
61
  "const files = staged.split(/\\r?\\n/).filter(Boolean);",
61
62
  'if (files.length === 0) process.exit(0);',
62
63
  '',
63
- '// 仓库类型:workspace 仓库 = 检出含 workspace-config.json',
64
- "const isWorkspace = fs.existsSync('workspace-config.json');",
64
+ '// 仓库类型:workspace 仓库 = 检出含 CBB-WORKSPACE.json(或旧名,改名过渡期识别)',
65
+ "const isWorkspace = fs.existsSync('CBB-WORKSPACE.json') || fs.existsSync('workspace-config.json');",
65
66
  '',
66
67
  'function deny(bad) {',
67
68
  " console.error('[cbb-guard] 主干上拦截载荷提交(ADR 0002):');",
68
69
  " bad.forEach(f => console.error(' ' + f));",
69
70
  " console.error('需求载荷须在需求分支上提交:本地模式先 git checkout -b <需求名>;worktree 模式在 .worktrees/ 工作树内提交。');",
70
- " console.error('控制面白名单:workspace-config.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');",
71
+ " console.error('控制面白名单:CBB-WORKSPACE.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');",
71
72
  " console.error('如确需在主干提交,须由用户显式 git commit --no-verify。');",
72
73
  ' process.exit(1);',
73
74
  '}',
74
75
  '',
75
76
  'if (isWorkspace) {',
76
- " const EXACT = new Set(['workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);",
77
+ ' // 旧名仅放行删除条目:更名迁移提交(git mv)会产生旧名删除 + 新名新增两条',
78
+ " const EXACT = new Set(['CBB-WORKSPACE.json', 'workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);",
77
79
  " const PREFIXES = ['openspec/schemas/', '.cbb/'];",
78
80
  ' const bad = files.filter(f => !EXACT.has(f) && !PREFIXES.some(p => f.indexOf(p) === 0));',
79
81
  ' if (bad.length) deny(bad);',
@@ -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 内 workspace-config.json 副本干扰)
9
- * 兜底:当前目录含 workspace-config.json
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
- // 兜底:当前目录含 workspace-config.json
47
+ // 兜底:当前目录含 CBB-WORKSPACE.json
48
48
  if (!wsRoot) {
49
49
  const cwd = process.cwd();
50
- if (fs.existsSync(path.join(cwd, 'workspace-config.json'))) {
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, 'workspace-config.json'))) {
56
+ if (!wsRoot || !fs.existsSync(path.join(wsRoot, 'CBB-WORKSPACE.json'))) {
57
57
  console.error('❌ 未找到工作空间根目录');
58
- console.error(' 原因:git worktree list 失败且当前目录无 workspace-config.json');
59
- console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含 workspace-config.json)下执行本技能');
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
 
@@ -20,7 +20,7 @@ const HOOK_FILE = 'pre-commit';
20
20
  const BACKUP_SUFFIX = '.cbb-backup';
21
21
 
22
22
  // 与 cbb/lib/utils/githook.js 的 buildPreCommitSource() 输出完全一致(构建时注入)
23
- const PRE_COMMIT_SOURCE = "#!/usr/bin/env node\n// managed-by-cbb v1 —— 分支感知提交防线(ADR 0002)\n// main 上:workspace 仓库只放行控制面白名单,应用仓库全拦;非 main 一律放行。\n// 绕过逃生口仅限用户显式 git commit --no-verify。\nconst { execSync } = require('child_process');\nconst fs = require('fs');\nfunction run(cmd) {\n try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim(); }\n catch (e) { return null; }\n}\nconst branch = run('git branch --show-current') || '';\n// 主干名:优先远端 HEAD 指向;探测失败按本地 main/master 存在性回退\nlet main = null;\nconst remotes = run('git remote');\nif (remotes) {\n const r = remotes.split(/\\r?\\n/)[0];\n const sym = run('git symbolic-ref \"refs/remotes/' + r + '/HEAD\"');\n if (sym) main = sym.replace('refs/remotes/' + r + '/', '');\n}\nif (!main) {\n if (run('git rev-parse --verify --quiet refs/heads/main')) main = 'main';\n else if (run('git rev-parse --verify --quiet refs/heads/master')) main = 'master';\n}\n// 非主干(含 detached / 探测失败)→ 放行\nif (!main || branch !== main) process.exit(0);\n\n// 主干上的提交:收集 staged 变更(空提交放行)\nconst staged = run('git diff --cached --name-only') || '';\nconst files = staged.split(/\\r?\\n/).filter(Boolean);\nif (files.length === 0) process.exit(0);\n\n// 仓库类型:workspace 仓库 = 检出含 workspace-config.json\nconst isWorkspace = fs.existsSync('workspace-config.json');\n\nfunction deny(bad) {\n console.error('[cbb-guard] 主干上拦截载荷提交(ADR 0002):');\n bad.forEach(f => console.error(' ' + f));\n console.error('需求载荷须在需求分支上提交:本地模式先 git checkout -b <需求名>;worktree 模式在 .worktrees/ 工作树内提交。');\n console.error('控制面白名单:workspace-config.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');\n console.error('如确需在主干提交,须由用户显式 git commit --no-verify。');\n process.exit(1);\n}\n\nif (isWorkspace) {\n const EXACT = new Set(['workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);\n const PREFIXES = ['openspec/schemas/', '.cbb/'];\n const bad = files.filter(f => !EXACT.has(f) && !PREFIXES.some(p => f.indexOf(p) === 0));\n if (bad.length) deny(bad);\n} else {\n deny(files);\n}\nprocess.exit(0);\n";
23
+ const PRE_COMMIT_SOURCE = "#!/usr/bin/env node\n// managed-by-cbb v1 —— 分支感知提交防线(ADR 0002)\n// main 上:workspace 仓库只放行控制面白名单,应用仓库全拦;非 main 一律放行。\n// 绕过逃生口仅限用户显式 git commit --no-verify。\nconst { execSync } = require('child_process');\nconst fs = require('fs');\nfunction run(cmd) {\n try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim(); }\n catch (e) { return null; }\n}\nconst branch = run('git branch --show-current') || '';\n// 主干名:优先远端 HEAD 指向;探测失败按本地 main/master 存在性回退\nlet main = null;\nconst remotes = run('git remote');\nif (remotes) {\n const r = remotes.split(/\\r?\\n/)[0];\n const sym = run('git symbolic-ref \"refs/remotes/' + r + '/HEAD\"');\n if (sym) main = sym.replace('refs/remotes/' + r + '/', '');\n}\nif (!main) {\n if (run('git rev-parse --verify --quiet refs/heads/main')) main = 'main';\n else if (run('git rev-parse --verify --quiet refs/heads/master')) main = 'master';\n}\n// 非主干(含 detached / 探测失败)→ 放行\nif (!main || branch !== main) process.exit(0);\n\n// 主干上的提交:收集 staged 变更(空提交放行)\nconst staged = run('git diff --cached --name-only') || '';\nconst files = staged.split(/\\r?\\n/).filter(Boolean);\nif (files.length === 0) process.exit(0);\n\n// 仓库类型:workspace 仓库 = 检出含 CBB-WORKSPACE.json(或旧名,改名过渡期识别)\nconst isWorkspace = fs.existsSync('CBB-WORKSPACE.json') || fs.existsSync('workspace-config.json');\n\nfunction deny(bad) {\n console.error('[cbb-guard] 主干上拦截载荷提交(ADR 0002):');\n bad.forEach(f => console.error(' ' + f));\n console.error('需求载荷须在需求分支上提交:本地模式先 git checkout -b <需求名>;worktree 模式在 .worktrees/ 工作树内提交。');\n console.error('控制面白名单:CBB-WORKSPACE.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');\n console.error('如确需在主干提交,须由用户显式 git commit --no-verify。');\n process.exit(1);\n}\n\nif (isWorkspace) {\n // 旧名仅放行删除条目:更名迁移提交(git mv)会产生旧名删除 + 新名新增两条\n const EXACT = new Set(['CBB-WORKSPACE.json', 'workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);\n const PREFIXES = ['openspec/schemas/', '.cbb/'];\n const bad = files.filter(f => !EXACT.has(f) && !PREFIXES.some(p => f.indexOf(p) === 0));\n if (bad.length) deny(bad);\n} else {\n deny(files);\n}\nprocess.exit(0);\n";
24
24
 
25
25
  function isCbbHookContent(content) {
26
26
  return typeof content === 'string' && content.includes(HOOK_MARKER);
@@ -9,7 +9,7 @@
9
9
  * 退出码 2(agent 应升级为用户决策:继续 / 收尾 / 升级 / 丢弃,不在本脚本内处理)
10
10
  * 2. 参与仓库 = workspace + 应用子集:
11
11
  * - --apps a,b → 指定应用(本地模式推荐:从需求语境提取涉及应用)
12
- * - --all-apps → workspace-config.json 全量应用
12
+ * - --all-apps → CBB-WORKSPACE.json 全量应用
13
13
  * - 缺省 → 仅 workspace(后续重跑幂等补齐,与 worktree-init 增补语义一致)
14
14
  * 3. 每个仓库:
15
15
  * - 当前已在 <branch> → reused
@@ -108,10 +108,10 @@ if (argApps >= 0) {
108
108
  appNames = raw.split(',').map(s => s.trim()).filter(Boolean);
109
109
  } else if (argAll) {
110
110
  try {
111
- const config = JSON.parse(fs.readFileSync(path.join(wsRoot, 'workspace-config.json'), 'utf-8'));
111
+ const config = JSON.parse(fs.readFileSync(path.join(wsRoot, 'CBB-WORKSPACE.json'), 'utf-8'));
112
112
  appNames = (config.apps || []).map(a => a.name);
113
113
  } catch (e) {
114
- console.error('❌ 读取 workspace-config.json 失败:' + e.message);
114
+ console.error('❌ 读取 CBB-WORKSPACE.json 失败:' + e.message);
115
115
  process.exit(2);
116
116
  }
117
117
  }
@@ -120,7 +120,7 @@ const targets = [{ name: 'workspace', dir: wsRoot }];
120
120
  for (const name of appNames) {
121
121
  const appDir = path.join(wsRoot, '.codespace', name);
122
122
  if (!fs.existsSync(path.join(appDir, '.git'))) {
123
- console.error('❌ 应用仓库不存在:.codespace/' + name + '(请检查 workspace-config.json 或先跑 cbb setup)');
123
+ console.error('❌ 应用仓库不存在:.codespace/' + name + '(请检查 CBB-WORKSPACE.json 或先跑 cbb setup)');
124
124
  process.exit(2);
125
125
  }
126
126
  targets.push({ name, dir: appDir });
@@ -20,7 +20,7 @@ const HOOK_FILE = 'pre-commit';
20
20
  const BACKUP_SUFFIX = '.cbb-backup';
21
21
 
22
22
  // 与 cbb/lib/utils/githook.js 的 buildPreCommitSource() 输出完全一致(构建时注入)
23
- const PRE_COMMIT_SOURCE = "#!/usr/bin/env node\n// managed-by-cbb v1 —— 分支感知提交防线(ADR 0002)\n// main 上:workspace 仓库只放行控制面白名单,应用仓库全拦;非 main 一律放行。\n// 绕过逃生口仅限用户显式 git commit --no-verify。\nconst { execSync } = require('child_process');\nconst fs = require('fs');\nfunction run(cmd) {\n try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim(); }\n catch (e) { return null; }\n}\nconst branch = run('git branch --show-current') || '';\n// 主干名:优先远端 HEAD 指向;探测失败按本地 main/master 存在性回退\nlet main = null;\nconst remotes = run('git remote');\nif (remotes) {\n const r = remotes.split(/\\r?\\n/)[0];\n const sym = run('git symbolic-ref \"refs/remotes/' + r + '/HEAD\"');\n if (sym) main = sym.replace('refs/remotes/' + r + '/', '');\n}\nif (!main) {\n if (run('git rev-parse --verify --quiet refs/heads/main')) main = 'main';\n else if (run('git rev-parse --verify --quiet refs/heads/master')) main = 'master';\n}\n// 非主干(含 detached / 探测失败)→ 放行\nif (!main || branch !== main) process.exit(0);\n\n// 主干上的提交:收集 staged 变更(空提交放行)\nconst staged = run('git diff --cached --name-only') || '';\nconst files = staged.split(/\\r?\\n/).filter(Boolean);\nif (files.length === 0) process.exit(0);\n\n// 仓库类型:workspace 仓库 = 检出含 workspace-config.json\nconst isWorkspace = fs.existsSync('workspace-config.json');\n\nfunction deny(bad) {\n console.error('[cbb-guard] 主干上拦截载荷提交(ADR 0002):');\n bad.forEach(f => console.error(' ' + f));\n console.error('需求载荷须在需求分支上提交:本地模式先 git checkout -b <需求名>;worktree 模式在 .worktrees/ 工作树内提交。');\n console.error('控制面白名单:workspace-config.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');\n console.error('如确需在主干提交,须由用户显式 git commit --no-verify。');\n process.exit(1);\n}\n\nif (isWorkspace) {\n const EXACT = new Set(['workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);\n const PREFIXES = ['openspec/schemas/', '.cbb/'];\n const bad = files.filter(f => !EXACT.has(f) && !PREFIXES.some(p => f.indexOf(p) === 0));\n if (bad.length) deny(bad);\n} else {\n deny(files);\n}\nprocess.exit(0);\n";
23
+ const PRE_COMMIT_SOURCE = "#!/usr/bin/env node\n// managed-by-cbb v1 —— 分支感知提交防线(ADR 0002)\n// main 上:workspace 仓库只放行控制面白名单,应用仓库全拦;非 main 一律放行。\n// 绕过逃生口仅限用户显式 git commit --no-verify。\nconst { execSync } = require('child_process');\nconst fs = require('fs');\nfunction run(cmd) {\n try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim(); }\n catch (e) { return null; }\n}\nconst branch = run('git branch --show-current') || '';\n// 主干名:优先远端 HEAD 指向;探测失败按本地 main/master 存在性回退\nlet main = null;\nconst remotes = run('git remote');\nif (remotes) {\n const r = remotes.split(/\\r?\\n/)[0];\n const sym = run('git symbolic-ref \"refs/remotes/' + r + '/HEAD\"');\n if (sym) main = sym.replace('refs/remotes/' + r + '/', '');\n}\nif (!main) {\n if (run('git rev-parse --verify --quiet refs/heads/main')) main = 'main';\n else if (run('git rev-parse --verify --quiet refs/heads/master')) main = 'master';\n}\n// 非主干(含 detached / 探测失败)→ 放行\nif (!main || branch !== main) process.exit(0);\n\n// 主干上的提交:收集 staged 变更(空提交放行)\nconst staged = run('git diff --cached --name-only') || '';\nconst files = staged.split(/\\r?\\n/).filter(Boolean);\nif (files.length === 0) process.exit(0);\n\n// 仓库类型:workspace 仓库 = 检出含 CBB-WORKSPACE.json(或旧名,改名过渡期识别)\nconst isWorkspace = fs.existsSync('CBB-WORKSPACE.json') || fs.existsSync('workspace-config.json');\n\nfunction deny(bad) {\n console.error('[cbb-guard] 主干上拦截载荷提交(ADR 0002):');\n bad.forEach(f => console.error(' ' + f));\n console.error('需求载荷须在需求分支上提交:本地模式先 git checkout -b <需求名>;worktree 模式在 .worktrees/ 工作树内提交。');\n console.error('控制面白名单:CBB-WORKSPACE.json / .gitignore / AGENTS.md / openspec/config.yaml / openspec/schemas/** / .cbb/**');\n console.error('如确需在主干提交,须由用户显式 git commit --no-verify。');\n process.exit(1);\n}\n\nif (isWorkspace) {\n // 旧名仅放行删除条目:更名迁移提交(git mv)会产生旧名删除 + 新名新增两条\n const EXACT = new Set(['CBB-WORKSPACE.json', 'workspace-config.json', '.gitignore', 'AGENTS.md', 'openspec/config.yaml']);\n const PREFIXES = ['openspec/schemas/', '.cbb/'];\n const bad = files.filter(f => !EXACT.has(f) && !PREFIXES.some(p => f.indexOf(p) === 0));\n if (bad.length) deny(bad);\n} else {\n deny(files);\n}\nprocess.exit(0);\n";
24
24
 
25
25
  function isCbbHookContent(content) {
26
26
  return typeof content === 'string' && content.includes(HOOK_MARKER);
@@ -9,7 +9,7 @@
9
9
  * 退出码 2(agent 应升级为用户决策:继续 / 收尾 / 升级 / 丢弃,不在本脚本内处理)
10
10
  * 2. 参与仓库 = workspace + 应用子集:
11
11
  * - --apps a,b → 指定应用(本地模式推荐:从需求语境提取涉及应用)
12
- * - --all-apps → workspace-config.json 全量应用
12
+ * - --all-apps → CBB-WORKSPACE.json 全量应用
13
13
  * - 缺省 → 仅 workspace(后续重跑幂等补齐,与 worktree-init 增补语义一致)
14
14
  * 3. 每个仓库:
15
15
  * - 当前已在 <branch> → reused
@@ -108,10 +108,10 @@ if (argApps >= 0) {
108
108
  appNames = raw.split(',').map(s => s.trim()).filter(Boolean);
109
109
  } else if (argAll) {
110
110
  try {
111
- const config = JSON.parse(fs.readFileSync(path.join(wsRoot, 'workspace-config.json'), 'utf-8'));
111
+ const config = JSON.parse(fs.readFileSync(path.join(wsRoot, 'CBB-WORKSPACE.json'), 'utf-8'));
112
112
  appNames = (config.apps || []).map(a => a.name);
113
113
  } catch (e) {
114
- console.error('❌ 读取 workspace-config.json 失败:' + e.message);
114
+ console.error('❌ 读取 CBB-WORKSPACE.json 失败:' + e.message);
115
115
  process.exit(2);
116
116
  }
117
117
  }
@@ -120,7 +120,7 @@ const targets = [{ name: 'workspace', dir: wsRoot }];
120
120
  for (const name of appNames) {
121
121
  const appDir = path.join(wsRoot, '.codespace', name);
122
122
  if (!fs.existsSync(path.join(appDir, '.git'))) {
123
- console.error('❌ 应用仓库不存在:.codespace/' + name + '(请检查 workspace-config.json 或先跑 cbb setup)');
123
+ console.error('❌ 应用仓库不存在:.codespace/' + name + '(请检查 CBB-WORKSPACE.json 或先跑 cbb setup)');
124
124
  process.exit(2);
125
125
  }
126
126
  targets.push({ name, dir: appDir });
@@ -12,10 +12,10 @@ description: "关闭/清理/删除需求工作空间的 worktree 和分支。触
12
12
  ## 核心原则
13
13
 
14
14
  - 本技能的所有原子操作封装为 `scripts/*.js` Node.js 脚本,**跨平台执行**
15
- - 本技能是 `cbb-worktree-init` 的逆操作:共用 `workspace-config.json`、共用 `.worktrees/worktree-<需求名>/` 物理直聚命名、共用统一的分支名(不加前缀)
15
+ - 本技能是 `cbb-worktree-init` 的逆操作:共用 `CBB-WORKSPACE.json`、共用 `.worktrees/worktree-<需求名>/` 物理直聚命名、共用统一的分支名(不加前缀)
16
16
  - App worktree **物理嵌套**在 workspace worktree 的 `.codespace/` 容器内(`.worktrees/worktree-<需求名>/.codespace/<应用名>/`,镜像空间根布局,ADR 0003),但 git 上属于各自仓库的独立 worktree
17
17
  - 只操作 `.worktrees/worktree-<需求名>` 这一类精确路径,**绝不碰其它 worktree**(如 IDE/工具自动创建的 `~/.qoder/worktree/...` 会话 worktree)
18
- - 通过检查 `.worktrees/worktree-<需求名>/.codespace/<应用名>/` **是否实际存在**来确定关联应用——创建时用户可能只关联了 `workspace-config.json` 中的部分应用,不能假设全部应用都关联
18
+ - 通过检查 `.worktrees/worktree-<需求名>/.codespace/<应用名>/` **是否实际存在**来确定关联应用——创建时用户可能只关联了 `CBB-WORKSPACE.json` 中的部分应用,不能假设全部应用都关联
19
19
  - **顺序硬约束:先移除所有 worktree,再删除分支。** 目标分支当前正检出于 worktree 中,先删分支会报 `error: Cannot delete branch '<分支>' checked out at '<worktree 路径>'`
20
20
  - **破坏性操作必须先报告、经用户确认才执行**:未提交修改、未合并/未推送的提交,绝不静默 `--force` 或 `-D` 丢弃
21
21
  - 软性检查失败时报告详情,询问用户是否继续
@@ -34,7 +34,7 @@ node "<skill_dir>/scripts/<name>.js" <参数>
34
34
  ```
35
35
 
36
36
  > - `<skill_dir>` = 本 SKILL.md 所在目录的绝对路径(AI 从读取路径即可推出)
37
- > - **cwd 必须保持在工作空间根目录**:脚本按 cwd 定位 `workspace-config.json` 与 git 仓库
37
+ > - **cwd 必须保持在工作空间根目录**:脚本按 cwd 定位 `CBB-WORKSPACE.json` 与 git 仓库
38
38
  > - 不要用 `./scripts/...` 裸相对路径(AI 的 cwd 不是技能目录,会解析失败)
39
39
 
40
40
  ---
@@ -62,9 +62,9 @@ node "<skill_dir>/scripts/find-workspace-root.js"
62
62
  - 退出码 0 + 末行(纯路径) → WS_ROOT 绝对路径
63
63
  - 退出码 1 → 未找到工作空间根目录,**终止流程**
64
64
 
65
- > ⓘ **为什么不用 workspace-config.json 存在性判断**:init-worktree 会把 workspace-config.json 提交到主分支,`git worktree add` 会自动 checkout 副本到 worktree 目录中。若用 workspace-config.json 存在性判断,在 worktree 内执行时会错误地把 worktree 目录当作 WS_ROOT。使用 `git worktree list` 的第一行(git 契约上始终为主仓库绝对路径)则不受该问题影响。
65
+ > ⓘ **为什么不用 CBB-WORKSPACE.json 存在性判断**:init-worktree 会把 CBB-WORKSPACE.json 提交到主分支,`git worktree add` 会自动 checkout 副本到 worktree 目录中。若用 CBB-WORKSPACE.json 存在性判断,在 worktree 内执行时会错误地把 worktree 目录当作 WS_ROOT。使用 `git worktree list` 的第一行(git 契约上始终为主仓库绝对路径)则不受该问题影响。
66
66
 
67
- > close-worktree 是 init-worktree 的逆操作,但本步骤的 WS_ROOT 定位逻辑与 init-worktree 不同:init-worktree 强制根目录执行(不需要处理 worktree 场景),close-worktree 支持 worktree 内执行(需要绕开 workspace-config.json 副本陷阱)。
67
+ > close-worktree 是 init-worktree 的逆操作,但本步骤的 WS_ROOT 定位逻辑与 init-worktree 不同:init-worktree 强制根目录执行(不需要处理 worktree 场景),close-worktree 支持 worktree 内执行(需要绕开 CBB-WORKSPACE.json 副本陷阱)。
68
68
 
69
69
  ---
70
70
 
@@ -97,7 +97,7 @@ node "<skill_dir>/scripts/find-target-worktree.js "<ws_root>"
97
97
  node "<skill_dir>/scripts/discover-apps.js "<ws_root>" "<branch>"
98
98
  ```
99
99
 
100
- 脚本自动从 `workspace-config.json` 读取应用列表,扫描 `.worktrees/worktree-<branch>/.codespace/<应用名>/`(兼容 ≤beta.23 旧平铺 `<应用名>/`)实际存在的子目录。
100
+ 脚本自动从 `CBB-WORKSPACE.json` 读取应用列表,扫描 `.worktrees/worktree-<branch>/.codespace/<应用名>/`(兼容 ≤beta.23 旧平铺 `<应用名>/`)实际存在的子目录。
101
101
 
102
102
  **解读末行 `DISCOVER_RESULT`**:
103
103
  - `workspace` 字段:workspace worktree 绝对路径(AI agent 记录供后续命令使用)
@@ -430,7 +430,7 @@ git -C "<ws_root>" worktree list
430
430
 
431
431
  ### 必须执行
432
432
 
433
- - 读 `workspace-config.json` 取应用名列表;以 `.worktrees/worktree-<需求名>/.codespace/<应用名>/` 实际存在性确定关联清单
433
+ - 读 `CBB-WORKSPACE.json` 取应用名列表;以 `.worktrees/worktree-<需求名>/.codespace/<应用名>/` 实际存在性确定关联清单
434
434
  - 移除/删除前执行安全评估(未提交修改 / 是否合并 / 是否推远程)并报告
435
435
  - 严格按 Step 4.2(移除 worktree)→ Step 4.4(删分支)顺序
436
436
  - 移除 workspace worktree 前先把会话移出(`cd "<WS_ROOT>" &&` 或 `git -C` 绝对路径)
@@ -3,14 +3,14 @@ require('./silence-popup');
3
3
  /**
4
4
  * cbb-worktree-close 环境健康探活
5
5
  *
6
- * close-worktree 必须在工作空间根目录或 worktree 内执行,且需找到 workspace-config.json。
7
- * 与 init/extend 探活同构,但额外校验 workspace-config.json 存在性。
6
+ * close-worktree 必须在工作空间根目录或 worktree 内执行,且需找到 CBB-WORKSPACE.json。
7
+ * 与 init/extend 探活同构,但额外校验 CBB-WORKSPACE.json 存在性。
8
8
  *
9
9
  * 退出码:
10
10
  * 0 - 探活通过
11
11
  * 1 - 致命错误(git 不可用)
12
12
  * 2 - 当前不在 git 仓库
13
- * 3 - 未找到 workspace-config.json
13
+ * 3 - 未找到 CBB-WORKSPACE.json
14
14
  */
15
15
 
16
16
  const { execSync } = require('child_process');
@@ -116,7 +116,7 @@ function deleteBranch(repoPath, name) {
116
116
  return true;
117
117
  }
118
118
 
119
- const configPath = path.join(wsRoot, 'workspace-config.json');
119
+ const configPath = path.join(wsRoot, 'CBB-WORKSPACE.json');
120
120
  let config = {};
121
121
  try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) {}
122
122
 
@@ -5,7 +5,7 @@ require('./silence-popup');
5
5
  *
6
6
  * 用法:node discover-apps.js <ws_root> <branch>
7
7
  *
8
- * 从 workspace-config.json 读取应用列表,扫描 .worktrees/worktree-<branch>/ 实际存在的子目录。
8
+ * 从 CBB-WORKSPACE.json 读取应用列表,扫描 .worktrees/worktree-<branch>/ 实际存在的子目录。
9
9
  *
10
10
  * 输出末行:DISCOVER_RESULT { workspace: <wt_path>, apps: [{name, repo, side, wt_path}] }
11
11
  *
@@ -26,9 +26,9 @@ if (!wsRoot || !branch) {
26
26
  process.exit(1);
27
27
  }
28
28
 
29
- const configPath = path.join(wsRoot, 'workspace-config.json');
29
+ const configPath = path.join(wsRoot, 'CBB-WORKSPACE.json');
30
30
  if (!fs.existsSync(configPath)) {
31
- console.error('❌ workspace-config.json 不存在:' + configPath);
31
+ console.error('❌ CBB-WORKSPACE.json 不存在:' + configPath);
32
32
  process.exit(1);
33
33
  }
34
34
 
@@ -36,7 +36,7 @@ let config;
36
36
  try {
37
37
  config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
38
38
  } catch (e) {
39
- console.error('❌ workspace-config.json 解析失败:' + e.message);
39
+ console.error('❌ CBB-WORKSPACE.json 解析失败:' + e.message);
40
40
  process.exit(1);
41
41
  }
42
42
 
@@ -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 内 workspace-config.json 副本干扰)
9
- * 兜底:当前目录含 workspace-config.json
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
- // 兜底:当前目录含 workspace-config.json
47
+ // 兜底:当前目录含 CBB-WORKSPACE.json
48
48
  if (!wsRoot) {
49
49
  const cwd = process.cwd();
50
- if (fs.existsSync(path.join(cwd, 'workspace-config.json'))) {
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, 'workspace-config.json'))) {
56
+ if (!wsRoot || !fs.existsSync(path.join(wsRoot, 'CBB-WORKSPACE.json'))) {
57
57
  console.error('❌ 未找到工作空间根目录');
58
- console.error(' 原因:git worktree list 失败且当前目录无 workspace-config.json');
59
- console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含 workspace-config.json)下执行本技能');
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
 
@@ -83,7 +83,7 @@ function removeWt(repoPath, wtPath, name) {
83
83
  }
84
84
 
85
85
  // 1. 应用 worktrees
86
- const configPath = path.join(wsRoot, 'workspace-config.json');
86
+ const configPath = path.join(wsRoot, 'CBB-WORKSPACE.json');
87
87
  let config = {};
88
88
  try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) {}
89
89
 
@@ -152,7 +152,7 @@ function checkRepo(name, repoPath, wtPath) {
152
152
  return { name, wt: wtPath, fetch_ok: fetchOk, dirty_files: dirtyFiles, merged, main, remote_exists: remoteExists, remote: remoteName, unpushed_count: unpushedCount };
153
153
  }
154
154
 
155
- const configPath = path.join(wsRoot, 'workspace-config.json');
155
+ const configPath = path.join(wsRoot, 'CBB-WORKSPACE.json');
156
156
  let config = {};
157
157
  try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) {}
158
158