@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.
Files changed (183) hide show
  1. package/README.md +41 -0
  2. package/cbb/dev-standards/rules/cbb-ai-behavior.md +104 -0
  3. package/cbb/dev-standards/rules/cbb-coding-rule.md +50 -0
  4. package/cbb/dev-standards/rules/cbb-priority.md +56 -0
  5. package/cbb/dev-standards/skills/architecture-specs/SKILL.md +129 -0
  6. package/cbb/dev-standards/skills/coding-specs/SKILL.md +376 -0
  7. package/cbb/dev-standards/skills/coding-specs/references/concurrency.md +53 -0
  8. package/cbb/dev-standards/skills/coding-specs/references/config-center.md +16 -0
  9. package/cbb/dev-standards/skills/coding-specs/references/distributed.md +42 -0
  10. package/cbb/dev-standards/skills/coding-specs/references/es-coding.md +60 -0
  11. package/cbb/dev-standards/skills/coding-specs/references/scheduled-task.md +25 -0
  12. package/cbb/dev-standards/skills/coding-specs/references/security.md +11 -0
  13. package/cbb/dev-standards/skills/coding-specs/references/unit-testing.md +43 -0
  14. package/cbb/dev-standards/skills/es-design-specs/SKILL.md +104 -0
  15. package/cbb/dev-standards/skills/mysql-design-specs/SKILL.md +89 -0
  16. package/cbb/lib/install/claude-code.js +20 -0
  17. package/cbb/lib/install/cleanup.js +64 -0
  18. package/cbb/lib/install/init.js +1875 -0
  19. package/cbb/lib/install/qoder.js +20 -0
  20. package/cbb/lib/install/workspaces.js +232 -0
  21. package/cbb/lib/openspec/index.js +554 -0
  22. package/cbb/lib/superpowers/index.js +265 -0
  23. package/cbb/lib/utils/check-update.js +147 -0
  24. package/cbb/lib/utils/checkbox.js +383 -0
  25. package/cbb/lib/utils/gitignore.js +69 -0
  26. package/cbb/lib/utils/output.js +64 -0
  27. package/cbb/lib/utils/settings.js +119 -0
  28. package/cbb/lib/utils/version.js +135 -0
  29. package/cbb/lib/wiki/api-client.js +358 -0
  30. package/cbb/lib/wiki/cli.js +427 -0
  31. package/cbb/lib/wiki/convert.js +464 -0
  32. package/cbb/lib/wiki/index.js +218 -0
  33. package/cbb/lib/wiki/mermaid-guard.js +103 -0
  34. package/cbb/lib/wiki/split.js +131 -0
  35. package/cbb/tools/cbb-decompile-jar/SKILL.md +220 -0
  36. package/cbb/tools/cbb-decompile-jar/scripts/decompile.py +863 -0
  37. package/cbb/tools/cbb-design-to-wiki/SKILL.md +180 -0
  38. package/cbb/tools/cbb-mvn-guide/SKILL.md +281 -0
  39. package/cbb/tools/cbb-mvn-guide/scripts/mvn_jdk_manager.py +378 -0
  40. package/cbb/tools/cbb-mvn-guide/scripts/mvn_pom_jdk_reader.py +197 -0
  41. package/cbb/tools/cbb-plantuml-authoring/SKILL.md +448 -0
  42. package/cbb/tools/cbb-plantuml-authoring/references/drawing-templates.md +479 -0
  43. package/cbb/tools/cbb-wiki-ops/SKILL.md +134 -0
  44. package/cbb/tools/cbb-wiki-ops/scripts/check-auth.js +44 -0
  45. package/cbb/worktrees/_shared/scripts/find-target-worktree.js +96 -0
  46. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +67 -0
  47. package/cbb/worktrees/_shared/scripts/push-core.js +136 -0
  48. package/cbb/worktrees/_shared/scripts/silence-popup.js +23 -0
  49. package/cbb/worktrees/commands/close.md +64 -0
  50. package/cbb/worktrees/commands/extend.md +65 -0
  51. package/cbb/worktrees/commands/init.md +55 -0
  52. package/cbb/worktrees/commands/push.md +42 -0
  53. package/cbb/worktrees/skills/openspec-close-worktree/SKILL.md +449 -0
  54. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-env.js +76 -0
  55. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-unarchived.js +48 -0
  56. package/cbb/worktrees/skills/openspec-close-worktree/scripts/delete-branches.js +136 -0
  57. package/cbb/worktrees/skills/openspec-close-worktree/scripts/discover-apps.js +76 -0
  58. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +96 -0
  59. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-workspace-root.js +67 -0
  60. package/cbb/worktrees/skills/openspec-close-worktree/scripts/remove-worktrees.js +124 -0
  61. package/cbb/worktrees/skills/openspec-close-worktree/scripts/safety-check.js +174 -0
  62. package/cbb/worktrees/skills/openspec-close-worktree/scripts/silence-popup.js +23 -0
  63. package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +390 -0
  64. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +95 -0
  65. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +98 -0
  66. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +135 -0
  67. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-target-worktree.js +96 -0
  68. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-workspace-root.js +67 -0
  69. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +150 -0
  70. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +88 -0
  71. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/push-core.js +136 -0
  72. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/silence-popup.js +23 -0
  73. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +93 -0
  74. package/cbb/worktrees/skills/openspec-init-worktree/SKILL.md +539 -0
  75. package/cbb/worktrees/skills/openspec-init-worktree/scripts/auto-open.js +136 -0
  76. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env-deep.js +87 -0
  77. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env.js +90 -0
  78. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-repos.js +171 -0
  79. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-branches.js +103 -0
  80. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-worktrees.js +154 -0
  81. package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +67 -0
  82. package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +93 -0
  83. package/cbb/worktrees/skills/openspec-init-worktree/scripts/install-ai.js +177 -0
  84. package/cbb/worktrees/skills/openspec-init-worktree/scripts/parse-config.js +67 -0
  85. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-branches.js +101 -0
  86. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +136 -0
  87. package/cbb/worktrees/skills/openspec-init-worktree/scripts/silence-popup.js +23 -0
  88. package/cbb/worktrees/skills/openspec-init-worktree/scripts/sync-repos.js +95 -0
  89. package/cbb/worktrees/skills/openspec-init-worktree/scripts/update-gitignore.js +134 -0
  90. package/cbb/worktrees/skills/openspec-push-worktrees/SKILL.md +307 -0
  91. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/commit-worktrees.js +269 -0
  92. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-target-worktree.js +96 -0
  93. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-workspace-root.js +67 -0
  94. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-core.js +136 -0
  95. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-worktrees.js +159 -0
  96. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +23 -0
  97. package/config/cbb.yaml +6 -0
  98. package/config/config.sample.json +16 -0
  99. package/config/openspec/config.yaml +28 -0
  100. package/config/openspec/schemas/spec-driven/schema.yaml +247 -0
  101. package/config/openspec/schemas/spec-driven/templates/design.md +475 -0
  102. package/config/openspec/schemas/spec-driven/templates/proposal.md +58 -0
  103. package/config/openspec/schemas/spec-driven/templates/spec.md +8 -0
  104. package/config/openspec/schemas/spec-driven/templates/tasks.md +9 -0
  105. package/config/workspaces.json +15 -0
  106. package/openspec/.version +6 -0
  107. package/openspec/commands/apply.md +182 -0
  108. package/openspec/commands/archive.md +223 -0
  109. package/openspec/commands/bulk-archive.md +334 -0
  110. package/openspec/commands/continue.md +112 -0
  111. package/openspec/commands/explore.md +206 -0
  112. package/openspec/commands/ff.md +111 -0
  113. package/openspec/commands/new.md +70 -0
  114. package/openspec/commands/onboard.md +555 -0
  115. package/openspec/commands/propose.md +157 -0
  116. package/openspec/commands/sync.md +256 -0
  117. package/openspec/commands/update.md +85 -0
  118. package/openspec/commands/verify.md +169 -0
  119. package/openspec/skills/openspec-apply-change/SKILL.md +187 -0
  120. package/openspec/skills/openspec-archive-change/SKILL.md +181 -0
  121. package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  122. package/openspec/skills/openspec-continue-change/SKILL.md +117 -0
  123. package/openspec/skills/openspec-explore/SKILL.md +342 -0
  124. package/openspec/skills/openspec-ff-change/SKILL.md +116 -0
  125. package/openspec/skills/openspec-new-change/SKILL.md +76 -0
  126. package/openspec/skills/openspec-onboard/SKILL.md +560 -0
  127. package/openspec/skills/openspec-propose/SKILL.md +162 -0
  128. package/openspec/skills/openspec-sync-specs/SKILL.md +261 -0
  129. package/openspec/skills/openspec-update-change/SKILL.md +90 -0
  130. package/openspec/skills/openspec-verify-change/SKILL.md +174 -0
  131. package/package.json +46 -0
  132. package/superpowers/.version +6 -0
  133. package/superpowers/skills/brainstorming/SKILL.md +250 -0
  134. package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
  135. package/superpowers/skills/brainstorming/scripts/helper.js +167 -0
  136. package/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
  137. package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
  138. package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
  139. package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  140. package/superpowers/skills/brainstorming/visual-companion.md +299 -0
  141. package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -0
  142. package/superpowers/skills/executing-plans/SKILL.md +64 -0
  143. package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -0
  144. package/superpowers/skills/receiving-code-review/SKILL.md +205 -0
  145. package/superpowers/skills/requesting-code-review/SKILL.md +95 -0
  146. package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -0
  147. package/superpowers/skills/subagent-driven-development/SKILL.md +568 -0
  148. package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -0
  149. package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -0
  150. package/superpowers/skills/subagent-driven-development/scripts/review-package +46 -0
  151. package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +40 -0
  152. package/superpowers/skills/subagent-driven-development/scripts/task-brief +41 -0
  153. package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
  154. package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  155. package/superpowers/skills/systematic-debugging/SKILL.md +283 -0
  156. package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  157. package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  158. package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  159. package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -0
  160. package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  161. package/superpowers/skills/systematic-debugging/test-academic.md +14 -0
  162. package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  163. package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  164. package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  165. package/superpowers/skills/test-driven-development/SKILL.md +320 -0
  166. package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -0
  167. package/superpowers/skills/using-git-worktrees/SKILL.md +167 -0
  168. package/superpowers/skills/using-superpowers/SKILL.md +63 -0
  169. package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
  170. package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -0
  171. package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -0
  172. package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -0
  173. package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
  174. package/superpowers/skills/verification-before-completion/SKILL.md +120 -0
  175. package/superpowers/skills/writing-plans/SKILL.md +171 -0
  176. package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  177. package/superpowers/skills/writing-skills/SKILL.md +679 -0
  178. package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  179. package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  180. package/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  181. package/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  182. package/superpowers/skills/writing-skills/render-graphs.js +169 -0
  183. package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
