@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 +48 -6
- package/package.json +1 -1
- package/src/commands/analyze.mjs +35 -23
- package/src/commands/apply.mjs +40 -22
- package/src/commands/archive.mjs +18 -21
- package/src/commands/collect-dep.mjs +19 -5
- package/src/commands/collect-req.mjs +22 -12
- package/src/commands/design.mjs +24 -6
- package/src/commands/merge.mjs +20 -5
- package/src/commands/status.mjs +11 -7
- package/src/commands/sync.mjs +2 -2
- package/src/commands/upgrade.mjs +139 -0
- package/src/index.mjs +7 -0
- package/src/lib/mode-utils.mjs +265 -0
- package/src/lib/workflow.mjs +38 -34
- package/src/templates/AGENTS.md +81 -11
- package/src/templates/WORKFLOW.md +7 -0
- package/src/templates/commands/analyze-codeflow.md +15 -0
- package/src/templates/commands/apply-increment-code.md +220 -366
- package/src/templates/commands/inc-archive.md +6 -1
- package/src/templates/commands/inc-upgrade.md +338 -0
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
|
-
#
|
|
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
package/src/commands/analyze.mjs
CHANGED
|
@@ -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
|
|
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
|
|
131
|
-
const modeLabel =
|
|
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
|
|
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
|
|
164
|
-
workflowName = await prompt(`请输入工作流名称 ${
|
|
183
|
+
const modeLabel = getModeLabel(mode);
|
|
184
|
+
workflowName = await prompt(`请输入工作流名称 ${modeLabel}`, `analyze-${moduleName}`);
|
|
165
185
|
}
|
|
166
|
-
workflow = startWorkflow(projectRoot, workflowName, { mode
|
|
167
|
-
const modeLabel =
|
|
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
|
|
186
|
-
workflowName = await prompt(`请输入新工作流名称 ${
|
|
205
|
+
const modeLabel = getModeLabel(mode);
|
|
206
|
+
workflowName = await prompt(`请输入新工作流名称 ${modeLabel}`, `analyze-${moduleName}`);
|
|
187
207
|
}
|
|
188
|
-
workflow = startWorkflow(projectRoot, workflowName, { mode
|
|
189
|
-
const modeLabel =
|
|
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
|
|
205
|
-
if (
|
|
206
|
-
print(colorize(
|
|
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
|
}
|
package/src/commands/apply.mjs
CHANGED
|
@@ -14,9 +14,15 @@ import {
|
|
|
14
14
|
readWorkflow,
|
|
15
15
|
updateStep,
|
|
16
16
|
STATUS,
|
|
17
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
125
|
-
|
|
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 (
|
|
142
|
-
// Quick mode instructions
|
|
143
|
-
|
|
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
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
}
|
package/src/commands/archive.mjs
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
}
|
package/src/commands/design.mjs
CHANGED
|
@@ -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
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
}
|
package/src/commands/merge.mjs
CHANGED
|
@@ -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
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
}
|
package/src/commands/status.mjs
CHANGED
|
@@ -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
|
|
56
|
-
const modeLabel =
|
|
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 =
|
|
76
|
+
const isSkipped = skippedSteps.includes(step.id);
|
|
73
77
|
|
|
74
|
-
//
|
|
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
|
|
104
|
-
if (
|
|
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;
|
package/src/commands/sync.mjs
CHANGED
|
@@ -61,8 +61,8 @@ export async function syncCommand(ctx) {
|
|
|
61
61
|
targets = await checkbox({
|
|
62
62
|
message: '选择要同步的目标:',
|
|
63
63
|
choices: [
|
|
64
|
-
{ ...SYNC_TARGETS.cursor
|
|
65
|
-
{ ...SYNC_TARGETS.claude
|
|
64
|
+
{ ...SYNC_TARGETS.cursor },
|
|
65
|
+
{ ...SYNC_TARGETS.claude },
|
|
66
66
|
],
|
|
67
67
|
});
|
|
68
68
|
|