@jspg-ai/coding-bb 0.0.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 +41 -0
- package/cbb/dev-standards/rules/cbb-ai-behavior.md +104 -0
- package/cbb/dev-standards/rules/cbb-coding-rule.md +50 -0
- package/cbb/dev-standards/rules/cbb-priority.md +56 -0
- package/cbb/dev-standards/skills/architecture-specs/SKILL.md +129 -0
- package/cbb/dev-standards/skills/coding-specs/SKILL.md +376 -0
- package/cbb/dev-standards/skills/coding-specs/references/concurrency.md +53 -0
- package/cbb/dev-standards/skills/coding-specs/references/config-center.md +16 -0
- package/cbb/dev-standards/skills/coding-specs/references/distributed.md +42 -0
- package/cbb/dev-standards/skills/coding-specs/references/es-coding.md +60 -0
- package/cbb/dev-standards/skills/coding-specs/references/scheduled-task.md +25 -0
- package/cbb/dev-standards/skills/coding-specs/references/security.md +11 -0
- package/cbb/dev-standards/skills/coding-specs/references/unit-testing.md +43 -0
- package/cbb/dev-standards/skills/es-design-specs/SKILL.md +104 -0
- package/cbb/dev-standards/skills/mysql-design-specs/SKILL.md +89 -0
- package/cbb/lib/install/claude-code.js +20 -0
- package/cbb/lib/install/cleanup.js +64 -0
- package/cbb/lib/install/init.js +1875 -0
- package/cbb/lib/install/qoder.js +20 -0
- package/cbb/lib/install/workspaces.js +232 -0
- package/cbb/lib/openspec/index.js +554 -0
- package/cbb/lib/superpowers/index.js +265 -0
- package/cbb/lib/utils/check-update.js +147 -0
- package/cbb/lib/utils/checkbox.js +383 -0
- package/cbb/lib/utils/gitignore.js +69 -0
- package/cbb/lib/utils/output.js +64 -0
- package/cbb/lib/utils/settings.js +119 -0
- package/cbb/lib/utils/version.js +135 -0
- package/cbb/lib/wiki/api-client.js +358 -0
- package/cbb/lib/wiki/cli.js +427 -0
- package/cbb/lib/wiki/convert.js +464 -0
- package/cbb/lib/wiki/index.js +218 -0
- package/cbb/lib/wiki/mermaid-guard.js +103 -0
- package/cbb/lib/wiki/split.js +131 -0
- package/cbb/tools/cbb-decompile-jar/SKILL.md +220 -0
- package/cbb/tools/cbb-decompile-jar/scripts/decompile.py +863 -0
- package/cbb/tools/cbb-design-to-wiki/SKILL.md +180 -0
- package/cbb/tools/cbb-mvn-guide/SKILL.md +281 -0
- package/cbb/tools/cbb-mvn-guide/scripts/mvn_jdk_manager.py +378 -0
- package/cbb/tools/cbb-mvn-guide/scripts/mvn_pom_jdk_reader.py +197 -0
- package/cbb/tools/cbb-plantuml-authoring/SKILL.md +448 -0
- package/cbb/tools/cbb-plantuml-authoring/references/drawing-templates.md +479 -0
- package/cbb/tools/cbb-wiki-ops/SKILL.md +134 -0
- package/cbb/tools/cbb-wiki-ops/scripts/check-auth.js +44 -0
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/_shared/scripts/push-core.js +136 -0
- package/cbb/worktrees/_shared/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/commands/close.md +64 -0
- package/cbb/worktrees/commands/extend.md +65 -0
- package/cbb/worktrees/commands/init.md +55 -0
- package/cbb/worktrees/commands/push.md +42 -0
- package/cbb/worktrees/skills/openspec-close-worktree/SKILL.md +449 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-env.js +76 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-unarchived.js +48 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/delete-branches.js +136 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/discover-apps.js +76 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/remove-worktrees.js +124 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/safety-check.js +174 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +390 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +95 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +98 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +135 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +150 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +88 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +93 -0
- package/cbb/worktrees/skills/openspec-init-worktree/SKILL.md +539 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/auto-open.js +136 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env-deep.js +87 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env.js +90 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-repos.js +171 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-branches.js +103 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-worktrees.js +154 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +93 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/install-ai.js +177 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/parse-config.js +67 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-branches.js +101 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/sync-repos.js +95 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/update-gitignore.js +134 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/SKILL.md +307 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/commit-worktrees.js +269 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-worktrees.js +159 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +23 -0
- package/config/cbb.yaml +6 -0
- package/config/config.sample.json +16 -0
- package/config/openspec/config.yaml +28 -0
- package/config/openspec/schemas/spec-driven/schema.yaml +247 -0
- package/config/openspec/schemas/spec-driven/templates/design.md +475 -0
- package/config/openspec/schemas/spec-driven/templates/proposal.md +58 -0
- package/config/openspec/schemas/spec-driven/templates/spec.md +8 -0
- package/config/openspec/schemas/spec-driven/templates/tasks.md +9 -0
- package/config/workspaces.json +15 -0
- package/openspec/.version +6 -0
- package/openspec/commands/apply.md +182 -0
- package/openspec/commands/archive.md +223 -0
- package/openspec/commands/bulk-archive.md +334 -0
- package/openspec/commands/continue.md +112 -0
- package/openspec/commands/explore.md +206 -0
- package/openspec/commands/ff.md +111 -0
- package/openspec/commands/new.md +70 -0
- package/openspec/commands/onboard.md +555 -0
- package/openspec/commands/propose.md +157 -0
- package/openspec/commands/sync.md +256 -0
- package/openspec/commands/update.md +85 -0
- package/openspec/commands/verify.md +169 -0
- package/openspec/skills/openspec-apply-change/SKILL.md +187 -0
- package/openspec/skills/openspec-archive-change/SKILL.md +181 -0
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -0
- package/openspec/skills/openspec-continue-change/SKILL.md +117 -0
- package/openspec/skills/openspec-explore/SKILL.md +342 -0
- package/openspec/skills/openspec-ff-change/SKILL.md +116 -0
- package/openspec/skills/openspec-new-change/SKILL.md +76 -0
- package/openspec/skills/openspec-onboard/SKILL.md +560 -0
- package/openspec/skills/openspec-propose/SKILL.md +162 -0
- package/openspec/skills/openspec-sync-specs/SKILL.md +261 -0
- package/openspec/skills/openspec-update-change/SKILL.md +90 -0
- package/openspec/skills/openspec-verify-change/SKILL.md +174 -0
- package/package.json +46 -0
- package/superpowers/.version +6 -0
- package/superpowers/skills/brainstorming/SKILL.md +250 -0
- package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
- package/superpowers/skills/brainstorming/scripts/helper.js +167 -0
- package/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
- package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
- package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
- package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/superpowers/skills/brainstorming/visual-companion.md +299 -0
- package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -0
- package/superpowers/skills/executing-plans/SKILL.md +64 -0
- package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -0
- package/superpowers/skills/receiving-code-review/SKILL.md +205 -0
- package/superpowers/skills/requesting-code-review/SKILL.md +95 -0
- package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -0
- package/superpowers/skills/subagent-driven-development/SKILL.md +568 -0
- package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -0
- package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -0
- package/superpowers/skills/subagent-driven-development/scripts/review-package +46 -0
- package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +40 -0
- package/superpowers/skills/subagent-driven-development/scripts/task-brief +41 -0
- package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
- package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/superpowers/skills/systematic-debugging/SKILL.md +283 -0
- package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -0
- package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/superpowers/skills/systematic-debugging/test-academic.md +14 -0
- package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/superpowers/skills/test-driven-development/SKILL.md +320 -0
- package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -0
- package/superpowers/skills/using-git-worktrees/SKILL.md +167 -0
- package/superpowers/skills/using-superpowers/SKILL.md +63 -0
- package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
- package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -0
- package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -0
- package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -0
- package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
- package/superpowers/skills/verification-before-completion/SKILL.md +120 -0
- package/superpowers/skills/writing-plans/SKILL.md +171 -0
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/superpowers/skills/writing-skills/SKILL.md +679 -0
- package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
- package/superpowers/skills/writing-skills/render-graphs.js +169 -0
- package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('./silence-popup');
|
|
3
|
+
/**
|
|
4
|
+
* openspec-init-worktree 环境感知 + 自动打开 IDE/CLI
|
|
5
|
+
*
|
|
6
|
+
* 用法:node auto-open.js <wt_path>
|
|
7
|
+
*
|
|
8
|
+
* 检测当前运行环境并自动在新窗口打开 worktree:
|
|
9
|
+
* - Qoder GUI → qoder --new-window
|
|
10
|
+
* - Cursor GUI → cursor --new-window
|
|
11
|
+
* - VS Code GUI → code --new-window
|
|
12
|
+
* - JetBrains → 通过 Windows 注册表 / macOS open -a / Linux command -v 查找(launcher 默认开新窗口)
|
|
13
|
+
* - CLI 模式 → 仅切换 cwd,输出 ENV=CLI
|
|
14
|
+
*
|
|
15
|
+
* 输出末行:
|
|
16
|
+
* ENV=QODER_GUI / CURSOR_GUI / VSCODE_GUI / JETBRAINS_GUI / CLI
|
|
17
|
+
* 或 OPEN_FAILED
|
|
18
|
+
*
|
|
19
|
+
* 退出码:始终 0(失败也返回,由末行判断)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const { execSync } = require('child_process');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const os = require('os');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
const wtPath = process.argv[2];
|
|
28
|
+
|
|
29
|
+
if (!wtPath) {
|
|
30
|
+
console.error('❌ 用法:node auto-open.js <wt_path>');
|
|
31
|
+
process.error = 'USAGE_ERROR';
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!fs.existsSync(wtPath)) {
|
|
36
|
+
console.error('❌ worktree 路径不存在:' + wtPath);
|
|
37
|
+
console.log('---');
|
|
38
|
+
console.log('OPEN_FAILED');
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function run(cmd, opts) {
|
|
43
|
+
try {
|
|
44
|
+
return { ok: true, out: execSync(cmd, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], ...opts }).trim() };
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return { ok: false };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const qoderAgent = process.env.QODER_AGENT === 'true';
|
|
51
|
+
const vscodePid = process.env.VSCODE_PID;
|
|
52
|
+
const vscodeBrand = process.env.VSCODE_BRAND;
|
|
53
|
+
const termEmu = process.env.TERMINAL_EMULATOR || '';
|
|
54
|
+
|
|
55
|
+
// Qoder GUI
|
|
56
|
+
if (qoderAgent && vscodePid) {
|
|
57
|
+
const r = run('qoder --new-window "' + wtPath + '"');
|
|
58
|
+
if (r.ok) {
|
|
59
|
+
console.log('ENV=QODER_GUI');
|
|
60
|
+
} else {
|
|
61
|
+
console.log('OPEN_FAILED');
|
|
62
|
+
}
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Cursor GUI
|
|
67
|
+
if (vscodePid && vscodeBrand === 'Cursor') {
|
|
68
|
+
const r = run('cursor --new-window "' + wtPath + '"');
|
|
69
|
+
if (r.ok) {
|
|
70
|
+
console.log('ENV=CURSOR_GUI');
|
|
71
|
+
} else {
|
|
72
|
+
console.log('OPEN_FAILED');
|
|
73
|
+
}
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 其他 VS Code 分支
|
|
78
|
+
if (vscodePid) {
|
|
79
|
+
const r = run('code --new-window "' + wtPath + '"');
|
|
80
|
+
if (r.ok) {
|
|
81
|
+
console.log('ENV=VSCODE_GUI');
|
|
82
|
+
} else {
|
|
83
|
+
console.log('OPEN_FAILED');
|
|
84
|
+
}
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// JetBrains
|
|
89
|
+
if (/jetbrains/i.test(termEmu)) {
|
|
90
|
+
const platform = os.platform();
|
|
91
|
+
let launcher = '';
|
|
92
|
+
|
|
93
|
+
if (platform === 'win32') {
|
|
94
|
+
// Windows:通过 PowerShell 查注册表
|
|
95
|
+
const psCmd = 'powershell -NoProfile -Command "Get-ItemProperty \'HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\',\'HKLM:\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\',\'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\' -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -match \'IntelliJ|WebStorm|PyCharm|GoLand|PhpStorm|Rider|CLion|RubyMine|DataGrip\' } | Select-Object -First 1 -ExpandProperty DisplayIcon"';
|
|
96
|
+
const r = run(psCmd);
|
|
97
|
+
if (r.ok && r.out) launcher = r.out;
|
|
98
|
+
} else if (platform === 'darwin') {
|
|
99
|
+
// macOS:通过 open -Ra 查找
|
|
100
|
+
const apps = ['IntelliJ IDEA', 'WebStorm', 'PyCharm', 'GoLand', 'PhpStorm', 'Rider', 'CLion', 'RubyMine', 'DataGrip'];
|
|
101
|
+
for (const app of apps) {
|
|
102
|
+
const check = run('open -Ra "' + app + '"');
|
|
103
|
+
if (check.ok) {
|
|
104
|
+
const open = run('open -a "' + app + '" "' + wtPath + '"');
|
|
105
|
+
if (open.ok) {
|
|
106
|
+
console.log('ENV=JETBRAINS_GUI');
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
// Linux:通过 command -v 查找
|
|
113
|
+
const cmds = ['idea64', 'idea', 'webstorm64', 'webstorm', 'pycharm64', 'pycharm', 'goland64', 'goland'];
|
|
114
|
+
for (const c of cmds) {
|
|
115
|
+
const which = run('command -v "' + c + '"');
|
|
116
|
+
if (which.ok && which.out) {
|
|
117
|
+
launcher = which.out;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (launcher) {
|
|
124
|
+
const r = run('"' + launcher + '" "' + wtPath + '"');
|
|
125
|
+
if (r.ok) {
|
|
126
|
+
console.log('ENV=JETBRAINS_GUI');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
console.log('ENV=CLI');
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// CLI 模式
|
|
135
|
+
console.log('ENV=CLI');
|
|
136
|
+
process.exit(0);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('./silence-popup');
|
|
3
|
+
/**
|
|
4
|
+
* check-env-deep:init-worktree 前的环境健康自检
|
|
5
|
+
*
|
|
6
|
+
* 用法:node check-env-deep.js
|
|
7
|
+
*
|
|
8
|
+
* 检测项:
|
|
9
|
+
* 1. Node.js 版本(>= 16.7.0)
|
|
10
|
+
* 2. npm 官方源可达性(https://registry.npmjs.org)
|
|
11
|
+
* 3. cbb 是否已安装(未安装视为软警告,由 Step 4 自动安装)
|
|
12
|
+
* 4. .worktrees/ 目录可写性
|
|
13
|
+
*
|
|
14
|
+
* 退出码:
|
|
15
|
+
* 0 - 全部通过(DOCTOR_OK)
|
|
16
|
+
* 2 - 致命问题(Node 版本 / npm 源 / 权限),必须修复后重试
|
|
17
|
+
*/
|
|
18
|
+
const { execSync } = require('child_process');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
function run(cmd) {
|
|
23
|
+
try {
|
|
24
|
+
return { ok: true, out: execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim() };
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let hasFatal = false;
|
|
31
|
+
|
|
32
|
+
// ── 1. Node.js 版本 ──
|
|
33
|
+
const nodeVersion = process.versions.node;
|
|
34
|
+
const nodeMajor = parseInt(nodeVersion.split('.')[0], 10);
|
|
35
|
+
if (nodeMajor < 16 || (nodeMajor === 16 && parseInt(nodeVersion.split('.')[1], 10) < 7)) {
|
|
36
|
+
console.error('❌ Node.js 版本过低:' + nodeVersion + '(需要 >= 16.7.0)');
|
|
37
|
+
console.error(' → 请到 https://nodejs.org 下载 LTS 版本');
|
|
38
|
+
hasFatal = true;
|
|
39
|
+
} else {
|
|
40
|
+
console.log('✅ Node.js: ' + nodeVersion);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── 2. npm 内部源可达性 ──
|
|
44
|
+
const npmPing = run('npm ping --registry=https://registry.npmjs.org');
|
|
45
|
+
if (!npmPing.ok) {
|
|
46
|
+
console.error('❌ npm 内部源不可达:' + npmPing.err);
|
|
47
|
+
console.error(' → 检查代理设置:npm config get registry');
|
|
48
|
+
console.error(' → 检查网络是否能访问 https://registry.npmjs.org');
|
|
49
|
+
hasFatal = true;
|
|
50
|
+
} else {
|
|
51
|
+
console.log('✅ npm 官方源可达(https://registry.npmjs.org)');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── 3. cbb 检测(软警告) ──
|
|
55
|
+
const cbbInfo = run('cbb --version');
|
|
56
|
+
if (cbbInfo.ok) {
|
|
57
|
+
console.log('✅ cbb 已安装:' + cbbInfo.out);
|
|
58
|
+
} else {
|
|
59
|
+
console.log('⚠️ cbb 未安装(Step 4 install-ai 会自动安装,软警告不阻塞)');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── 4. .worktrees 目录可写性 ──
|
|
63
|
+
const wsRoot = process.cwd();
|
|
64
|
+
const wtDir = path.join(wsRoot, '.worktrees');
|
|
65
|
+
try {
|
|
66
|
+
if (!fs.existsSync(wtDir)) {
|
|
67
|
+
fs.mkdirSync(wtDir, { recursive: true });
|
|
68
|
+
console.log('✅ .worktrees/ 已创建');
|
|
69
|
+
} else {
|
|
70
|
+
fs.accessSync(wtDir, fs.constants.W_OK);
|
|
71
|
+
console.log('✅ .worktrees/ 可写');
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error('❌ .worktrees/ 不可写:' + e.message);
|
|
75
|
+
console.error(' → 检查目录权限或当前用户是否为目录所有者');
|
|
76
|
+
hasFatal = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log('---');
|
|
80
|
+
if (hasFatal) {
|
|
81
|
+
console.error('DOCTOR_FAILED');
|
|
82
|
+
console.error('请修复上述致命问题后重试 init-worktree。');
|
|
83
|
+
process.exit(2);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('DOCTOR_OK');
|
|
87
|
+
process.exit(0);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('./silence-popup');
|
|
3
|
+
/**
|
|
4
|
+
* openspec-init-worktree 环境健康探活
|
|
5
|
+
*
|
|
6
|
+
* 提前发现 Qoder 沙箱 DLL 问题(0xc0000142)以及其他子进程启动失败。
|
|
7
|
+
* 失败时输出明确错误信息并以非零退出码终止,AI agent 据此决定是否继续。
|
|
8
|
+
*
|
|
9
|
+
* 跨平台:
|
|
10
|
+
* - 路径用 path.join 处理
|
|
11
|
+
* - 子进程用 execSync 同步等待
|
|
12
|
+
* - 不使用 /dev/null / [ $? -eq 0 ] 等 bash 专有语法
|
|
13
|
+
*
|
|
14
|
+
* 退出码:
|
|
15
|
+
* 0 - 探活通过(仅警告项可继续)
|
|
16
|
+
* 1 - 致命错误(git 不可用),AI agent 必须终止流程
|
|
17
|
+
* 2 - 当前不在 git 仓库(init-worktree 必须在 git 仓库中执行)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
|
|
22
|
+
function tryExec(cmd, opts = {}) {
|
|
23
|
+
try {
|
|
24
|
+
const out = execSync(cmd, {
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
27
|
+
...opts,
|
|
28
|
+
});
|
|
29
|
+
return { ok: true, out: out.trim() };
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const checks = {};
|
|
36
|
+
|
|
37
|
+
// ── 必检:git ─────────────────────────────────────────
|
|
38
|
+
checks.git = tryExec('git --version');
|
|
39
|
+
if (!checks.git.ok) {
|
|
40
|
+
console.error('❌ git 启动失败');
|
|
41
|
+
console.error(' 可能是 Qoder 沙箱 DLL 问题(0xc0000142)');
|
|
42
|
+
console.error(' 解决方案:到系统终端(非 Qoder AI 终端)重新执行本技能');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
console.log('✅ git OK:', checks.git.out);
|
|
46
|
+
|
|
47
|
+
// ── 必检:当前目录是 git 仓库 ─────────────────────────
|
|
48
|
+
const insideRepo = tryExec('git rev-parse --is-inside-work-tree');
|
|
49
|
+
if (!insideRepo.ok || insideRepo.out !== 'true') {
|
|
50
|
+
console.error('❌ 当前目录不是 Git 仓库');
|
|
51
|
+
console.error(' init-worktree 必须在工作空间根目录(包含 CONFIG.json)下执行');
|
|
52
|
+
process.exit(2);
|
|
53
|
+
}
|
|
54
|
+
console.log('✅ 当前目录是 git 仓库');
|
|
55
|
+
|
|
56
|
+
// ── 选检:node.js(脚本运行时,所有 .js 脚本依赖) ──
|
|
57
|
+
checks.node = tryExec('node --version');
|
|
58
|
+
if (!checks.node.ok) {
|
|
59
|
+
console.log('⚠️ node 不可用(脚本将无法执行,建议安装 Node.js >= 16.7.0)');
|
|
60
|
+
} else {
|
|
61
|
+
console.log('✅ node OK:', checks.node.out);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── 选检:cbb(Step 5 才需要) ────────────────────
|
|
65
|
+
checks.cbbInfo = tryExec('cbb --version');
|
|
66
|
+
if (!checks.cbbInfo.ok) {
|
|
67
|
+
console.log('ℹ️ cbb 未全局安装(Step 5 会兜底自动安装)');
|
|
68
|
+
} else {
|
|
69
|
+
console.log('✅ cbb OK:', checks.cbbInfo.out);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── 沙箱检测 ─────────────────────────────────────────
|
|
73
|
+
const inWorktree = !!(process.env.QODER_AGENT || process.env.QODER_WORKTREE);
|
|
74
|
+
if (inWorktree) {
|
|
75
|
+
console.log('🛡️ Qoder 沙箱环境:若后续 node/git DLL 错误,请到系统终端重试');
|
|
76
|
+
} else {
|
|
77
|
+
console.log('✅ 非沙箱环境:所有子进程以默认 PATH 运行');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 输出机器可读摘要(AI agent 可解析)
|
|
81
|
+
const summary = {
|
|
82
|
+
git: checks.git.ok,
|
|
83
|
+
node: checks.node.ok,
|
|
84
|
+
cbbInfo: checks.cbbInfo.ok,
|
|
85
|
+
inWorktree,
|
|
86
|
+
ok: true,
|
|
87
|
+
};
|
|
88
|
+
console.log('---');
|
|
89
|
+
console.log('ENV_OK', JSON.stringify(summary));
|
|
90
|
+
process.exit(0);
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('./silence-popup');
|
|
3
|
+
/**
|
|
4
|
+
* openspec-init-worktree 状态检查
|
|
5
|
+
*
|
|
6
|
+
* 用法:node check-repos.js <ws_root>
|
|
7
|
+
*
|
|
8
|
+
* 检查项:
|
|
9
|
+
* workspace 仓库(完整检查 5 项):
|
|
10
|
+
* \u2460 路径存在且是 git 仓库
|
|
11
|
+
* \u2461 不在 worktree 中(排除 submodule)
|
|
12
|
+
* \u2462 不是 submodule
|
|
13
|
+
* \u2463 git fetch 拉取远程最新
|
|
14
|
+
* \u2464 本地主分支已最新 + 当前在主分支
|
|
15
|
+
*
|
|
16
|
+
* app 仓库(轻量检查 3 项):
|
|
17
|
+
* \u2460 路径存在且是 git 仓库
|
|
18
|
+
* \u2461 不在 worktree 中(排除 submodule)
|
|
19
|
+
* \u2462 git fetch + origin/main 引用可用
|
|
20
|
+
*
|
|
21
|
+
* 退出码:
|
|
22
|
+
* 0 - 全部通过
|
|
23
|
+
* 1 - 参数错误
|
|
24
|
+
* 2 - 部分失败
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const { execSync } = require("child_process");
|
|
28
|
+
const fs = require("fs");
|
|
29
|
+
const path = require("path");
|
|
30
|
+
|
|
31
|
+
const wsRoot = process.argv[2];
|
|
32
|
+
|
|
33
|
+
if (!wsRoot) {
|
|
34
|
+
console.error("Usage: node check-repos.js <ws_root>");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function loadAppsFromConfig() {
|
|
39
|
+
const configPath = path.join(wsRoot, "CONFIG.json");
|
|
40
|
+
if (!fs.existsSync(configPath)) return null;
|
|
41
|
+
try {
|
|
42
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
43
|
+
return Array.isArray(config.apps) ? config.apps : null;
|
|
44
|
+
} catch (e) { return null; }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const apps = loadAppsFromConfig();
|
|
48
|
+
if (!apps) {
|
|
49
|
+
console.error("CONFIG.json missing or apps empty");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function tryExec(cmd, cwd) {
|
|
54
|
+
try {
|
|
55
|
+
return { ok: true, out: execSync(cmd, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim() };
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function detectMainBranch(cwd) {
|
|
62
|
+
const remote = tryExec("git remote", cwd);
|
|
63
|
+
if (remote.ok && remote.out) {
|
|
64
|
+
remote.out = remote.out.split(/\r?\n/)[0];
|
|
65
|
+
}
|
|
66
|
+
if (!remote.ok) return "";
|
|
67
|
+
const r = remote.out;
|
|
68
|
+
const symbolic = tryExec("git symbolic-ref \"refs/remotes/" + r + "/HEAD\"", cwd);
|
|
69
|
+
if (symbolic.ok) {
|
|
70
|
+
return symbolic.out.replace("refs/remotes/" + r + "/", "");
|
|
71
|
+
}
|
|
72
|
+
const listMain = tryExec("git branch --list main master", cwd);
|
|
73
|
+
if (listMain.ok && listMain.out) {
|
|
74
|
+
const lines = listMain.out.split(/\r?\n/).filter(Boolean);
|
|
75
|
+
return (lines[0] || "").replace(/[*\s]/g, "");
|
|
76
|
+
}
|
|
77
|
+
return "main";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function checkRepo(repoPath, name, level) {
|
|
81
|
+
const problems = [];
|
|
82
|
+
|
|
83
|
+
// 1: path exists
|
|
84
|
+
if (!fs.existsSync(repoPath)) {
|
|
85
|
+
return { name, level, problems: ["path not exist"], ok: false };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 2: is git repo
|
|
89
|
+
const inside = tryExec("git rev-parse --is-inside-work-tree", repoPath);
|
|
90
|
+
if (!inside.ok || inside.out !== "true") {
|
|
91
|
+
return { name, level, problems: ["not a git repo"], ok: false };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 3: not in worktree (exclude submodule)
|
|
95
|
+
const gitDir = tryExec("git rev-parse --git-dir", repoPath);
|
|
96
|
+
const gitCommon = tryExec("git rev-parse --git-common-dir", repoPath);
|
|
97
|
+
const superRef = tryExec("git rev-parse --show-superproject-working-tree", repoPath);
|
|
98
|
+
|
|
99
|
+
const isWorktree = gitDir.ok && gitCommon.ok && gitDir.out !== gitCommon.out && !superRef.out;
|
|
100
|
+
if (isWorktree) {
|
|
101
|
+
problems.push("already in worktree");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 4: not submodule
|
|
105
|
+
if (superRef.out) {
|
|
106
|
+
problems.push("is git submodule");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 5: fetch
|
|
110
|
+
const remote = tryExec("git remote", repoPath);
|
|
111
|
+
if (!remote.ok || !remote.out) {
|
|
112
|
+
problems.push("no remote");
|
|
113
|
+
} else {
|
|
114
|
+
const r = remote.out.split(/\r?\n/)[0];
|
|
115
|
+
const fetch = tryExec("git fetch -q \"" + r + "\"", repoPath);
|
|
116
|
+
if (!fetch.ok) {
|
|
117
|
+
problems.push("git fetch failed");
|
|
118
|
+
} else if (level === "workspace") {
|
|
119
|
+
const main = detectMainBranch(repoPath);
|
|
120
|
+
if (!main) {
|
|
121
|
+
problems.push("cannot detect main branch");
|
|
122
|
+
} else {
|
|
123
|
+
const behind = tryExec("git log HEAD..\"" + r + "/" + main + "\" --oneline", repoPath);
|
|
124
|
+
if (behind.ok && behind.out) {
|
|
125
|
+
problems.push("main branch has unpulled commits");
|
|
126
|
+
}
|
|
127
|
+
const current = tryExec("git rev-parse --abbrev-ref HEAD", repoPath);
|
|
128
|
+
if (current.ok && current.out !== main) {
|
|
129
|
+
problems.push("not on main branch (current " + current.out + ", expected " + main + ")");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
// app lightweight check: origin/main available
|
|
134
|
+
const main = detectMainBranch(repoPath);
|
|
135
|
+
const refCheck = tryExec("git rev-parse --verify --quiet \"refs/remotes/" + r + "/" + main + "\"", repoPath);
|
|
136
|
+
if (!refCheck.ok) {
|
|
137
|
+
problems.push("remote has no " + main + " branch");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { name, level, problems, ok: problems.length === 0 };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const results = [];
|
|
146
|
+
|
|
147
|
+
// workspace
|
|
148
|
+
const wsResult = checkRepo(wsRoot, path.basename(wsRoot) || "workspace", "workspace");
|
|
149
|
+
results.push(wsResult);
|
|
150
|
+
if (wsResult.ok) {
|
|
151
|
+
console.log("\u2705 " + wsResult.name + " (workspace): OK");
|
|
152
|
+
} else {
|
|
153
|
+
console.error("\u274c " + wsResult.name + " (workspace): " + wsResult.problems.join("; "));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// apps
|
|
157
|
+
for (const app of apps) {
|
|
158
|
+
const appPath = path.join(wsRoot, ".code", app.name);
|
|
159
|
+
const r = checkRepo(appPath, app.name, "app");
|
|
160
|
+
results.push(r);
|
|
161
|
+
if (r.ok) {
|
|
162
|
+
console.log("\u2705 " + r.name + " (app): OK");
|
|
163
|
+
} else {
|
|
164
|
+
console.error("\u274c " + r.name + " (app): " + r.problems.join("; "));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const allOk = results.every(r => r.ok);
|
|
169
|
+
console.log("---");
|
|
170
|
+
console.log("CHECK_RESULT", allOk ? "ALL_OK" : "HAS_FAILURES");
|
|
171
|
+
process.exit(allOk ? 0 : 2);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('./silence-popup');
|
|
3
|
+
/**
|
|
4
|
+
* openspec-init-worktree 分支创建
|
|
5
|
+
*
|
|
6
|
+
* Usage: node create-branches.js <ws_root> <branch>
|
|
7
|
+
*/
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const wsRoot = process.argv[2];
|
|
13
|
+
const branch = process.argv[3];
|
|
14
|
+
|
|
15
|
+
if (!wsRoot || !branch) {
|
|
16
|
+
console.error('Usage: node create-branches.js <ws_root> <branch>');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function loadAppsFromConfig() {
|
|
21
|
+
const configPath = path.join(wsRoot, 'CONFIG.json');
|
|
22
|
+
if (!fs.existsSync(configPath)) return null;
|
|
23
|
+
try {
|
|
24
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
25
|
+
return Array.isArray(config.apps) ? config.apps : null;
|
|
26
|
+
} catch (e) { return null; }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const apps = loadAppsFromConfig();
|
|
30
|
+
if (!apps) {
|
|
31
|
+
console.error('CONFIG.json missing or apps empty');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function tryExec(cmd, cwd) {
|
|
36
|
+
try {
|
|
37
|
+
return { ok: true, out: execSync(cmd, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).trim() };
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function detectMainBranch(cwd) {
|
|
44
|
+
const remote = tryExec('git remote', cwd);
|
|
45
|
+
if (!remote.ok || !remote.out) return 'main';
|
|
46
|
+
const r = remote.out.split(/\r?\n/)[0];
|
|
47
|
+
const symbolic = tryExec('git symbolic-ref "refs/remotes/' + r + '/HEAD"', cwd);
|
|
48
|
+
if (symbolic.ok && symbolic.out) {
|
|
49
|
+
return symbolic.out.replace('refs/remotes/' + r + '/', '');
|
|
50
|
+
}
|
|
51
|
+
return 'main';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const results = [];
|
|
55
|
+
|
|
56
|
+
// workspace: create from HEAD
|
|
57
|
+
const wsCheck = tryExec('git branch --list "' + branch + '"', wsRoot);
|
|
58
|
+
if (wsCheck.ok && wsCheck.out) {
|
|
59
|
+
console.log('Skip workspace: branch exists, reuse');
|
|
60
|
+
results.push({ name: 'workspace', status: 'reused' });
|
|
61
|
+
} else {
|
|
62
|
+
const created = tryExec('git branch "' + branch + '"', wsRoot);
|
|
63
|
+
if (created.ok) {
|
|
64
|
+
console.log('OK workspace: branch ' + branch + ' created (from HEAD)');
|
|
65
|
+
results.push({ name: 'workspace', status: 'created' });
|
|
66
|
+
} else {
|
|
67
|
+
console.error('FAIL workspace: branch create failed');
|
|
68
|
+
results.push({ name: 'workspace', status: 'failed', error: created.err });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// apps: create from origin/main
|
|
73
|
+
for (const app of apps) {
|
|
74
|
+
const appPath = path.join(wsRoot, '.code', app.name);
|
|
75
|
+
const appCheck = tryExec('git branch --list "' + branch + '"', appPath);
|
|
76
|
+
if (appCheck.ok && appCheck.out) {
|
|
77
|
+
console.log('Skip ' + app.name + ': branch exists, reuse');
|
|
78
|
+
results.push({ name: app.name, status: 'reused' });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const remote = tryExec('git remote', appPath);
|
|
83
|
+
if (!remote.ok || !remote.out) {
|
|
84
|
+
console.error('FAIL ' + app.name + ': no remote');
|
|
85
|
+
results.push({ name: app.name, status: 'failed', error: 'no remote' });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const r = remote.out.split(/\r?\n/)[0];
|
|
89
|
+
const main = detectMainBranch(appPath);
|
|
90
|
+
const created = tryExec('git branch "' + branch + '" "' + r + '/' + main + '"', appPath);
|
|
91
|
+
if (created.ok) {
|
|
92
|
+
console.log('OK ' + app.name + ': branch ' + branch + ' created (from ' + r + '/' + main + ')');
|
|
93
|
+
results.push({ name: app.name, status: 'created' });
|
|
94
|
+
} else {
|
|
95
|
+
console.error('FAIL ' + app.name + ': branch create failed');
|
|
96
|
+
results.push({ name: app.name, status: 'failed', error: created.err });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const hasFailed = results.some(r => r.status === 'failed');
|
|
101
|
+
console.log('---');
|
|
102
|
+
console.log('BRANCH_RESULT', JSON.stringify(results));
|
|
103
|
+
process.exit(hasFailed ? 2 : 0);
|