kld-sdd 2.4.16 → 2.4.17

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/lib/init.js CHANGED
@@ -547,8 +547,8 @@ function hookCommandText(hook) {
547
547
 
548
548
  function isSddClaudeHook(hook) {
549
549
  const text = hookCommandText(hook);
550
- return /(?:^|\s|["'])\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text) ||
551
- /(?:^|\s|["'])\$\{CLAUDE_PROJECT_DIR\}[\\/]+\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text);
550
+ return /(?:^|\s|["'])\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text) ||
551
+ /(?:^|\s|["'])\$\{CLAUDE_PROJECT_DIR\}[\\/]+\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text);
552
552
  }
553
553
 
554
554
  function sameHookCommand(left, right) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kld-sdd",
3
- "version": "2.4.16",
3
+ "version": "2.4.17",
4
4
  "description": "KLD SDD OpenSpec 项目初始化工具 - 一键部署 SDD skills",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  * 检查逻辑:
9
9
  * 1. 检测当前是否存在活跃的 apply 阶段(state 文件)
10
10
  * 2. 若存在,回溯 events 目录确认 check 阶段是否已完成
11
- * 3. 若 check 未完成,阻断本次写入并提示用户先执行 /opsx:check
11
+ * 3. 若 check 未完成,阻断本次写入并提示用户先执行 /opsx-check
12
12
  */
13
13
  const fs = require('fs');
14
14
  const path = require('path');
@@ -110,7 +110,7 @@ function hasCompletedCheck(projectRoot, changeName) {
110
110
  for (let i = lines.length - 1; i >= 0; i--) {
111
111
  try {
112
112
  const event = JSON.parse(lines[i]);
113
- if (event.type === 'stage_end' && event.command === 'check' && event.result === 'success') {
113
+ if (event.type === 'stage_end' && event.command === 'check' && (event.result === 'success' || event.result === 'partial')) {
114
114
  return true;
115
115
  }
116
116
  } catch {
@@ -125,16 +125,18 @@ function hasCompletedCheck(projectRoot, changeName) {
125
125
  }
126
126
 
127
127
  /**
128
- * 将 change 名称转为安全的目录名(与 log.cjs 中 safeChangeName 逻辑一致)
128
+ * 将 change 名称转为安全的目录名(与 L1 门禁 && log.cjs 中 safeChangeName 逻辑一致)
129
+ *
130
+ * 规则:转小写 → 空格/下划线转连字符 → 剔除非法字符 → 压缩连字符 → 去头尾连字符
129
131
  */
130
132
  function safeChangeName(name) {
131
- if (!name) return 'general';
133
+ if (!name) return '';
132
134
  return String(name)
133
- .replace(/[\\/:*?"<>|]/g, '-')
134
- .replace(/[\s.]+/g, '-')
135
+ .toLowerCase()
136
+ .replace(/[\s_]+/g, '-')
137
+ .replace(/[^a-z0-9一-鿿\-]/g, '-')
135
138
  .replace(/-+/g, '-')
136
- .replace(/^-|-$/g, '')
137
- .toLowerCase() || 'general';
139
+ .replace(/^-|-$/g, '');
138
140
  }
139
141
 
140
142
  // ── 主逻辑 ─────────────────────────────────────────────────
@@ -166,6 +168,6 @@ if (hasCompletedCheck(projectRoot, activeApply.change)) {
166
168
  const changeName = activeApply.change || 'unknown';
167
169
  console.log(JSON.stringify({
168
170
  decision: 'block',
169
- reason: `[SDD Apply Gate] 检测到 apply 阶段正在执行(change: ${changeName}),但 check 阶段尚未完成。\n\n请先执行 /opsx:check 完成质量门禁检查,再执行 /opsx:apply 进行代码实施。\n\n操作顺序:/opsx:check → /opsx:apply`,
171
+ reason: `[SDD Apply Gate] 检测到 apply 阶段正在执行(change: ${changeName}),但 check 阶段尚未完成。\n\n请先执行 /opsx-check 完成质量门禁检查,再执行 /opsx-apply 进行代码实施。\n\n操作顺序:/opsx-check → /opsx-apply`,
170
172
  }));
171
173
  process.exit(2);
@@ -0,0 +1,267 @@
1
+ /**
2
+ * sdd-skill-apply-gate.cjs
3
+ *
4
+ * PreToolUse(Skill) 门禁 —— 在 opsx-apply Skill 被调用的瞬间阻断,不再等到 Write/Edit 阶段。
5
+ *
6
+ * 三层门禁体系中的第一层:
7
+ * L1: sdd-skill-apply-gate (PreToolUse/Skill) ← 本文件
8
+ * L2: sdd-apply-gate (PreToolUse/Write|Edit)
9
+ * L3: SKILL.md Step 1.2 (Skill 自检)
10
+ *
11
+ * 判定逻辑:
12
+ * - 非 opsx-apply 调用 → 放行
13
+ * - 提供了 change-name → 检查该变更是否已完成 check,未完成则阻断
14
+ * - 未提供 change-name → 扫描所有变更,只要有一个已完成 check 则放行,否则阻断
15
+ *
16
+ * 退出码约定(遵循 Claude Code hook 规范):
17
+ * 0 → 放行(stdout 可为空,或输出允许决策 JSON)
18
+ * 2 → 阻断(stdout 需包含 { decision: "block", reason: "..." })
19
+ */
20
+
21
+ 'use strict';
22
+
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // 工具函数
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /** 读取 stdin(与 sdd-prompt.cjs 保持一致的简洁实现) */
31
+ function readStdin() {
32
+ try {
33
+ return fs.readFileSync(0, 'utf8');
34
+ } catch (_) {
35
+ return '';
36
+ }
37
+ }
38
+
39
+ /** 安全解析 hook 输入 JSON */
40
+ function parseInput(raw) {
41
+ if (!raw || !raw.trim()) return null;
42
+ try {
43
+ return JSON.parse(raw);
44
+ } catch (_) {
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 向上查找项目根目录 —— 以 skywalk-sdd/log.cjs 文件存在为标志
51
+ */
52
+ function findProjectRoot(startDir) {
53
+ let dir = startDir;
54
+ for (let i = 0; i < 20; i++) {
55
+ if (fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.cjs'))) {
56
+ return dir;
57
+ }
58
+ const parent = path.dirname(dir);
59
+ if (parent === dir) break;
60
+ dir = parent;
61
+ }
62
+ return null;
63
+ }
64
+
65
+ /** 从 hook 输入中提取项目根目录 */
66
+ function getProjectRoot(input) {
67
+ if (!input) return null;
68
+ const cwd = input.cwd || process.cwd();
69
+ return findProjectRoot(cwd);
70
+ }
71
+
72
+ /**
73
+ * 规范化变更名称 —— 与 openspec/changes/ 下的目录名保持一致
74
+ * 规则:
75
+ * - 转小写
76
+ * - 特殊字符 → 连字符
77
+ * - 中文保留原样
78
+ */
79
+ function safeChangeName(name) {
80
+ if (!name) return '';
81
+ return name
82
+ .toLowerCase()
83
+ .replace(/[\s_]+/g, '-')
84
+ .replace(/[^a-z0-9一-鿿\-]/g, '-')
85
+ .replace(/-+/g, '-')
86
+ .replace(/^-|-$/g, '');
87
+ }
88
+
89
+ /**
90
+ * 判断指定变更是否已完成 check 阶段。
91
+ *
92
+ * 检测方式:读取 skywalk-sdd/events/<changeName>/ 下的 JSONL 事件文件,
93
+ * 查找 stage_end + command=check + result=success 事件。
94
+ */
95
+ function hasCompletedCheck(projectRoot, changeName) {
96
+ if (!projectRoot || !changeName) return false;
97
+ const eventsDir = path.join(projectRoot, 'skywalk-sdd', 'events', changeName);
98
+ if (!fs.existsSync(eventsDir)) return false;
99
+
100
+ try {
101
+ const files = fs.readdirSync(eventsDir).filter(f => f.endsWith('.jsonl'));
102
+ for (const file of files) {
103
+ const filePath = path.join(eventsDir, file);
104
+ const content = fs.readFileSync(filePath, 'utf8');
105
+ const lines = content.split('\n').filter(l => l.trim());
106
+ for (const line of lines) {
107
+ try {
108
+ const evt = JSON.parse(line);
109
+ if (
110
+ evt.type === 'stage_end' &&
111
+ evt.command === 'check' &&
112
+ (evt.result === 'success' || evt.result === 'partial')
113
+ ) {
114
+ return true;
115
+ }
116
+ } catch (_) { /* skip malformed lines */ }
117
+ }
118
+ }
119
+ } catch (_) {
120
+ return false;
121
+ }
122
+ return false;
123
+ }
124
+
125
+ /**
126
+ * 扫描 openspec/changes/ 下所有已通过 check 的变更。
127
+ * 返回已通过 check 的变更名称列表。
128
+ */
129
+ function getPassedChanges(projectRoot) {
130
+ if (!projectRoot) return [];
131
+ const changesDir = path.join(projectRoot, 'openspec', 'changes');
132
+ if (!fs.existsSync(changesDir)) return [];
133
+
134
+ const passed = [];
135
+ try {
136
+ const entries = fs.readdirSync(changesDir, { withFileTypes: true });
137
+ for (const entry of entries) {
138
+ if (!entry.isDirectory()) continue;
139
+ if (entry.name.startsWith('.')) continue;
140
+ if (entry.name === 'archive') continue;
141
+ if (hasCompletedCheck(projectRoot, entry.name)) {
142
+ passed.push(entry.name);
143
+ }
144
+ }
145
+ } catch (_) { /* ignore */ }
146
+ return passed;
147
+ }
148
+
149
+ /**
150
+ * 判断给定的 tool_input 字符串是否为 opsx-apply Skill 调用。
151
+ *
152
+ * Skill 的 tool_input 格式为 JSON 字符串: {"skill": "opsx-apply", "args": "..."}
153
+ */
154
+ function isOpsxApplySkill(toolInput) {
155
+ if (!toolInput) return false;
156
+ let input;
157
+ if (typeof toolInput === 'string') {
158
+ try { input = JSON.parse(toolInput); } catch (_) { return false; }
159
+ } else {
160
+ input = toolInput;
161
+ }
162
+ if (!input || typeof input !== 'object') return false;
163
+ const skill = input.skill || '';
164
+ return skill === 'opsx-apply';
165
+ }
166
+
167
+ /**
168
+ * 从 tool_input 中提取 change-name。
169
+ * opsx-apply 的 args 格式为: "change-name" 或 "--change change-name"
170
+ */
171
+ function extractChangeName(toolInput) {
172
+ if (!toolInput) return null;
173
+ let input;
174
+ if (typeof toolInput === 'string') {
175
+ try { input = JSON.parse(toolInput); } catch (_) { return null; }
176
+ } else {
177
+ input = toolInput;
178
+ }
179
+ if (!input || typeof input !== 'object') return null;
180
+
181
+ const args = input.args || '';
182
+ if (!args.trim()) return null;
183
+
184
+ // args 可能是 "change-name" 或 "--change change-name ..." 格式
185
+ const trimmed = args.trim();
186
+
187
+ // 尝试 --change <name> 格式
188
+ const changeFlagMatch = trimmed.match(/^--change\s+(.+)$/);
189
+ if (changeFlagMatch) {
190
+ return safeChangeName(changeFlagMatch[1].trim().split(/\s+/)[0]);
191
+ }
192
+
193
+ // 否则整个 args 的第一个 token 就是 change-name
194
+ const firstToken = trimmed.split(/\s+/)[0];
195
+ return safeChangeName(firstToken);
196
+ }
197
+
198
+ // ---------------------------------------------------------------------------
199
+ // 主逻辑
200
+ // ---------------------------------------------------------------------------
201
+
202
+ function main() {
203
+ const raw = readStdin();
204
+ const input = parseInput(raw);
205
+
206
+ if (!input) {
207
+ // 无法解析输入,保守放行(避免阻断非 opsx-apply 操作)
208
+ process.exit(0);
209
+ }
210
+
211
+ // --- 仅处理 Skill 工具调用 ---
212
+ const toolName = input.tool_name || '';
213
+ if (toolName !== 'Skill') {
214
+ // 非 Skill 调用,放行
215
+ process.exit(0);
216
+ }
217
+
218
+ // --- 确认是否为 opsx-apply ---
219
+ const toolInput = input.tool_input;
220
+ if (!isOpsxApplySkill(toolInput)) {
221
+ // 不是 opsx-apply skill,放行
222
+ process.exit(0);
223
+ }
224
+
225
+ // --- 确定项目根目录 ---
226
+ const projectRoot = getProjectRoot(input);
227
+ if (!projectRoot) {
228
+ // 找不到项目根目录,说明不在 kld-sdd 项目中,放行
229
+ process.exit(0);
230
+ }
231
+
232
+ // --- 提取 change-name ---
233
+ const changeName = extractChangeName(toolInput);
234
+
235
+ if (changeName) {
236
+ // 场景 A:指定了 change-name → 精确检查
237
+ if (hasCompletedCheck(projectRoot, changeName)) {
238
+ process.exit(0); // 已通过 check,放行
239
+ }
240
+ // 未通过 check,阻断
241
+ const reason = `变更 "${changeName}" 尚未完成 check 阶段。请先执行 /opsx-check ${changeName} 完成检查后再 apply。`;
242
+ console.log(JSON.stringify({ decision: 'block', reason }));
243
+ process.exit(2);
244
+ } else {
245
+ // 场景 B:未指定 change-name → 扫描所有变更
246
+ const passedChanges = getPassedChanges(projectRoot);
247
+
248
+ if (passedChanges.length === 0) {
249
+ const reason = '当前项目没有任何变更已完成 check 阶段。请先执行 /opsx-check <change-name> 完成检查后再 apply。';
250
+ console.log(JSON.stringify({ decision: 'block', reason }));
251
+ process.exit(2);
252
+ }
253
+
254
+ // 有已通过 check 的变更,放行(后续由 Skill 自身引导用户选择)
255
+ if (passedChanges.length === 1) {
256
+ const msg = `检测到已通过 check 的变更: "${passedChanges[0]}",允许进入 apply。`;
257
+ console.log(JSON.stringify({ decision: 'allow', reason: msg }));
258
+ } else {
259
+ const msg = `检测到 ${passedChanges.length} 个已通过 check 的变更: ${passedChanges.join(', ')},允许进入 apply。`;
260
+ console.log(JSON.stringify({ decision: 'allow', reason: msg }));
261
+ }
262
+ process.exit(0);
263
+ }
264
+ }
265
+
266
+ // --- 入口 ---
267
+ main();
@@ -11,6 +11,15 @@
11
11
  }
12
12
  ],
13
13
  "PreToolUse": [
14
+ {
15
+ "matcher": "Skill",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/sdd-skill-apply-gate.cjs\""
20
+ }
21
+ ]
22
+ },
14
23
  {
15
24
  "matcher": "Bash",
16
25
  "hooks": [
@@ -129,20 +129,20 @@ openspec list --json
129
129
  > **必须先执行质量门禁检查,再开始代码实施:**
130
130
  >
131
131
  > ```
132
- > /opsx:check <change-name>
132
+ > /opsx-check <change-name>
133
133
  > ```
134
134
  >
135
135
  > **原因**:check 阶段验证文档完整性、一致性、可执行性,跳过 check 直接 apply 可能导致需求误解或设计缺陷。
136
136
  >
137
- > **操作顺序**:`/opsx:check → /opsx:apply`
137
+ > **操作顺序**:`/opsx-check → /opsx-apply`
138
138
  >
139
139
  > 是否要现在执行 check?"
140
140
 
141
- - 若用户确认执行 check → 引导执行 `/opsx:check`
141
+ - 若用户确认执行 check → 引导执行 `/opsx-check`
142
142
  - 若用户坚持跳过 → **强制拒绝**,不得跳过 check 直接 apply
143
143
 
144
144
  4. **若 telemetry 数据缺失**(如新项目无历史数据):
145
- > "⚠️ 未找到 check 阶段记录。如果这是首次执行,请先运行 `/opsx:check <change-name>` 完成质量门禁。
145
+ > "⚠️ 未找到 check 阶段记录。如果这是首次执行,请先运行 `/opsx-check <change-name>` 完成质量门禁。
146
146
  >
147
147
  > 是否要现在执行 check?"
148
148
 
@@ -343,7 +343,7 @@ node skywalk-sdd/log.cjs record --type=ai_adoption_review --command=apply --proj
343
343
 
344
344
  ## Guardrails
345
345
 
346
- - **⛔ Check 门禁检查**:apply 阶段开始前,必须确认 check 阶段已完成。若 check 未完成,**强制拒绝** apply,引导用户先执行 `/opsx:check`。与 `sdd-apply-gate.cjs` Hook 形成双重保障。
346
+ - **⛔ Check 门禁检查**:apply 阶段开始前,必须确认 check 阶段已完成。若 check 未完成,**强制拒绝** apply,引导用户先执行 `/opsx-check`。与 `sdd-apply-gate.cjs` Hook 形成双重保障。
347
347
  - **⛔ 渐进式加载**:只加载当前 Capability 的四文档链
348
348
  - **⛔ 隔离红线**:绝对禁止加载同级其他 Capability 的文档
349
349
  - **⛔ DAG 依赖拦截**:执行任务前必须检查依赖,前置未完成必须拦截
@@ -23,7 +23,7 @@ allowed-tools:
23
23
  > - ❌ **禁止**:创建/修改任何代码文件、执行代码生成、运行测试
24
24
  >
25
25
  > 即使检查发现代码相关问题,也只记录在检查报告中,**不自动修复代码**。
26
- > 代码修复将在 `/opsx:apply` 阶段进行。
26
+ > 代码修复将在 `/opsx-apply` 阶段进行。
27
27
 
28
28
 
29
29
  > **🖥️ 跨平台执行规则**
@@ -58,7 +58,7 @@ allowed-tools:
58
58
  openspec list
59
59
  ```
60
60
 
61
- 若变更不存在,提示用户先运行 `/opsx:propose <name>` 创建变更。
61
+ 若变更不存在,提示用户先运行 `/opsx-propose <name>` 创建变更。
62
62
 
63
63
  ### 2. 读取完整文档链
64
64
 
@@ -168,13 +168,13 @@ node skywalk-sdd/log.cjs record --type=conformance_review --command=check --proj
168
168
 
169
169
  **全部通过**:
170
170
  > "✅ 质量检查通过!建议下一步:
171
- > - A. 运行 `/opsx:apply` 开始实施
171
+ > - A. 运行 `/opsx-apply` 开始实施
172
172
  > - B. 再次确认某个文档细节"
173
173
 
174
174
  **有问题**:
175
175
  > "❌ 发现 [N] 个问题需要修复:
176
- > - 问题 1:[描述] → 建议运行 `/opsx:spec` 修复
177
- > - 问题 2:[描述] → 建议运行 `/opsx:design` 修复
176
+ > - 问题 1:[描述] → 建议运行 `/opsx-spec` 修复
177
+ > - 问题 2:[描述] → 建议运行 `/opsx-design` 修复
178
178
  >
179
179
  > 请选择:
180
180
  > - A. 逐个修复(引导到对应命令)
@@ -23,7 +23,7 @@ allowed-tools:
23
23
  > - ❌ **禁止**:创建/修改任何代码文件、执行代码生成、运行测试
24
24
  > - ⛔ **单阶段原则**:完成 design.md 后**必须立即停止**,等待用户主动触发下一阶段
25
25
  >
26
- > 代码实现将在 `/opsx:apply` 阶段进行。
26
+ > 代码实现将在 `/opsx-apply` 阶段进行。
27
27
  > **完成本阶段后,绝对禁止自动继续执行 task 等后续阶段。**
28
28
 
29
29
  > **⚠️ 渐进式上下文加载原则**
@@ -172,7 +172,7 @@ openspec list
172
172
 
173
173
  最终输出:
174
174
  - 文档路径
175
- - 下一步提示:"运行 `/opsx:task <name> <capability>` 创建任务拆解文档"
175
+ - 下一步提示:"运行 `/opsx-task <name> <capability>` 创建任务拆解文档"
176
176
 
177
177
  ---
178
178
 
@@ -185,4 +185,4 @@ openspec list
185
185
  - 必须 100% 覆盖 spec.md 定义的需求项
186
186
  - 代码锚点必须具体到类/方法级别
187
187
  - **⛔ 阶段边界**:禁止执行任何代码创建/修改操作
188
- - **⛔ 单阶段原则:完成 design.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx:task`,**绝对禁止自动执行 task 等后续阶段**。每个阶段必须由用户主动触发。
188
+ - **⛔ 单阶段原则:完成 design.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx-task`,**绝对禁止自动执行 task 等后续阶段**。每个阶段必须由用户主动触发。
@@ -47,7 +47,7 @@ openspec list
47
47
  ```
48
48
 
49
49
  若没有任何变更,提示:
50
- > "当前项目还没有任何变更。运行 `/opsx:propose <变更描述>` 开始第一个变更。"
50
+ > "当前项目还没有任何变更。运行 `/opsx-propose <变更描述>` 开始第一个变更。"
51
51
 
52
52
  ### 2. 检查每个变更的 SDD 文档完整性
53
53
 
@@ -68,18 +68,18 @@ openspec status --change "<name>" --json
68
68
  >
69
69
  > | 变更名称 | P | S | D | T | openspec状态 | 建议下一步 |
70
70
  > |---------|---|---|---|---|------------|---------|
71
- > | add-user-auth | ✅ | ✅ | ✅ | ❌ | PENDING | `/opsx:task add-user-auth` |
72
- > | payment-refund | ✅ | ❌ | ❌ | ❌ | PENDING | `/opsx:spec payment-refund` |
73
- > | points-exchange | ✅ | ✅ | ✅ | ✅ | IMPLEMENTING | `/opsx:check points-exchange` |"
71
+ > | add-user-auth | ✅ | ✅ | ✅ | ❌ | PENDING | `/opsx-task add-user-auth` |
72
+ > | payment-refund | ✅ | ❌ | ❌ | ❌ | PENDING | `/opsx-spec payment-refund` |
73
+ > | points-exchange | ✅ | ✅ | ✅ | ✅ | IMPLEMENTING | `/opsx-check points-exchange` |"
74
74
 
75
75
  ### 4. 【交互引导】选择操作
76
76
 
77
77
  使用 **AskUserQuestion** 让用户选择:
78
78
  > "请选择操作:
79
79
  > - A. 查看变更详情:输入变更名称
80
- > - B. 创建新变更:运行 `/opsx:propose`
81
- > - C. 执行质量检查:运行 `/opsx:check <name>`
82
- > - D. 申请实施:运行 `/opsx:apply <name>`
80
+ > - B. 创建新变更:运行 `/opsx-propose`
81
+ > - C. 执行质量检查:运行 `/opsx-check <name>`
82
+ > - D. 申请实施:运行 `/opsx-apply <name>`
83
83
  > - E. 退出浏览"
84
84
 
85
85
  ### 5. 若用户选择查看详情
@@ -24,7 +24,7 @@ allowed-tools:
24
24
  > - ⛔ **单阶段原则**:完成 proposal.md 后**必须立即停止**,等待用户主动触发下一阶段
25
25
  >
26
26
  > 即使用户提供了代码作为上下文,也只用于理解需求背景,**不执行任何代码操作**。
27
- > 代码实现请引导用户使用 `/opsx:apply` 命令。
27
+ > 代码实现请引导用户使用 `/opsx-apply` 命令。
28
28
  > **完成本阶段后,绝对禁止自动继续执行 spec/design/task 等后续阶段。**
29
29
 
30
30
 
@@ -80,7 +80,7 @@ allowed-tools:
80
80
  ### 2. 【上下文加载】识别并读取用户提供的文件
81
81
 
82
82
  **自动识别上下文文件**:
83
- 若用户在命令中指定了文件路径(如 `/opsx:propose atp-calc ./需求.md ./算法逻辑.md`),
83
+ 若用户在命令中指定了文件路径(如 `/opsx-propose atp-calc ./需求.md ./算法逻辑.md`),
84
84
  或在对话中附加/引用了文件,**必须自动读取这些文件**。
85
85
 
86
86
  **上下文处理原则**:
@@ -249,7 +249,7 @@ openspec instructions proposal --change "<name>" --json
249
249
  最终输出:
250
250
  - 文档路径
251
251
  - 内容摘要
252
- - 下一步提示:"运行 `/opsx:spec` 创建技术契约文档 (specs/<capability>/spec.md)"
252
+ - 下一步提示:"运行 `/opsx-spec` 创建技术契约文档 (specs/<capability>/spec.md)"
253
253
 
254
254
  ---
255
255
 
@@ -263,5 +263,5 @@ openspec instructions proposal --change "<name>" --json
263
263
  - 若跳过此文档,后续 specs 必须补齐影响范围
264
264
  - 文档写入后验证文件确实存在
265
265
  - 每次生成都提供文档摘要,等待用户确认后再继续
266
- - **⛔ 阶段边界**:本阶段禁止执行任何代码创建/修改操作。若用户要求处理代码,回复:「当前处于 Propose 阶段,代码操作请在完成文档后使用 `/opsx:apply` 执行。」
267
- - **⛔ 单阶段原则:完成 proposal.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx:spec`,**绝对禁止自动执行 spec/design/task 等后续阶段**。每个阶段必须由用户主动触发。
266
+ - **⛔ 阶段边界**:本阶段禁止执行任何代码创建/修改操作。若用户要求处理代码,回复:「当前处于 Propose 阶段,代码操作请在完成文档后使用 `/opsx-apply` 执行。」
267
+ - **⛔ 单阶段原则:完成 proposal.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx-spec`,**绝对禁止自动执行 spec/design/task 等后续阶段**。每个阶段必须由用户主动触发。
@@ -24,7 +24,7 @@ allowed-tools:
24
24
  > - ⛔ **单阶段原则**:完成 spec.md 后**必须立即停止**,等待用户主动触发下一阶段
25
25
  >
26
26
  > 即使用户提供了代码作为上下文,也只用于分析现有实现,**不执行任何代码操作**。
27
- > 代码实现将在 `/opsx:apply` 阶段进行。
27
+ > 代码实现将在 `/opsx-apply` 阶段进行。
28
28
  > **完成本阶段后,绝对禁止自动继续执行 design/task 等后续阶段。**
29
29
 
30
30
 
@@ -72,7 +72,7 @@ openspec/changes/<name>/
72
72
  ```bash
73
73
  openspec list
74
74
  ```
75
- 若变更不存在,引导用户先运行 `/opsx:propose <name>`。
75
+ 若变更不存在,引导用户先运行 `/opsx-propose <name>`。
76
76
 
77
77
  ### 2. 【交互引导】确认 Capability
78
78
 
@@ -184,7 +184,7 @@ openspec list
184
184
 
185
185
  最终输出:
186
186
  - 文档路径
187
- - 下一步提示:"运行 `/opsx:design <name> <capability>` 创建技术设计文档"
187
+ - 下一步提示:"运行 `/opsx-design <name> <capability>` 创建技术设计文档"
188
188
 
189
189
  ---
190
190
 
@@ -196,4 +196,4 @@ openspec list
196
196
  - 每个需求项必须有清晰的验收标准
197
197
  - 技术契约必须可执行、无歧义
198
198
  - **⛔ 阶段边界**:禁止执行任何代码创建/修改操作
199
- - **⛔ 单阶段原则:完成 spec.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx:design`,**绝对禁止自动执行 design/task 等后续阶段**。每个阶段必须由用户主动触发。
199
+ - **⛔ 单阶段原则:完成 spec.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx-design`,**绝对禁止自动执行 design/task 等后续阶段**。每个阶段必须由用户主动触发。
@@ -24,7 +24,7 @@ allowed-tools:
24
24
  > - ⛔ **单阶段原则**:完成 tasks.md 后**必须立即停止**,等待用户主动触发下一阶段
25
25
  >
26
26
  > tasks.md 定义的是「待执行的任务清单」,**不是立即执行代码**。
27
- > 请引导用户使用 `/opsx:apply` 进入实施阶段。
27
+ > 请引导用户使用 `/opsx-apply` 进入实施阶段。
28
28
  > **完成本阶段后,绝对禁止自动继续执行 apply/check 等后续阶段。**
29
29
 
30
30
  > **⚠️ 渐进式上下文加载原则**
@@ -200,7 +200,7 @@ allowed-tools:
200
200
 
201
201
  最终输出:
202
202
  - 文档路径
203
- - 下一步提示:"运行 `/opsx:check <name>` 执行质量检查,或 `/opsx:apply <name> <capability>` 开始实施"
203
+ - 下一步提示:"运行 `/opsx-check <name>` 执行质量检查,或 `/opsx-apply <name> <capability>` 开始实施"
204
204
 
205
205
  ---
206
206
 
@@ -213,4 +213,4 @@ allowed-tools:
213
213
  - **⛔ 无循环依赖**:DAG 中不允许存在环
214
214
  - 任务颗粒度宁可过细也不要过粗
215
215
  - **⛔ 阶段边界**:禁止执行任何代码创建/修改操作
216
- - **⛔ 单阶段原则:完成 tasks.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx:check` 或 `/opsx:apply`,**绝对禁止自动执行 apply/check 等后续阶段**。每个阶段必须由用户主动触发。
216
+ - **⛔ 单阶段原则:完成 tasks.md 后必须立即停止**。仅提示用户下一步可运行 `/opsx-check` 或 `/opsx-apply`,**绝对禁止自动执行 apply/check 等后续阶段**。每个阶段必须由用户主动触发。
@@ -19,7 +19,7 @@ allowed-tools:
19
19
 
20
20
  > **⚠️ 命令定位**
21
21
  >
22
- > 本技能专注于**单元测试执行**,是 `/opsx:apply` 流程的可选验证环节。
22
+ > 本技能专注于**单元测试执行**,是 `/opsx-apply` 流程的可选验证环节。
23
23
  > - 用户可在完成代码实现后主动调用
24
24
  > - 输出标准化测试报告,便于质量追踪
25
25
 
@@ -124,7 +124,7 @@ allowed-tools:
124
124
  **全部通过**:
125
125
  > "✅ 所有测试通过!建议下一步:
126
126
  > - A. 继续实施下一个任务
127
- > - B. 运行 `/opsx:archive` 归档变更"
127
+ > - B. 运行 `/opsx-archive` 归档变更"
128
128
 
129
129
  **有失败**:
130
130
  > "❌ [N] 个测试失败,请选择: