@localsummer/incspec 0.2.5 → 0.3.0

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 CHANGED
@@ -142,9 +142,36 @@ AI 编程助手在处理复杂前端代码库时常常力不从心,因为 API
142
142
  └────────────────────┘
143
143
  ```
144
144
 
145
+ ### 极简模式 (3步)
146
+
147
+ 适用于紧急修复、单文件小改动、不需要新基线的变更。
148
+
149
+ ```
150
+ ┌────────────────────┐
151
+ │ 1. 分析 │ 分析现有代码流程
152
+ │ 代码流程 │ 生成基线快照
153
+ └────────┬───────────┘
154
+
155
+
156
+ ┌────────────────────┐
157
+ │ 5. 应用 │ 基于口头需求
158
+ │ 变更 │ 直接实现代码变更
159
+ └────────┬───────────┘
160
+
161
+
162
+ ┌────────────────────┐
163
+ │ 7. 归档 │ 归档本轮产出
164
+ │ 产出 │ 清空工作区
165
+ └────────────────────┘
166
+ ```
167
+
145
168
  **模式选择建议:**
146
169
  - **完整模式**: 复杂 UI 功能、多组件交互、需要详细设计审查
147
170
  - **快速模式**: Bug 修复、简单功能、不涉及 UI 依赖变更
171
+ - **极简模式**: 紧急修复、单文件小改动、无需生成新基线
172
+
173
+ **模式升级:**
174
+ 支持从宽松模式升级到严格模式(`minimal → quick → full`),使用 `incspec upgrade <mode>` 补齐缺失步骤。
148
175
 
149
176
  > **提示**: 如果已有基准报告,可使用 `incspec analyze --baseline=<file>` 直接跳过分析步骤,快速进入后续工作流。
150
177
 
@@ -218,7 +245,7 @@ incspec init
218
245
 
219
246
  同步到 Cursor 或 Claude Code:
220
247
  ```bash
221
- incspec sync # 交互式选择
248
+ incspec sync # 交互式选择(默认不预选)
222
249
  incspec sync --cursor # 仅 Cursor
223
250
  incspec sync --claude # 仅 Claude Code
224
251
  incspec sync --all # 全部
@@ -260,6 +287,14 @@ $ incspec analyze src/views/Home --quick # 启动快速模式工作流
260
287
  ```
261
288
  快速模式跳过步骤 3 (UI依赖采集) 和步骤 4 (增量设计),直接从需求进入代码应用。
262
289
 
290
+ **启动极简模式** (3步流程):
291
+
292
+ 适用于紧急修复或单文件小改动:
293
+ ```bash
294
+ $ incspec analyze src/views/Home --minimal # 启动极简模式工作流
295
+ ```
296
+ 极简模式跳过步骤 2、3、4、6,仅保留分析 → 应用 → 归档;如需补齐步骤可使用 `incspec upgrade <mode>`。
297
+
263
298
  **使用现有基准报告** (跳过分析):
264
299
 
265
300
  如果已有基准报告文件,可直接使用,跳过分析步骤:
@@ -462,7 +497,7 @@ incspec reset -t 3 # 短选项形式
462
497
 
463
498
  **回退行为:** 保留目标步骤及之前状态,重置后续步骤为 pending,被重置步骤的产出自动归档。
464
499
 
465
- **限制:** 目标步骤必须已完成(1-6),快速模式下不能回退到被跳过的步骤(3、4)。
500
+ **限制:** 目标步骤必须已完成(1-6),快速模式下不能回退到被跳过的步骤(3、4),极简模式下不能回退到被跳过的步骤(2、3、4、6)。
466
501
 
467
502
  ## 目录结构
468
503
 
@@ -520,9 +555,10 @@ incspec help <command> # 显示特定命令帮助
520
555
 
521
556
  ```bash
522
557
  # 步骤 1:分析代码流程
523
- incspec analyze <source-path> [--module=name] [--quick] # 别名:a
558
+ incspec analyze <source-path> [--module=name] [--quick|--minimal] # 别名:a
524
559
  incspec a src/views/Home --module=home
525
560
  incspec analyze src/views/Home --quick # 启动快速模式
561
+ incspec analyze src/views/Home --minimal # 启动极简模式
526
562
  incspec analyze src/views/Home --complete -o baselines/home-baseline-v1.md
527
563
  incspec analyze --baseline=home-baseline-v1.md # 使用现有基准(自动从归档恢复)
528
564
 
@@ -530,23 +566,24 @@ incspec analyze --baseline=home-baseline-v1.md # 使用现有基准(自动从
530
566
  incspec collect-req # 别名:cr
531
567
  incspec cr --complete
532
568
 
533
- # 步骤 3:收集 UI 依赖(快速模式跳过)
569
+ # 步骤 3:收集 UI 依赖(快速/极简模式跳过)
534
570
  incspec collect-dep # 别名:cd
535
571
  incspec cd --complete
536
572
 
537
- # 步骤 4:生成增量设计(快速模式跳过)
573
+ # 步骤 4:生成增量设计(快速/极简模式跳过)
538
574
  incspec design [--feature=name] # 别名:d
539
575
  incspec d --feature=user-auth --complete -o increments/auth-increment-v1.md
540
576
 
541
577
  # 步骤 5:应用代码变更
542
578
  incspec apply [increment-path] # 别名:ap
543
579
  incspec ap --source-dir=src/ --complete
544
- # 快速模式下自动使用 requirements/structured-requirements.md 作为输入
580
+ # 快速/极简模式下自动使用 requirements/structured-requirements.md 作为输入
545
581
 
546
582
  # 步骤 6:合并到基线
547
583
  incspec merge [increment-path] # 别名:m
548
584
  incspec m --complete -o baselines/home-baseline-v2.md
549
585
  # 快速模式下重新分析代码生成新基线
586
+ # 极简模式默认跳过步骤 6(需升级模式后执行)
550
587
  ```
551
588
 
552
589
  </details>
@@ -572,6 +609,10 @@ incspec archive -y # 跳过确认提示
572
609
  incspec reset # 重置当前工作流(别名:rs)
573
610
  incspec reset --to=3 # 回退到步骤 3,保留步骤 1-3 的状态
574
611
  incspec reset -t 3 # 同上,短选项形式
612
+
613
+ incspec upgrade <mode> # 升级工作流模式(别名:ug)
614
+ incspec upgrade quick # minimal → quick
615
+ incspec upgrade full # quick/minimal → full
575
616
  ```
576
617
 
577
618
  </details>
@@ -594,6 +635,7 @@ incspec reset -t 3 # 同上,短选项形式
594
635
  | `sync` | `s` | 同步 |
595
636
  | `update` | `up` | 更新 |
596
637
  | `reset` | `rs` | 重置/回退 |
638
+ | `upgrade` | `ug` | 模式升级 |
597
639
  | `help` | `h` | 帮助 |
598
640
 
599
641
  </details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localsummer/incspec",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "面向 AI 编程助手的增量规范驱动开发工具",
