@jspg-ai/coding-bb 0.0.3-beta.9 → 0.0.5-beta.1
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/README.md +1 -0
- package/cbb/dev-standards/rules/cbb-ai-behavior.md +0 -15
- package/cbb/dev-standards/rules/cbb-workspace-discipline.md +38 -0
- package/cbb/lib/external/index.js +228 -0
- package/cbb/lib/install/agents-nav.js +92 -0
- package/cbb/lib/install/claude-code.js +8 -1
- package/cbb/lib/install/command-skill.js +105 -0
- package/cbb/lib/install/init.js +399 -129
- package/cbb/lib/install/minimax.js +60 -0
- package/cbb/lib/install/rule-rewrite.js +1 -1
- package/cbb/lib/install/setup-decision.js +92 -0
- package/cbb/lib/install/tool-selection.js +23 -0
- package/cbb/lib/install/trae.js +18 -8
- package/cbb/lib/install/workbuddy.js +36 -0
- package/cbb/lib/install/workspaces.js +15 -61
- package/cbb/lib/utils/check-update.js +13 -5
- package/cbb/lib/utils/githook.js +230 -0
- package/cbb/lib/utils/gitignore.js +17 -4
- package/cbb/lib/utils/plugin-hook.js +92 -0
- package/cbb/worktrees/_shared/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/_shared/scripts/check-unarchived.js +77 -0
- package/cbb/worktrees/_shared/scripts/delete-branches.js +147 -0
- package/cbb/worktrees/_shared/scripts/deprecate-branches.js +119 -0
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +148 -96
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +8 -8
- package/cbb/worktrees/_shared/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/_shared/scripts/junction-ai-config.js +192 -0
- package/cbb/worktrees/_shared/scripts/merge-branches.js +580 -0
- package/cbb/worktrees/_shared/scripts/push-core.js +1 -1
- package/cbb/worktrees/_shared/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/_shared/scripts/start-local.js +180 -0
- package/cbb/worktrees/skills/cbb-local-mode/SKILL.md +194 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/check-local-state.js +114 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/delete-branches.js +147 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/deprecate-branches.js +119 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-local-mode/scripts/merge-branches.js +580 -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 +134 -81
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-env.js +3 -3
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/check-unarchived.js +77 -48
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/delete-branches.js +147 -136
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/deprecate-branches.js +119 -0
- 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 +8 -8
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/junction-ai-config.js +192 -0
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/merge-branches.js +580 -0
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/remove-worktrees.js +44 -9
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/safety-check.js +15 -4
- package/cbb/worktrees/skills/cbb-worktree-close/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/SKILL.md +131 -120
- 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/install-git-hook.js +70 -0
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/junction-ai-config.js +192 -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/push-core.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/silence-popup.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/sync-repos.js +11 -7
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/update-gitignore.js +17 -5
- package/cbb/worktrees/skills/cbb-worktree-push/SKILL.md +213 -56
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/check-unarchived.js +77 -0
- 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 +8 -8
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/make-mr-urls.js +211 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/merge-branches.js +580 -0
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-core.js +1 -1
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/push-worktrees.js +67 -20
- package/cbb/worktrees/skills/cbb-worktree-push/scripts/silence-popup.js +1 -1
- package/config/{workspace-config.sample.json → CBB-WORKSPACE.sample.json} +1 -1
- package/config/openspec/schemas/spec-driven/schema.yaml +20 -0
- package/config/upstream-mirrors.json +5 -0
- 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 -2
- package/openspec/commands/archive.md +15 -8
- package/openspec/commands/bulk-archive.md +13 -6
- package/openspec/commands/continue.md +0 -1
- package/openspec/commands/explore.md +1 -1
- package/openspec/commands/ff.md +1 -1
- package/openspec/commands/onboard.md +9 -4
- package/openspec/commands/update.md +11 -5
- package/openspec/commands/verify.md +57 -26
- package/openspec/skills/openspec-apply-change/SKILL.md +1 -1
- package/openspec/skills/openspec-archive-change/SKILL.md +16 -9
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +14 -7
- package/openspec/skills/openspec-continue-change/SKILL.md +1 -2
- package/openspec/skills/openspec-explore/SKILL.md +2 -2
- package/openspec/skills/openspec-ff-change/SKILL.md +2 -2
- package/openspec/skills/openspec-new-change/SKILL.md +1 -1
- package/openspec/skills/openspec-onboard/SKILL.md +10 -5
- package/openspec/skills/openspec-propose/SKILL.md +1 -1
- package/openspec/skills/openspec-sync-specs/SKILL.md +1 -1
- package/openspec/skills/openspec-update-change/SKILL.md +12 -6
- package/openspec/skills/openspec-verify-change/SKILL.md +59 -27
- package/package.json +3 -2
- package/superpowers/.version +3 -3
- package/superpowers/skills/writing-plans/SKILL.md +32 -20
- package/cbb/lib/install/codebuddy.js +0 -30
- package/cbb/worktrees/skills/cbb-worktree-init/scripts/find-workspace-root.js +0 -67
- package/config/workspace-agents.sample.md +0 -41
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* worktree 模式 AI 配置 junction(ADR 0002,防线 B)。
|
|
4
|
+
*
|
|
5
|
+
* 用法:node junction-ai-config.js <ws_root> <wt_path> [--remove]
|
|
6
|
+
*
|
|
7
|
+
* 目的:让开发会话能开进 worktree(工作树内加载 AI 配置),同时保持
|
|
8
|
+
* 「单层安装」实质——配置唯一物理副本在空间根,cbb update 一处生效。
|
|
9
|
+
*
|
|
10
|
+
* 策略(规避 ADR 0001 否决时的状态污染):
|
|
11
|
+
* - 只 junction **只读内容子目录**(rules / skills / commands):
|
|
12
|
+
* 工具向配置根写状态(如 settings.local.json)落在 worktree 自建的
|
|
13
|
+
* 物理(空壳)配置目录里,按项目隔离,不互相覆盖;
|
|
14
|
+
* - 配置根目录本身在 worktree 侧是物理目录(不是链接);
|
|
15
|
+
* - .opencode/opencode.json 为文件(junction 不支持文件):直接复制
|
|
16
|
+
* (cbb update 后需重跑本脚本同步;worktree 为瞬态,影响可控)。
|
|
17
|
+
*
|
|
18
|
+
* 幂等:linkPath 已指向同一 target → skip;指向不同 → 重建;
|
|
19
|
+
* 存在同名**物理目录**(非链接)→ warn 跳过(不覆盖用户内容)。
|
|
20
|
+
*
|
|
21
|
+
* --remove(cbb-worktree-close 调用):
|
|
22
|
+
* - 拆除 worktree 内已建 junction 与复制件,**源文件零接触**:
|
|
23
|
+
* 只解除链接本身(fs.rmSync 对 reparse point 仅删链接、不穿透目标,
|
|
24
|
+
* 已由 Windows 实测验证),复制件为普通文件直接删除;
|
|
25
|
+
* - 拆除前校验链接目标位于空间根内——目标在空间根外 / readlink 失败
|
|
26
|
+
* → 跳过并警告(防误删外部目录);同名物理目录/文件 → 跳过不碰。
|
|
27
|
+
*
|
|
28
|
+
* 退出码:0 成功(含全部 skip);1 参数错误;2 执行失败。
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const fs = require('fs');
|
|
32
|
+
const path = require('path');
|
|
33
|
+
|
|
34
|
+
const wsRoot = process.argv[2];
|
|
35
|
+
const wtPath = process.argv[3];
|
|
36
|
+
const removeMode = process.argv[4] === '--remove';
|
|
37
|
+
|
|
38
|
+
if (!wsRoot || !wtPath) {
|
|
39
|
+
console.error('Usage: node junction-ai-config.js <ws_root> <wt_path> [--remove]');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 各工具的项目级配置根(存在才处理)与本包部署的内容子目录
|
|
44
|
+
const CONFIG_ROOTS = ['.claude', '.qoder', '.opencode', '.workbuddy', '.trae', '.minimax'];
|
|
45
|
+
const CONTENT_SUBDIRS = ['rules', 'skills', 'commands'];
|
|
46
|
+
// 文件级内容(复制而非 junction):opencode 的 instructions 登记
|
|
47
|
+
const CONTENT_FILES = { '.opencode': ['opencode.json'] };
|
|
48
|
+
|
|
49
|
+
const linked = [];
|
|
50
|
+
const copied = [];
|
|
51
|
+
const skipped = [];
|
|
52
|
+
const warned = [];
|
|
53
|
+
let hasFailure = false;
|
|
54
|
+
|
|
55
|
+
/** 归一化 junction 目标路径(Windows readlink 返回 \\?\ 前缀) */
|
|
56
|
+
function normLinkTarget(p) {
|
|
57
|
+
return path.resolve(String(p).replace(/^\\\\\?\\/, ''));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 目标是否位于空间根内(防误删空间根外目录的守卫) */
|
|
61
|
+
function isWithin(p, root) {
|
|
62
|
+
const r = path.resolve(root) + path.sep;
|
|
63
|
+
return path.resolve(p).startsWith(r);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── remove 模式:显式拆除 junction 与复制件(源文件零接触)──
|
|
67
|
+
if (removeMode) {
|
|
68
|
+
const removed = [];
|
|
69
|
+
const guarded = [];
|
|
70
|
+
|
|
71
|
+
for (const root of CONFIG_ROOTS) {
|
|
72
|
+
for (const sub of CONTENT_SUBDIRS) {
|
|
73
|
+
const linkPath = path.join(wtPath, root, sub);
|
|
74
|
+
const label = root + '/' + sub;
|
|
75
|
+
let st;
|
|
76
|
+
try { st = fs.lstatSync(linkPath); } catch (e) { continue; } // 不存在 → 跳过(dangling 链接 lstat 仍成功,可拆)
|
|
77
|
+
if (!st.isSymbolicLink()) continue; // 物理目录/文件(工具状态空壳或用户内容)→ 不碰
|
|
78
|
+
|
|
79
|
+
const target = normLinkTarget(fs.readlinkSync(linkPath));
|
|
80
|
+
if (!isWithin(target, wsRoot)) {
|
|
81
|
+
guarded.push(label + ' → ' + target + '(目标不在空间根内,跳过)');
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
// 只解除链接:Node 对 reparse point 仅删除链接本身,不递归、不触达目标内容
|
|
87
|
+
fs.rmSync(linkPath, { recursive: true, force: true });
|
|
88
|
+
removed.push(label);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.error('❌ 拆除失败 ' + label + ' — ' + e.message);
|
|
91
|
+
hasFailure = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const file of (CONTENT_FILES[root] || [])) {
|
|
96
|
+
const linkPath = path.join(wtPath, root, file);
|
|
97
|
+
if (!fs.existsSync(linkPath)) continue;
|
|
98
|
+
try {
|
|
99
|
+
fs.unlinkSync(linkPath); // 复制件为普通文件,删除不影响源
|
|
100
|
+
removed.push(root + '/' + file);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.error('❌ 删除失败 ' + root + '/' + file + ' — ' + e.message);
|
|
103
|
+
hasFailure = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (removed.length) console.log('✅ 已拆除 junction/复制件:' + removed.join(', '));
|
|
109
|
+
if (guarded.length) console.log('⚠️ ' + guarded.join(';'));
|
|
110
|
+
if (removed.length === 0 && guarded.length === 0) console.log('ℹ️ 无待拆除项(幂等)');
|
|
111
|
+
|
|
112
|
+
console.log('---');
|
|
113
|
+
console.log('JUNCTION_REMOVE_RESULT', JSON.stringify({ removed, guarded, wt: wtPath }));
|
|
114
|
+
process.exit(hasFailure ? 2 : 0);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function linkDir(target, linkPath, label) {
|
|
118
|
+
if (fs.existsSync(linkPath)) {
|
|
119
|
+
const st = fs.lstatSync(linkPath);
|
|
120
|
+
if (st.isSymbolicLink()) {
|
|
121
|
+
const existing = normLinkTarget(fs.readlinkSync(linkPath));
|
|
122
|
+
if (existing === path.resolve(target)) {
|
|
123
|
+
skipped.push(label);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
fs.unlinkSync(linkPath); // 指向不同 → 重建
|
|
127
|
+
} else if (st.isDirectory()) {
|
|
128
|
+
warned.push(label + '(存在同名物理目录,未覆盖)');
|
|
129
|
+
return;
|
|
130
|
+
} else {
|
|
131
|
+
fs.unlinkSync(linkPath); // 同名文件,罕见,重建
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
fs.mkdirSync(path.dirname(linkPath), { recursive: true });
|
|
135
|
+
try {
|
|
136
|
+
if (process.platform === 'win32') {
|
|
137
|
+
fs.symlinkSync(path.resolve(target), linkPath, 'junction');
|
|
138
|
+
} else {
|
|
139
|
+
fs.symlinkSync(path.resolve(target), linkPath, 'dir');
|
|
140
|
+
}
|
|
141
|
+
linked.push(label);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.error('❌ junction 失败 ' + label + ' — ' + e.message);
|
|
144
|
+
hasFailure = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function copyFile(target, dest, label) {
|
|
149
|
+
if (fs.existsSync(dest) && fs.existsSync(target) &&
|
|
150
|
+
fs.readFileSync(dest, 'utf-8') === fs.readFileSync(target, 'utf-8')) {
|
|
151
|
+
skipped.push(label);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
156
|
+
fs.copyFileSync(target, dest);
|
|
157
|
+
copied.push(label);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
console.error('❌ 复制失败 ' + label + ' — ' + e.message);
|
|
160
|
+
hasFailure = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const root of CONFIG_ROOTS) {
|
|
165
|
+
const srcRoot = path.join(wsRoot, root);
|
|
166
|
+
if (!fs.existsSync(srcRoot) || !fs.statSync(srcRoot).isDirectory()) continue;
|
|
167
|
+
|
|
168
|
+
for (const sub of CONTENT_SUBDIRS) {
|
|
169
|
+
const src = path.join(srcRoot, sub);
|
|
170
|
+
if (!fs.existsSync(src) || !fs.statSync(src).isDirectory()) continue;
|
|
171
|
+
linkDir(src, path.join(wtPath, root, sub), root + '/' + sub);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (const file of (CONTENT_FILES[root] || [])) {
|
|
175
|
+
const src = path.join(srcRoot, file);
|
|
176
|
+
if (!fs.existsSync(src) || !fs.statSync(src).isFile()) continue;
|
|
177
|
+
copyFile(src, path.join(wtPath, root, file), root + '/' + file);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (linked.length === 0 && copied.length === 0 && skipped.length === 0 && warned.length === 0) {
|
|
182
|
+
console.log('ℹ️ 空间根无 AI 配置目录,跳过(cbb setup 选择工具后再装)');
|
|
183
|
+
} else {
|
|
184
|
+
if (linked.length) console.log('✅ junction:' + linked.join(', '));
|
|
185
|
+
if (copied.length) console.log('✅ 复制:' + copied.join(', '));
|
|
186
|
+
if (skipped.length) console.log('⏭️ 已就绪:' + skipped.join(', '));
|
|
187
|
+
if (warned.length) console.log('⚠️ ' + warned.join(';'));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log('---');
|
|
191
|
+
console.log('JUNCTION_RESULT', JSON.stringify({ linked, copied, skipped, warned, wt: wtPath }));
|
|
192
|
+
process.exit(hasFailure ? 2 : 0);
|