@jspg-ai/coding-bb 0.0.1 → 0.0.2-beta.22

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 (145) hide show
  1. package/cbb/bin/cbb.js +6 -0
  2. package/cbb/bin/cbbm.js +6 -0
  3. package/cbb/dev-standards/rules/cbb-ai-behavior.md +103 -103
  4. package/cbb/dev-standards/rules/cbb-priority.md +55 -55
  5. package/cbb/lib/install/claude-code.js +2 -0
  6. package/cbb/lib/install/init.js +496 -290
  7. package/cbb/lib/install/opencode.js +31 -0
  8. package/cbb/lib/install/qoder.js +2 -0
  9. package/cbb/lib/install/workspaces.js +53 -13
  10. package/cbb/lib/openspec/index.js +3 -3
  11. package/cbb/lib/superpowers/index.js +1 -1
  12. package/cbb/lib/utils/check-update.js +16 -14
  13. package/cbb/lib/utils/gitignore.js +2 -1
  14. package/cbb/lib/utils/output.js +92 -4
  15. package/cbb/lib/utils/version.js +2 -31
  16. package/cbb/lib/wiki/cli.js +25 -25
  17. package/cbb/lib/wiki/index.js +16 -16
  18. package/cbb/tools/cbb-design-to-wiki/SKILL.md +14 -14
  19. package/cbb/tools/cbb-wiki-ops/SKILL.md +22 -22
  20. package/cbb/worktrees/_shared/scripts/find-target-worktree.js +2 -2
  21. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
  22. package/cbb/worktrees/_shared/scripts/push-core.js +18 -0
  23. package/cbb/worktrees/commands/{close.md → worktree-close.md} +8 -8
  24. package/cbb/worktrees/commands/{init.md → worktree-init.md} +9 -9
  25. package/cbb/worktrees/commands/{push.md → worktree-push.md} +3 -3
  26. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/SKILL.md +20 -20
  27. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-env.js +4 -4
  28. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-unarchived.js +1 -1
  29. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/delete-branches.js +3 -3
  30. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/discover-apps.js +6 -6
  31. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-close}/scripts/find-target-worktree.js +2 -2
  32. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-close}/scripts/find-workspace-root.js +7 -7
  33. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/remove-worktrees.js +4 -4
  34. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/safety-check.js +4 -4
  35. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/SKILL.md +81 -107
  36. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/auto-open.js +1 -1
  37. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env-deep.js +4 -4
  38. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env.js +6 -6
  39. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-repos.js +4 -4
  40. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-branches.js +4 -4
  41. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-worktrees.js +8 -7
  42. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-init}/scripts/find-workspace-root.js +7 -7
  43. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/install-ai.js +33 -33
  44. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/parse-config.js +7 -7
  45. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/push-branches.js +9 -7
  46. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/push-core.js +18 -0
  47. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/sync-repos.js +10 -12
  48. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/update-gitignore.js +19 -6
  49. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/SKILL.md +16 -16
  50. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/commit-worktrees.js +2 -2
  51. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/find-target-worktree.js +2 -2
  52. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-push}/scripts/find-workspace-root.js +7 -7
  53. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-core.js +18 -0
  54. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-worktrees.js +7 -5
  55. package/config/workspace-config.sample.json +18 -0
  56. package/config/workspaces.json +11 -6
  57. package/openspec/.version +6 -6
  58. package/openspec/commands/apply.md +7 -7
  59. package/openspec/commands/archive.md +7 -7
  60. package/openspec/commands/bulk-archive.md +7 -7
  61. package/openspec/commands/continue.md +7 -7
  62. package/openspec/commands/explore.md +7 -7
  63. package/openspec/commands/ff.md +7 -7
  64. package/openspec/commands/new.md +7 -7
  65. package/openspec/commands/onboard.md +7 -7
  66. package/openspec/commands/propose.md +7 -7
  67. package/openspec/commands/sync.md +7 -7
  68. package/openspec/commands/update.md +7 -7
  69. package/openspec/commands/verify.md +7 -7
  70. package/openspec/skills/openspec-apply-change/SKILL.md +187 -187
  71. package/openspec/skills/openspec-archive-change/SKILL.md +181 -181
  72. package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -338
  73. package/openspec/skills/openspec-continue-change/SKILL.md +117 -117
  74. package/openspec/skills/openspec-explore/SKILL.md +342 -342
  75. package/openspec/skills/openspec-ff-change/SKILL.md +116 -116
  76. package/openspec/skills/openspec-new-change/SKILL.md +76 -76
  77. package/openspec/skills/openspec-onboard/SKILL.md +560 -560
  78. package/openspec/skills/openspec-propose/SKILL.md +162 -162
  79. package/openspec/skills/openspec-sync-specs/SKILL.md +261 -261
  80. package/openspec/skills/openspec-update-change/SKILL.md +90 -90
  81. package/openspec/skills/openspec-verify-change/SKILL.md +174 -174
  82. package/package.json +4 -3
  83. package/superpowers/.version +6 -6
  84. package/superpowers/skills/brainstorming/SKILL.md +250 -250
  85. package/superpowers/skills/brainstorming/scripts/helper.js +167 -167
  86. package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -209
  87. package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -120
  88. package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -49
  89. package/superpowers/skills/brainstorming/visual-companion.md +299 -299
  90. package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -167
  91. package/superpowers/skills/executing-plans/SKILL.md +64 -64
  92. package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -225
  93. package/superpowers/skills/receiving-code-review/SKILL.md +205 -205
  94. package/superpowers/skills/requesting-code-review/SKILL.md +95 -95
  95. package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -181
  96. package/superpowers/skills/subagent-driven-development/SKILL.md +568 -568
  97. package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -154
  98. package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -115
  99. package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -207
  100. package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -119
  101. package/superpowers/skills/systematic-debugging/SKILL.md +283 -283
  102. package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  103. package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -115
  104. package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -122
  105. package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -72
  106. package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -169
  107. package/superpowers/skills/systematic-debugging/test-academic.md +14 -14
  108. package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -58
  109. package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -68
  110. package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -69
  111. package/superpowers/skills/test-driven-development/SKILL.md +320 -320
  112. package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -198
  113. package/superpowers/skills/using-git-worktrees/SKILL.md +167 -167
  114. package/superpowers/skills/using-superpowers/SKILL.md +63 -63
  115. package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -23
  116. package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -108
  117. package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -63
  118. package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -56
  119. package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -16
  120. package/superpowers/skills/verification-before-completion/SKILL.md +120 -120
  121. package/superpowers/skills/writing-plans/SKILL.md +171 -171
  122. package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -49
  123. package/superpowers/skills/writing-skills/SKILL.md +679 -679
  124. package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -1150
  125. package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
  126. package/superpowers/skills/writing-skills/persuasion-principles.md +187 -187
  127. package/superpowers/skills/writing-skills/render-graphs.js +169 -169
  128. package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -384
  129. package/cbb/worktrees/commands/extend.md +0 -65
  130. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +0 -96
  131. package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +0 -390
  132. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +0 -95
  133. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +0 -98
  134. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +0 -135
  135. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +0 -150
  136. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +0 -88
  137. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +0 -93
  138. package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +0 -67
  139. package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +0 -93
  140. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +0 -136
  141. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +0 -23
  142. package/config/config.sample.json +0 -16
  143. /package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/silence-popup.js +0 -0
  144. /package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/silence-popup.js +0 -0
  145. /package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-push}/scripts/silence-popup.js +0 -0
