@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,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);
|
package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js
DELETED
|
@@ -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);
|