@jspg-ai/coding-bb 0.0.1 → 0.0.2-beta.23
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/bin/cbb.js +6 -0
- package/cbb/bin/cbbm.js +6 -0
- package/cbb/dev-standards/rules/cbb-ai-behavior.md +103 -103
- package/cbb/dev-standards/rules/cbb-priority.md +55 -55
- package/cbb/lib/install/claude-code.js +2 -0
- package/cbb/lib/install/init.js +496 -290
- package/cbb/lib/install/opencode.js +31 -0
- package/cbb/lib/install/qoder.js +2 -0
- package/cbb/lib/install/workspaces.js +53 -13
- package/cbb/lib/openspec/index.js +3 -3
- package/cbb/lib/superpowers/index.js +1 -1
- package/cbb/lib/utils/check-update.js +16 -14
- package/cbb/lib/utils/gitignore.js +2 -1
- package/cbb/lib/utils/output.js +92 -4
- package/cbb/lib/utils/version.js +2 -31
- package/cbb/lib/wiki/cli.js +25 -25
- package/cbb/lib/wiki/index.js +16 -16
- package/cbb/tools/cbb-design-to-wiki/SKILL.md +14 -14
- package/cbb/tools/cbb-wiki-ops/SKILL.md +22 -22
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +2 -2
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/_shared/scripts/push-core.js +18 -0
- package/cbb/worktrees/commands/{close.md → worktree-close.md} +8 -8
- package/cbb/worktrees/commands/{init.md → worktree-init.md} +9 -9
- package/cbb/worktrees/commands/{push.md → worktree-push.md} +3 -3
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/SKILL.md +20 -20
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-env.js +4 -4
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-unarchived.js +1 -1
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/delete-branches.js +3 -3
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/discover-apps.js +6 -6
- package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-close}/scripts/find-target-worktree.js +2 -2
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-close}/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/remove-worktrees.js +4 -4
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/safety-check.js +4 -4
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/SKILL.md +81 -107
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/auto-open.js +1 -1
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env-deep.js +4 -4
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env.js +6 -6
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-repos.js +4 -4
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-branches.js +4 -4
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-worktrees.js +8 -7
- package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-init}/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/install-ai.js +33 -33
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/parse-config.js +7 -7
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/push-branches.js +9 -7
- package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/push-core.js +18 -0
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/sync-repos.js +10 -12
- package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/update-gitignore.js +19 -6
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/SKILL.md +16 -16
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/commit-worktrees.js +2 -2
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/find-target-worktree.js +2 -2
- package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-push}/scripts/find-workspace-root.js +7 -7
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-core.js +18 -0
- package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-worktrees.js +7 -5
- package/config/workspace-config.sample.json +18 -0
- package/config/workspaces.json +11 -6
- package/openspec/.version +6 -6
- package/openspec/commands/apply.md +7 -7
- package/openspec/commands/archive.md +7 -7
- package/openspec/commands/bulk-archive.md +7 -7
- package/openspec/commands/continue.md +7 -7
- package/openspec/commands/explore.md +7 -7
- package/openspec/commands/ff.md +7 -7
- package/openspec/commands/new.md +7 -7
- package/openspec/commands/onboard.md +7 -7
- package/openspec/commands/propose.md +7 -7
- package/openspec/commands/sync.md +7 -7
- package/openspec/commands/update.md +7 -7
- package/openspec/commands/verify.md +7 -7
- package/openspec/skills/openspec-apply-change/SKILL.md +187 -187
- package/openspec/skills/openspec-archive-change/SKILL.md +181 -181
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -338
- package/openspec/skills/openspec-continue-change/SKILL.md +117 -117
- package/openspec/skills/openspec-explore/SKILL.md +342 -342
- package/openspec/skills/openspec-ff-change/SKILL.md +116 -116
- package/openspec/skills/openspec-new-change/SKILL.md +76 -76
- package/openspec/skills/openspec-onboard/SKILL.md +560 -560
- package/openspec/skills/openspec-propose/SKILL.md +162 -162
- package/openspec/skills/openspec-sync-specs/SKILL.md +261 -261
- package/openspec/skills/openspec-update-change/SKILL.md +90 -90
- package/openspec/skills/openspec-verify-change/SKILL.md +174 -174
- package/package.json +4 -3
- package/superpowers/.version +6 -6
- package/superpowers/skills/brainstorming/SKILL.md +250 -250
- package/superpowers/skills/brainstorming/scripts/helper.js +167 -167
- package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -209
- package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -120
- package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -49
- package/superpowers/skills/brainstorming/visual-companion.md +299 -299
- package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -167
- package/superpowers/skills/executing-plans/SKILL.md +64 -64
- package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -225
- package/superpowers/skills/receiving-code-review/SKILL.md +205 -205
- package/superpowers/skills/requesting-code-review/SKILL.md +95 -95
- package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -181
- package/superpowers/skills/subagent-driven-development/SKILL.md +568 -568
- package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -154
- package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -115
- package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -207
- package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/superpowers/skills/systematic-debugging/SKILL.md +283 -283
- package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -72
- package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/superpowers/skills/systematic-debugging/test-academic.md +14 -14
- package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/superpowers/skills/test-driven-development/SKILL.md +320 -320
- package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -198
- package/superpowers/skills/using-git-worktrees/SKILL.md +167 -167
- package/superpowers/skills/using-superpowers/SKILL.md +63 -63
- package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -23
- package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -108
- package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -63
- package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -56
- package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -16
- package/superpowers/skills/verification-before-completion/SKILL.md +120 -120
- package/superpowers/skills/writing-plans/SKILL.md +171 -171
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -49
- package/superpowers/skills/writing-skills/SKILL.md +679 -679
- package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/superpowers/skills/writing-skills/persuasion-principles.md +187 -187
- package/superpowers/skills/writing-skills/render-graphs.js +169 -169
- package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/cbb/worktrees/commands/extend.md +0 -65
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +0 -96
- package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +0 -390
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +0 -95
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +0 -98
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +0 -135
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +0 -150
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +0 -88
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +0 -93
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +0 -67
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +0 -93
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +0 -136
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +0 -23
- package/config/config.sample.json +0 -16
- /package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/silence-popup.js +0 -0
- /package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/silence-popup.js +0 -0
- /package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-push}/scripts/silence-popup.js +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('./silence-popup');
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* cbb-worktree-init 创建 Worktree(含自愈清理)
|
|
5
5
|
*
|
|
6
|
-
* 用法:node create-worktrees.js <ws_root>
|
|
6
|
+
* 用法:node create-worktrees.js <ws_root> <branch>
|
|
7
|
+
* (apps 由脚本内部从 <ws_root>/workspace-config.json 读取)
|
|
7
8
|
*
|
|
8
9
|
* 行为:
|
|
9
10
|
* 1. 自愈清理:prune + 物理目录清理
|
|
@@ -31,7 +32,7 @@ if (!wsRoot || !branch) {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
function loadAppsFromConfig() {
|
|
34
|
-
const configPath = path.join(wsRoot, '
|
|
35
|
+
const configPath = path.join(wsRoot, 'workspace-config.json');
|
|
35
36
|
if (!fs.existsSync(configPath)) return null;
|
|
36
37
|
try {
|
|
37
38
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
@@ -41,7 +42,7 @@ function loadAppsFromConfig() {
|
|
|
41
42
|
|
|
42
43
|
const apps = loadAppsFromConfig();
|
|
43
44
|
if (!apps) {
|
|
44
|
-
console.error('❌
|
|
45
|
+
console.error('❌ workspace-config.json 缺失或 apps 为空');
|
|
45
46
|
process.exit(1);
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -57,7 +58,7 @@ function run(cmd, cwd) {
|
|
|
57
58
|
console.log('=== 自愈清理 ===');
|
|
58
59
|
|
|
59
60
|
// 1.1 prune 所有仓库
|
|
60
|
-
const allRepos = [wsRoot, ...apps.map(a => path.join(wsRoot, '.
|
|
61
|
+
const allRepos = [wsRoot, ...apps.map(a => path.join(wsRoot, '.codespace', a.name))];
|
|
61
62
|
for (const repo of allRepos) {
|
|
62
63
|
if (fs.existsSync(repo)) {
|
|
63
64
|
run('git worktree prune', repo);
|
|
@@ -114,7 +115,7 @@ if (fs.existsSync(wtDir)) {
|
|
|
114
115
|
console.log('=== 创建 App Worktrees ===');
|
|
115
116
|
const results = [];
|
|
116
117
|
for (const app of apps) {
|
|
117
|
-
const appPath = path.join(wsRoot, '.
|
|
118
|
+
const appPath = path.join(wsRoot, '.codespace', app.name);
|
|
118
119
|
const nestedWt = path.join(wtDir, app.name);
|
|
119
120
|
|
|
120
121
|
if (fs.existsSync(nestedWt) && fs.existsSync(path.join(nestedWt, '.git'))) {
|
|
@@ -141,7 +142,7 @@ if (hasFailed) {
|
|
|
141
142
|
console.error('⚠️ 部分 app worktree 创建失败,需手动清理:');
|
|
142
143
|
console.error(' cd ' + wsRoot + ' && git worktree remove .worktrees/worktree-' + branch);
|
|
143
144
|
for (const r of results.filter(x => x.status === 'failed')) {
|
|
144
|
-
console.error(' git -C .
|
|
145
|
+
console.error(' git -C .codespace/' + r.name + ' worktree remove <worktree-path>');
|
|
145
146
|
}
|
|
146
147
|
console.error('---');
|
|
147
148
|
console.error('WORKTREE_RESULT', JSON.stringify(results));
|
|
@@ -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 内 workspace-config.json 副本干扰)
|
|
9
|
+
* 兜底:当前目录含 workspace-config.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
|
+
// 兜底:当前目录含 workspace-config.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, 'workspace-config.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, 'workspace-config.json'))) {
|
|
57
57
|
console.error('❌ 未找到工作空间根目录');
|
|
58
|
-
console.error(' 原因:git worktree list 失败且当前目录无
|
|
59
|
-
console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含
|
|
58
|
+
console.error(' 原因:git worktree list 失败且当前目录无 workspace-config.json');
|
|
59
|
+
console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含 workspace-config.json)下执行本技能');
|
|
60
60
|
process.exit(1);
|
|
61
61
|
}
|
|
62
62
|
|
package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/install-ai.js
RENAMED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('./silence-popup');
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* cbb-worktree-init 在 worktree 中安装 AI 配置(必要步骤)
|
|
5
5
|
*
|
|
6
6
|
* 用法:node install-ai.js <wt_path>
|
|
7
7
|
*
|
|
8
8
|
* 行为:
|
|
9
|
-
* 1. 检测
|
|
10
|
-
* 2. 直接用 npm 全局 bin 路径调用
|
|
11
|
-
* 3. 在 worktree 内执行
|
|
9
|
+
* 1. 检测 cbbm 是否全局安装,未安装则自动安装
|
|
10
|
+
* 2. 直接用 npm 全局 bin 路径调用 cbbm(避免 PowerShell PATH 缓存)
|
|
11
|
+
* 3. 在 worktree 内执行 cbbm init --yes
|
|
12
12
|
* 4. 失败则 exit 2,阻塞 init-worktree 流程(与 push-branches.js 语义一致)
|
|
13
13
|
*
|
|
14
14
|
* 退出码:
|
|
15
15
|
* 0 - 成功
|
|
16
16
|
* 1 - 参数错误(脚本 bug 或调用错误)
|
|
17
|
-
* 2 -
|
|
17
|
+
* 2 - cbbm init 执行失败(**阻塞 init-worktree**,用户必须手动恢复)
|
|
18
18
|
*/
|
|
19
19
|
const { execSync } = require('child_process');
|
|
20
20
|
const fs = require('fs');
|
|
@@ -40,11 +40,11 @@ function run(cmd, cwd, env) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// 查找
|
|
43
|
+
// 查找 cbbm 可执行文件:先 PATH,再 npm 全局 bin
|
|
44
44
|
function findCbb() {
|
|
45
|
-
// 1. 直接调用
|
|
46
|
-
let r = run('
|
|
47
|
-
if (r.ok) return { cmd: '
|
|
45
|
+
// 1. 直接调用 cbbm --version
|
|
46
|
+
let r = run('cbbm --version');
|
|
47
|
+
if (r.ok) return { cmd: 'cbbm', version: r.out };
|
|
48
48
|
|
|
49
49
|
// 2. 查 npm 全局 bin 目录
|
|
50
50
|
const npmRoot = run('npm root -g');
|
|
@@ -53,15 +53,15 @@ function findCbb() {
|
|
|
53
53
|
// Unix: <npm_root>/../bin/cbb
|
|
54
54
|
const candidates = [];
|
|
55
55
|
if (process.platform === 'win32') {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
candidates.push(path.join(npmRoot.out, 'cbbm.cmd'));
|
|
57
|
+
candidates.push(path.join(npmRoot.out, '..', 'cbbm.cmd'));
|
|
58
|
+
candidates.push(path.join(npmRoot.out, '..', 'bin', 'cbbm.cmd'));
|
|
59
|
+
// npm 全局 bin 通常是 %APPDATA%\npm\cbbm.cmd
|
|
60
|
+
const appdata = process.env.APPDATA || process.env.USERPROFILE;
|
|
61
|
+
if (appdata) candidates.push(path.join(appdata, 'npm', 'cbbm.cmd'));
|
|
62
|
+
} else {
|
|
63
|
+
candidates.push(path.join(npmRoot.out, '..', 'bin', 'cbbm'));
|
|
64
|
+
candidates.push(path.join(npmRoot.out, '..', 'cbbm'));
|
|
65
65
|
}
|
|
66
66
|
for (const c of candidates) {
|
|
67
67
|
if (fs.existsSync(c)) {
|
|
@@ -77,7 +77,7 @@ function findCbb() {
|
|
|
77
77
|
// 1. 检测/安装 cbb
|
|
78
78
|
let cbbInfo = findCbb();
|
|
79
79
|
if (!cbbInfo) {
|
|
80
|
-
console.log('WARN:
|
|
80
|
+
console.log('WARN: cbbm not globally installed, try auto-install...');
|
|
81
81
|
const install = run('npm install -g @jspg-ai/coding-bb');
|
|
82
82
|
if (!install.ok) {
|
|
83
83
|
console.error('ERROR: cbb auto-install failed: ' + install.err);
|
|
@@ -85,7 +85,7 @@ if (!cbbInfo) {
|
|
|
85
85
|
console.error('━━━ init-worktree 已中断 ━━━');
|
|
86
86
|
console.error('请手动安装 cbb 后重跑 init-worktree:');
|
|
87
87
|
console.error(' 1. npm install -g @jspg-ai/coding-bb');
|
|
88
|
-
console.error(' 2. cd "' + wtPath + '" &&
|
|
88
|
+
console.error(' 2. cd "' + wtPath + '" && cbbm init --yes');
|
|
89
89
|
console.error(' 3. 在 ai-workspace 根目录重跑 init-worktree');
|
|
90
90
|
console.log('---');
|
|
91
91
|
console.log('AI_INIT_FAILED');
|
|
@@ -98,8 +98,8 @@ if (!cbbInfo) {
|
|
|
98
98
|
const npmRoot = run('npm root -g');
|
|
99
99
|
if (npmRoot.ok) {
|
|
100
100
|
const candidates = process.platform === 'win32'
|
|
101
|
-
? [path.join(npmRoot.out, '..', '
|
|
102
|
-
: [path.join(npmRoot.out, '..', 'bin', '
|
|
101
|
+
? [path.join(npmRoot.out, '..', 'cbbm.cmd'), path.join(npmRoot.out, '..', 'bin', 'cbbm.cmd')]
|
|
102
|
+
: [path.join(npmRoot.out, '..', 'bin', 'cbbm')];
|
|
103
103
|
for (const c of candidates) {
|
|
104
104
|
if (fs.existsSync(c)) {
|
|
105
105
|
cbbInfo = { cmd: '"' + c + '"', version: 'located at ' + c };
|
|
@@ -109,26 +109,26 @@ if (!cbbInfo) {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
if (!cbbInfo) {
|
|
112
|
-
console.error('ERROR:
|
|
112
|
+
console.error('ERROR: cbbm not found after install. Likely npm PATH cache issue.');
|
|
113
113
|
console.error('');
|
|
114
114
|
console.error('━━━ init-worktree 已中断 ━━━');
|
|
115
115
|
console.error('可能原因:npm 全局 bin 目录不在当前 shell 的 PATH 中。');
|
|
116
116
|
console.error('手动恢复步骤:');
|
|
117
|
-
console.error(' 1. 重启终端让 PATH 生效,或手动定位
|
|
117
|
+
console.error(' 1. 重启终端让 PATH 生效,或手动定位 cbbm:');
|
|
118
118
|
console.error(' npm root -g # 拿到全局 node_modules 路径');
|
|
119
|
-
console.error(' <path>/../
|
|
120
|
-
console.error(' 2. cd "' + wtPath + '" &&
|
|
119
|
+
console.error(' <path>/../cbbm.cmd # Windows / <path>/../bin/cbbm # Unix');
|
|
120
|
+
console.error(' 2. cd "' + wtPath + '" && cbbm init --yes');
|
|
121
121
|
console.error(' 3. 在 ai-workspace 根目录重跑 init-worktree');
|
|
122
122
|
console.log('---');
|
|
123
123
|
console.log('AI_INIT_FAILED');
|
|
124
124
|
process.exit(2);
|
|
125
125
|
}
|
|
126
|
-
console.log('OK:
|
|
126
|
+
console.log('OK: cbbm located: ' + cbbInfo.version);
|
|
127
127
|
} else {
|
|
128
|
-
console.log('OK:
|
|
128
|
+
console.log('OK: cbbm found: ' + cbbInfo.version);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
// 2. 在 worktree 中执行
|
|
131
|
+
// 2. 在 worktree 中执行 cbbm init --yes
|
|
132
132
|
console.log('Installing AI config in worktree: ' + wtPath);
|
|
133
133
|
const initCmd = cbbInfo.cmd + ' init --yes';
|
|
134
134
|
const init = run(initCmd, wtPath);
|
|
@@ -145,21 +145,21 @@ if (init.ok) {
|
|
|
145
145
|
console.error('ERROR: AI config install failed: ' + init.err);
|
|
146
146
|
console.error('');
|
|
147
147
|
console.error('━━━ init-worktree 已中断 ━━━');
|
|
148
|
-
console.error('原因:
|
|
148
|
+
console.error('原因:cbbm init 是必要步骤。AI 配置缺失将导致后续 openspec-* ');
|
|
149
149
|
console.error(' (propose/apply/verify/ff 等)技能全部不可用。');
|
|
150
150
|
console.error('');
|
|
151
151
|
console.error('━━━ 手动恢复步骤(请按顺序执行)━━━');
|
|
152
152
|
console.error('');
|
|
153
153
|
console.error('1. 验证环境');
|
|
154
|
-
console.error(' $
|
|
154
|
+
console.error(' $ cbbm --version');
|
|
155
155
|
console.error(' $ node --version # 需要 >= 16.7.0');
|
|
156
156
|
console.error('');
|
|
157
|
-
console.error('2.
|
|
157
|
+
console.error('2. 若未安装(cbbm 不在 PATH),先安装');
|
|
158
158
|
console.error(' $ npm install -g @jspg-ai/coding-bb');
|
|
159
159
|
console.error('');
|
|
160
160
|
console.error('3. 进入 worktree 并初始化 AI 配置');
|
|
161
161
|
console.error(' $ cd "' + wtPath + '"');
|
|
162
|
-
console.error(' $
|
|
162
|
+
console.error(' $ cbbm init --yes');
|
|
163
163
|
console.error('');
|
|
164
164
|
console.error('4. 重新执行 init-worktree');
|
|
165
165
|
console.error(' 在 ai-workspace 根目录重跑,会跳过已初始化的部分');
|
package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/parse-config.js
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('./silence-popup');
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* cbb-worktree-init 读取并校验 workspace-config.json
|
|
5
5
|
*
|
|
6
6
|
* 退出码:
|
|
7
7
|
* 0 - 成功,输出应用列表 JSON
|
|
@@ -15,10 +15,10 @@ require('./silence-popup');
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
|
|
18
|
-
const configPath = path.join(process.cwd(), '
|
|
18
|
+
const configPath = path.join(process.cwd(), 'workspace-config.json');
|
|
19
19
|
|
|
20
20
|
if (!fs.existsSync(configPath)) {
|
|
21
|
-
console.error('❌
|
|
21
|
+
console.error('❌ workspace-config.json 不存在');
|
|
22
22
|
console.error(' 请先在 cbb setup 阶段创建,或手动配置');
|
|
23
23
|
console.error('---');
|
|
24
24
|
console.error('CONFIG_MISSING');
|
|
@@ -29,7 +29,7 @@ let config;
|
|
|
29
29
|
try {
|
|
30
30
|
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
31
31
|
} catch (e) {
|
|
32
|
-
console.error('❌
|
|
32
|
+
console.error('❌ workspace-config.json 解析失败:', e.message);
|
|
33
33
|
console.error(' 请检查 JSON 格式');
|
|
34
34
|
console.error('---');
|
|
35
35
|
console.error('CONFIG_INVALID');
|
|
@@ -38,8 +38,8 @@ try {
|
|
|
38
38
|
|
|
39
39
|
const apps = config.apps || [];
|
|
40
40
|
if (apps.length === 0) {
|
|
41
|
-
console.error('❌
|
|
42
|
-
console.error(' 请编辑
|
|
41
|
+
console.error('❌ workspace-config.json 中 apps 为空');
|
|
42
|
+
console.error(' 请编辑 workspace-config.json 配置关联应用');
|
|
43
43
|
console.error('---');
|
|
44
44
|
console.error('CONFIG_EMPTY');
|
|
45
45
|
process.exit(2);
|
|
@@ -61,7 +61,7 @@ for (const app of apps) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
console.log('✅
|
|
64
|
+
console.log('✅ workspace-config.json 有效(' + apps.length + ' 个应用)');
|
|
65
65
|
console.log('---');
|
|
66
66
|
console.log('CONFIG_OK', JSON.stringify(apps));
|
|
67
67
|
process.exit(0);
|
package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/push-branches.js
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require('./silence-popup');
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* cbb-worktree-init 推送并建立 upstream
|
|
4
4
|
*
|
|
5
5
|
* 薄壳脚本:核心 push 逻辑委托给同目录的 push-core.js(共享脚本,源仓库真源在 _shared/scripts/)。
|
|
6
|
-
* 本脚本只负责 CLI 入口编排(编排 init-worktree 关注的 workspace + .
|
|
6
|
+
* 本脚本只负责 CLI 入口编排(编排 init-worktree 关注的 workspace + .codespace/<app>/ 列表)。
|
|
7
7
|
*
|
|
8
8
|
* Usage: node push-branches.js <ws_root> <branch>
|
|
9
9
|
*
|
|
@@ -12,7 +12,7 @@ require('./silence-popup');
|
|
|
12
12
|
* 1 - 参数错误(CONFIG 缺失或 argv 不足)
|
|
13
13
|
* 2 - 部分/全部失败(AI agent 必须阻塞流程)
|
|
14
14
|
*
|
|
15
|
-
* 新场景(开发完成后跨 worktree 推送)请使用
|
|
15
|
+
* 新场景(开发完成后跨 worktree 推送)请使用 cbb-worktree-push/scripts/push-worktrees.js。
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
const { pushSingle, classifyError, collectRemoteMetadata } = require('./push-core');
|
|
@@ -20,7 +20,7 @@ const fs = require('fs');
|
|
|
20
20
|
const path = require('path');
|
|
21
21
|
|
|
22
22
|
function loadAppsFromConfig(wsRoot) {
|
|
23
|
-
const configPath = path.join(wsRoot, '
|
|
23
|
+
const configPath = path.join(wsRoot, 'workspace-config.json');
|
|
24
24
|
if (!fs.existsSync(configPath)) return null;
|
|
25
25
|
try {
|
|
26
26
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
@@ -40,7 +40,7 @@ function executePush(opts) {
|
|
|
40
40
|
const branch = opts.branch;
|
|
41
41
|
const apps = opts.apps != null ? opts.apps : loadAppsFromConfig(wsRoot);
|
|
42
42
|
if (apps == null) {
|
|
43
|
-
throw new Error('
|
|
43
|
+
throw new Error('workspace-config.json missing or apps empty');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const results = [];
|
|
@@ -48,7 +48,7 @@ function executePush(opts) {
|
|
|
48
48
|
results.push(pushSingle(wsRoot, 'workspace', branch, { execSyncImpl: opts.execSyncImpl }));
|
|
49
49
|
// apps
|
|
50
50
|
for (const app of apps) {
|
|
51
|
-
const appPath = path.join(wsRoot, '.
|
|
51
|
+
const appPath = path.join(wsRoot, '.codespace', app.name);
|
|
52
52
|
results.push(pushSingle(appPath, app.name, branch, { execSyncImpl: opts.execSyncImpl }));
|
|
53
53
|
}
|
|
54
54
|
return results;
|
|
@@ -68,7 +68,7 @@ function main() {
|
|
|
68
68
|
|
|
69
69
|
const apps = loadAppsFromConfig(wsRoot);
|
|
70
70
|
if (apps == null) {
|
|
71
|
-
console.error('❌
|
|
71
|
+
console.error('❌ workspace-config.json 缺失或 apps 为空');
|
|
72
72
|
process.exit(1);
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -81,6 +81,8 @@ function main() {
|
|
|
81
81
|
for (const r of results) {
|
|
82
82
|
if (r.status === 'pushed') {
|
|
83
83
|
console.log('✅ ' + r.name + ': 已推送 ' + r.upstream);
|
|
84
|
+
} else if (r.status === 'skipped') {
|
|
85
|
+
console.log('⏭️ ' + r.name + ': 远程分支与本地一致,跳过推送');
|
|
84
86
|
} else if (r.status === 'remote-exists') {
|
|
85
87
|
console.log('⚠️ ' + r.name + ': 远程分支已存在(需用户决策)');
|
|
86
88
|
} else {
|
package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/push-core.js
RENAMED
|
@@ -12,6 +12,12 @@ require('./silence-popup');
|
|
|
12
12
|
* - pushSingle(repoPath, repoName, branch) 推送单个仓库并建立 upstream
|
|
13
13
|
* - collectRemoteMetadata(repoPath, branch, remote) 采集远程 commit 元信息
|
|
14
14
|
*
|
|
15
|
+
* pushSingle 状态契约:
|
|
16
|
+
* - pushed 本次推送成功(新建分支或快进)
|
|
17
|
+
* - skipped 远程同名分支已存在且与本地一致 → 无需推送(幂等,重跑 init 场景)
|
|
18
|
+
* - remote-exists 远程同名分支存在但与本地不一致 → 需用户决策(附 metadata)
|
|
19
|
+
* - failed 推送失败,error 见错误码契约
|
|
20
|
+
*
|
|
15
21
|
* 错误码契约(classifyError 输出):
|
|
16
22
|
* - ssh-auth-failed Permission denied (publickey)
|
|
17
23
|
* - https-auth-failed Authentication failed
|
|
@@ -115,6 +121,18 @@ function pushSingle(repoPath, repoName, branch, opts) {
|
|
|
115
121
|
const r = remote.out.split(/\r?\n/)[0];
|
|
116
122
|
const branchEsc = escapeBranch(branch);
|
|
117
123
|
const remoteEsc = '"' + String(r).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
124
|
+
|
|
125
|
+
// 幂等:远程同名分支已存在且 hash 与本地完全一致 → 此前已推送,直接跳过。
|
|
126
|
+
// 让 init-worktree 可安全重跑(补齐新增应用/中断恢复),且不会重复推送或误报 remote-exists。
|
|
127
|
+
const lsRemote = tryExec('git ls-remote --heads ' + remoteEsc + ' ' + escapeBranch('refs/heads/' + branch), repoPath, execImpl);
|
|
128
|
+
if (lsRemote.ok && lsRemote.out) {
|
|
129
|
+
const remoteHash = lsRemote.out.split(/\s+/)[0];
|
|
130
|
+
const localHash = tryExec('git rev-parse --verify ' + branchEsc, repoPath, execImpl);
|
|
131
|
+
if (localHash.ok && localHash.out && localHash.out === remoteHash) {
|
|
132
|
+
return { name: repoName, status: 'skipped', upstream: r + '/' + branch, message: '远程分支与本地一致,无需推送' };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
118
136
|
const pushResult = tryExec('git push -u ' + remoteEsc + ' ' + branchEsc, repoPath, execImpl);
|
|
119
137
|
if (pushResult.ok) {
|
|
120
138
|
return { name: repoName, status: 'pushed', upstream: r + '/' + branch };
|
package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/sync-repos.js
RENAMED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('./silence-popup');
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* cbb-worktree-init 同步 .codespace/ 仓库
|
|
5
5
|
*
|
|
6
|
-
* 用法:node sync-repos.js <ws_root>
|
|
7
|
-
* - ws_root:
|
|
8
|
-
* - apps_json: 应用列表 JSON 数组(来自 parse-config.js)
|
|
6
|
+
* 用法:node sync-repos.js <ws_root>
|
|
7
|
+
* - ws_root: 工作空间根绝对路径(apps 从 <ws_root>/workspace-config.json 读取)
|
|
9
8
|
*
|
|
10
9
|
* 对每个 app:
|
|
11
|
-
* - .
|
|
10
|
+
* - .codespace/<name>/.git 存在 → fetch --all
|
|
12
11
|
* - 不存在 → clone(从 repo URL)
|
|
13
12
|
*
|
|
14
13
|
* 退出码:
|
|
@@ -22,7 +21,6 @@ const fs = require('fs');
|
|
|
22
21
|
const path = require('path');
|
|
23
22
|
|
|
24
23
|
const wsRoot = process.argv[2];
|
|
25
|
-
const appsJson = process.argv[3];
|
|
26
24
|
|
|
27
25
|
if (!wsRoot) {
|
|
28
26
|
console.error('❌ 用法:node sync-repos.js <ws_root>');
|
|
@@ -30,23 +28,23 @@ if (!wsRoot) {
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
|
-
* 从
|
|
31
|
+
* 从 workspace-config.json 读取 apps(避免 shell 字符串传递中的转义问题)
|
|
34
32
|
*/
|
|
35
33
|
function loadAppsFromConfig() {
|
|
36
|
-
const configPath = path.join(wsRoot, '
|
|
34
|
+
const configPath = path.join(wsRoot, 'workspace-config.json');
|
|
37
35
|
if (!fs.existsSync(configPath)) {
|
|
38
|
-
console.error('❌
|
|
36
|
+
console.error('❌ workspace-config.json 不存在:' + configPath);
|
|
39
37
|
return null;
|
|
40
38
|
}
|
|
41
39
|
try {
|
|
42
40
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
43
41
|
if (!config.apps || !Array.isArray(config.apps) || config.apps.length === 0) {
|
|
44
|
-
console.error('❌
|
|
42
|
+
console.error('❌ workspace-config.json 中 apps 为空');
|
|
45
43
|
return null;
|
|
46
44
|
}
|
|
47
45
|
return config.apps;
|
|
48
46
|
} catch (e) {
|
|
49
|
-
console.error('❌
|
|
47
|
+
console.error('❌ workspace-config.json 解析失败:' + e.message);
|
|
50
48
|
return null;
|
|
51
49
|
}
|
|
52
50
|
}
|
|
@@ -56,7 +54,7 @@ if (!apps) {
|
|
|
56
54
|
process.exit(1);
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
const codeDir = path.join(wsRoot, '.
|
|
57
|
+
const codeDir = path.join(wsRoot, '.codespace');
|
|
60
58
|
fs.mkdirSync(codeDir, { recursive: true });
|
|
61
59
|
|
|
62
60
|
const results = [];
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('./silence-popup');
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* cbb-worktree-init 安全更新 .gitignore
|
|
5
5
|
*
|
|
6
6
|
* 用法:node update-gitignore.js <ws_root> <branch>
|
|
7
7
|
*
|
|
8
8
|
* 行为:
|
|
9
9
|
* 1. stash 当前未提交修改
|
|
10
10
|
* 2. 切换到目标分支
|
|
11
|
-
* 3. 检查 .worktrees/ 和 .
|
|
11
|
+
* 3. 检查 .worktrees/ 和 .codespace/ 是否在 .gitignore
|
|
12
12
|
* 4. 添加缺失条目
|
|
13
13
|
* 5. 提交 .gitignore
|
|
14
14
|
* 6. 切回原分支
|
|
15
15
|
* 7. pop stash(如有)
|
|
16
16
|
*
|
|
17
|
+
* 幂等:目标分支已在某个 worktree 中检出(init-worktree 重跑场景,上次已处理过
|
|
18
|
+
* .gitignore)时,跳过全部操作直接输出 GITIGNORE_OK——避免 checkout 与 worktree 检出冲突。
|
|
19
|
+
*
|
|
17
20
|
* 退出码:
|
|
18
21
|
* 0 - 成功
|
|
19
22
|
* 1 - 参数错误
|
|
@@ -48,6 +51,16 @@ if (!origBranch.ok) {
|
|
|
48
51
|
}
|
|
49
52
|
console.log('当前分支:' + origBranch.out);
|
|
50
53
|
|
|
54
|
+
// 1.1 幂等检查:目标分支已被某 worktree 检出 → 上次 init-worktree 已处理 .gitignore
|
|
55
|
+
const wtList = run('git worktree list --porcelain', wsRoot);
|
|
56
|
+
const branchInWorktree = wtList.ok && wtList.out.split(/\r?\n/).some(l => l.trim() === 'branch refs/heads/' + branch);
|
|
57
|
+
if (branchInWorktree) {
|
|
58
|
+
console.log('ℹ️ 分支 ' + branch + ' 已在 worktree 中检出(init-worktree 重跑场景),跳过 .gitignore 处理');
|
|
59
|
+
console.log('---');
|
|
60
|
+
console.log('GITIGNORE_OK');
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
51
64
|
// 2. stash 当前未提交修改
|
|
52
65
|
let stashed = false;
|
|
53
66
|
const status = run('git status --porcelain', wsRoot);
|
|
@@ -73,13 +86,13 @@ if (!checkout.ok) {
|
|
|
73
86
|
}
|
|
74
87
|
console.log('✅ 切换到分支:' + branch);
|
|
75
88
|
|
|
76
|
-
// 4. 检查并添加 .worktrees/ 和 .
|
|
89
|
+
// 4. 检查并添加 .worktrees/ 和 .codespace/ 到 .gitignore
|
|
77
90
|
const gitignorePath = path.join(wsRoot, '.gitignore');
|
|
78
91
|
let content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
79
92
|
const original = content;
|
|
80
93
|
const needCommit = [];
|
|
81
94
|
|
|
82
|
-
for (const dir of ['.worktrees/', '.
|
|
95
|
+
for (const dir of ['.worktrees/', '.codespace/']) {
|
|
83
96
|
const check = run('git check-ignore -q "' + dir + '"', wsRoot);
|
|
84
97
|
if (!check.ok) {
|
|
85
98
|
// 未忽略:添加
|
|
@@ -90,7 +103,7 @@ for (const dir of ['.worktrees/', '.code/']) {
|
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
if (needCommit.length === 0) {
|
|
93
|
-
console.log('ℹ️ .worktrees/ 和 .
|
|
106
|
+
console.log('ℹ️ .worktrees/ 和 .codespace/ 均已在 .gitignore 中,跳过提交');
|
|
94
107
|
} else {
|
|
95
108
|
fs.writeFileSync(gitignorePath, content);
|
|
96
109
|
console.log('✅ .gitignore 已添加:' + needCommit.join(', '));
|
|
@@ -101,7 +114,7 @@ if (needCommit.length === 0) {
|
|
|
101
114
|
if (stashed) run('git stash pop', wsRoot);
|
|
102
115
|
process.exit(2);
|
|
103
116
|
}
|
|
104
|
-
const commit = run('git commit -m "chore: add .worktrees/ and .
|
|
117
|
+
const commit = run('git commit -m "chore: add .worktrees/ and .codespace/ to gitignore"', wsRoot);
|
|
105
118
|
if (!commit.ok) {
|
|
106
119
|
console.error('❌ git commit 失败:' + commit.err);
|
|
107
120
|
run('git checkout "' + origBranch.out + '"', wsRoot);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: cbb-worktree-push
|
|
3
3
|
description: "跨 worktree 提交并推送当前需求的所有关联仓库。触发:用户说'提交'/'commit'/'push'/'推送'/'提交并push'/'推到远端';用户在 .worktrees/worktree-<需求名>/ 下工作要求批量推送;apply 完成后准备推送所有 worktree;close-worktree 前需要先推送未提交改动。"
|
|
4
4
|
license: MIT
|
|
5
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).
|
|
@@ -11,17 +11,17 @@ metadata:
|
|
|
11
11
|
|
|
12
12
|
# Push Worktrees(跨平台脚本化版本 v1.0)
|
|
13
13
|
|
|
14
|
-
跨 worktree 提交并推送当前需求的所有关联仓库到 origin。专门解决"开发完成后批量推送"和"用户口语化提交并push"两类场景,弥补 [
|
|
14
|
+
跨 worktree 提交并推送当前需求的所有关联仓库到 origin。专门解决"开发完成后批量推送"和"用户口语化提交并push"两类场景,弥补 [cbb-worktree-init Step 3.4](file:///d:/workspace/va-ai/coding-bb/cbb/worktrees/skills/cbb-worktree-init/SKILL.md) 仅推送初始空 commit 的缺口。
|
|
15
15
|
|
|
16
|
-
**启动时声明:** "我正在使用
|
|
16
|
+
**启动时声明:** "我正在使用 cbb-worktree-push 技能来批量提交并推送当前需求的所有 worktree 仓库。"
|
|
17
17
|
|
|
18
18
|
## 核心原则
|
|
19
19
|
|
|
20
20
|
- 本技能的所有原子操作封装为 `scripts/*.js` Node.js 脚本,**跨平台执行**
|
|
21
21
|
- **两阶段**:先 `commit-worktrees.js` 提交所有 dirty 仓库,再 `push-worktrees.js` 推送所有 worktree 仓库。两个脚本独立退出码,AI agent 区分阶段
|
|
22
|
-
- 复用 `
|
|
23
|
-
- `find-workspace-root.js` / `find-target-worktree.js` 为共享脚本:源仓库真源在 `cbb/worktrees/_shared/scripts/`,部署后位于本 skill 的 `scripts/` 下,与 `
|
|
24
|
-
- **本技能支持两层执行位置**(与 `
|
|
22
|
+
- 复用 `cbb-worktree-push/scripts/push-core.js` 的 `pushSingle` / `classifyError` —— 与 `cbb-worktree-init` 的 `push-branches.js` 行为完全一致,错误码契约统一
|
|
23
|
+
- `find-workspace-root.js` / `find-target-worktree.js` 为共享脚本:源仓库真源在 `cbb/worktrees/_shared/scripts/`,部署后位于本 skill 的 `scripts/` 下,与 `cbb-worktree-init` / `cbb-worktree-close` 逻辑完全一致
|
|
24
|
+
- **本技能支持两层执行位置**(与 `cbb-worktree-close` 对称):
|
|
25
25
|
- 工作空间根目录(`WS_ROOT/`)
|
|
26
26
|
- worktree 内部(`WS_ROOT/.worktrees/worktree-<需求名>/` 或其子目录)
|
|
27
27
|
- 输入约定:**自由文本**(commit 信息、需求名等)直接在对话中提问并等待回复;**固定选项多选**(如 "应用统一信息 vs 分别信息")使用 `AskUserQuestion`
|
|
@@ -33,7 +33,7 @@ metadata:
|
|
|
33
33
|
**所有脚本必须用绝对路径调用**(Qoder 沙箱中 AI agent 的 cwd 不一定是技能目录)。
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
node "<ws_root>/.qoder/skills/
|
|
36
|
+
node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/<name>.js" <参数>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
脚本输出:
|
|
@@ -46,7 +46,7 @@ node "<ws_root>/.qoder/skills/openspec-push-worktrees/scripts/<name>.js" <参数
|
|
|
46
46
|
## Step 0:定位工作空间
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
node "<ws_root>/.qoder/skills/
|
|
49
|
+
node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/find-workspace-root.js"
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
**解读末行**:
|
|
@@ -58,13 +58,13 @@ node "<ws_root>/.qoder/skills/openspec-push-worktrees/scripts/find-workspace-roo
|
|
|
58
58
|
## Step 1:识别目标 worktree
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
node "<ws_root>/.qoder/skills/
|
|
61
|
+
node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/find-target-worktree.js" "<ws_root>"
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
**解读末行**:
|
|
65
65
|
- 退出码 0 + 末行(需求名) → 唯一识别,自动用之
|
|
66
66
|
- 退出码 1 + 末行 `MULTIPLE_WORKTREEES` → 多个 worktree,AI agent 在对话中让用户输入序号或分支名
|
|
67
|
-
- 退出码 2 + 末行 `NO_WORKTREE` → 无 worktree,提示用户先用 `
|
|
67
|
+
- 退出码 2 + 末行 `NO_WORKTREE` → 无 worktree,提示用户先用 `cbb-worktree-init`
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
@@ -72,7 +72,7 @@ node "<ws_root>/.qoder/skills/openspec-push-worktrees/scripts/find-target-worktr
|
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
# 仅 commit 阶段先做 dry-run 预览
|
|
75
|
-
node "<ws_root>/.qoder/skills/
|
|
75
|
+
node "<ws_root>/.qoder/skills/cbb-worktree-push/scripts/commit-worktrees.js" "<ws_root>" "<branch>" --message "preview" --dry-run
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
**解读末行 `COMMIT_RESULT`**:每项仓库的状态
|
|
@@ -94,7 +94,7 @@ AI agent 在执行真实 commit 前**必须**在对话中向用户确认 commit
|
|
|
94
94
|
|
|
95
95
|
```
|
|
96
96
|
检测到以下 worktree 仓库有未提交改动:
|
|
97
|
-
- workspace: 5 个文件(
|
|
97
|
+
- workspace: 5 个文件(workspace-config.json, openspec/changes/foo/...)
|
|
98
98
|
- ep-foo-app: 12 个文件
|
|
99
99
|
- ep-bar-app: 3 个文件
|
|
100
100
|
|
|
@@ -119,7 +119,7 @@ AI agent 在执行真实 commit 前**必须**在对话中向用户确认 commit
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
# 统一信息
|
|
122
|
-
node "<ws_root>/.qoder/skills/
|
|
122
|
+
node "<ws_root>/.qoder/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>/.qoder/skills/
|
|
158
|
+
node "<ws_root>/.qoder/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>"
|
|
@@ -211,7 +211,7 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
211
211
|
ep-foo-app: ✅ origin/<branch>
|
|
212
212
|
ep-bar-app: ⚠️ 远程分支已存在(需用户决策 → 已关联)
|
|
213
213
|
AI 配置目录:worktree 内独立安装,无需处理
|
|
214
|
-
后续:可继续开发 / 调 /opsx:verify 验证 / 调 /opsx:archive 归档 / 调 /
|
|
214
|
+
后续:可继续开发 / 调 /opsx:verify 验证 / 调 /opsx:archive 归档 / 调 /cbb:worktree-close 关闭
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
---
|
|
@@ -258,7 +258,7 @@ node "..." "<ws_root>/.worktrees/worktree-<branch>"
|
|
|
258
258
|
|
|
259
259
|
### 多仓库用同一条 commit 信息
|
|
260
260
|
|
|
261
|
-
- **问题:** workspace 改了
|
|
261
|
+
- **问题:** workspace 改了 workspace-config.json,ep-foo-app 改了 Java 代码,硬塞同一条 "feat: 实现 XX" 信息不准确
|
|
262
262
|
- **修复:** 用 `--per-repo` 模式,让用户逐仓库提供
|
|
263
263
|
|
|
264
264
|
### push 失败时跳过失败仓库直接继续
|