@@ -1,98 +0,0 @@
1
- #!/usr/bin/env node
2
- require('./silence-popup');
3
- /**
4
- * openspec-extend-worktree 状态检查 (app only)
5
- */
6
- const { execSync } = require('child_process');
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- const wsRoot = process.argv[2];
11
- const appsNames = process.argv[3];
12
-
13
- if (!wsRoot || !appsNames) {
14
- console.error('Usage: node check-repos.js <ws_root> <app1,app2,...>');
15
- process.exit(1);
16
- }
17
-
18
- function loadSelectedApps() {
19
- const configPath = path.join(wsRoot, 'CONFIG.json');
20
- if (!fs.existsSync(configPath)) return null;
21
- let config;
22
- try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) { return null; }
23
- const allApps = Array.isArray(config.apps) ? config.apps : [];
24
- const namesSet = new Set(appsNames.split(',').map(s => s.trim()).filter(Boolean));
25
- return allApps.filter(a => namesSet.has(a.name));
26
- }
27
-
28
- const apps = loadSelectedApps();
29
- if (!apps) {
30
- console.error('Apps not found in CONFIG.json: ' + appsNames);
31
- process.exit(1);
32
- }
33
-
34
- function tryExec(cmd, cwd) {
35
- try {
36
- return { ok: true, out: execSync(cmd, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).trim() };
37
- } catch (e) {
38
- return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
39
- }
40
- }
41
-
42
- function checkApp(appPath, name) {
43
- const problems = [];
44
- if (!fs.existsSync(appPath)) return { name, problems: ['path not exist'], ok: false };
45
-
46
- const inside = tryExec('git rev-parse --is-inside-work-tree', appPath);
47
- if (!inside.ok || inside.out !== 'true') {
48
- return { name, problems: ['not a git repo'], ok: false };
49
- }
50
-
51
- const gitDir = tryExec('git rev-parse --git-dir', appPath);
52
- const gitCommon = tryExec('git rev-parse --git-common-dir', appPath);
53
- const superRef = tryExec('git rev-parse --show-superproject-working-tree', appPath);
54
-
55
- const isWorktree = gitDir.ok && gitCommon.ok && gitDir.out !== gitCommon.out && !superRef.out;
56
- if (isWorktree) problems.push('already in worktree');
57
- if (superRef.out) problems.push('is git submodule');
58
-
59
- const remote = tryExec('git remote', appPath);
60
- if (!remote.ok || !remote.out) {
61
- problems.push('no remote');
62
- } else {
63
- const r = remote.out.split(/\r?\n/)[0];
64
- const fetch = tryExec('git fetch -q "' + r + '"', appPath);
65
- if (!fetch.ok) {
66
- problems.push('git fetch failed');
67
- } else {
68
- const symbolic = tryExec('git symbolic-ref "refs/remotes/' + r + '/HEAD"', appPath);
69
- let main = 'main';
70
- if (symbolic.ok && symbolic.out) {
71
- main = symbolic.out.replace('refs/remotes/' + r + '/', '');
72
- }
73
- const refCheck = tryExec('git rev-parse --verify --quiet "refs/remotes/' + r + '/' + main + '"', appPath);
74
- if (!refCheck.ok) {
75
- problems.push('remote has no ' + main + ' branch');
76
- }
77
- }
78
- }
79
-
80
- return { name, problems, ok: problems.length === 0 };
81
- }
82
-
83
- const results = [];
84
- for (const app of apps) {
85
- const appPath = path.join(wsRoot, '.code', app.name);
86
- const r = checkApp(appPath, app.name);
87
- results.push(r);
88
- if (r.ok) {
89
- console.log('OK ' + r.name + ': status check passed');
90
- } else {
91
- console.error('FAIL ' + r.name + ': ' + r.problems.join('; '));
92
- }
93
- }
94
-
95
- const allOk = results.every(r => r.ok);
96
- console.log('---');
97
- console.log('CHECK_RESULT', allOk ? 'ALL_OK' : 'HAS_FAILURES');
98
- process.exit(allOk ? 0 : 2);
@@ -1,135 +0,0 @@
1
- #!/usr/bin/env node
2
- require('./silence-popup');
3
- /**
4
- * openspec-extend-worktree 分支创建 + 嵌套 worktree
5
- */
6
- const { execSync } = require('child_process');
7
- const { pushSingle } = require('./push-core');
8
- const fs = require('fs');
9
- const path = require('path');
10
-
11
- const wsRoot = process.argv[2];
12
- const branch = process.argv[3];
13
- const appsNames = process.argv[4];
14
-
15
- if (!wsRoot || !branch || !appsNames) {
16
- console.error('Usage: node create-branches-and-worktrees.js <ws_root> <branch> <app1,app2,...>');
17
- process.exit(1);
18
- }
19
-
20
- function loadSelectedApps() {
21
- const configPath = path.join(wsRoot, 'CONFIG.json');
22
- if (!fs.existsSync(configPath)) return null;
23
- let config;
24
- try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) { return null; }
25
- const allApps = Array.isArray(config.apps) ? config.apps : [];
26
- const namesSet = new Set(appsNames.split(',').map(s => s.trim()).filter(Boolean));
27
- return allApps.filter(a => namesSet.has(a.name));
28
- }
29
-
30
- const apps = loadSelectedApps();
31
- if (!apps || apps.length === 0) {
32
- console.error('Apps not found in CONFIG.json: ' + appsNames);
33
- process.exit(1);
34
- }
35
-
36
- function tryExec(cmd, cwd) {
37
- try {
38
- return { ok: true, out: execSync(cmd, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).trim() };
39
- } catch (e) {
40
- return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
41
- }
42
- }
43
-
44
- function detectMainBranch(cwd) {
45
- const remote = tryExec('git remote', cwd);
46
- if (!remote.ok || !remote.out) return 'main';
47
- const r = remote.out.split(/\r?\n/)[0];
48
- const symbolic = tryExec('git symbolic-ref "refs/remotes/' + r + '/HEAD"', cwd);
49
- if (symbolic.ok && symbolic.out) {
50
- return symbolic.out.replace('refs/remotes/' + r + '/', '');
51
- }
52
- return 'main';
53
- }
54
-
55
- const results = [];
56
-
57
- function processApp(app) {
58
- const appPath = path.join(wsRoot, '.code', app.name);
59
- const nestedWt = path.join(wsRoot, '.worktrees', 'worktree-' + branch, app.name);
60
-
61
- // 1: branch check
62
- const branchCheck = tryExec('git branch --list "' + branch + '"', appPath);
63
- let branchCreated = false;
64
- if (branchCheck.ok && branchCheck.out) {
65
- console.log('Skip ' + app.name + ': branch exists, reuse');
66
- } else {
67
- const remote = tryExec('git remote', appPath);
68
- if (!remote.ok || !remote.out) {
69
- console.error('FAIL ' + app.name + ': no remote');
70
- results.push({ name: app.name, status: 'failed', step: 'branch', error: 'no remote' });
71
- return;
72
- }
73
- const r = remote.out.split(/\r?\n/)[0];
74
- const main = detectMainBranch(appPath);
75
- const create = tryExec('git branch "' + branch + '" "' + r + '/' + main + '"', appPath);
76
- if (create.ok) {
77
- console.log('OK ' + app.name + ': branch ' + branch + ' created (from ' + r + '/' + main + ')');
78
- branchCreated = true;
79
- } else {
80
- console.error('FAIL ' + app.name + ': branch create failed');
81
- results.push({ name: app.name, status: 'failed', step: 'branch', error: create.err });
82
- return;
83
- }
84
- }
85
-
86
- // 2: nested worktree check
87
- if (fs.existsSync(nestedWt) && fs.existsSync(path.join(nestedWt, '.git'))) {
88
- console.log('Skip ' + app.name + ': nested worktree exists, reuse');
89
- results.push({ name: app.name, status: 'reused' });
90
- return;
91
- }
92
-
93
- fs.mkdirSync(path.dirname(nestedWt), { recursive: true });
94
- const wtCreate = tryExec('git worktree add "' + nestedWt + '" "' + branch + '"', appPath);
95
- if (wtCreate.ok) {
96
- console.log('OK ' + app.name + ': nested worktree created');
97
- results.push({ name: app.name, status: branchCreated ? 'created' : 'branch-reused-wt-created' });
98
- } else {
99
- console.error('FAIL ' + app.name + ': worktree create failed');
100
- results.push({ name: app.name, status: 'failed', step: 'worktree', error: wtCreate.err });
101
- }
102
- }
103
-
104
- for (const app of apps) {
105
- processApp(app);
106
- }
107
-
108
- // 3: 推送本次新建的分支并建立 upstream(仅 status='created',避免对 init-worktree 已推过的复用分支重复 push)
109
- const newlyCreated = results.filter(r => r.status === 'created');
110
- if (newlyCreated.length > 0) {
111
- console.log('=== 推送新分支建立 upstream ===');
112
- for (const r of newlyCreated) {
113
- const app = apps.find(a => a.name === r.name);
114
- if (!app) continue;
115
- const appPath = path.join(wsRoot, '.code', app.name);
116
- const pushResult = pushSingle(appPath, app.name, branch);
117
- if (pushResult.status === 'pushed') {
118
- console.log('OK ' + app.name + ': pushed ' + pushResult.upstream);
119
- } else if (pushResult.status === 'remote-exists') {
120
- console.log('WARN ' + app.name + ': remote branch already exists (需要用户决策)');
121
- } else {
122
- console.error('FAIL ' + app.name + ': push failed - ' + (pushResult.message || pushResult.error));
123
- }
124
- // 覆盖原 result,附加 push 状态
125
- const idx = results.findIndex(x => x.name === r.name);
126
- if (idx >= 0) {
127
- results[idx] = Object.assign({}, results[idx], { push_status: pushResult.status, push_error: pushResult.error, push_upstream: pushResult.upstream });
128
- }
129
- }
130
- }
131
-
132
- const hasFailed = results.some(r => r.status === 'failed' || r.push_status === 'failed' || r.push_status === 'remote-exists');
133
- console.log('---');
134
- console.log('BRANCH_WT_RESULT', JSON.stringify(results));
135
- process.exit(hasFailed ? 2 : 0);
@@ -1,150 +0,0 @@
1
- #!/usr/bin/env node
2
- require('./silence-popup');
3
- /**
4
- * openspec-extend-worktree 确保 workspace worktree 已装 AI 配置(必要步骤)
5
- *
6
- * 用法:node install-ai.js <ws_root> <branch>
7
- *
8
- * 行为:
9
- * - 仅对 workspace worktree 跑 cbb init --yes(开发约束不在 Java 应用 worktree 中)
10
- * - 用 .cbb/.managed-by-cbb 判重,已 init 过的 workspace 跳过
11
- * - 失败则 exit 2,阻塞 extend-worktree 流程(与 init-worktree 一致)
12
- *
13
- * 退出码:
14
- * 0 - 成功 / 跳过
15
- * 1 - 参数错误
16
- * 2 - cbb init 执行失败(**阻塞 extend-worktree**,用户必须手动恢复)
17
- */
18
- const { execSync } = require('child_process');
19
- const fs = require('fs');
20
- const path = require('path');
21
-
22
- const wsRoot = process.argv[2];
23
- const branch = process.argv[3];
24
-
25
- if (!wsRoot || !branch) {
26
- console.error('❌ 用法:node install-ai.js <ws_root> <branch>');
27
- process.exit(1);
28
- }
29
-
30
- const wtRoot = path.join(wsRoot, '.worktrees', 'worktree-' + branch);
31
-
32
- if (!fs.existsSync(wtRoot)) {
33
- console.error('❌ workspace worktree 不存在:' + wtRoot);
34
- console.error(' → 请先确保 init-worktree 已创建 workspace worktree');
35
- process.exit(1);
36
- }
37
-
38
- function run(cmd, cwd, env) {
39
- try {
40
- return { ok: true, out: execSync(cmd, { cwd: cwd || process.cwd(), encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], env: env || process.env, input: '\n' }).trim() };
41
- } catch (e) {
42
- return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
43
- }
44
- }
45
-
46
- // 判重:init-worktree 已经 init 过的 workspace,跳过
47
- const marker = path.join(wtRoot, '.cbb', '.managed-by-cbb');
48
- if (fs.existsSync(marker)) {
49
- console.log('⏭️ workspace worktree AI 配置已存在(.cbb/.managed-by-cbb),跳过');
50
- console.log('---');
51
- console.log('AI_INIT_OK');
52
- process.exit(0);
53
- }
54
-
55
- // 查找 cbb 可执行文件
56
- function findCbb() {
57
- let r = run('cbb --version');
58
- if (r.ok) return { cmd: 'cbb', version: r.out };
59
-
60
- const npmRoot = run('npm root -g');
61
- if (npmRoot.ok) {
62
- const candidates = [];
63
- if (process.platform === 'win32') {
64
- candidates.push(path.join(npmRoot.out, 'cbb.cmd'));
65
- candidates.push(path.join(npmRoot.out, '..', 'cbb.cmd'));
66
- candidates.push(path.join(npmRoot.out, '..', 'bin', 'cbb.cmd'));
67
- const appdata = process.env.APPDATA || process.env.USERPROFILE;
68
- if (appdata) candidates.push(path.join(appdata, 'npm', 'cbb.cmd'));
69
- } else {
70
- candidates.push(path.join(npmRoot.out, '..', 'bin', 'cbb'));
71
- candidates.push(path.join(npmRoot.out, '..', 'cbb'));
72
- }
73
- for (const c of candidates) {
74
- if (fs.existsSync(c)) {
75
- r = run('"' + c + '" --version');
76
- if (r.ok) return { cmd: '"' + c + '"', version: r.out };
77
- }
78
- }
79
- }
80
- return null;
81
- }
82
-
83
- // 1. 检测/安装 cbb
84
- let cbbInfo = findCbb();
85
- if (!cbbInfo) {
86
- console.log('WARN: cbb not globally installed, try auto-install...');
87
- const install = run('npm install -g @jspg-ai/coding-bb');
88
- if (!install.ok) {
89
- console.error('ERROR: cbb auto-install failed: ' + install.err);
90
- console.error('');
91
- console.error('━━━ extend-worktree 已中断 ━━━');
92
- console.error('请手动安装 cbb 后重跑 extend-worktree:');
93
- console.error(' 1. npm install -g @jspg-ai/coding-bb');
94
- console.error(' 2. cd "' + wtRoot + '" && cbb init --yes');
95
- console.error(' 3. 重跑 extend-worktree');
96
- console.log('---');
97
- console.log('AI_INIT_FAILED');
98
- process.exit(2);
99
- }
100
- cbbInfo = findCbb();
101
- if (!cbbInfo) {
102
- console.error('ERROR: cbb not found after install. Likely npm PATH cache issue.');
103
- console.error('');
104
- console.error('━━━ extend-worktree 已中断 ━━━');
105
- console.error('手动恢复:cd "' + wtRoot + '" && cbb init --yes');
106
- console.error('然后重跑 extend-worktree。');
107
- console.log('---');
108
- console.log('AI_INIT_FAILED');
109
- process.exit(2);
110
- }
111
- console.log('OK: cbb located: ' + cbbInfo.version);
112
- } else {
113
- console.log('OK: cbb found: ' + cbbInfo.version);
114
- }
115
-
116
- // 2. 在 workspace worktree 中执行 cbb init --yes
117
- console.log('Installing AI config in workspace worktree: ' + wtRoot);
118
- const initCmd = cbbInfo.cmd + ' init --yes';
119
- const init = run(initCmd, wtRoot);
120
- if (init.ok) {
121
- console.log('✅ workspace worktree AI 配置安装完成');
122
- console.log('---');
123
- console.log('AI_INIT_OK');
124
- process.exit(0);
125
- } else {
126
- console.error('ERROR: AI config install failed: ' + init.err);
127
- console.error('');
128
- console.error('━━━ extend-worktree 已中断 ━━━');
129
- console.error('原因:cbb init 是必要步骤。AI 配置缺失将导致后续 openspec-* ');
130
- console.error(' (propose/apply/verify/ff 等)技能全部不可用。');
131
- console.error('');
132
- console.error('━━━ 手动恢复步骤(请按顺序执行)━━━');
133
- console.error('');
134
- console.error('1. 验证环境');
135
- console.error(' $ cbb --version');
136
- console.error(' $ node --version # 需要 >= 16.7.0');
137
- console.error('');
138
- console.error('2. 若 cbb 未安装,先安装');
139
- console.error(' $ npm install -g @jspg-ai/coding-bb');
140
- console.error('');
141
- console.error('3. 进入 workspace worktree 并初始化');
142
- console.error(' $ cd "' + wtRoot + '"');
143
- console.error(' $ cbb init --yes');
144
- console.error('');
145
- console.error('4. 重新执行 extend-worktree');
146
- console.error(' (脚本会用 .cbb/.managed-by-cbb 判重自动跳过已恢复部分)');
147
- console.log('---');
148
- console.log('AI_INIT_FAILED');
149
- process.exit(2);
150
- }
@@ -1,88 +0,0 @@
1
- #!/usr/bin/env node
2
- require('./silence-popup');
3
- /**
4
- * openspec-extend-worktree 计算"未关联"应用清单
5
- *
6
- * 用法:node list-available-apps.js <ws_root> <branch>
7
- *
8
- * 从 CONFIG.json 读取全部应用,减去目标 worktree 中已存在的应用子目录。
9
- *
10
- * 输出末行:LIST_RESULT { available: [...], already: [...] }
11
- *
12
- * 退出码:
13
- * 0 - 有可用应用
14
- * 1 - 参数错误
15
- * 2 - 所有应用都已关联(无新增项)
16
- */
17
-
18
- const fs = require('fs');
19
- const path = require('path');
20
-
21
- const wsRoot = process.argv[2];
22
- const branch = process.argv[3];
23
-
24
- if (!wsRoot || !branch) {
25
- console.error('❌ 用法:node list-available-apps.js <ws_root> <branch>');
26
- process.exit(1);
27
- }
28
-
29
- const configPath = path.join(wsRoot, 'CONFIG.json');
30
- if (!fs.existsSync(configPath)) {
31
- console.error('❌ CONFIG.json 不存在:' + configPath);
32
- process.exit(1);
33
- }
34
-
35
- let config;
36
- try {
37
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
38
- } catch (e) {
39
- console.error('❌ CONFIG.json 解析失败:' + e.message);
40
- process.exit(1);
41
- }
42
-
43
- const apps = config.apps || [];
44
- const wtDir = path.join(wsRoot, '.worktrees', 'worktree-' + branch);
45
- if (!fs.existsSync(wtDir)) {
46
- console.error('❌ 目标 worktree 不存在:' + wtDir);
47
- console.error(' 请先执行 openspec-init-worktree 创建该需求的工作空间');
48
- process.exit(1);
49
- }
50
-
51
- const available = [];
52
- const already = [];
53
-
54
- for (const app of apps) {
55
- const wtSub = path.join(wtDir, app.name);
56
- if (fs.existsSync(wtSub) && fs.existsSync(path.join(wtSub, '.git'))) {
57
- already.push(app);
58
- } else {
59
- available.push(app);
60
- }
61
- }
62
-
63
- console.log('=== 已关联应用(跳过) ===');
64
- if (already.length === 0) {
65
- console.log(' (无)');
66
- } else {
67
- already.forEach(a => {
68
- console.log(' [' + (a.side || 'back') + '] ' + a.name);
69
- });
70
- }
71
- console.log('');
72
- console.log('=== 可补加应用 ===');
73
- if (available.length === 0) {
74
- console.log(' (无)');
75
- } else {
76
- available.forEach(a => {
77
- console.log(' [' + (a.side || 'back') + '] ' + a.name);
78
- });
79
- }
80
-
81
- console.log('---');
82
- const result = {
83
- available: available.map(a => a.name),
84
- already: already.map(a => a.name),
85
- availableDetails: available,
86
- };
87
- console.log('LIST_RESULT', JSON.stringify(result));
88
- process.exit(available.length === 0 ? 2 : 0);
@@ -1,93 +0,0 @@
1
- #!/usr/bin/env node
2
- require('./silence-popup');
3
- /**
4
- * openspec-extend-worktree 同步待补加应用的 .code/ 仓库
5
- *
6
- * 用法:node sync-repos.js <ws_root> '<apps_json>'
7
- *
8
- * 对每个待补加应用:
9
- * - .code/<name>/.git 存在 → fetch --all
10
- * - 不存在 → clone(从 app.repo)
11
- *
12
- * 退出码:
13
- * 0 - 全部成功
14
- * 1 - 参数错误
15
- * 2 - 部分失败
16
- */
17
-
18
- const { execSync } = require('child_process');
19
- const fs = require('fs');
20
- const path = require('path');
21
-
22
- const wsRoot = process.argv[2];
23
- // appsNames: 应用名逗号分隔字符串,如 "app1,app2,app3"
24
- const appsNames = process.argv[3];
25
-
26
- if (!wsRoot || !appsNames) {
27
- console.error('❌ 用法:node sync-repos.js <ws_root> <app1,app2,...>');
28
- process.exit(1);
29
- }
30
-
31
- /**
32
- * 从 CONFIG.json 读取所有 apps,过滤出 appsNames 中指定的应用。
33
- * appsNames 格式:逗号分隔的应用名字符串
34
- */
35
- function loadSelectedApps() {
36
- const configPath = path.join(wsRoot, 'CONFIG.json');
37
- if (!fs.existsSync(configPath)) return null;
38
- let config;
39
- try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch (e) { return null; }
40
- const allApps = Array.isArray(config.apps) ? config.apps : [];
41
- const namesSet = new Set(appsNames.split(',').map(s => s.trim()).filter(Boolean));
42
- const selected = allApps.filter(a => namesSet.has(a.name));
43
- if (selected.length === 0) return null;
44
- return selected;
45
- }
46
-
47
- const apps = loadSelectedApps();
48
- if (!apps) {
49
- console.error('❌ CONFIG.json 中未找到指定应用(' + appsNames + ')');
50
- process.exit(1);
51
- }
52
-
53
- const codeDir = path.join(wsRoot, '.code');
54
- fs.mkdirSync(codeDir, { recursive: true });
55
-
56
- const results = [];
57
-
58
- for (const app of apps) {
59
- const target = path.join(codeDir, app.name);
60
- const isGit = fs.existsSync(path.join(target, '.git'));
61
-
62
- if (isGit) {
63
- // 已存在:fetch --all
64
- try {
65
- execSync('git fetch --all -q', { cwd: target, stdio: 'pipe' });
66
- console.log('✅ ' + app.name + ': 代码已更新(fetch)');
67
- results.push({ name: app.name, status: 'updated' });
68
- } catch (e) {
69
- console.log('⚠️ ' + app.name + ': fetch 失败(离线或无权限,使用本地已有代码)');
70
- results.push({ name: app.name, status: 'fetch-failed' });
71
- }
72
- } else {
73
- // 不存在:clone
74
- if (!app.repo) {
75
- console.error('❌ ' + app.name + ': 在 CONFIG.json 中找不到 repo URL');
76
- results.push({ name: app.name, status: 'no-repo' });
77
- continue;
78
- }
79
- try {
80
- execSync('git clone -q "' + app.repo + '" "' + target + '"', { stdio: 'pipe' });
81
- console.log('✅ ' + app.name + ': 已 clone(' + target + ')');
82
- results.push({ name: app.name, status: 'cloned' });
83
- } catch (e) {
84
- console.error('❌ ' + app.name + ': clone 失败 — ' + app.repo);
85
- results.push({ name: app.name, status: 'clone-failed', error: (e.stderr || e.message || '').toString().trim() });
86
- }
87
- }
88
- }
89
-
90
- const hasFailures = results.some(r => r.status === 'clone-failed' || r.status === 'no-repo');
91
- console.log('---');
92
- console.log('SYNC_RESULT', JSON.stringify(results));
93
- process.exit(hasFailures ? 2 : 0);
@@ -1,67 +0,0 @@
1
- require('./silence-popup');
2
- /**
3
- * openspec-shared 工作空间根目录定位
4
- *
5
- * 唯一真源:cbb/worktrees/_shared/scripts/find-workspace-root.js
6
- * 由 scripts/sync-shared.js 展开到各 skill 的 scripts/ 下(init / extend / close / push)。
7
- *
8
- * 优先:git worktree list 第一行(主仓库根目录,不受 worktree 内 CONFIG.json 副本干扰)
9
- * 兜底:当前目录含 CONFIG.json
10
- *
11
- * 退出码:
12
- * 0 - 定位成功,输出 WS_ROOT 绝对路径
13
- * 1 - 未找到工作空间根目录
14
- *
15
- * 输出格式:
16
- * 第一行:人类可读报告
17
- * 最后一行:纯路径(便于 AI agent 解析后用于 cd)
18
- */
19
-
20
- const { execSync } = require('child_process');
21
- const fs = require('fs');
22
- const path = require('path');
23
-
24
- function tryExec(cmd) {
25
- try {
26
- return { ok: true, out: execSync(cmd, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).trim() };
27
- } catch (e) {
28
- return { ok: false };
29
- }
30
- }
31
-
32
- let wsRoot = '';
33
-
34
- // 优先:git worktree list 第一行
35
- const worktreeList = tryExec('git worktree list');
36
- if (worktreeList.ok) {
37
- const firstLine = worktreeList.out.split('\n')[0];
38
- if (firstLine) {
39
- // 格式:<path> <sha> [<branch>]
40
- const candidate = firstLine.split(/\s+/)[0];
41
- if (candidate && fs.existsSync(candidate)) {
42
- wsRoot = candidate;
43
- }
44
- }
45
- }
46
-
47
- // 兜底:当前目录含 CONFIG.json
48
- if (!wsRoot) {
49
- const cwd = process.cwd();
50
- if (fs.existsSync(path.join(cwd, 'CONFIG.json'))) {
51
- wsRoot = cwd;
52
- }
53
- }
54
-
55
- // 校验
56
- if (!wsRoot || !fs.existsSync(path.join(wsRoot, 'CONFIG.json'))) {
57
- console.error('❌ 未找到工作空间根目录');
58
- console.error(' 原因:git worktree list 失败且当前目录无 CONFIG.json');
59
- console.error(' 请在业务工作空间根目录(由 cbb setup 初始化、包含 CONFIG.json)下执行本技能');
60
- process.exit(1);
61
- }
62
-
63
- console.log('✅ 工作空间根目录:' + wsRoot);
64
- console.log('---');
65
- // 最后一行输出纯路径,AI agent 可直接 cd 使用
66
- console.log(wsRoot);
67
- process.exit(0);