@@ -0,0 +1,449 @@
1
+ ---
2
+ name: openspec-close-worktree
3
+ description: "关闭/清理/删除需求工作空间的 worktree 和分支。触发:用户明确说关闭/清理/删除 worktree、结束隔离开发、合并完要清理。禁止在 openspec-init-worktree 执行后自动调用——只有用户主动要求关闭时才触发。"
4
+ license: MIT
5
+ compatibility: Requires git (>=2.30) and Node.js (>=16.7.0). All commands are pure Node.js scripts under `scripts/`, fully cross-platform (Windows / macOS / Linux, bash / PowerShell / Git Bash).
6
+ metadata:
7
+ author: Contributors
8
+ version: "2.0"
9
+ generatedBy: coding-bb
10
+ ---
11
+
12
+ # Close Worktree(跨平台脚本化版本 v2.0)
13
+
14
+ 关闭一个由 `openspec-init-worktree` 创建的多仓库联动隔离环境:移除 workspace worktree 及所有关联应用 worktree,并默认保留特性分支(按需手动清理)。当你需要结束一次跨多仓库的隔离开发、把环境打扫干净时,本技能一次性完成 worktree 移除与会话收尾。
15
+
16
+ **启动时声明:** "我正在使用 openspec-close-worktree 技能来关闭多仓库联动的隔离 worktree 环境。"
17
+
18
+ ## 核心原则
19
+
20
+ - 本技能的所有原子操作封装为 `scripts/*.js` Node.js 脚本,**跨平台执行**
21
+ - 本技能是 `openspec-init-worktree` 的逆操作:共用 `CONFIG.json`、共用 `.worktrees/worktree-<需求名>/` 物理直聚命名、共用统一的分支名(不加前缀)
22
+ - App worktree **物理嵌套**在 workspace worktree 内(`.worktrees/worktree-<需求名>/<应用名>/`),但 git 上属于各自仓库的独立 worktree
23
+ - 只操作 `.worktrees/worktree-<需求名>` 这一类精确路径,**绝不碰其它 worktree**(如 IDE/工具自动创建的 `~/.qoder/worktree/...` 会话 worktree)
24
+ - 通过检查 `.worktrees/worktree-<需求名>/<应用名>/` **是否实际存在**来确定关联应用——创建时用户可能只关联了 `CONFIG.json` 中的部分应用,不能假设全部应用都关联
25
+ - **顺序硬约束:先移除所有 worktree,再删除分支。** 目标分支当前正检出于 worktree 中,先删分支会报 `error: Cannot delete branch '<分支>' checked out at '<worktree 路径>'`
26
+ - **破坏性操作必须先报告、经用户确认才执行**:未提交修改、未合并/未推送的提交,绝不静默 `--force` 或 `-D` 丢弃
27
+ - 软性检查失败时报告详情,询问用户是否继续
28
+ - 输入约定:凡是需要用户自由输入文本(如分支名、确认)的场景,**必须直接在对话中提问并等待用户回复**,禁止使用 `AskUserQuestion` 工具;`AskUserQuestion` 仅用于固定选项场景(选择归档哪些 change、是否丢弃未提交修改)
29
+
30
+ ---
31
+
32
+ ## Step 0:前置校验
33
+
34
+ ### 0.1 环境健康探活
35
+
36
+ ```bash
37
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/check-env.js"
38
+ ```
39
+
40
+ **解读输出**:
41
+ - 退出码 0 + 末行 `ENV_OK {...}` → 探活通过
42
+ - 退出码 1 → git 不可用,**终止流程**
43
+ - 退出码 2 → 当前不在 git 仓库,**终止流程**
44
+
45
+ ### 0.2 定位工作空间根目录
46
+
47
+ ```bash
48
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/find-workspace-root.js"
49
+ ```
50
+
51
+ **解读输出**:
52
+ - 退出码 0 + 末行(纯路径) → WS_ROOT 绝对路径
53
+ - 退出码 1 → 未找到工作空间根目录,**终止流程**
54
+
55
+ > ⓘ **为什么不用 CONFIG.json 存在性判断**:init-worktree 会把 CONFIG.json 提交到主分支,`git worktree add` 会自动 checkout 副本到 worktree 目录中。若用 CONFIG.json 存在性判断,在 worktree 内执行时会错误地把 worktree 目录当作 WS_ROOT。使用 `git worktree list` 的第一行(git 契约上始终为主仓库绝对路径)则不受该问题影响。
56
+
57
+ > close-worktree 是 init-worktree 的逆操作,但本步骤的 WS_ROOT 定位逻辑与 init-worktree 不同:init-worktree 强制根目录执行(不需要处理 worktree 场景),close-worktree 支持 worktree 内执行(需要绕开 CONFIG.json 副本陷阱)。
58
+
59
+ ---
60
+
61
+ ## Step 1:信息收集
62
+
63
+ 本步骤只做读取,不修改任何状态。收集三项信息:目标 worktree、关联应用、未归档 change。
64
+
65
+ ### 1.1 确定目标 worktree
66
+
67
+ 1. 解析用户输入,提取已提及的分支名(例如 "关闭 feature-20260612-275729-myb-saas-auth-migrate")
68
+ 2. **WS_ROOT 已在 Step 0.2 定位完成**,本步骤直接使用
69
+ 3. AI agent 列出 `.worktrees/` 下的所有 worktree:
70
+
71
+ ```bash
72
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/find-target-worktree.js "<ws_root>"
73
+ ```
74
+
75
+ > 注:本技能支持工作空间根目录或 worktree 内执行,find-target-worktree 自动从 cwd 反推或列出。
76
+
77
+ 4. 确定目标:
78
+ - 用户已指定分支名 → 目标 = `.worktrees/worktree-<需求名>`,校验该目录确实存在
79
+ - 未指定且只有一个 worktree → 直接用它,但仍需向用户确认
80
+ - 未指定且有多个 → **直接在对话中**列出(worktree 目录名 + 分支名),请用户输入要关闭的分支名,等待纯文本回复
81
+
82
+ > ⚠️ 必须只挑选 `.worktrees/worktree-<需求名>` 形态的目录。`git worktree list` 里出现的 `~/.qoder/worktree/...` 等非 `.worktrees/` 路径**不是本流程创建的**,一律排除。
83
+
84
+ ### 1.2 发现关联应用 worktree
85
+
86
+ ```bash
87
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/discover-apps.js "<ws_root>" "<branch>"
88
+ ```
89
+
90
+ 脚本自动从 `CONFIG.json` 读取应用列表,扫描 `.worktrees/worktree-<branch>/<应用名>/` 实际存在的子目录。
91
+
92
+ **解读末行 `DISCOVER_RESULT`**:
93
+ - `workspace` 字段:workspace worktree 绝对路径(AI agent 记录供后续命令使用)
94
+ - `apps` 数组:实际存在的应用 worktree 列表(每项含 `name`, `repo`, `side`, `wt_path`, `app_path`)
95
+
96
+ > 说明:app worktree 物理嵌套在 workspace worktree 内,移除 workspace worktree 时嵌套的子目录会一并消失,但各 app 仓库的 git worktree 元数据(`.git/worktrees/`)仍需通过 `git worktree remove` 逐个清理。AI 配置目录(`.claude/`、`.qoder/`、`.cbb/`)在每个 worktree 内由 init-worktree 独立安装,随 worktree 目录删除而清理,skill 无需特殊处理。
97
+
98
+ ### 1.3 检查未归档 change
99
+
100
+ ```bash
101
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/check-unarchived.js "<ws_root>"
102
+ ```
103
+
104
+ 脚本扫描 `openspec/changes/` 目录,筛选出非 `archive/` 子目录的 change 名称列表。
105
+
106
+ **解读末行 `UNARCHIVED_RESULT`**:
107
+ - `changes`:未归档 change 名称数组(空数组 = 全部已归档)
108
+ - 退出码 0 → 检查完成(无论是否有未归档 change)
109
+ - 退出码 1 → `openspec/changes/` 目录不存在,视为无未归档 change
110
+
111
+ > ⓘ 本检查为信息收集性质,不阻断流程。结果将在 Step 3 用户决策时展示。
112
+
113
+ ---
114
+
115
+ ## Step 2:安全评估(核心保护)
116
+
117
+ 对 workspace worktree 和每个关联应用 worktree,依次执行三项检查并汇总成安全状态表。**这是破坏性操作前的必经环节,结果将驱动 Step 3 的用户决策。**
118
+
119
+ ```bash
120
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/safety-check.js "<ws_root>" "<branch>"
121
+ ```
122
+
123
+ 脚本内部对每个仓库自动执行:
124
+ - **2.0** 主动 `git fetch` 刷新远程引用(避免 `origin/master` 陈旧导致合并误判)
125
+ - **2.1** 未提交修改检查(`git status --porcelain`)
126
+ - **2.2** 合并判定(merge-base + cherry + release-* 中转,含 squash/cherry-pick 兜底)
127
+ - **2.3** 远程分支存在性检查(fetch 成功后读本地引用,否则 ls-remote)
128
+ - **2.4** 未推送 commit 检查(`git rev-list --count @{u}..HEAD`)— 防止 close 时 ahead 提交因用户未推送而永久丢失
129
+
130
+ **解读末行 `SAFETY_RESULT`**:每项仓库的状态数组
131
+ - `dirty_files`:未提交修改的文件列表(空数组 = 干净)
132
+ - `merged`:合并到的目标(如 `main`、`origin/main`、`main-via-release-1.2.0`);`null` = 未合并
133
+ - `remote_exists`:远程分支是否存在(`true` / `false` / `null`)
134
+ - `fetch_ok`:fetch 是否成功
135
+ - `unpushed_count`:未推送 commit 数(`-1` = 无 upstream / `0` = 已全部推送 / `>0` = ahead 数量)
136
+
137
+ > ⚠️ **判定前先 `git fetch` 刷新远程引用**:feature 多由他人经 MR 合入 `release→master`,**合并发生在远端**;本地 `origin/master`、`origin/release-*` 等远程跟踪引用若长期未 fetch 会陈旧,`merged_to_main` 会把"已合并"误判成"未合并",进而 Step 3 误警告、Step 4 错用 `-D` 强删。故 `safety-check.js` 在判定前对每个仓库主动 `git fetch`(仅更新 `refs/remotes/*`,不动工作区/暂存/本地分支,安全;离线失败则降级判定并提示)。这是合并判定准确的前提。
138
+
139
+ > 被忽略的未跟踪文件(如 `.idea/`、构建产物)不会出现在 `--porcelain` 中,也不阻塞 `git worktree remove`,因此不计入 2.1 的"未提交修改"
140
+
141
+ ---
142
+
143
+ ## Step 3:用户决策(AskUserQuestion)
144
+
145
+ 依据 Step 1.3 和 Step 2 的收集结果,分最多两个维度与用户确认。均为**固定选项**场景,使用 `AskUserQuestion`。
146
+
147
+ ### 3.1 未提交修改如何处理(仅当 2.1 任一 worktree 有未提交修改时出现)
148
+
149
+ ```
150
+ ⚠️ 以下 worktree 存在未提交修改,移除将永久丢失这些工作:
151
+ - ep-user-info-server(2 项)
152
+
153
+ 请选择处理方式:
154
+ [中断](推荐)终止流程,我先去提交/stash 这些修改后再回来
155
+ [丢弃] 用 --force 移除这些 worktree,永久丢弃未提交修改
156
+ [中止] 完全终止
157
+ ```
158
+
159
+ - 用户选择「中断」/「中止」→ 终止流程,不做任何移除
160
+ - 用户选择「丢弃」→ Step 4 调用 remove-worktrees.js 时传 `<force>` = `"true"`
161
+
162
+ ### 3.2 未归档 change 如何处理(仅当 1.3 存在未归档 change 时出现)
163
+
164
+ **情况 A:1 个未归档 change**
165
+
166
+ ```
167
+ ⚠️ 检测到 1 个未归档的 change:ai-call-send-im-msg
168
+
169
+ 请选择处理方式:
170
+ [帮我归档](推荐)自动完成归档,然后继续关闭流程
171
+ [跳过] 不归档,直接继续关闭
172
+ [中止] 完全终止
173
+ ```
174
+
175
+ **情况 B:多个未归档 change**
176
+
177
+ ```
178
+ ⚠️ 检测到 3 个未归档的 change:
179
+ [1] ai-call-send-im-msg
180
+ [2] feature-user-migration
181
+ [3] fix-payment-timeout
182
+
183
+ 请选择处理方式:
184
+ [全部归档](推荐)自动归档以上所有 change,然后继续关闭
185
+ [选择归档] 让我勾选要归档的 change
186
+ [跳过] 不归档,直接继续关闭
187
+ [中止] 完全终止
188
+ ```
189
+
190
+ 选择「选择归档」时,用 `AskUserQuestion`(`multiSelect: true`)让用户勾选,options 从 Step 1.3 的结果动态生成:
191
+
192
+ ```
193
+ AskUserQuestion({
194
+ questions: [{
195
+ header: "选择归档",
196
+ multiSelect: true,
197
+ options: Step 1.3 返回的 changes 数组,每项 label 为 change 名称
198
+ }]
199
+ })
200
+ ```
201
+
202
+ **归档执行逻辑**(用户选择归档后,在 Step 4 中依次对每个待归档 change 执行):
203
+
204
+ 1. `openspec status --change "<name>" --json` → 检查 artifacts 完成状态
205
+ 2. 读取 `tasks.md` → 检查任务完成状态
206
+ 3. 检查 `openspec/changes/<name>/specs/` → 判断 delta specs 是否需要同步
207
+ 4. 执行归档(`mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>`)
208
+
209
+ **逐项确认规则**:
210
+ - 若某个 change 有 artifacts 或 tasks 未完成 → 对该 change 单独弹出确认:*"<name> 有 N 个任务未完成,仍要归档吗?"*
211
+ - 若 delta specs 需要同步 → 对该 change 单独提示同步选项(同步 / 跳过同步直接归档)
212
+ - 每个 change 的归档结果独立记录(✅ 已归档 / ⏭️ 跳过 / ❌ 失败)
213
+
214
+ ### 3.3 分支处理方式(默认保留,不询问)
215
+
216
+ 历史版本此步骤会询问"保留 / 删本地 / 删本地+远程",但绝大多数场景仅需移除 worktree、自动保留分支;频繁弹窗会打断 close-worktree 的批量清理节奏。改为 **默认 `MODE = keep`,不再触发 `AskUserQuestion`**。
217
+
218
+ **默认行为**:
219
+
220
+ - `MODE = keep` → 仅移除 worktree,**本地分支与远程分支都不动**
221
+ - Step 2 安全评估结果(合并状态 / 远程存在性)仅用于内部决策展示,**不再弹出分支处理问卷**
222
+
223
+ **逃生通道**(确需主动删分支时手动调用):
224
+
225
+ 如用户在 Step 1.1 选定要关闭的 worktree 时同步要求"删除分支",或运行后需要清理本地/远程分支,可手动调用脚本:
226
+
227
+ ```bash
228
+ # 仅删本地分支(已合并自动 -d,未合并自动 -D;含 squash 合并 -D 兜底)
229
+ node "<skill>/scripts/delete-branches.js" "<ws_root>" "<branch>" local
230
+
231
+ # 删本地 + 远程分支
232
+ node "<skill>/scripts/delete-branches.js" "<ws_root>" "<branch>" local_remote
233
+ ```
234
+
235
+ **调用前的强警告**(调用方需自评):
236
+
237
+ - **未合并分支**(Step 2.2 `merged: null`):删除会永久丢失未合并的提交,必须二次确认
238
+ - **远程分支**:删除后无法直接恢复,需确认其他仓库/同事是否还在引用
239
+ - **推荐做法**:默认 `keep` 关闭 worktree 即可,确有必要再单独执行脚本;这样误删风险被显式手动动作兜住
240
+
241
+ > 合并代码到主分支属于另一项工作(参见 `finishing-a-development-branch`),本技能不代为合并;若用户其实想合并,引导其先完成合并再回来关闭。
242
+
243
+ ### 3.4 未推送 commit 处理(仅当 2.4 任一 worktree `unpushed_count > 0` 时出现)
244
+
245
+ **场景**:
246
+ - 用户在 worktree 中做了 commit,但**没有调** `openspec-push-worktrees` 推送
247
+ - 本地有 ahead 提交未推送到 origin
248
+ - 一旦 close worktree + 后续走 `local` / `local_remote` 删分支,ahead 提交可能永久丢失(取决于上游 `delete-branches.js` 行为)
249
+
250
+ **报告**:
251
+ ```
252
+ ⚠️ 检测到未推送的提交(ahead of origin/<branch>):
253
+ - workspace: 3 个 commit
254
+ - ep-user-info-server: 1 个 commit
255
+ - ep-baz-app: 2 个 commit
256
+
257
+ 请选择处理方式:
258
+ [先推送](推荐)调 openspec-push-worktrees 推送所有 ahead 提交
259
+ [接受丢失] 继续关闭,ahead 提交在删分支后永久丢失
260
+ [中止] 终止流程,我先手动处理
261
+ ```
262
+
263
+ - 用户选择「先推送」→ AI 引导用户执行 `openspec-push-worktrees`(或 `/opsx:push`),完成后**重新跑** Step 2 safety-check 确认 `unpushed_count = 0` 再回到本步骤
264
+ - 用户选择「接受丢失」→ 必须二次确认(ahead 提交真的会丢),确认后继续 Step 4
265
+ - 用户选择「中止」→ 终止流程
266
+
267
+ > ⓘ **为什么必须二次确认**:close-worktree 的默认 MODE=keep 不会删分支,ahead 提交仍在本地;只有用户主动走 `local` / `local_remote` 删分支模式才会真正丢。AI 必须先在报告中讲清楚后果,再询问用户决策。
268
+
269
+ ---
270
+
271
+ ## Step 4:执行清理
272
+
273
+ 按顺序执行破坏性操作。AI agent 在执行前**主动 `cd` 回 WS_ROOT**(防御性:避免前置步骤的副作用影响后续命令)。
274
+
275
+ ### 4.1 归档未归档 change(如果 Step 3.2 选择了归档)
276
+
277
+ 对 Step 3.2 确定的待归档 change 列表,**依次逐个**执行归档:
278
+
279
+ 1. 检查 artifacts 完成状态(`openspec status --change "<name>" --json`)
280
+ 2. 检查 tasks.md 任务完成状态
281
+ 3. 检查 delta specs 同步需求
282
+ 4. 逐项确认(如有未完成项)
283
+ 5. 执行 `mv` 归档
284
+
285
+ 每个 change 归档后记录结果,全部完成后汇总。
286
+
287
+ ### 4.2 移除 Worktree(含自动降级)
288
+
289
+ **顺序:先移除各应用 worktree,再移除 workspace worktree**(逆序于创建;也为后续删分支扫清"分支仍被检出"的障碍)。
290
+
291
+ ```bash
292
+ node "D:/workspace/<ws_root>/.qoder/skills/openspec-close-worktree/scripts/remove-worktrees.js "<ws_root>" "<branch>" "<force>"
293
+ ```
294
+
295
+ **三层降级策略**:`git worktree remove` 实际包含两个动作——①清理 git 元数据(`.git/worktrees/`)②删除物理目录。当 IDE 占用目录时 ② 会被 Windows 文件锁阻塞,但 ① 永远不受影响。脚本将这两个动作解耦:
296
+
297
+ - **第 1 层(正常路径):** `git worktree remove` 一步完成元数据 + 物理目录清理
298
+ - **第 2 层(解耦清理):** 当目录被锁时,先 `prune` 清理 git 元数据(始终成功),再 `rmdir`/`rm -rf` 尝试物理删除
299
+ - **第 3 层(延迟清理):** Windows 下 IDE 持有排他句柄时触发。元数据已清理保证分支删除不受影响;物理目录留给 init-worktree 下次创建时自愈(见 init Step 4.0)
300
+
301
+ **解读末行 `REMOVE_RESULT`**:
302
+ - `has_locked: false` → 全部清理成功
303
+ - `has_locked: true` → 有被锁目录,AI agent 提示用户关闭 IDE 后重试
304
+
305
+ **关于 `FORCE` 标志**:
306
+ - Step 3.1 用户选择「丢弃」时传 `"true"`,`git worktree remove` 加 `--force`(覆盖未提交修改)
307
+ - 其他情况传 `"false"`,git 自带保护会拒绝移除有未提交修改的 worktree
308
+
309
+ ### 4.3 IDE 窗口回根(环境感知)
310
+
311
+ 所有 worktree 已成功移除后,如果当前 shell 的工作目录位于**已被关闭的 worktree 内**,需要主动让 IDE 窗口切回 `WS_ROOT`,避免 IDE 窗口指向已删除的目录。
312
+
313
+ > ⓘ **本节是 close-worktree 专属逻辑**:与 init-worktree 的 Step 5 不共享、不交叉同步。init-worktree 负责"创建后**在新窗口打开** worktree",本节负责"关闭后切回根目录",两者职责独立。
314
+
315
+ **AI agent 行为**:
316
+ 1. 检查当前 cwd 是否在被关闭的 worktree 内
317
+ 2. 仅当匹配时,调用对应 IDE 的 `--reuse-window` 命令切回 WS_ROOT:
318
+ - Qoder → `qoder --reuse-window "<ws_root>"`
319
+ - Cursor → `cursor --reuse-window "<ws_root>"`
320
+ - VS Code → `code --reuse-window "<ws_root>"`
321
+ 3. **JetBrains 跳过主动切换**——`idea64 <path>` 会启动新进程或提示"打开/在新窗口打开",让用户手动操作
322
+
323
+ **关键点**:
324
+ - **只在 pwd 匹配被关闭的 worktree 时触发**——如果 IDE 窗口本身在 WS_ROOT 内,或会话位于其他目录,再切一次是多余的
325
+ - **仅切 Qoder / Cursor / VS Code**——这三者的 `--reuse-window` 是轻量级"切目录",不重启 IDE
326
+ - **不会产生孤立窗口**——`--reuse-window` 是复用当前窗口切换目录,**不会打开新窗口**。即使 IDE 已开着指向 WS_ROOT 的其他窗口,本步骤也不会重复创建,仅是把当前指向已删除目录的窗口切走
327
+ - **失败不致命**——`--reuse-window` 失败时仅警告,后续分支删除不受影响
328
+
329
+ ### 4.4 分支处理(默认跳过,按需手动调用)
330
+
331
+ 默认 `MODE = keep`(见 Step 3.3),本步骤**不主动调用** `delete-branches.js`,本地分支与远程分支均保留。
332
+
333
+ 如用户在 Step 1.1 选定 worktree 时已要求"删除分支",或运行后需要单独清理,可在此步骤**手动调用**:
334
+
335
+ ```bash
336
+ node "<skill>/scripts/delete-branches.js" "<ws_root>" "<branch>" local
337
+ # 或
338
+ node "<skill>/scripts/delete-branches.js" "<ws_root>" "<branch>" local_remote
339
+ ```
340
+
341
+ 脚本内部对每个仓库:
342
+ - **本地分支**:检测是否已合并(复用 safety-check 的合并判定算法)
343
+ - 已合并 → `git branch -d`(安全删除)
344
+ - 未合并 → `git branch -D`(强制删除)
345
+ - squash 合并可能让 `-d` 失败 → 自动回退到 `-D`(squash 合并同样安全)
346
+ - **远程分支**(仅 `local_remote` 模式):`git push <remote> --delete <branch>`
347
+ - 分支不存在时 push --delete 会报错,按"已删除/本就无"处理即可
348
+ - 远程引用已在 Step 2.0 主动 fetch 刷新并持久化在 .git,此处直接读取无需重复 fetch
349
+
350
+ **解读末行 `BRANCH_DELETE_RESULT`**:
351
+ - `mode`:keep / local / local_remote
352
+ - `ok`:是否全部成功
353
+
354
+ > 默认跳过分支删除是安全红线的取舍:未合并分支误删会永久丢失提交、远程分支误删会冲击其他仓库/同事。保留为显式手动动作可让调用方在执行前再做一次审视。
355
+
356
+ > 关于 `.gitignore`:创建时把 `.worktrees/` 加入 `.gitignore` 并**提交到了 feature 分支**(非主分支)。
357
+ > - 分支未合并、被 `-D` 删除 → 这些 commit 随分支一起消失,主分支的 `.gitignore` 不受影响
358
+ > - 分支已合并到主分支 → `.gitignore` 条目留在主分支(无害,仅是忽略规则)
359
+ >
360
+ > 因此**关闭流程无需手动清理任何仓库的 `.gitignore`**,切忌画蛇添足去改主分支。
361
+
362
+ ---
363
+
364
+ ## Step 5:确认收尾
365
+
366
+ AI agent 主动 `cd` 回 WS_ROOT 并核对目标已彻底移除:
367
+
368
+ ```bash
369
+ git -C "<ws_root>" worktree list
370
+ ```
371
+
372
+ 目标 worktree 应已不在列表中。
373
+
374
+ ---
375
+
376
+ ## 最终报告
377
+
378
+ ```
379
+ ✅ 工作空间 worktree 已关闭
380
+ 当前目录:<工作空间根目录绝对路径>
381
+ 已移除 worktree:
382
+ - .worktrees/worktree-feature-xxx(workspace)
383
+ - .worktrees/worktree-feature-xxx/ep-user-info-server(嵌套,ep-user-info-server 仓库)
384
+ - .worktrees/worktree-feature-xxx/ep-user-management-app(嵌套,ep-user-management-app 仓库)
385
+ 未提交修改:已丢弃(--force)/ 无
386
+ 未归档 change 处理:
387
+ ✅ ai-call-send-im-msg → 已归档到 archive/2026-07-08-ai-call-send-im-msg
388
+ ⏭️ fix-payment-timeout → 用户选择跳过
389
+ (无未归档 change 时不显示本节)
390
+ 分支处理:feature-xxx 已保留(默认行为;如需删除分支,手动调用 scripts/delete-branches.js)
391
+ AI 配置:worktree 内独立安装,随 worktree 删除而清理;工作空间根目录的 AI 配置保留
392
+ 剩余工作空间 worktree:<列出仍存在的,或 "无" >
393
+ Workspace cleaned up.
394
+ ```
395
+
396
+ ---
397
+
398
+ ## 性能要点
399
+
400
+ 实测(5 仓库):本地操作(`merge-base`/`git cherry`/`status`)均毫秒级,**网络是唯一瓶颈**——主要是 Step 2.0 的主动 `git fetch`(~1s/仓库,需传输新增对象)。fetch 成功后 2.3 远程存在性改读本地引用,省掉原先的 `ls-remote`。
401
+
402
+ - Step 2.0 主动 fetch 刷新 `origin/master`、`origin/release-*`:是合并判定准确的前提
403
+ - Step 2 / Step 4.4 逐仓库检查与删除:原 bash 用 `&`+`wait` 实现并行,Node.js + execSync 实际是串行(Node 单线程),仍可通过 shell 启动多个脚本进程优化(本版本保持单进程简洁性)
404
+ - Step 4.4 删远程分支省掉 `push` 前 `ls-remote` 预查:`push --delete` 自带权威性
405
+
406
+ ## 红线与常见错误
407
+
408
+ ### 绝不允许
409
+
410
+ - 先删分支再删 worktree(分支正检出于 worktree,会报 `Cannot delete branch ... checked out at ...`)
411
+ - 未经用户确认用 `--force` 丢弃未提交修改,或主动调用 `delete-branches.js` 对未合并分支执行 `-D` 强删
412
+ - 操作 `.worktrees/worktree-<需求名>` 以外的任何 worktree(如 `~/.qoder/worktree/...` 会话 worktree)
413
+ - 移除/删除前跳过 Step 2 安全评估
414
+ - 删除工作空间根目录的 AI 配置目录(`.claude/`、`.qoder/`、`.cbb/` 等源目录)
415
+ - 用 `AskUserQuestion` 收集自由文本(分支名等直接对话提问)
416
+ - 手动改任何仓库的 `.gitignore`(关闭流程不碰它)
417
+ - 沙箱内 node 不可用时强行继续 → 改为 fail-fast 提示用户
418
+
419
+ ### 必须执行
420
+
421
+ - 读 `CONFIG.json` 取应用名列表;以 `.worktrees/worktree-<需求名>/<应用名>/` 实际存在性确定关联清单
422
+ - 移除/删除前执行安全评估(未提交修改 / 是否合并 / 是否推远程)并报告
423
+ - 严格按 Step 4.2(移除 worktree)→ Step 4.4(删分支)顺序
424
+ - 移除 workspace worktree 前先把会话移出(`cd "<WS_ROOT>" &&` 或 `git -C` 绝对路径)
425
+ - 收尾切回 WS 根目录、`pwd` 确认
426
+
427
+ ### 非显而易见的陷阱(含原因)
428
+
429
+ - **合并判定依赖刷新后的远程引用,故 Step 2.0 先主动 `git fetch`**:feature 多由他人经 MR 合入远端,本地引用否则会陈旧误判
430
+ - **并行块用临时文件收结果、不用共享变量**:原 bash 版本中 `&` 后台任务跑在独立子 shell;Node.js 同步执行无此问题
431
+ - **`.gitignore` 无需清理**:创建时的 `.worktrees/` 条目提交在 feature 分支上,删分支时随分支消失(未合并)或无害保留(已合并)
432
+ - **AI 配置目录在每个 worktree 内独立安装**:关闭 worktree 时这些目录随 worktree 目录一起删除
433
+ - **部分 `worktree remove` 失败**:已移除的无需回退,未移除的报告详情让用户处理后重跑
434
+ - **Windows IDE 目录锁的三层降级**:`git worktree remove` 内部做两件事——①清元数据 ②删目录。Windows 文件锁只阻塞 ②,不阻塞 ①
435
+
436
+ ---
437
+
438
+ ## 附录:脚本清单
439
+
440
+ | 脚本 | 功能 | 参数 | 退出码 |
441
+ |------|------|------|--------|
442
+ | `check-env.js` | 环境探活 | 无 | 0/1/2 |
443
+ | `find-workspace-root.js` | 定位工作空间根目录(共享脚本,源仓库真源在 `_shared/scripts/`) | 无 | 0/1 |
444
+ | `find-target-worktree.js` | 目标 worktree 识别(共享脚本,源仓库真源在 `_shared/scripts/`) | ws_root | 0/1/2 |
445
+ | `discover-apps.js` | 发现关联应用 worktree | ws_root, branch | 0/1/2 |
446
+ | `check-unarchived.js` | 检查未归档 change | ws_root | 0/1 |
447
+ | `safety-check.js` | 安全评估(合并判定 + 未提交 + 远程) | ws_root, branch | 0/1 |
448
+ | `remove-worktrees.js` | 移除 worktree(三层降级) | ws_root, branch, force | 0/1 |
449
+ | `delete-branches.js` | 删除分支(按 mode) | ws_root, branch, mode | 0/1/2 |
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ require('./silence-popup');
3
+ /**
4
+ * openspec-close-worktree 环境健康探活
5
+ *
6
+ * close-worktree 必须在工作空间根目录或 worktree 内执行,且需找到 CONFIG.json。
7
+ * 与 init/extend 探活同构,但额外校验 CONFIG.json 存在性。
8
+ *
9
+ * 退出码:
10
+ * 0 - 探活通过
11
+ * 1 - 致命错误(git 不可用)
12
+ * 2 - 当前不在 git 仓库
13
+ * 3 - 未找到 CONFIG.json
14
+ */
15
+
16
+ const { execSync } = require('child_process');
17
+ const fs = require('fs');
18
+
19
+ function tryExec(cmd, opts = {}) {
20
+ try {
21
+ const out = execSync(cmd, {
22
+ encoding: 'utf-8',
23
+ stdio: ['ignore', 'pipe', 'pipe'],
24
+ ...opts,
25
+ });
26
+ return { ok: true, out: out.trim() };
27
+ } catch (e) {
28
+ return { ok: false, err: (e.stderr || e.message || String(e)).trim() };
29
+ }
30
+ }
31
+
32
+ const checks = {};
33
+
34
+ // ── 必检:git ─────────────────────────────────────────
35
+ checks.git = tryExec('git --version');
36
+ if (!checks.git.ok) {
37
+ console.error('❌ git 启动失败(可能是 Qoder 沙箱 DLL 问题 0xc0000142)');
38
+ console.error(' 解决方案:到系统终端重新执行本技能');
39
+ process.exit(1);
40
+ }
41
+ console.log('✅ git OK:', checks.git.out);
42
+
43
+ // ── 必检:当前目录是 git 仓库 ─────────────────────────
44
+ const insideRepo = tryExec('git rev-parse --is-inside-work-tree');
45
+ if (!insideRepo.ok || insideRepo.out !== 'true') {
46
+ console.error('❌ 当前目录不是 Git 仓库');
47
+ console.error(' close-worktree 必须在工作空间根目录或 worktree 内执行');
48
+ process.exit(2);
49
+ }
50
+ console.log('✅ 当前目录是 git 仓库');
51
+
52
+ // ── 选检:node.js(脚本运行时,所有 .js 脚本依赖) ──
53
+ checks.node = tryExec('node --version');
54
+ if (!checks.node.ok) {
55
+ console.log('⚠️ node 不可用(脚本将无法执行,建议安装 Node.js >= 16.7.0)');
56
+ } else {
57
+ console.log('✅ node OK:', checks.node.out);
58
+ }
59
+
60
+ // ── 沙箱检测 ─────────────────────────────────────────
61
+ const inWorktree = !!(process.env.QODER_AGENT || process.env.QODER_WORKTREE);
62
+ if (inWorktree) {
63
+ console.log('🛡️ Qoder 沙箱环境:移除 worktree 时如遇 IDE 锁,将降级处理');
64
+ } else {
65
+ console.log('✅ 非沙箱环境');
66
+ }
67
+
68
+ const summary = {
69
+ git: checks.git.ok,
70
+ node: checks.node.ok,
71
+ inWorktree,
72
+ ok: true,
73
+ };
74
+ console.log('---');
75
+ console.log('ENV_OK', JSON.stringify(summary));
76
+ process.exit(0);
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ require('./silence-popup');
3
+ /**
4
+ * openspec-close-worktree 未归档 change 检查
5
+ *
6
+ * 用法:node check-unarchived.js <ws_root>
7
+ *
8
+ * 扫描 openspec/changes/ 目录,筛选出非 archive/ 子目录的 change 名称列表。
9
+ * 本检查为信息收集性质,不阻断流程。
10
+ *
11
+ * 退出码:
12
+ * 0 - 检查完成(无论是否有未归档 change)
13
+ * 1 - 参数错误或 openspec/changes/ 目录不存在
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+
19
+ const wsRoot = process.argv[2];
20
+
21
+ if (!wsRoot) {
22
+ console.error('Usage: node check-unarchived.js <ws_root>');
23
+ process.exit(1);
24
+ }
25
+
26
+ const changesDir = path.join(wsRoot, 'openspec', 'changes');
27
+
28
+ if (!fs.existsSync(changesDir)) {
29
+ console.log('UNARCHIVED_RESULT {"changes":[]}');
30
+ process.exit(0);
31
+ }
32
+
33
+ let entries;
34
+ try {
35
+ entries = fs.readdirSync(changesDir, { withFileTypes: true });
36
+ } catch (e) {
37
+ console.error('Failed to read openspec/changes/:', e.message);
38
+ console.log('UNARCHIVED_RESULT {"changes":[]}');
39
+ process.exit(0);
40
+ }
41
+
42
+ const unarchived = entries
43
+ .filter(e => e.isDirectory() && e.name !== 'archive')
44
+ .map(e => e.name)
45
+ .sort();
46
+
47
+ console.log('UNARCHIVED_RESULT', JSON.stringify({ changes: unarchived }));
48
+ process.exit(0);