5
5
  "bin": {
6
6
  "incspec": "src/index.mjs"
@@ -19,6 +19,7 @@ import {
19
19
  isWorkflowIncomplete,
20
20
  getWorkflowProgress,
21
21
  } from '../lib/workflow.mjs';
22
+ import { getModeLabel, formatModeInfo } from '../lib/mode-utils.mjs';
22
23
  import { getNextVersion } from '../lib/spec.mjs';
23
24
  import {
24
25
  colors,
@@ -87,6 +88,23 @@ export async function analyzeCommand(ctx) {
87
88
  // Ensure initialized
88
89
  const projectRoot = ensureInitialized(cwd);
89
90
 
91
+ // Handle --complete flag as independent mode (skip all interactive flows)
92
+ if (options.complete) {
93
+ const workflow = readWorkflow(projectRoot);
94
+ if (!workflow?.currentWorkflow) {
95
+ printError('没有活跃的工作流,无法标记完成。');
96
+ process.exit(1);
97
+ }
98
+ const output = typeof options.output === 'string' ? options.output : null;
99
+ if (!output) {
100
+ printError('请通过 --output 指定输出文件名。');
101
+ process.exit(1);
102
+ }
103
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
104
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成: ${output}`);
105
+ return;
106
+ }
107
+
90
108
  // Handle --baseline option: use existing baseline report
91
109
  if (options.baseline) {
92
110
  const baselineFile = typeof options.baseline === 'string' ? options.baseline : '';
@@ -124,11 +142,12 @@ export async function analyzeCommand(ctx) {
124
142
 
125
143
  // Handle workflow state
126
144
  let workflow = readWorkflow(projectRoot);
127
- const isQuick = options.quick || options.q;
145
+ const mode = options.minimal ? MODE.MINIMAL :
146
+ options.quick || options.q ? MODE.QUICK : MODE.FULL;
128
147
  if (!workflow?.currentWorkflow) {
129
148
  const workflowName = typeof options.workflow === 'string' ? options.workflow : `analyze-${moduleName}`;
130
- workflow = startWorkflow(projectRoot, workflowName, { mode: isQuick ? MODE.QUICK : MODE.FULL });
131
- const modeLabel = isQuick ? '(快速模式: 5步)' : '';
149
+ workflow = startWorkflow(projectRoot, workflowName, { mode });
150
+ const modeLabel = getModeLabel(mode);
132
151
  printSuccess(`已创建新工作流: ${workflowName} ${modeLabel}`);
133
152
  }
134
153
 
@@ -154,17 +173,18 @@ export async function analyzeCommand(ctx) {
154
173
 
155
174
  // Get workflow state
156
175
  let workflow = readWorkflow(projectRoot);
157
- const isQuick = options.quick || options.q;
176
+ const mode = options.minimal ? MODE.MINIMAL :
177
+ options.quick || options.q ? MODE.QUICK : MODE.FULL;
158
178
 
159
179
  // Check if starting new workflow
160
180
  if (!workflow?.currentWorkflow) {
161
181
  let workflowName = typeof options.workflow === 'string' ? options.workflow : '';
162
182
  if (!workflowName) {
163
- const modeHint = isQuick ? '(快速模式)' : '';
164
- workflowName = await prompt(`请输入工作流名称 ${modeHint}`, `analyze-${moduleName}`);
183
+ const modeLabel = getModeLabel(mode);
184
+ workflowName = await prompt(`请输入工作流名称 ${modeLabel}`, `analyze-${moduleName}`);
165
185
  }
166
- workflow = startWorkflow(projectRoot, workflowName, { mode: isQuick ? MODE.QUICK : MODE.FULL });
167
- const modeLabel = isQuick ? '(快速模式: 5步)' : '';
186
+ workflow = startWorkflow(projectRoot, workflowName, { mode });
187
+ const modeLabel = getModeLabel(mode);
168
188
  printSuccess(`已创建新工作流: ${workflowName} ${modeLabel}`);
169
189
  } else if (isWorkflowIncomplete(workflow)) {
170
190
  // Current workflow is incomplete, ask for confirmation
@@ -182,11 +202,11 @@ export async function analyzeCommand(ctx) {
182
202
  } else {
183
203
  let workflowName = typeof options.workflow === 'string' ? options.workflow : '';
184
204
  if (!workflowName) {
185
- const modeHint = isQuick ? '(快速模式)' : '';
186
- workflowName = await prompt(`请输入新工作流名称 ${modeHint}`, `analyze-${moduleName}`);
205
+ const modeLabel = getModeLabel(mode);
206
+ workflowName = await prompt(`请输入新工作流名称 ${modeLabel}`, `analyze-${moduleName}`);
187
207
  }
188
- workflow = startWorkflow(projectRoot, workflowName, { mode: isQuick ? MODE.QUICK : MODE.FULL });
189
- const modeLabel = isQuick ? '(快速模式: 5步)' : '';
208
+ workflow = startWorkflow(projectRoot, workflowName, { mode });
209
+ const modeLabel = getModeLabel(mode);
190
210
  printSuccess(`已归档旧工作流,创建新工作流: ${workflowName} ${modeLabel}`);
191
211
  }
192
212
  }
@@ -201,10 +221,9 @@ export async function analyzeCommand(ctx) {
201
221
  print(colorize('─────────────────────', colors.dim));
202
222
  print('');
203
223
 
204
- // Show quick mode info
205
- if (isQuick) {
206
- print(colorize('快速模式流程: 分析 -> 需求收集 -> 应用代码 -> 合并基线', colors.yellow));
207
- print(colorize('(跳过 UI依赖采集 和 增量设计)', colors.dim));
224
+ // Show mode info
225
+ if (mode !== MODE.FULL) {
226
+ print(colorize(formatModeInfo(mode), colors.yellow));
208
227
  print('');
209
228
  }
210
229
 
@@ -234,11 +253,4 @@ export async function analyzeCommand(ctx) {
234
253
  print(colorize('完成分析后,运行以下命令标记完成:', colors.dim));
235
254
  print(colorize(` incspec analyze --complete --output=${outputFile}`, colors.dim));
236
255
  print('');
237
-
238
- // Handle --complete flag
239
- if (options.complete) {
240
- const output = typeof options.output === 'string' ? options.output : outputFile;
241
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
242
- printSuccess(`步骤 1 已标记为完成: ${output}`);
243
- }
244
256
  }
@@ -14,9 +14,15 @@ import {
14
14
  readWorkflow,
15
15
  updateStep,
16
16
  STATUS,
17
- isQuickMode,
17
+ MODE,
18
18
  getMissingPrereqs,
19
19
  } from '../lib/workflow.mjs';
20
+ import {
21
+ isMinimalMode,
22
+ isQuickMode,
23
+ isFullMode,
24
+ getApplyInputFile,
25
+ } from '../lib/mode-utils.mjs';
20
26
  import { listSpecs } from '../lib/spec.mjs';
21
27
  import {
22
28
  colors,
@@ -57,12 +63,23 @@ export async function applyCommand(ctx) {
57
63
  // Get workflow state
58
64
  const workflow = readWorkflow(projectRoot);
59
65
 
66
+ // Handle --complete flag as independent mode (skip all checks)
67
+ if (options.complete) {
68
+ if (!workflow?.currentWorkflow) {
69
+ printWarning('没有活跃的工作流,无法标记完成。');
70
+ return;
71
+ }
72
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, '代码已应用');
73
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成`);
74
+ return;
75
+ }
76
+
60
77
  if (!workflow?.currentWorkflow) {
61
78
  printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
62
79
  return;
63
80
  }
64
81
 
65
- const quickMode = isQuickMode(workflow);
82
+ const mode = workflow.mode || MODE.FULL;
66
83
  const missingSteps = getMissingPrereqs(workflow, STEP_NUMBER);
67
84
  if (missingSteps && missingSteps.length > 0 && !options.force) {
68
85
  printWarning(`请先完成步骤 ${missingSteps.join(', ')} 后再继续。`);
@@ -80,16 +97,7 @@ export async function applyCommand(ctx) {
80
97
  let inputPath;
81
98
  let inputType;
82
99
 
83
- if (quickMode) {
84
- // Quick mode: use requirements document
85
- const reqFile = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
86
- if (!fs.existsSync(reqFile)) {
87
- printWarning('未找到需求文件。请先运行步骤 2 (collect-req)。');
88
- return;
89
- }
90
- inputPath = path.join(INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
91
- inputType = 'requirements';
92
- } else {
100
+ if (isFullMode(workflow)) {
93
101
  // Full mode: use increment design file
94
102
  let incrementPath = args[0];
95
103
  if (!incrementPath) {
@@ -117,12 +125,22 @@ export async function applyCommand(ctx) {
117
125
  }
118
126
  inputPath = incrementPath;
119
127
  inputType = 'increment';
128
+ } else {
129
+ // Quick/Minimal mode: use requirements document
130
+ const reqFile = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
131
+ if (!fs.existsSync(reqFile)) {
132
+ printWarning('未找到需求文件。请先运行步骤 2 (collect-req)。');
133
+ return;
134
+ }
135
+ inputPath = path.join(INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
136
+ inputType = 'requirements';
120
137
  }
121
138
 
122
139
  print('');
123
140
  print(colorize('步骤 5: 应用代码变更', colors.bold, colors.cyan));
124
- if (quickMode) {
125
- print(colorize('(快速模式 - 基于需求文档)', colors.yellow));
141
+ if (mode !== MODE.FULL) {
142
+ const modeLabel = mode === MODE.MINIMAL ? '极简模式' : '快速模式';
143
+ print(colorize(`(${modeLabel} - 基于需求文档)`, colors.yellow));
126
144
  }
127
145
  print(colorize('────────────────────', colors.dim));
128
146
  print('');
@@ -138,9 +156,10 @@ export async function applyCommand(ctx) {
138
156
  print(colorize('使用说明:', colors.bold));
139
157
  print('');
140
158
 
141
- if (quickMode) {
142
- // Quick mode instructions
143
- print(colorize('快速模式下,请直接根据需求文档实现代码变更:', colors.cyan));
159
+ if (mode !== MODE.FULL) {
160
+ // Quick/Minimal mode instructions
161
+ const modeLabel = mode === MODE.MINIMAL ? '极简模式' : '快速模式';
162
+ print(colorize(`${modeLabel}下,请直接根据需求文档实现代码变更:`, colors.cyan));
144
163
  print('');
145
164
  print(colorize('在 Cursor 中:', colors.dim));
146
165
  print(colorize(` /incspec/inc-apply ${inputPath}`, colors.bold, colors.white));
@@ -176,9 +195,8 @@ export async function applyCommand(ctx) {
176
195
  printInfo(`完成后运行 'incspec status' 查看进度`);
177
196
  print('');
178
197
 
179
- // Handle --complete flag
180
- if (options.complete) {
181
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, '代码已应用');
182
- printSuccess(`步骤 5 已标记为完成`);
183
- }
198
+ // Provide command to mark as complete
199
+ print(colorize('完成代码应用后,运行以下命令标记完成:', colors.dim));
200
+ print(colorize(` incspec apply --complete`, colors.dim));
201
+ print('');
184
202
  }
@@ -10,7 +10,8 @@ import {
10
10
  DIRS,
11
11
  } from '../lib/config.mjs';
12
12
  import { archiveSpec, getSpecInfo } from '../lib/spec.mjs';
13
- import { archiveWorkflow, readWorkflow, updateStep, STATUS, isQuickMode, MODE } from '../lib/workflow.mjs';
13
+ import { archiveWorkflow, readWorkflow, updateStep, STATUS, MODE } from '../lib/workflow.mjs';
14
+ import { getArchivableStepsForMode } from '../lib/mode-utils.mjs';
14
15
  import {
15
16
  colors,
16
17
  colorize,
@@ -21,25 +22,6 @@ import {
21
22
  confirm,
22
23
  } from '../lib/terminal.mjs';
23
24
 
24
- // Full mode: archivable steps are 1, 2, 3, 4, 6 (0-based: 0, 1, 2, 3, 5)
25
- // Note: Step 5 (apply) has no file output, Step 7 (archive) is this command itself
26
- const FULL_MODE_ARCHIVABLE_INDEXES = [0, 1, 2, 3, 5];
27
- // Quick mode: archivable steps are 1, 2, 6 (0-based: 0, 1, 5)
28
- // Note: Steps 3, 4 are skipped in quick mode
29
- const QUICK_MODE_ARCHIVABLE_INDEXES = [0, 1, 5];
30
-
31
- /**
32
- * Get archivable step indexes based on workflow mode
33
- * @param {Object} workflow
34
- * @returns {number[]}
35
- */
36
- function getArchivableStepIndexes(workflow) {
37
- if (isQuickMode(workflow)) {
38
- return QUICK_MODE_ARCHIVABLE_INDEXES;
39
- }
40
- return FULL_MODE_ARCHIVABLE_INDEXES;
41
- }
42
-
43
25
  function escapeRegExp(value) {
44
26
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
45
27
  }
@@ -132,7 +114,8 @@ function getArchivableOutputs(workflow) {
132
114
  return null;
133
115
  }
134
116
 
135
- const archivableIndexes = getArchivableStepIndexes(workflow);
117
+ const mode = workflow.mode || MODE.FULL;
118
+ const archivableIndexes = getArchivableStepsForMode(mode);
136
119
  const outputs = [];
137
120
 
138
121
  for (const index of archivableIndexes) {
@@ -254,6 +237,20 @@ export async function archiveCommand(ctx) {
254
237
  return;
255
238
  }
256
239
 
240
+ // 极简模式提醒
241
+ if (workflow.mode === MODE.MINIMAL && !skipConfirm) {
242
+ print(colorize('⚠️ 极简模式提醒:', colors.yellow, colors.bold));
243
+ print(colorize(' 极简模式跳过了步骤6(合并基线),当前归档的是初始基线和应用后的代码。', colors.dim));
244
+ print(colorize(' 如需生成新基线快照,请先运行: incspec merge', colors.dim));
245
+ print('');
246
+ const shouldContinue = await confirm('是否继续归档当前文件?');
247
+ if (!shouldContinue) {
248
+ print(colorize('已取消。', colors.dim));
249
+ return;
250
+ }
251
+ print('');
252
+ }
253
+
257
254
  if (targets.length > 0) {
258
255
  print(colorize('将归档以下文件:', colors.dim));
259
256
  targets.forEach(target => print(colorize(` - ${target.name}`, colors.dim)));
@@ -40,6 +40,21 @@ export async function collectDepCommand(ctx) {
40
40
  // Get workflow state
41
41
  const workflow = readWorkflow(projectRoot);
42
42
 
43
+ // Handle --complete flag as independent mode (skip all checks)
44
+ if (options.complete) {
45
+ if (!workflow?.currentWorkflow) {
46
+ printWarning('没有活跃的工作流,无法标记完成。');
47
+ return;
48
+ }
49
+ if (!isStepAllowed(STEP_NUMBER, workflow.mode)) {
50
+ printWarning('当前工作流为快速模式,步骤 3 已跳过,无需标记完成。');
51
+ return;
52
+ }
53
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, OUTPUT_FILE);
54
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成: ${OUTPUT_FILE}`);
55
+ return;
56
+ }
57
+
43
58
  if (!workflow?.currentWorkflow) {
44
59
  printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
45
60
  return;
@@ -91,9 +106,8 @@ export async function collectDepCommand(ctx) {
91
106
  printInfo(`完成后运行 'incspec status' 查看进度`);
92
107
  print('');
93
108
 
94
- // Handle --complete flag
95
- if (options.complete) {
96
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, OUTPUT_FILE);
97
- printSuccess(`步骤 3 已标记为完成: ${OUTPUT_FILE}`);
98
- }
109
+ // Provide command to mark as complete
110
+ print(colorize('完成依赖采集后,运行以下命令标记完成:', colors.dim));
111
+ print(colorize(` incspec collect-dep --complete`, colors.dim));
112
+ print('');
99
113
  }
@@ -40,6 +40,24 @@ export async function collectReqCommand(ctx) {
40
40
  // Get workflow state
41
41
  const workflow = readWorkflow(projectRoot);
42
42
 
43
+ // Handle --complete flag as independent mode (skip all checks)
44
+ if (options.complete) {
45
+ if (!workflow?.currentWorkflow) {
46
+ printWarning('没有活跃的工作流,无法标记完成。');
47
+ return;
48
+ }
49
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, OUTPUT_FILE);
50
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成: ${OUTPUT_FILE}`);
51
+
52
+ // Quick mode hint
53
+ if (isQuickMode(workflow)) {
54
+ print('');
55
+ printInfo('快速模式: 跳过步骤 3、4,直接进入步骤 5');
56
+ print(colorize(" 运行 'incspec apply' 继续", colors.cyan));
57
+ }
58
+ return;
59
+ }
60
+
43
61
  if (!workflow?.currentWorkflow) {
44
62
  printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
45
63
  return;
@@ -81,16 +99,8 @@ export async function collectReqCommand(ctx) {
81
99
  printInfo(`完成后运行 'incspec status' 查看进度`);
82
100
  print('');
83
101
 
84
- // Handle --complete flag
85
- if (options.complete) {
86
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, OUTPUT_FILE);
87
- printSuccess(`步骤 2 已标记为完成: ${OUTPUT_FILE}`);
88
-
89
- // Quick mode hint
90
- if (isQuickMode(workflow)) {
91
- print('');
92
- printInfo('快速模式: 跳过步骤 3、4,直接进入步骤 5');
93
- print(colorize(" 运行 'incspec apply' 继续", colors.cyan));
94
- }
95
- }
102
+ // Provide command to mark as complete
103
+ print(colorize('完成需求收集后,运行以下命令标记完成:', colors.dim));
104
+ print(colorize(` incspec collect-req --complete`, colors.dim));
105
+ print('');
96
106
  }
@@ -42,6 +42,26 @@ export async function designCommand(ctx) {
42
42
  // Get workflow state
43
43
  const workflow = readWorkflow(projectRoot);
44
44
 
45
+ // Handle --complete flag as independent mode (skip all checks)
46
+ if (options.complete) {
47
+ if (!workflow?.currentWorkflow) {
48
+ printWarning('没有活跃的工作流,无法标记完成。');
49
+ return;
50
+ }
51
+ if (!isStepAllowed(STEP_NUMBER, workflow.mode)) {
52
+ printWarning('当前工作流为快速模式,步骤 4 已跳过,无需标记完成。');
53
+ return;
54
+ }
55
+ const output = typeof options.output === 'string' ? options.output : null;
56
+ if (!output) {
57
+ printWarning('请通过 --output 指定输出文件名。');
58
+ return;
59
+ }
60
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
61
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成: ${output}`);
62
+ return;
63
+ }
64
+
45
65
  if (!workflow?.currentWorkflow) {
46
66
  printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
47
67
  return;
@@ -132,10 +152,8 @@ export async function designCommand(ctx) {
132
152
  printInfo(`完成后运行 'incspec status' 查看进度`);
133
153
  print('');
134
154
 
135
- // Handle --complete flag
136
- if (options.complete) {
137
- const output = typeof options.output === 'string' ? options.output : outputFile;
138
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
139
- printSuccess(`步骤 4 已标记为完成: ${output}`);
140
- }
155
+ // Provide command to mark as complete
156
+ print(colorize('完成增量设计后,运行以下命令标记完成:', colors.dim));
157
+ print(colorize(` incspec design --complete --output=${outputFile}`, colors.dim));
158
+ print('');
141
159
  }
@@ -55,6 +55,22 @@ export async function mergeCommand(ctx) {
55
55
  // Get workflow state
56
56
  const workflow = readWorkflow(projectRoot);
57
57
 
58
+ // Handle --complete flag as independent mode (skip all checks)
59
+ if (options.complete) {
60
+ if (!workflow?.currentWorkflow) {
61
+ printWarning('没有活跃的工作流,无法标记完成。');
62
+ return;
63
+ }
64
+ const output = typeof options.output === 'string' ? options.output : null;
65
+ if (!output) {
66
+ printWarning('请通过 --output 指定输出文件名。');
67
+ return;
68
+ }
69
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
70
+ printSuccess(`步骤 ${STEP_NUMBER} 已标记为完成: ${output}`);
71
+ return;
72
+ }
73
+
58
74
  if (!workflow?.currentWorkflow) {
59
75
  printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
60
76
  return;
@@ -163,9 +179,8 @@ export async function mergeCommand(ctx) {
163
179
  printInfo(`完成后运行 'incspec status' 查看进度`);
164
180
  print('');
165
181
 
166
- // Handle --complete flag
167
- if (options.complete) {
168
- updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, outputFile);
169
- printSuccess(`步骤 6 已标记为完成: ${outputFile}`);
170
- }
182
+ // Provide command to mark as complete
183
+ print(colorize('完成基线合并后,运行以下命令标记完成:', colors.dim));
184
+ print(colorize(` incspec merge --complete --output=${outputFile}`, colors.dim));
185
+ print('');
171
186
  }
@@ -11,9 +11,12 @@ import {
11
11
  STEPS,
12
12
  STATUS,
13
13
  MODE,
14
- QUICK_MODE_SKIPPED,
15
14
  isQuickMode,
16
15
  } from '../lib/workflow.mjs';
16
+ import {
17
+ getModeLabel,
18
+ getSkippedStepsForMode,
19
+ } from '../lib/mode-utils.mjs';
17
20
  import {
18
21
  colors,
19
22
  colorize,
@@ -52,8 +55,9 @@ export async function statusCommand(ctx) {
52
55
 
53
56
  // Current workflow
54
57
  if (workflow?.currentWorkflow) {
55
- const quickMode = isQuickMode(workflow);
56
- const modeLabel = quickMode ? '快速模式 (5步)' : '完整模式 (7步)';
58
+ const mode = workflow.mode || MODE.FULL;
59
+ const modeLabel = getModeLabel(mode);
60
+ const skippedSteps = getSkippedStepsForMode(mode);
57
61
 
58
62
  print(colorize(`当前工作流: `, colors.bold) + colorize(workflow.currentWorkflow, colors.cyan));
59
63
  print(colorize(`工作流模式: ${modeLabel}`, colors.dim));
@@ -69,9 +73,9 @@ export async function statusCommand(ctx) {
69
73
  const stepData = workflow.steps[index] || {};
70
74
  let status = stepData.status || STATUS.PENDING;
71
75
  const isCurrent = workflow.currentStep === step.id;
72
- const isSkipped = quickMode && QUICK_MODE_SKIPPED.includes(step.id);
76
+ const isSkipped = skippedSteps.includes(step.id);
73
77
 
74
- // Quick mode: mark skipped steps
78
+ // Mark skipped steps
75
79
  if (isSkipped && status !== STATUS.SKIPPED) {
76
80
  status = STATUS.SKIPPED;
77
81
  }
@@ -100,8 +104,8 @@ export async function statusCommand(ctx) {
100
104
  // Next step hint
101
105
  const nextStepIndex = workflow.steps.findIndex((step, index) => {
102
106
  const stepNumber = index + 1;
103
- // Skip excluded steps in quick mode
104
- if (quickMode && QUICK_MODE_SKIPPED.includes(stepNumber)) {
107
+ // Skip excluded steps based on mode
108
+ if (skippedSteps.includes(stepNumber)) {
105
109
  return false;
106
110
  }
107
111
  return (step?.status || STATUS.PENDING) !== STATUS.COMPLETED;
@@ -61,8 +61,8 @@ export async function syncCommand(ctx) {
61
61
  targets = await checkbox({
62
62
  message: '选择要同步的目标:',
63
63
  choices: [
64
- { ...SYNC_TARGETS.cursor, checked: true },
65
- { ...SYNC_TARGETS.claude, checked: false },
64
+ { ...SYNC_TARGETS.cursor },
65
+ { ...SYNC_TARGETS.claude },
66
66
  ],
67
67
  });
68
68