@jspg-ai/coding-bb 0.0.3-beta.3 → 0.0.3-beta.31
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 +135 -116
- package/cbb/lib/external/index.js +228 -0
- package/cbb/lib/install/agents-nav.js +92 -0
- package/cbb/lib/install/claude-code.js +7 -2
- package/cbb/lib/install/command-skill.js +105 -0
- package/cbb/lib/install/init.js +502 -168
- package/cbb/lib/install/minimax.js +60 -0
- package/cbb/lib/install/opencode.js +3 -5
- package/cbb/lib/install/qoder.js +1 -3
- package/cbb/lib/install/rule-rewrite.js +27 -0
- package/cbb/lib/install/setup-decision.js +48 -0
- package/cbb/lib/install/tool-selection.js +45 -0
- package/cbb/lib/install/trae.js +43 -0
- package/cbb/lib/install/workbuddy.js +36 -0
- package/cbb/lib/install/workspaces.js +21 -17
- package/cbb/lib/openspec/index.js +337 -554
- package/cbb/lib/superpowers/index.js +246 -265
- package/cbb/lib/utils/check-update.js +17 -2
- package/cbb/lib/utils/githook.js +226 -0
- package/cbb/lib/utils/gitignore.js +16 -3
- package/cbb/lib/utils/plugin-hook.js +92 -0
- package/cbb/lib/utils/settings.js +17 -4
- package/cbb/lib/utils/tar.js +92 -0
- package/cbb/lib/utils/upstream.js +90 -0
- package/cbb/worktrees/_shared/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/_shared/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/_shared/scripts/junction-ai-config.js +127 -0
- package/cbb/worktrees/_shared/scripts/start-local.js +180 -0
- package/cbb/worktrees/skills/cbb-local-mode/SKILL.md +158 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/start-local.js +180 -0
- package/cbb/worktrees/skills/cbb-worktree-close/SKILL.md +60 -43
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-env.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-unarchived.js +75 -48
- 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-target-worktree.js +148 -96
- 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 +13 -4
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/safety-check.js +11 -2
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +138 -129
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-env.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/check-repos.js +2 -2
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-branches.js +33 -8
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/create-worktrees.js +60 -46
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/junction-ai-config.js +127 -0
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/parse-config.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/push-branches.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/sync-repos.js +11 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/update-gitignore.js +37 -9
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +140 -71
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/commit-worktrees.js +70 -12
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/make-mr-urls.js +211 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-worktrees.js +67 -20
- package/config/{workspace-config.sample.json → CBB-WORKSPACE.sample.json} +1 -1
- package/config/openspec/schemas/spec-driven/schema.yaml +40 -30
- package/config/openspec/schemas/spec-driven/templates/design.md +0 -18
- package/config/openspec/schemas/spec-driven/templates/proposal.md +4 -3
- package/config/upstream-mirrors.json +17 -0
- package/config/workspace-agents.sample.md +4 -33
- package/external/frontend-design/.version +6 -0
- package/external/frontend-design/LICENSE.txt +177 -0
- package/external/frontend-design/SKILL.md +71 -0
- package/openspec/.version +2 -3
- package/openspec/commands/apply.md +189 -175
- package/openspec/commands/archive.md +244 -216
- package/openspec/commands/bulk-archive.md +362 -327
- package/openspec/commands/continue.md +115 -105
- package/openspec/commands/explore.md +230 -199
- package/openspec/commands/ff.md +115 -104
- package/openspec/commands/new.md +74 -63
- package/openspec/commands/onboard.md +562 -548
- package/openspec/commands/propose.md +161 -150
- package/openspec/commands/sync.md +277 -249
- package/openspec/commands/update.md +98 -80
- package/openspec/commands/verify.md +206 -162
- package/openspec/skills/openspec-apply-change/SKILL.md +20 -5
- package/openspec/skills/openspec-archive-change/SKILL.md +40 -11
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +46 -9
- package/openspec/skills/openspec-continue-change/SKILL.md +14 -3
- package/openspec/skills/openspec-explore/SKILL.md +22 -10
- package/openspec/skills/openspec-ff-change/SKILL.md +15 -3
- package/openspec/skills/openspec-new-change/SKILL.md +13 -1
- package/openspec/skills/openspec-onboard/SKILL.md +58 -43
- package/openspec/skills/openspec-propose/SKILL.md +15 -3
- package/openspec/skills/openspec-sync-specs/SKILL.md +31 -2
- package/openspec/skills/openspec-update-change/SKILL.md +34 -15
- package/openspec/skills/openspec-verify-change/SKILL.md +72 -26
- package/package.json +3 -2
- package/superpowers/.version +4 -4
- package/superpowers/skills/brainstorming/SKILL.md +47 -12
- package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -213
- package/superpowers/skills/brainstorming/scripts/server.cjs +723 -723
- package/superpowers/skills/brainstorming/visual-companion.md +6 -6
- package/superpowers/skills/diagnosing-superpowers/SKILL.md +120 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/analyst-common.md +38 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/cost-and-time.md +28 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/plan-adherence.md +29 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/quality-evidence.md +26 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/repeated-work.md +30 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/request-conflicts.md +20 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/scrub-audit.md +33 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/scrub.md +29 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/similar-session.md +38 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/skill-timeline.md +30 -0
- package/superpowers/skills/diagnosing-superpowers/prompts/stumbles.md +28 -0
- package/superpowers/skills/diagnosing-superpowers/references/context-safety.md +22 -0
- package/superpowers/skills/diagnosing-superpowers/references/github-issues.md +47 -0
- package/superpowers/skills/diagnosing-superpowers/references/redaction-policy.md +34 -0
- package/superpowers/skills/diagnosing-superpowers/references/session-discovery.md +31 -0
- package/superpowers/skills/diagnosing-superpowers/templates/bundle-README.md +77 -0
- package/superpowers/skills/diagnosing-superpowers/templates/case.md +64 -0
- package/superpowers/skills/diagnosing-superpowers/templates/issue.md +51 -0
- package/superpowers/skills/diagnosing-superpowers/templates/report.md +82 -0
- package/superpowers/skills/executing-plans/SKILL.md +350 -41
- package/superpowers/skills/executing-plans/scripts/task-done +52 -0
- package/superpowers/skills/executing-plans/scripts/task-start +28 -0
- package/superpowers/skills/requesting-code-review/SKILL.md +1 -1
- package/superpowers/skills/requesting-code-review/code-reviewer.md +17 -0
- package/superpowers/skills/subagent-driven-development/SKILL.md +18 -18
- package/superpowers/skills/subagent-driven-development/re-review-prompt.md +1 -1
- package/superpowers/skills/subagent-driven-development/scripts/review-package +53 -46
- package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +82 -40
- package/superpowers/skills/subagent-driven-development/scripts/task-brief +43 -41
- package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +2 -2
- package/superpowers/skills/systematic-debugging/root-cause-tracing.md +1 -1
- package/superpowers/skills/test-driven-development/SKILL.md +10 -0
- package/superpowers/skills/using-superpowers/SKILL.md +2 -0
- package/superpowers/skills/using-superpowers/references/claude-code-tools.md +29 -0
- package/superpowers/skills/using-superpowers/references/muse-tools.md +35 -0
- package/superpowers/skills/writing-plans/SKILL.md +62 -29
- package/superpowers/skills/writing-skills/SKILL.md +4 -2
- package/superpowers/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/cbb/worktrees/commands/worktree-close.md +0 -64
- package/cbb/worktrees/commands/worktree-init.md +0 -51
- package/cbb/worktrees/commands/worktree-push.md +0 -42
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
|
@@ -6,13 +6,13 @@ require('./silence-popup');
|
|
|
6
6
|
* 用法:node update-gitignore.js <ws_root> <branch>
|
|
7
7
|
*
|
|
8
8
|
* 行为:
|
|
9
|
-
* 1. stash
|
|
10
|
-
* 2.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
9
|
+
* 1. stash 当前未提交修改(仅 untracked 时不产生 stash)
|
|
10
|
+
* 2. 目标分支不存在则从 <remote>/<main> 创建(首跑时分支尚未由 create-branches.js 建立,
|
|
11
|
+
* 顺序无关自愈;create-branches.js 后续会报 reused;基线不取 HEAD,见 ADR 0002)
|
|
12
|
+
* 3. 切换到目标分支
|
|
13
|
+
* 4. 检查 .worktrees/ 和 .codespace/ 是否在 .gitignore,缺失则添加并提交
|
|
14
|
+
* 5. 切回原分支
|
|
15
|
+
* 6. pop stash(如有)
|
|
16
16
|
*
|
|
17
17
|
* 幂等:目标分支已在某个 worktree 中检出(init-worktree 重跑场景,上次已处理过
|
|
18
18
|
* .gitignore)时,跳过全部操作直接输出 GITIGNORE_OK——避免 checkout 与 worktree 检出冲突。
|
|
@@ -67,8 +67,12 @@ const status = run('git status --porcelain', wsRoot);
|
|
|
67
67
|
if (status.ok && status.out) {
|
|
68
68
|
const stash = run('git stash push -m "init-worktree-temp"', wsRoot);
|
|
69
69
|
if (stash.ok) {
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
if (/No local changes to save/.test(stash.out)) {
|
|
71
|
+
console.log('ℹ️ 仅 untracked 文件,无需 stash');
|
|
72
|
+
} else {
|
|
73
|
+
stashed = true;
|
|
74
|
+
console.log('✅ 已 stash 未提交修改');
|
|
75
|
+
}
|
|
72
76
|
} else {
|
|
73
77
|
console.error('❌ git stash 失败:' + stash.err);
|
|
74
78
|
process.exit(2);
|
|
@@ -77,6 +81,30 @@ if (status.ok && status.out) {
|
|
|
77
81
|
console.log('ℹ️ 无未提交修改,跳过 stash');
|
|
78
82
|
}
|
|
79
83
|
|
|
84
|
+
// 2.1 目标分支不存在则创建(Step 3.2 先于 Step 3.3 执行时分支尚未建立)
|
|
85
|
+
// 基线取 <remote>/<main>(ADR 0002,与 create-branches.js 一致):本地模式进行中根可能检出在
|
|
86
|
+
// feature 分支,从 HEAD 建会把未合并的开发态带进新分支;无 remote 时回退 HEAD
|
|
87
|
+
const branchList = run('git branch --list "' + branch + '"', wsRoot);
|
|
88
|
+
if (branchList.ok && !branchList.out) {
|
|
89
|
+
const remoteOut = run('git remote', wsRoot);
|
|
90
|
+
let base = 'HEAD';
|
|
91
|
+
if (remoteOut.ok && remoteOut.out) {
|
|
92
|
+
const r = remoteOut.out.split(/\r?\n/)[0];
|
|
93
|
+
const symbolic = run('git symbolic-ref "refs/remotes/' + r + '/HEAD"', wsRoot);
|
|
94
|
+
const main = (symbolic.ok && symbolic.out)
|
|
95
|
+
? symbolic.out.replace('refs/remotes/' + r + '/', '')
|
|
96
|
+
: 'main';
|
|
97
|
+
base = r + '/' + main;
|
|
98
|
+
}
|
|
99
|
+
const create = run('git branch "' + branch + '" "' + base + '"', wsRoot);
|
|
100
|
+
if (!create.ok) {
|
|
101
|
+
console.error('❌ 创建分支 ' + branch + ' 失败:' + create.err);
|
|
102
|
+
if (stashed) run('git stash pop', wsRoot);
|
|
103
|
+
process.exit(2);
|
|
104
|
+
}
|
|
105
|
+
console.log('✅ 分支 ' + branch + ' 不存在,已从 ' + base + ' 创建');
|
|
106
|
+
}
|
|
107
|
+
|
|
80
108
|
// 3. 切换到目标分支
|
|
81
109
|
const checkout = run('git checkout "' + branch + '"', wsRoot);
|
|
82
110
|
if (!checkout.ok) {
|
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cbb-worktree-push
|
|
3
|
-
description: "
|
|
4
|
-
license: MIT
|
|
5
|
-
compatibility: Requires git (>=2.30) and Node.js (>=16.7.0). All commands are pure Node.js scripts under `scripts/`, fully cross-platform (Windows / macOS / Linux, bash / PowerShell / Git Bash).
|
|
6
|
-
metadata:
|
|
7
|
-
author: Contributors
|
|
8
|
-
version: "1.0"
|
|
9
|
-
generatedBy: coding-bb
|
|
3
|
+
description: "提交并推送当前需求的所有关联仓库(跨 worktree 批量),推送后提案生成 MR(合并请求)预填链接。触发:用户说'提交'/'commit'/'push'/'推送'/'提交并push'/'推到远端'/'提MR'/'提合并请求'/'merge request';用户在 .worktrees/worktree-<需求名>/ 下工作要求批量推送;apply 完成后准备推送所有 worktree;close-worktree 前需要先推送未提交改动。注意:本技能会先识别场景——不在 cbb 工作空间时降级为普通单仓库提交推送。"
|
|
10
4
|
---
|
|
11
5
|
|
|
12
|
-
# Push Worktrees(跨平台脚本化版本
|
|
6
|
+
# Push Worktrees(跨平台脚本化版本 v2.0)
|
|
13
7
|
|
|
14
|
-
|
|
8
|
+
提交并推送当前需求的所有关联仓库(跨仓库批量,ADR 0002 双布局:worktree 布局或本地模式布局自动发现)。专门解决"开发完成后批量推送"和"用户口语化提交并push"两类场景——本技能是**唯一的远端推送出口**(cbb-worktree-init 自 0.0.3-beta.22 起 lazy push,创建流程零远端副作用;首次 push 自动建立 upstream)。
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
> **本技能描述含宽泛触发词("提交"/"push"),允许被误触发**。因此第一步永远是 **Step 0 场景识别**:在 cbb 工作空间内才走跨 worktree 批量流程;在普通 git 仓库降级为单仓库提交推送;非 git 目录则退出。
|
|
11
|
+
|
|
12
|
+
**启动时声明:** "我正在使用 cbb-worktree-push 技能来推送当前需求的关联仓库。"
|
|
17
13
|
|
|
18
14
|
## 核心原则
|
|
19
15
|
|
|
20
16
|
- 本技能的所有原子操作封装为 `scripts/*.js` Node.js 脚本,**跨平台执行**
|
|
21
17
|
- **两阶段**:先 `commit-worktrees.js` 提交所有 dirty 仓库,再 `push-worktrees.js` 推送所有 worktree 仓库。两个脚本独立退出码,AI agent 区分阶段
|
|
18
|
+
- **push 后 MR 提案(Step 7)**:`make-mr-urls.js` 生成预填合并请求链接(可自动开浏览器);只生成链接,提交/评审/合并全部由人在平台完成,不触碰任何凭据
|
|
22
19
|
- 复用 `cbb-worktree-push/scripts/push-core.js` 的 `pushSingle` / `classifyError` —— 与 `cbb-worktree-init` 的 `push-branches.js` 行为完全一致,错误码契约统一
|
|
23
20
|
- `find-workspace-root.js` / `find-target-worktree.js` 为共享脚本:源仓库真源在 `cbb/worktrees/_shared/scripts/`,部署后位于本 skill 的 `scripts/` 下,与 `cbb-worktree-init` / `cbb-worktree-close` 逻辑完全一致
|
|
24
21
|
- **本技能支持两层执行位置**(与 `cbb-worktree-close` 对称):
|
|
25
22
|
- 工作空间根目录(`WS_ROOT/`)
|
|
26
23
|
- worktree 内部(`WS_ROOT/.worktrees/worktree-<需求名>/` 或其子目录)
|
|
27
|
-
-
|
|
24
|
+
- 输入约定:**自由文本**(需求名等)直接在对话中提问并等待回复;**固定选项多选**使用 `AskUserQuestion`。**例外:commit 信息由 agent 自行生成,不提问、不等待确认**
|
|
28
25
|
|
|
29
26
|
---
|
|
30
27
|
|
|
31
28
|
## 调用脚本的统一方式
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
**重要**:本技能的所有脚本位于**本 SKILL.md 所在目录的 `scripts/` 下**(skill 目录)。
|
|
31
|
+
|
|
32
|
+
调用时用**本技能目录的绝对路径**拼接脚本名(AI 读取本 SKILL.md 时即已知该目录):
|
|
34
33
|
|
|
35
34
|
```
|
|
36
|
-
node "<
|
|
35
|
+
node "<skill_dir>/scripts/<name>.js" <参数>
|
|
37
36
|
```
|
|
38
37
|
|
|
38
|
+
> - `<skill_dir>` = 本 SKILL.md 所在目录的绝对路径(AI 从读取路径即可推出)
|
|
39
|
+
> - **cwd 必须保持在工作空间根目录**:脚本按 cwd 定位 `CBB-WORKSPACE.json` 与 git 仓库
|
|
40
|
+
> - 不要用 `./scripts/...` 裸相对路径(AI 的 cwd 不是技能目录,会解析失败)
|
|
41
|
+
|
|
39
42
|
脚本输出:
|
|
40
43
|
- 人类可读报告(OK / FAIL / WARN)
|
|
41
44
|
- 机器可读摘要(末行以 `COMMIT_RESULT` / `PUSH_RESULT` 开头)
|
|
@@ -43,28 +46,54 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/<name>.js" <参数>
|
|
|
43
46
|
|
|
44
47
|
---
|
|
45
48
|
|
|
46
|
-
## Step 0
|
|
49
|
+
## Step 0:场景识别(先判场景,再定策略)
|
|
50
|
+
|
|
51
|
+
**本技能允许被"提交"/"push"这类宽泛措辞误触发**。执行任何操作前,先判断当前处于哪种场景,按场景选择策略——**不要硬套 cbb 工作空间流程**。
|
|
52
|
+
|
|
53
|
+
判断依据(任一命中即定场景):
|
|
54
|
+
|
|
55
|
+
| 场景 | 判据 | 策略 |
|
|
56
|
+
|------|------|------|
|
|
57
|
+
| **A. cbb 工作空间根** | cwd(或其 git 顶层)含 `CBB-WORKSPACE.json`;`find-workspace-root.js` 退出码 0 | 走 **Step 1 → 6** 的跨 worktree 批量流程 |
|
|
58
|
+
| **B. worktree 内** | cwd 命中 `<ws_root>/.worktrees/worktree-<需求名>/` | 用 cwd 反推 `<需求名>`,走 **Step 1 → 6** 批量流程 |
|
|
59
|
+
| **C. 普通 git 仓库** | 在 git 仓库内,但无 `CBB-WORKSPACE.json`(`find-workspace-root.js` 退出码 1) | **降级为单仓库提交推送**:不调 worktree 脚本,按常规 `git add -u` → agent 生成 commit 信息 → `git commit` → `git push`(信息生成规则与 A/B 场景一致:精炼最简、5–50 字符) |
|
|
60
|
+
| **D. 非 git 目录** | `git rev-parse --is-inside-work-tree` 失败 | 说明"当前目录不是 git 仓库",终止,不做任何操作 |
|
|
61
|
+
|
|
62
|
+
**判场景与定位(A/B 场景):**
|
|
47
63
|
|
|
48
64
|
```bash
|
|
49
|
-
node "<
|
|
65
|
+
node "<skill_dir>/scripts/find-workspace-root.js"
|
|
50
66
|
```
|
|
51
67
|
|
|
52
68
|
**解读末行**:
|
|
53
|
-
- 退出码 0 + 末行(纯路径) → WS_ROOT
|
|
54
|
-
- 退出码 1 →
|
|
69
|
+
- 退出码 0 + 末行(纯路径) → WS_ROOT(场景 A/B),继续 Step 1
|
|
70
|
+
- 退出码 1 → 无工作空间:**先判断场景 C 还是 D**(`git rev-parse --is-inside-work-tree`):
|
|
71
|
+
- 是 git 仓库 → 场景 C,按降级策略走(见下)
|
|
72
|
+
- 不是 → 场景 D,终止
|
|
73
|
+
|
|
74
|
+
**场景 C 降级流程**(普通仓库误触):
|
|
75
|
+
|
|
76
|
+
1. `git status` 报告改动现状
|
|
77
|
+
2. agent 基于改动内容生成 commit 信息(精炼最简,5–50 字符;规则见 Step 3)
|
|
78
|
+
3. `git add -u`(默认不含未追踪文件;用户明确要求时才 `git add -A`)
|
|
79
|
+
4. `git commit -m "<agent 生成的信息>"`
|
|
80
|
+
5. `git push`(无 upstream 时先询问用户是否 `-u`)
|
|
81
|
+
6. 汇报结果;**不要**提及 worktree 批量流程
|
|
82
|
+
|
|
83
|
+
> 场景 C 是兜底:让"提交代码"在普通仓库里也能正常完成,而不是因找不到 `CBB-WORKSPACE.json` 报错。
|
|
55
84
|
|
|
56
85
|
---
|
|
57
86
|
|
|
58
|
-
## Step 1:识别目标 worktree
|
|
87
|
+
## Step 1:识别目标 worktree(A/B 场景)
|
|
59
88
|
|
|
60
89
|
```bash
|
|
61
|
-
node "<
|
|
90
|
+
node "<skill_dir>/scripts/find-target-worktree.js" "<ws_root>"
|
|
62
91
|
```
|
|
63
92
|
|
|
64
93
|
**解读末行**:
|
|
65
|
-
- 退出码 0 + 末行(需求名) →
|
|
66
|
-
- 退出码 1 + 末行 `MULTIPLE_WORKTREEES` →
|
|
67
|
-
- 退出码 2 + 末行 `NO_WORKTREE` →
|
|
94
|
+
- 退出码 0 + 末行(需求名) → 唯一识别,自动用之(脚本自动合并 worktree 布局与本地模式布局候选,`(local)` 标本地模式进行中)
|
|
95
|
+
- 退出码 1 + 末行 `MULTIPLE_WORKTREEES` → 多个进行中需求,AI agent 在对话中让用户输入序号或分支名
|
|
96
|
+
- 退出码 2 + 末行 `NO_WORKTREE` → 无进行中需求,提示用户先执行 `cbb-worktree-init`(worktree 模式)或 `cbb-local-mode`(本地模式)
|
|
68
97
|
|
|
69
98
|
---
|
|
70
99
|
|
|
@@ -72,7 +101,7 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/find-target-worktree.js"
|
|
|
72
101
|
|
|
73
102
|
```bash
|
|
74
103
|
# 仅 commit 阶段先做 dry-run 预览
|
|
75
|
-
node "<
|
|
104
|
+
node "<skill_dir>/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "preview" --dry-run
|
|
76
105
|
```
|
|
77
106
|
|
|
78
107
|
**解读末行 `COMMIT_RESULT`**:每项仓库的状态
|
|
@@ -82,36 +111,27 @@ node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/commit-worktrees.js" "<w
|
|
|
82
111
|
- `skipped (skip-repo)`:用户指定跳过
|
|
83
112
|
- `failed`:错误
|
|
84
113
|
|
|
85
|
-
> ⓘ **dry-run
|
|
114
|
+
> ⓘ **dry-run 必跑**:把将要 commit 的文件清单与 agent 生成的 commit 信息一并展示给用户(透明可见,**不停顿等待回复**),避免误纳 `.idea/` 等被 git 忽略的文件(虽然 `git add -u` 已天然排除,但 dry-run 仍是最后兜底)。
|
|
86
115
|
|
|
87
116
|
---
|
|
88
117
|
|
|
89
|
-
## Step 3
|
|
118
|
+
## Step 3:生成 commit 信息(agent 自主)
|
|
90
119
|
|
|
91
|
-
AI agent
|
|
120
|
+
AI agent 在执行 commit 前**自行生成** commit 信息,**不向用户提问、不等待确认**。
|
|
92
121
|
|
|
93
|
-
|
|
122
|
+
**生成规则(硬约束)**:
|
|
94
123
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
回复示例(统一):
|
|
106
|
-
feat(<branch>): 实现客户运费逻辑
|
|
107
|
-
|
|
108
|
-
回复示例(分别):
|
|
109
|
-
workspace: chore(<branch>): 同步 openspec 标准
|
|
110
|
-
ep-foo-app: feat(<branch>): 实现 saveClientExpectFreight
|
|
111
|
-
ep-bar-app: refactor(<branch>): 拆分 PlanService
|
|
112
|
-
```
|
|
124
|
+
| 规则 | 要求 |
|
|
125
|
+
|------|------|
|
|
126
|
+
| 长度 | **5–50 字符**(按字符计:1 个中文字 = 1,1 个英文字母 / 空格 / 标点 = 1);超出范围不得提交 |
|
|
127
|
+
| 风格 | 精炼、最简——一句话说清"改了什么",不写缘由、不换行、不堆砌 |
|
|
128
|
+
| 依据 | 以 Step 2 dry-run 的实际改动 + `openspec/changes/<branch>/tasks.md` 已完成 task 为准;禁止凭空编造 |
|
|
129
|
+
| 格式 | 沿用 Conventional Commits 前缀(`feat` / `fix` / `refactor` / `chore` / `docs` 等)+ 需求名,如 `feat(<branch>): 实现客户运费逻辑` |
|
|
130
|
+
| 多仓库 | 各仓库改动语义不同时**逐仓库分别生成**(经 `--per-repo`),禁止硬塞同一条 |
|
|
131
|
+
|
|
132
|
+
**展示时机**:生成的每条信息在 Step 2 dry-run 预览中随待提交文件一并输出(透明可见),但**不停顿等待回复**,直接进入 Step 4。
|
|
113
133
|
|
|
114
|
-
|
|
134
|
+
> ⓘ 用户若在对话中显式给出 commit 信息,直接采用(不覆盖用户意图);未给出时按上述规则自行生成。
|
|
115
135
|
|
|
116
136
|
---
|
|
117
137
|
|
|
@@ -119,22 +139,22 @@ AI agent 在执行真实 commit 前**必须**在对话中向用户确认 commit
|
|
|
119
139
|
|
|
120
140
|
```bash
|
|
121
141
|
# 统一信息
|
|
122
|
-
node "<
|
|
142
|
+
node "<skill_dir>/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "feat(<branch>): 实现客户运费逻辑"
|
|
123
143
|
|
|
124
144
|
# 多仓库分别
|
|
125
|
-
node "
|
|
145
|
+
node "<skill_dir>/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --per-repo "ep-foo-app:feat(<branch>): 实现 saveClientExpectFreight;ep-bar-app:refactor(<branch>): 拆分 PlanService"
|
|
126
146
|
|
|
127
147
|
# 含未追踪文件
|
|
128
|
-
node "
|
|
148
|
+
node "<skill_dir>/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "..." --untracked
|
|
129
149
|
|
|
130
150
|
# wt_path 形式(用户在 worktree 内)
|
|
131
|
-
node "
|
|
151
|
+
node "<skill_dir>/scripts/commit-worktrees.js" "<ws_root>/.worktrees/worktree-<branch>" --message "..."
|
|
132
152
|
```
|
|
133
153
|
|
|
134
154
|
**选项**:
|
|
135
155
|
| 选项 | 说明 |
|
|
136
156
|
|------|------|
|
|
137
|
-
| `--message / -m` | 必填(除非 --per-repo 完全覆盖)。commit
|
|
157
|
+
| `--message / -m` | 必填(除非 --per-repo 完全覆盖)。commit 信息(agent 生成,5–50 字符) |
|
|
138
158
|
| `--per-repo "<name>:msg;<name>:msg"` | 覆盖特定仓库的 commit 信息 |
|
|
139
159
|
| `--untracked` | 同时 stage 未追踪文件(默认 `git add -u`,加此项时 `git add -A`) |
|
|
140
160
|
| `--allow-empty` | 允许空提交 |
|
|
@@ -155,10 +175,10 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>" --message "..."
|
|
|
155
175
|
## Step 5:批量 push
|
|
156
176
|
|
|
157
177
|
```bash
|
|
158
|
-
node "<
|
|
178
|
+
node "<skill_dir>/scripts/push-worktrees.js" "<ws_root>" "<branch>"
|
|
159
179
|
|
|
160
180
|
# 或 wt_path 形式
|
|
161
|
-
node "
|
|
181
|
+
node "<skill_dir>/scripts/push-worktrees.js" "<ws_root>/.worktrees/worktree-<branch>"
|
|
162
182
|
```
|
|
163
183
|
|
|
164
184
|
**解读末行 `PUSH_RESULT`**:
|
|
@@ -196,6 +216,39 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
196
216
|
|
|
197
217
|
---
|
|
198
218
|
|
|
219
|
+
## Step 7:MR 提案(push 完成后)
|
|
220
|
+
|
|
221
|
+
Step 5 的 `PUSH_RESULT` 中至少一个仓库为 `pushed` / `skipped`(feature 分支已在远端)时,用 `AskUserQuestion`(固定选项)提案:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
推送完成。要提 MR(合并请求)吗?
|
|
225
|
+
[提 MR 到测试分支] 生成预填的 MR 创建链接(如 dev/test)
|
|
226
|
+
[提 MR 到正式分支] 生成预填的 MR 创建链接(如 main/master)
|
|
227
|
+
[暂不提 MR] 结束本步
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
用户选择提 MR 后:
|
|
231
|
+
|
|
232
|
+
1. **确定目标分支(交互式,禁止 AI 代决)**:`git branch -r` 列出现场实际的主干候选(dev / test / develop / main / master / release-*),请用户指定一个;全仓库统一用该目标分支(不存在此分支的仓库由脚本自动跳过)
|
|
233
|
+
2. **生成链接**:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
node "<skill_dir>/scripts/make-mr-urls.js" "<ws_root>" "<branch>" "<target>" --open
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**解读末行 `MR_RESULT`**(逐仓库):
|
|
240
|
+
- `ok` → 已生成 URL(`--open` 时已开浏览器;用户在平台页面确认标题/评审人后提交)
|
|
241
|
+
- `no-diff` → 与目标分支无差异,跳过
|
|
242
|
+
- `not-pushed` → feature 分支不在远端(提示先完成 push)
|
|
243
|
+
- `no-target` → 远端无该目标分支(回退重新指定候选)
|
|
244
|
+
- `manual` → origin 无法解析为已知平台,输出手动创建指引;可用 `--platform gitlab|github|gitee` 强制
|
|
245
|
+
|
|
246
|
+
> 平台识别:`github.com` → PR compare、`gitee.com` → compare、**其余默认 GitLab**(企业自建主流);误判用 `--platform` 覆盖。
|
|
247
|
+
|
|
248
|
+
3. **提 MR 后提醒用户后续链路**:测试环境部署 → 用户验收 → 验收通过后 `/opsx:archive` → 正式分支合并走公司发布流程 → 最后 `cbb-worktree-close`
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
199
252
|
## 最终报告
|
|
200
253
|
|
|
201
254
|
```
|
|
@@ -210,8 +263,7 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
210
263
|
workspace: ✅ origin/<branch>
|
|
211
264
|
ep-foo-app: ✅ origin/<branch>
|
|
212
265
|
ep-bar-app: ⚠️ 远程分支已存在(需用户决策 → 已关联)
|
|
213
|
-
|
|
214
|
-
后续:可继续开发 / 调 /opsx:verify 验证 / 调 /opsx:archive 归档 / 调 /cbb:worktree-close 关闭
|
|
266
|
+
后续:Step 7 提 MR 到测试分支 → 部署验收 → 验收通过后 /opsx:archive → 正式发布(公司流程)→ cbb-worktree-close
|
|
215
267
|
```
|
|
216
268
|
|
|
217
269
|
---
|
|
@@ -220,26 +272,37 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
220
272
|
|
|
221
273
|
| 场景 | 处理方式 |
|
|
222
274
|
|------|----------|
|
|
223
|
-
|
|
|
224
|
-
|
|
|
225
|
-
|
|
|
226
|
-
|
|
|
275
|
+
| **任何触发** | **先做 Step 0 场景识别**,再决定策略 |
|
|
276
|
+
| 场景 A:cwd 在 cbb 工作空间根 | find-workspace-root 成功 → 多个 worktree 时让用户选 |
|
|
277
|
+
| 场景 B:cwd 在 worktree 内 | 自动用 cwd 反推分支,扫描后 agent 生成 commit 信息 |
|
|
278
|
+
| 场景 C:cwd 在普通 git 仓库(无 CBB-WORKSPACE.json) | **降级为单仓库提交推送**,不调用 worktree 脚本 |
|
|
279
|
+
| 场景 D:cwd 非 git 目录 | 说明情况并终止,不做任何操作 |
|
|
280
|
+
| commit 信息 | agent 自行生成(5–50 字符,精炼最简),不询问用户;dry-run 预览时一并展示 |
|
|
281
|
+
| 多仓库改动语义不同 | agent 逐仓库分别生成,用 `--per-repo "ep-foo:msg;ep-bar:msg"` |
|
|
227
282
|
| 仓库干净 | commit-worktrees 自动 skipped,只 push 不 commit |
|
|
228
283
|
| 仓库已有 ahead commit | commit-worktrees 自动 skipped(不重复 commit),只 push |
|
|
229
284
|
| 未追踪文件 | 默认不纳入(避免误纳 .idea);用户明确要求时加 `--untracked` |
|
|
230
285
|
| 远程分支已存在 | push 退出码 2,AI 输出元信息后由用户决策(关联/终止) |
|
|
231
286
|
| push 失败(SSH/HTTPS/网络/保护) | push 退出码 2,AI 按错误码分类处理,阻塞并询问用户 |
|
|
232
287
|
| close-worktree 前调用 | 先调本 skill 把 ahead 推送完,避免 close 时丢提交 |
|
|
288
|
+
| push 完成后 | Step 7 MR 提案:AskUserQuestion 固定选项 → make-mr-urls.js 生成预填链接 + 开浏览器;只生成链接,不代合并 |
|
|
289
|
+
| MR 目标分支 | 交互式:`git branch -r` 列主干候选由用户指定,全仓库统一;缺该分支的仓库自动跳过(no-target) |
|
|
290
|
+
| MR 平台误判 | 非 github.com/gitee.com 默认按 GitLab 拼 URL;有误判用 `--platform gitlab\|github\|gitee` 强制 |
|
|
233
291
|
| --dry-run | 任何时候想预览将要 commit 的内容时使用,不实际修改任何东西 |
|
|
234
292
|
|
|
235
293
|
---
|
|
236
294
|
|
|
237
295
|
## 常见错误
|
|
238
296
|
|
|
239
|
-
###
|
|
297
|
+
### 误触后硬套 worktree 流程
|
|
298
|
+
|
|
299
|
+
- **问题:** 用户在普通仓库说"提交代码",技能被 description 匹配触发,直接跑 `find-workspace-root.js` 失败并报错终止
|
|
300
|
+
- **修复:** Step 0 先判场景;场景 C(普通 git 仓库)降级为单仓库提交推送,不调用 worktree 脚本、不提及批量流程
|
|
301
|
+
|
|
302
|
+
### commit 信息超长或空洞
|
|
240
303
|
|
|
241
|
-
- **问题:** agent
|
|
242
|
-
- **修复:** Step 3
|
|
304
|
+
- **问题:** agent 生成的 commit 信息过长(罗列全部改动、写缘由)或过于笼统("更新代码"),与"5–50 字符、精炼最简"不符
|
|
305
|
+
- **修复:** Step 3 按规则生成——以实际 diff / 已完成 task 为依据,一句话说清改了什么,长度落在 5–50 字符
|
|
243
306
|
|
|
244
307
|
### 误纳未追踪文件
|
|
245
308
|
|
|
@@ -256,10 +319,10 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
256
319
|
- **问题:** apply 实现完 → 用户关掉 IDE → 调 close-worktree → ahead 提交永久丢失
|
|
257
320
|
- **修复:** 强烈建议 apply 完成后立即调本 skill 推送;或 close-worktree Step 3.4 兜底
|
|
258
321
|
|
|
259
|
-
###
|
|
322
|
+
### 多仓库硬塞同一条 commit 信息
|
|
260
323
|
|
|
261
|
-
- **问题:** workspace 改了
|
|
262
|
-
- **修复:**
|
|
324
|
+
- **问题:** workspace 改了 CBB-WORKSPACE.json,ep-foo-app 改了 Java 代码,硬塞同一条 "feat: 实现 XX" 信息不准确
|
|
325
|
+
- **修复:** agent 逐仓库生成各自的 commit 信息,用 `--per-repo` 传入
|
|
263
326
|
|
|
264
327
|
### push 失败时跳过失败仓库直接继续
|
|
265
328
|
|
|
@@ -277,22 +340,27 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
277
340
|
|
|
278
341
|
**绝不允许**
|
|
279
342
|
|
|
280
|
-
-
|
|
343
|
+
- commit 信息超出 5–50 字符范围 / 空洞无意义 / 与改动不符
|
|
281
344
|
- 默认 `git add -A` 误纳未追踪文件
|
|
282
345
|
- push 失败后跳过失败仓库直接继续
|
|
283
346
|
- 远程分支已存在时脚本自动 set-upstream-to
|
|
284
347
|
- AI 询问关联选项前不输出 commit 元信息
|
|
285
348
|
- 运行环境 node 不可用时强行继续 → 改为 fail-fast 提示用户
|
|
349
|
+
- 代为合并 MR / 直接向测试、正式分支 push / 触碰平台凭据 → MR 只生成预填链接,提交与合并由人在平台完成
|
|
350
|
+
- MR 目标分支由 AI 猜测代决 → 必须列候选让用户指定
|
|
286
351
|
|
|
287
352
|
**必须执行**
|
|
288
353
|
|
|
289
|
-
- 严格按 Step 0 → 1 → 2 → 3 → 4 → 5 → 6
|
|
290
|
-
- 所有脚本调用以 `node "
|
|
291
|
-
-
|
|
292
|
-
- Step
|
|
293
|
-
- commit
|
|
354
|
+
- 严格按 Step 0 → 1 → 2 → 3 → 4 → 5 → 6 顺序执行(场景 C/D 除外,按 Step 0 降级策略)
|
|
355
|
+
- 所有脚本调用以 `node "<skill_dir>/scripts/<name>.js"` 形式发起(`<skill_dir>` = 本 SKILL.md 所在目录)
|
|
356
|
+
- 执行脚本时 cwd 保持在工作空间根;场景 C 降级时按普通 git 流程
|
|
357
|
+
- Step 2 dry-run 必跑,把待提交文件清单与 agent 生成的 commit 信息一并展示给用户
|
|
358
|
+
- Step 3 由 agent 自行生成 commit 信息(5–50 字符、精炼最简),不向用户提问、不等待确认;生成结果在 dry-run 预览中展示
|
|
359
|
+
- commit 信息必须依据实际 diff / 已完成 task 生成,沿用 Conventional Commits 前缀(feature/refactor/fix 等语义)
|
|
360
|
+
- 多个仓库改动语义不同时必须逐仓库分别生成(`--per-repo`),禁止硬塞同一条
|
|
294
361
|
- commit-worktrees / push-worktrees 退出码 2 时必须阻塞流程
|
|
295
362
|
- 远程分支已存在时 AI 必须先输出 commit 元信息再询问
|
|
363
|
+
- push 成功后必须走 Step 7 MR 提案(AskUserQuestion 固定选项;用户选"暂不提"则正常结束)
|
|
296
364
|
|
|
297
365
|
---
|
|
298
366
|
|
|
@@ -304,4 +372,5 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
304
372
|
| `find-target-worktree.js` | 目标需求名识别(共享脚本,源仓库真源在 `_shared/scripts/`) | ws_root | 0/1/2 |
|
|
305
373
|
| `commit-worktrees.js` | 批量 commit(默认 `-u`,加 `--untracked` 时 `-A`) | ws_root, branch, --message / --per-repo / --untracked / --allow-empty / --dry-run / --skip-repo | 0/1/2 |
|
|
306
374
|
| `push-worktrees.js` | 批量 push(复用 push-core 错误归类) | ws_root, branch(或 wt_path) | 0/1/2 |
|
|
375
|
+
| `make-mr-urls.js` | 生成预填 MR/PR 创建链接(平台识别 + 远端校验 + diff 判定 + `--open` 开浏览器) | ws_root, branch, target(或 wt_path, target), --platform, --open | 0/1/2 |
|
|
307
376
|
| `push-core.js` | 推送核心(classifyError / pushSingle / collectRemoteMetadata,共享脚本,源仓库真源在 `_shared/scripts/`) | (共享模块) | - |
|
|
@@ -7,7 +7,9 @@ require('./silence-popup');
|
|
|
7
7
|
* node commit-worktrees.js <wt_path> --message "msg" [options]
|
|
8
8
|
*
|
|
9
9
|
* 行为:
|
|
10
|
-
* 1.
|
|
10
|
+
* 1. 按需求名发现参与仓库(ADR 0002 双布局):
|
|
11
|
+
* - worktree 布局:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内各 app worktree(镜像主布局,ADR 0003)
|
|
12
|
+
* - 本地布局:根 / .codespace/<app>/ 检出恰在 <branch> 分支上
|
|
11
13
|
* 2. 对每个仓库:
|
|
12
14
|
* a. git status --porcelain 检测 dirty
|
|
13
15
|
* b. 若 clean 或已有 ahead commit → 跳过
|
|
@@ -95,23 +97,79 @@ function isGitRepo(p) {
|
|
|
95
97
|
return fs.existsSync(path.join(p, '.git'));
|
|
96
98
|
}
|
|
97
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
|
+
|
|
110
|
+
function currentBranch(p) {
|
|
111
|
+
try {
|
|
112
|
+
return execSync('git branch --show-current', { cwd: p, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
113
|
+
} catch (e) { return ''; }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 按需求名发现参与仓库(ADR 0002 双布局):
|
|
118
|
+
* 布局一 worktree:.worktrees/worktree-<branch>/ 的 workspace + 其 .codespace/<app>/ 容器内 app worktree(ADR 0003 镜像主布局;≤beta.23 旧平铺顶层布局按配置 app 名兼容)
|
|
119
|
+
* 布局二 本地模式:根 / .codespace/<app>/ 的检出恰在 <branch> 分支上(同名仓库以 worktree 布局优先)
|
|
120
|
+
* 两者皆空 → error。
|
|
121
|
+
*/
|
|
98
122
|
function scanWorktreeRepos(wsRoot, branch) {
|
|
99
123
|
const wtRoot = path.join(wsRoot, '.worktrees', 'worktree-' + branch);
|
|
100
124
|
const repos = [];
|
|
101
|
-
|
|
102
|
-
|
|
125
|
+
|
|
126
|
+
// 布局一:worktree
|
|
127
|
+
if (fs.existsSync(wtRoot)) {
|
|
128
|
+
if (isGitRepo(wtRoot)) {
|
|
129
|
+
repos.push({ name: 'workspace', wt: wtRoot, repo: wsRoot, layout: 'worktree' });
|
|
130
|
+
}
|
|
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
|
+
}
|
|
149
|
+
}
|
|
103
150
|
}
|
|
104
|
-
|
|
105
|
-
|
|
151
|
+
|
|
152
|
+
// 布局二:本地模式(检出在需求分支上)
|
|
153
|
+
const names = new Set(repos.map(r => r.name));
|
|
154
|
+
if (!names.has('workspace') && isGitRepo(wsRoot) && currentBranch(wsRoot) === branch) {
|
|
155
|
+
repos.push({ name: 'workspace', wt: wsRoot, repo: wsRoot, layout: 'local' });
|
|
106
156
|
}
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
157
|
+
const codeDir = path.join(wsRoot, '.codespace');
|
|
158
|
+
if (fs.existsSync(codeDir)) {
|
|
159
|
+
for (const name of fs.readdirSync(codeDir).sort()) {
|
|
160
|
+
if (names.has(name)) continue;
|
|
161
|
+
const appDir = path.join(codeDir, name);
|
|
162
|
+
if (!isGitRepo(appDir)) continue;
|
|
163
|
+
if (currentBranch(appDir) === branch) {
|
|
164
|
+
repos.push({ name, wt: appDir, repo: appDir, layout: 'local' });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
113
167
|
}
|
|
114
|
-
|
|
168
|
+
|
|
169
|
+
const error = repos.length === 0
|
|
170
|
+
? ('未发现需求 ' + branch + ' 的参与仓库(worktree 不存在,且无仓库检出在 ' + branch + ' 分支上)')
|
|
171
|
+
: null;
|
|
172
|
+
return { wtRoot, repos, error };
|
|
115
173
|
}
|
|
116
174
|
|
|
117
175
|
function run(cmd, cwd) {
|