@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,96 @@
|
|
|
1
|
+
require('./silence-popup');
|
|
2
|
+
/**
|
|
3
|
+
* openspec-shared 目标需求名识别
|
|
4
|
+
*
|
|
5
|
+
* 唯一真源:cbb/worktrees/_shared/scripts/find-target-worktree.js
|
|
6
|
+
* 由 scripts/sync-shared.js 展开到各 skill 的 scripts/ 下(extend / close / push)。
|
|
7
|
+
*
|
|
8
|
+
* 用法:node find-target-worktree.js <ws_root>
|
|
9
|
+
*
|
|
10
|
+
* 优先级:
|
|
11
|
+
* 1. cwd 在 .worktrees/worktree-xxx/ 内 → 自动从路径反推
|
|
12
|
+
* 2. .worktrees/ 下只有一个 worktree → 自动选用
|
|
13
|
+
* 3. 多个 worktree → 按 mtime 倒序,第一个为推荐
|
|
14
|
+
*
|
|
15
|
+
* 输出:
|
|
16
|
+
* 末行输出需求名(用于 AI agent 解析)
|
|
17
|
+
* 多个时按 [1] xxx ⭐ / [2] yyy 列出
|
|
18
|
+
*
|
|
19
|
+
* 退出码:
|
|
20
|
+
* 0 - 唯一识别(自动或唯一)
|
|
21
|
+
* 1 - 多个 worktree,需用户输入
|
|
22
|
+
* 2 - 无 worktree
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const { execSync } = require('child_process');
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
const wsRoot = process.argv[2];
|
|
30
|
+
|
|
31
|
+
if (!wsRoot) {
|
|
32
|
+
console.error('❌ 用法:node find-target-worktree.js <ws_root>');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 优先级 1:cwd 反推
|
|
37
|
+
const cwd = process.cwd();
|
|
38
|
+
const cwdMatch = cwd.match(/\.worktrees[\\\/]worktree-([^\\\/]+)/);
|
|
39
|
+
if (cwdMatch) {
|
|
40
|
+
const branch = cwdMatch[1];
|
|
41
|
+
console.log('✅ 从 cwd 反推需求名:' + branch);
|
|
42
|
+
console.log('---');
|
|
43
|
+
console.log(branch);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const worktreesDir = path.join(wsRoot, '.worktrees');
|
|
48
|
+
if (!fs.existsSync(worktreesDir)) {
|
|
49
|
+
console.error('❌ .worktrees 目录不存在:' + worktreesDir);
|
|
50
|
+
console.error(' 请先执行 openspec-init-worktree 创建 worktree');
|
|
51
|
+
console.log('---');
|
|
52
|
+
console.log('NO_WORKTREE');
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 列出所有 worktree-xxx 目录
|
|
57
|
+
const entries = fs.readdirSync(worktreesDir, { withFileTypes: true })
|
|
58
|
+
.filter(e => e.isDirectory() && e.name.startsWith('worktree-'))
|
|
59
|
+
.map(e => ({
|
|
60
|
+
name: e.name.substring('worktree-'.length),
|
|
61
|
+
fullName: e.name,
|
|
62
|
+
path: path.join(worktreesDir, e.name),
|
|
63
|
+
mtime: fs.statSync(path.join(worktreesDir, e.name)).mtime.getTime(),
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
if (entries.length === 0) {
|
|
67
|
+
console.error('❌ 未找到任何 worktree');
|
|
68
|
+
console.error(' 请先执行 openspec-init-worktree 创建 worktree');
|
|
69
|
+
console.log('---');
|
|
70
|
+
console.log('NO_WORKTREE');
|
|
71
|
+
process.exit(2);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 优先级 2:唯一
|
|
75
|
+
if (entries.length === 1) {
|
|
76
|
+
console.log('✅ 自动选用唯一 worktree:' + entries[0].name);
|
|
77
|
+
console.log('---');
|
|
78
|
+
console.log(entries[0].name);
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 优先级 3:多个 → 按 mtime 倒序
|
|
83
|
+
entries.sort((a, b) => b.mtime - a.mtime);
|
|
84
|
+
|
|
85
|
+
console.log('⚠️ 检测到 ' + entries.length + ' 个 worktree(按最近修改排序):');
|
|
86
|
+
entries.forEach((e, i) => {
|
|
87
|
+
if (i === 0) {
|
|
88
|
+
console.log(' [' + (i + 1) + '] ' + e.name + ' ⭐ (推荐:最近修改)');
|
|
89
|
+
} else {
|
|
90
|
+
console.log(' [' + (i + 1) + '] ' + e.name);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
console.log('请在对话中输入序号(1/2/3)或完整分支名:');
|
|
94
|
+
console.log('---');
|
|
95
|
+
console.log('MULTIPLE_WORKTREEES');
|
|
96
|
+
process.exit(1);
|
|
@@ -0,0 +1,67 @@
|
|
|
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);
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require('./silence-popup');
|
|
2
|
+
/**
|
|
3
|
+
* openspec-shared 推送核心模块
|
|
4
|
+
*
|
|
5
|
+
* 唯一真源:cbb/worktrees/_shared/scripts/push-core.js
|
|
6
|
+
* 由 scripts/sync-shared.js 展开到各 skill 的 scripts/ 下(init-worktree / extend-worktree / push-worktrees)。
|
|
7
|
+
*
|
|
8
|
+
* 公开 API:
|
|
9
|
+
* - tryExec(cmd, cwd, execImpl) 包装 execSync,统一返回 {ok, out|err}
|
|
10
|
+
* - escapeBranch(name) 分支名 shell 转义(防命令注入)
|
|
11
|
+
* - classifyError(stderr) 将 stderr 归类为 8 种错误码之一
|
|
12
|
+
* - pushSingle(repoPath, repoName, branch) 推送单个仓库并建立 upstream
|
|
13
|
+
* - collectRemoteMetadata(repoPath, branch, remote) 采集远程 commit 元信息
|
|
14
|
+
*
|
|
15
|
+
* 错误码契约(classifyError 输出):
|
|
16
|
+
* - ssh-auth-failed Permission denied (publickey)
|
|
17
|
+
* - https-auth-failed Authentication failed
|
|
18
|
+
* - network-unreachable Could not resolve host / hung up / connection refused
|
|
19
|
+
* - branch-protected protected branch / deny updating
|
|
20
|
+
* - remote-exists already exists
|
|
21
|
+
* - no-remote (pushSingle 内部判定)
|
|
22
|
+
* - non-fast-forward non-fast-forward
|
|
23
|
+
* - unknown 兜底
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const { execSync: realExecSync } = require('child_process');
|
|
27
|
+
|
|
28
|
+
const PUSH_TIMEOUT_MS = 60000;
|
|
29
|
+
|
|
30
|
+
function tryExec(cmd, cwd, execImpl) {
|
|
31
|
+
const execSync = (execImpl || realExecSync);
|
|
32
|
+
try {
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
out: execSync(cmd, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], timeout: PUSH_TIMEOUT_MS }).toString().trim(),
|
|
36
|
+
};
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const stderr = (e.stderr ? e.stderr.toString() : e.message || String(e)).trim();
|
|
39
|
+
return { ok: false, err: stderr };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function escapeBranch(name) {
|
|
44
|
+
return '"' + String(name).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function classifyError(stderr) {
|
|
48
|
+
const s = (stderr || '').toLowerCase();
|
|
49
|
+
if (s.includes('permission denied (publickey)')) return 'ssh-auth-failed';
|
|
50
|
+
if (s.includes('authentication failed')) return 'https-auth-failed';
|
|
51
|
+
if (s.includes('could not resolve host') || s.includes('hung up') || s.includes('connection refused')) {
|
|
52
|
+
return 'network-unreachable';
|
|
53
|
+
}
|
|
54
|
+
if (s.includes('protected branch') || s.includes('deny updating')) return 'branch-protected';
|
|
55
|
+
if (s.includes('already exists')) return 'remote-exists';
|
|
56
|
+
if (s.includes('non-fast-forward')) return 'non-fast-forward';
|
|
57
|
+
return 'unknown';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 采集远程分支的元信息(hash/author/date/message + 本地 hash)
|
|
62
|
+
* 任意子命令失败时返回 null(不抛错)
|
|
63
|
+
* @param {string} repoPath
|
|
64
|
+
* @param {string} branch
|
|
65
|
+
* @param {string} remote
|
|
66
|
+
* @param {{ execSyncImpl?: Function }} [opts]
|
|
67
|
+
* @returns {{ remote: {hash, author, date, message}, local: {hash} } | null}
|
|
68
|
+
*/
|
|
69
|
+
function collectRemoteMetadata(repoPath, branch, remote, opts) {
|
|
70
|
+
const execImpl = opts && opts.execSyncImpl;
|
|
71
|
+
try {
|
|
72
|
+
const remoteHash = tryExec('git rev-parse ' + escapeBranch(remote + '/' + branch), repoPath, execImpl);
|
|
73
|
+
if (!remoteHash.ok || !remoteHash.out) return null;
|
|
74
|
+
|
|
75
|
+
const remoteLog = tryExec('git log -1 --format="%an <%ae> | %ad | %s" ' + escapeBranch(remote + '/' + branch), repoPath, execImpl);
|
|
76
|
+
const localHash = tryExec('git rev-parse ' + escapeBranch(branch), repoPath, execImpl);
|
|
77
|
+
if (!remoteLog.ok || !localHash.ok || !localHash.out) return null;
|
|
78
|
+
|
|
79
|
+
// 解析 "author <email> | date | message"
|
|
80
|
+
const parts = remoteLog.out.split(' | ');
|
|
81
|
+
const author = parts[0] || '';
|
|
82
|
+
const date = parts[1] || '';
|
|
83
|
+
const message = parts.slice(2).join(' | ') || '';
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
remote: {
|
|
87
|
+
hash: remoteHash.out,
|
|
88
|
+
author,
|
|
89
|
+
date,
|
|
90
|
+
message,
|
|
91
|
+
},
|
|
92
|
+
local: {
|
|
93
|
+
hash: localHash.out,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
} catch (e) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 推送单个仓库的分支并建立 upstream
|
|
103
|
+
* @param {string} repoPath
|
|
104
|
+
* @param {string} repoName
|
|
105
|
+
* @param {string} branch
|
|
106
|
+
* @param {{ execSyncImpl?: Function }} [opts]
|
|
107
|
+
* @returns {{ name: string, status: string, upstream?: string, error?: string, message?: string, metadata?: object }}
|
|
108
|
+
*/
|
|
109
|
+
function pushSingle(repoPath, repoName, branch, opts) {
|
|
110
|
+
const execImpl = opts && opts.execSyncImpl;
|
|
111
|
+
const remote = tryExec('git remote', repoPath, execImpl);
|
|
112
|
+
if (!remote.ok || !remote.out) {
|
|
113
|
+
return { name: repoName, status: 'failed', error: 'no-remote', message: '无远程配置' };
|
|
114
|
+
}
|
|
115
|
+
const r = remote.out.split(/\r?\n/)[0];
|
|
116
|
+
const branchEsc = escapeBranch(branch);
|
|
117
|
+
const remoteEsc = '"' + String(r).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
118
|
+
const pushResult = tryExec('git push -u ' + remoteEsc + ' ' + branchEsc, repoPath, execImpl);
|
|
119
|
+
if (pushResult.ok) {
|
|
120
|
+
return { name: repoName, status: 'pushed', upstream: r + '/' + branch };
|
|
121
|
+
}
|
|
122
|
+
const errCode = classifyError(pushResult.err);
|
|
123
|
+
if (errCode === 'remote-exists') {
|
|
124
|
+
const metadata = collectRemoteMetadata(repoPath, branch, r, opts);
|
|
125
|
+
return {
|
|
126
|
+
name: repoName,
|
|
127
|
+
status: 'remote-exists',
|
|
128
|
+
error: errCode,
|
|
129
|
+
message: '远程分支已存在,需用户决策',
|
|
130
|
+
metadata,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return { name: repoName, status: 'failed', error: errCode, message: pushResult.err.split(/\r?\n/)[0] };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = { tryExec, escapeBranch, classifyError, pushSingle, collectRemoteMetadata };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// silence-popup.js (shared)
|
|
2
|
+
// Silences Windows 0xc0000142 (STATUS_DLL_INIT_FAILED) popups from child git processes.
|
|
3
|
+
// Cross-platform: only effective on Windows; no-op on macOS/Linux.
|
|
4
|
+
// koffi is resolved from cbb global install (no local node_modules needed).
|
|
5
|
+
//
|
|
6
|
+
// 唯一真源:cbb/worktrees/_shared/scripts/silence-popup.js
|
|
7
|
+
// 由 scripts/sync-shared.js 展开到各 skill 的 scripts/ 下(init / extend / close / push)。
|
|
8
|
+
// skill 内同目录引用:脚本第一行 `require('./silence-popup')`。
|
|
9
|
+
if (process.platform === 'win32') {
|
|
10
|
+
try {
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const globalRoot = execSync('npm root -g', { stdio: 'pipe', timeout: 5000 }).toString().trim();
|
|
14
|
+
const koffiPath = path.join(globalRoot, '@jspg-ai', 'coding-bb', 'node_modules', 'koffi');
|
|
15
|
+
const koffi = require(koffiPath);
|
|
16
|
+
const kernel32 = koffi.load('kernel32.dll');
|
|
17
|
+
const SetErrorMode = kernel32.func('uint __stdcall SetErrorMode(uint uMode)');
|
|
18
|
+
// SEM_FAILCRITICALERRORS=0x0001 | SEM_NOGPFAULTERRORBOX=0x0002 | SEM_NOOPENFILEERRORBOX=0x8000
|
|
19
|
+
SetErrorMode(0x0001 | 0x0002 | 0x8000);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
// koffi unavailable or SetErrorMode failed: silently continue (worst case: popups may reappear)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "OPSX: Close"
|
|
3
|
+
description: 关闭/清理由 init-worktree 创建的多仓库联动 worktree 工作空间,移除 worktree 并按用户选择处理特性分支
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [worktree, cleanup, worktree, git-worktree]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# OPSX: Close - 关闭 Worktree
|
|
9
|
+
|
|
10
|
+
## 重要:第一步必须用 Read 工具直接打开 SKILL.md
|
|
11
|
+
|
|
12
|
+
**禁止**用 `ls` / `find` / `cat` / `head` / `grep` 等 bash 命令搜索 SKILL.md。这些命令在 Qoder Windows PowerShell 沙箱中经常失败。
|
|
13
|
+
|
|
14
|
+
**直接路径**:
|
|
15
|
+
- Qoder 适配器:`.qoder/skills/openspec-close-worktree/SKILL.md`
|
|
16
|
+
- Claude Code 适配器:`.claude/skills/openspec-close-worktree/SKILL.md`
|
|
17
|
+
|
|
18
|
+
**第一步**:
|
|
19
|
+
1. 用 Read 工具直接打开 SKILL.md
|
|
20
|
+
2. 按 SKILL.md 的 Step 0 → 1 → 2 → 3 → 4 → 5 → 6 顺序执行
|
|
21
|
+
3. 每次调用 Node.js 脚本时使用**绝对路径**
|
|
22
|
+
|
|
23
|
+
## Input
|
|
24
|
+
|
|
25
|
+
参数 `<分支名>`(可选),指定要关闭的 worktree 对应的特性分支。**未提供时按 SKILL.md Step 1 在对话中询问或自动选取唯一 worktree**。
|
|
26
|
+
|
|
27
|
+
**Steps 概述**(完整流程见 SKILL.md)
|
|
28
|
+
|
|
29
|
+
1. Step 0:前置校验(Git 仓库检测、CONFIG.json 检测,支持向上查找)
|
|
30
|
+
2. Step 1:确定要关闭的目标 worktree(列出 `.worktrees/` 下的工作空间 worktree,用户选择或自动选取)
|
|
31
|
+
3. Step 2:发现关联应用 worktree(读 CONFIG.json,按实际存在性确定关联清单)
|
|
32
|
+
4. Step 3:安全检查(未提交修改 / 是否合并到主分支 / 是否推到远程,含主动 fetch 刷新远程引用)
|
|
33
|
+
5. Step 4:用户决策(未提交修改处理方式 + 分支处理方式,AskUserQuestion 固定选项)
|
|
34
|
+
6. Step 5:移除 Worktree(三层降级策略:正常移除 → prune+物理删除 → 仅 prune 延迟清理)
|
|
35
|
+
7. Step 5.5:二次确认 worktree 已移除(确保分支不再被检出)
|
|
36
|
+
8. Step 6:删除分支(按用户选择的 MODE:保留 / 删本地 / 删本地+远程)
|
|
37
|
+
9. Step 8:确认收尾(pwd 确认、残留检查、最终报告)
|
|
38
|
+
|
|
39
|
+
**Output**
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
✅ 工作空间 worktree 已关闭
|
|
43
|
+
当前目录:<工作空间根目录绝对路径>
|
|
44
|
+
已移除 worktree:
|
|
45
|
+
- .worktrees/worktree-<需求名>(workspace)
|
|
46
|
+
- .worktrees/worktree-<需求名>/<应用名1>(嵌套)
|
|
47
|
+
- .worktrees/worktree-<需求名>/<应用名2>(嵌套)
|
|
48
|
+
未提交修改:已丢弃(--force)/ 无
|
|
49
|
+
分支处理:<需求名> 已删除(本地+远程)/ 已删除(本地)/ 已保留
|
|
50
|
+
剩余工作空间 worktree:<列出仍存在的,或 "无" >
|
|
51
|
+
Workspace cleaned up.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
详细输出格式与安全检查报告,见 SKILL.md「最终报告」与「Step 3」段。
|
|
55
|
+
|
|
56
|
+
**Guardrails**
|
|
57
|
+
|
|
58
|
+
- 必须在业务工作空间根目录执行(包含 CONFIG.json 的目录),支持从 worktree 内部向上查找
|
|
59
|
+
- 顺序硬约束:**先移除所有 worktree,再删除分支**(先删分支会报 `Cannot delete branch checked out at`)
|
|
60
|
+
- 破坏性操作必须先报告、经用户确认才执行(未提交修改、未合并分支绝不静默 `--force` 或 `-D`)
|
|
61
|
+
- 只操作 `.worktrees/worktree-<需求名>` 路径,绝不碰其它 worktree(如 IDE 会话 worktree)
|
|
62
|
+
- 关联应用以实际存在的 worktree 为准,不假设 CONFIG.json 中所有应用都有关联
|
|
63
|
+
- 依赖 shell 函数的脚本必须整段在一次 Bash 调用中执行(函数不跨调用保留)
|
|
64
|
+
- git 操作一律用 `git -C <仓库>` 绝对路径,不依赖跨调用的 cwd
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "OPSX: Extend"
|
|
3
|
+
description: 为已存在的 worktree(init-worktree 创建的工作空间)补加关联应用,添加嵌套 worktree,不影响现有开发
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [worktree, extend, worktree, git-worktree, add-app]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# OPSX: Extend - 补加应用到现有 Worktree
|
|
9
|
+
|
|
10
|
+
## 重要:第一步必须用 Read 工具直接打开 SKILL.md
|
|
11
|
+
|
|
12
|
+
**禁止**用 `ls` / `find` / `cat` / `head` / `grep` 等 bash 命令搜索 SKILL.md。这些命令在 Qoder Windows PowerShell 沙箱中经常失败。
|
|
13
|
+
|
|
14
|
+
**直接路径**:
|
|
15
|
+
- Qoder 适配器:`.qoder/skills/openspec-extend-worktree/SKILL.md`
|
|
16
|
+
- Claude Code 适配器:`.claude/skills/openspec-extend-worktree/SKILL.md`
|
|
17
|
+
|
|
18
|
+
**第一步**:
|
|
19
|
+
1. 用 Read 工具直接打开 SKILL.md
|
|
20
|
+
2. 按 SKILL.md 的 Step 0 → 1 → 2 → 3 → 4 → 5 顺序执行
|
|
21
|
+
3. 每次调用 Node.js 脚本时使用**绝对路径**
|
|
22
|
+
|
|
23
|
+
## Input
|
|
24
|
+
|
|
25
|
+
无必需参数。
|
|
26
|
+
|
|
27
|
+
- 未指定时自动识别目标 worktree:cwd 在 worktree 内则反推需求名;唯一 worktree 时自动选用;多个时按 SKILL.md Step 0.2 在对话中提问
|
|
28
|
+
- 也可在斜杠命令后直接传 `<需求名>`(kebab-case),与已有 worktree 匹配则使用
|
|
29
|
+
|
|
30
|
+
**Steps 概述**(完整流程见 SKILL.md)
|
|
31
|
+
|
|
32
|
+
1. Step 0:前置校验(向上查找 CONFIG.json + cwd 反推需求名 + 校验目标 worktree 存在)
|
|
33
|
+
2. Step 1:选择要补加的应用(CONFIG.json 减去已关联 → AskUserQuestion multiSelect)
|
|
34
|
+
3. Step 2:状态检查(仅对新增应用,workspace 跳过)
|
|
35
|
+
4. Step 3:创建分支 + 嵌套 worktree(仅对新增应用,分支已存在则复用)
|
|
36
|
+
5. Step 4:在新增 worktree 中执行 `cbb init -y`(`.cbb/.managed-by-cbb` 判重)
|
|
37
|
+
6. Step 5:报告扩展前后对比(**不切 IDE 窗口**,用户留在原 worktree)
|
|
38
|
+
|
|
39
|
+
**Output**
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
✅ worktree 已扩展
|
|
43
|
+
目标 worktree: <需求名>
|
|
44
|
+
工作空间根: <WS_ROOT>
|
|
45
|
+
当前目录: <cwd>
|
|
46
|
+
补加应用:
|
|
47
|
+
- ep-user-info-server → .worktrees/<需求名>/ep-user-info-server
|
|
48
|
+
- ep-user-web → .worktrees/<需求名>/ep-user-web
|
|
49
|
+
AI 配置: ✅ 已安装(新建)/ 跳过(已存在)
|
|
50
|
+
已存在的关联应用(本次未变):
|
|
51
|
+
- ep-user-auth-app
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
详细输出格式与失败回滚命令,见 SKILL.md「最终报告」与「常见错误」段。
|
|
55
|
+
|
|
56
|
+
**Guardrails**
|
|
57
|
+
|
|
58
|
+
- **目标 worktree 必须已存在**(`.worktrees/<需求名>/` 必须存在),否则提示用 init-worktree
|
|
59
|
+
- **不重建、修改、删除任何已存在的 worktree**——只增量添加
|
|
60
|
+
- 嵌套 worktree 路径与 init-worktree 完全一致:`.worktrees/<需求名>/<应用名>/`
|
|
61
|
+
- 分支名与 init-worktree 一致:`<需求名>`(不加前缀)
|
|
62
|
+
- 仅对待补加应用执行状态检查、clone/fetch、创建分支、worktree add
|
|
63
|
+
- **不切 IDE 窗口**——用户在原 worktree 继续开发,扩展的工作是嵌套子目录
|
|
64
|
+
- 自由文本输入(需求名、应用 URL)禁止使用 `AskUserQuestion`,仅在固定选项场景(应用多选)使用
|
|
65
|
+
- 必须单次 Bash 调用合并 `cd "..." && ...`,不依赖跨调用的 cwd
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "OPSX: Init"
|
|
3
|
+
description: 为一个需求在 workspace 与各关联应用仓库同步创建同名 git worktree,物理直聚在 `.worktrees/<需求名>/` 目录
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [worktree, isolation, worktree, git-worktree]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# OPSX: Init - 创建 Worktree
|
|
9
|
+
|
|
10
|
+
## 重要:第一步必须用 Read 工具直接打开 SKILL.md
|
|
11
|
+
|
|
12
|
+
**禁止**用 `ls` / `find` / `cat` / `head` / `grep` 等 bash 命令搜索 SKILL.md 是否存在。**这些命令在 Qoder Windows PowerShell 沙箱中经常失败**(如 `head` 不存在、stderr 重定向无效等)。
|
|
13
|
+
|
|
14
|
+
**直接路径**:
|
|
15
|
+
- Qoder 适配器:`.qoder/skills/openspec-init-worktree/SKILL.md`
|
|
16
|
+
- Claude Code 适配器:`.claude/skills/openspec-init-worktree/SKILL.md`
|
|
17
|
+
|
|
18
|
+
**第一步**:
|
|
19
|
+
1. 用 Read 工具直接打开 `.qoder/skills/openspec-init-worktree/SKILL.md`(或 `.claude/skills/...`)
|
|
20
|
+
2. 按 SKILL.md 的 Step 0 → 1 → 2 → 3 → 4 → 5 → 6 顺序执行
|
|
21
|
+
3. 每次调用 Node.js 脚本时,使用**绝对路径**(避免依赖相对路径):
|
|
22
|
+
```
|
|
23
|
+
node "D:\workspace\<用户工作空间>\.qoder\skills\openspec-init-worktree\scripts\<name>.js" <参数>
|
|
24
|
+
```
|
|
25
|
+
- 参数形式:
|
|
26
|
+
- `check-env.js`:无参数
|
|
27
|
+
- `parse-config.js`:无参数
|
|
28
|
+
- `sync-repos.js`:`<ws_root>`
|
|
29
|
+
- `check-repos.js`:`<ws_root>`
|
|
30
|
+
- `create-branches.js`:`<ws_root> <branch>`
|
|
31
|
+
- `update-gitignore.js`:`<ws_root> <branch>`
|
|
32
|
+
- `create-worktrees.js`:`<ws_root> <branch>`
|
|
33
|
+
- `install-ai.js`:`<wt_path>`
|
|
34
|
+
- `auto-open.js`:`<wt_path>`
|
|
35
|
+
|
|
36
|
+
## Input
|
|
37
|
+
|
|
38
|
+
参数 `<需求名>`(kebab-case),同时作分支名和 workspace 工作树目录名。**未提供时按 SKILL.md Step 3.1 在对话中询问**。
|
|
39
|
+
|
|
40
|
+
## 流程总览(完整流程见 SKILL.md)
|
|
41
|
+
|
|
42
|
+
1. Step 0:环境探活 + 解析 CONFIG.json
|
|
43
|
+
2. Step 1:同步 .code/ 仓库(fetch --all)
|
|
44
|
+
3. Step 2:状态检查(5 项 / 3 项分级)
|
|
45
|
+
4. Step 3:创建分支(workspace 从 HEAD,app 从 origin/master)
|
|
46
|
+
5. Step 4:创建 worktree(workspace + 嵌套 app)
|
|
47
|
+
6. Step 5:在 worktree 中安装 AI 配置(cbb init -y)
|
|
48
|
+
7. Step 6:环境感知 + 进入工作目录
|
|
49
|
+
|
|
50
|
+
## 关键 Guardrails
|
|
51
|
+
|
|
52
|
+
- workspace 主分支 tracked 的所有内容(openspec/、cbb/ 等)由 git worktree 自动 checkout——**禁止 cp / clone / symlink “带过来”**
|
|
53
|
+
- 必须用 `git branch` 而非 `git checkout -b`(分支不能同时在主目录与 worktree 检出)
|
|
54
|
+
- 沙箱内 node 不可用时 fail-fast:终止流程并提示用户到系统终端重试
|
|
55
|
+
- **不要试图搜索 SKILL.md**——直接用 Read 工具打开
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "OPSX: Push"
|
|
3
|
+
description: 跨 worktree 提交并推送当前需求的所有关联仓库到 origin
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [workflow, push, commit, worktree, experimental]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
跨 worktree 提交并推送当前需求的所有关联仓库到 origin。
|
|
9
|
+
|
|
10
|
+
**Input**: 可选指定需求名(如 `/opsx:push ft-diff-on-cargo`)。省略时从 cwd 的 `.worktrees/worktree-<需求名>/` 路径推断(cwd 在工作空间根目录时由 Step 0 定位)。
|
|
11
|
+
|
|
12
|
+
**何时使用**:
|
|
13
|
+
|
|
14
|
+
- apply 完成后准备推送所有改动
|
|
15
|
+
- close-worktree 前需要先确保 ahead 提交已推送(避免丢)
|
|
16
|
+
- 开发过程中想保存中间进度
|
|
17
|
+
- 用户口语化说"提交并push" / "推一下"
|
|
18
|
+
|
|
19
|
+
**Steps 摘要**(详细见 [openspec-push-worktrees SKILL.md](../../skills/openspec-push-worktrees/SKILL.md)):
|
|
20
|
+
|
|
21
|
+
1. **Step 0**:定位工作空间根(find-workspace-root.js)
|
|
22
|
+
2. **Step 1**:识别目标 worktree(find-target-worktree.js)
|
|
23
|
+
3. **Step 2**:扫描所有 worktree 仓库状态(commit-worktrees.js --dry-run)
|
|
24
|
+
4. **Step 3**:对话中收集 commit 信息(必须由用户提供)
|
|
25
|
+
5. **Step 4**:批量 commit(commit-worktrees.js)
|
|
26
|
+
6. **Step 5**:批量 push(push-worktrees.js)
|
|
27
|
+
7. **Step 6**:汇总报告
|
|
28
|
+
|
|
29
|
+
**关键 Guardrails**:
|
|
30
|
+
|
|
31
|
+
- 严格按 Step 0 → 1 → 2 → 3 → 4 → 5 → 6 顺序执行
|
|
32
|
+
- **Step 2 dry-run 必跑**,让用户看到将要 commit 的内容
|
|
33
|
+
- **Step 3 必问用户 commit 信息**(自由文本),禁止自动生成
|
|
34
|
+
- 默认 `git add -u`(仅 tracked),避免误纳未追踪文件
|
|
35
|
+
- push 失败时阻塞并按错误码分类处理,**禁止**自动跳过失败仓库
|
|
36
|
+
- 远程分支已存在时必须输出 commit 元信息再询问用户决策
|
|
37
|
+
|
|
38
|
+
**Failure Handling**:
|
|
39
|
+
|
|
40
|
+
- commit-worktrees.js 退出码 2 → 部分 commit 失败,**阻塞流程**,询问用户
|
|
41
|
+
- push-worktrees.js 退出码 2 → 部分 push 失败,**阻塞流程**,按错误码询问用户
|
|
42
|
+
- 远程分支已存在 → 先输出元信息,再 AskUserQuestion 让用户选择「关联」或「终止」
|