@localsummer/incspec 0.2.6 → 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 +18 -16
- package/src/commands/apply.mjs +25 -17
- package/src/commands/archive.mjs +18 -21
- 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
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工作流模式工具函数
|
|
3
|
+
* 提供纯函数接口,无副作用
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { MODE, STEPS } from './workflow.mjs';
|
|
7
|
+
|
|
8
|
+
// ============ 类型定义 ============
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {'full' | 'quick' | 'minimal'} WorkflowMode
|
|
12
|
+
* 工作流模式枚举
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} ModeConfig
|
|
17
|
+
* @property {number[]} steps - 模式包含的步骤ID列表
|
|
18
|
+
* @property {number[]} skippedSteps - 模式跳过的步骤ID列表
|
|
19
|
+
* @property {string} label - 模式的显示标签
|
|
20
|
+
* @property {string} description - 模式的描述
|
|
21
|
+
* @property {number[]} archivableSteps - 可归档的步骤ID列表
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {Object} ValidationResult
|
|
26
|
+
* @property {boolean} valid - 是否有效
|
|
27
|
+
* @property {string} [reason] - 无效原因
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ============ 常量定义 ============
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 模式配置映射表
|
|
34
|
+
* @type {Object.<string, ModeConfig>}
|
|
35
|
+
*/
|
|
36
|
+
export const MODE_CONFIG = {
|
|
37
|
+
full: {
|
|
38
|
+
steps: [1, 2, 3, 4, 5, 6, 7],
|
|
39
|
+
skippedSteps: [],
|
|
40
|
+
label: '完整模式',
|
|
41
|
+
description: '7步完整工作流,适合复杂功能开发和架构变更',
|
|
42
|
+
archivableSteps: [1, 2, 3, 4, 5, 6] // 步骤7是归档本身,不可归档
|
|
43
|
+
},
|
|
44
|
+
quick: {
|
|
45
|
+
steps: [1, 2, 5, 6, 7],
|
|
46
|
+
skippedSteps: [3, 4],
|
|
47
|
+
label: '快速模式',
|
|
48
|
+
description: '5步简化工作流,跳过依赖采集和增量设计,适合简单功能迭代',
|
|
49
|
+
archivableSteps: [1, 2, 5, 6]
|
|
50
|
+
},
|
|
51
|
+
minimal: {
|
|
52
|
+
steps: [1, 5, 7],
|
|
53
|
+
skippedSteps: [2, 3, 4, 6],
|
|
54
|
+
label: '极简模式',
|
|
55
|
+
description: '3步最简工作流(分析→应用→归档),适合Bug修复和简单变更',
|
|
56
|
+
archivableSteps: [1, 5] // 步骤7是归档本身,步骤6被跳过
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 模式升级顺序(从宽松到严格)
|
|
62
|
+
*/
|
|
63
|
+
export const MODE_UPGRADE_ORDER = ['minimal', 'quick', 'full'];
|
|
64
|
+
|
|
65
|
+
// ============ 模式判断函数 ============
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 判断工作流是否为极简模式
|
|
69
|
+
* @param {Object} workflow - 工作流状态对象
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
export function isMinimalMode(workflow) {
|
|
73
|
+
return workflow?.mode === 'minimal';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 判断工作流是否为快速模式
|
|
78
|
+
* @param {Object} workflow - 工作流状态对象
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
export function isQuickMode(workflow) {
|
|
82
|
+
return workflow?.mode === 'quick';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 判断工作流是否为完整模式
|
|
87
|
+
* @param {Object} workflow - 工作流状态对象
|
|
88
|
+
* @returns {boolean}
|
|
89
|
+
*/
|
|
90
|
+
export function isFullMode(workflow) {
|
|
91
|
+
return workflow?.mode === 'full';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ============ 步骤管理函数 ============
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 获取指定模式包含的步骤ID列表
|
|
98
|
+
* @param {string} mode - 模式名称 ('full' | 'quick' | 'minimal')
|
|
99
|
+
* @returns {number[]} 步骤ID数组
|
|
100
|
+
* @throws {Error} 如果模式不存在
|
|
101
|
+
*/
|
|
102
|
+
export function getStepsForMode(mode) {
|
|
103
|
+
const config = MODE_CONFIG[mode];
|
|
104
|
+
if (!config) {
|
|
105
|
+
throw new Error(`Unknown mode: ${mode}`);
|
|
106
|
+
}
|
|
107
|
+
return [...config.steps];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取指定模式跳过的步骤ID列表
|
|
112
|
+
* @param {string} mode - 模式名称
|
|
113
|
+
* @returns {number[]} 跳过的步骤ID数组
|
|
114
|
+
* @throws {Error} 如果模式不存在
|
|
115
|
+
*/
|
|
116
|
+
export function getSkippedStepsForMode(mode) {
|
|
117
|
+
const config = MODE_CONFIG[mode];
|
|
118
|
+
if (!config) {
|
|
119
|
+
throw new Error(`Unknown mode: ${mode}`);
|
|
120
|
+
}
|
|
121
|
+
return [...config.skippedSteps];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 判断步骤在指定模式下是否激活(未被跳过)
|
|
126
|
+
* @param {number} stepId - 步骤ID (1-7)
|
|
127
|
+
* @param {string} mode - 模式名称
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
export function isStepActiveInMode(stepId, mode) {
|
|
131
|
+
const steps = getStepsForMode(mode);
|
|
132
|
+
return steps.includes(stepId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 获取指定模式下可归档的步骤索引(用于 archive 命令)
|
|
137
|
+
* @param {string} mode - 模式名称
|
|
138
|
+
* @returns {number[]} 可归档的步骤索引数组(0-based)
|
|
139
|
+
*/
|
|
140
|
+
export function getArchivableStepsForMode(mode) {
|
|
141
|
+
const config = MODE_CONFIG[mode];
|
|
142
|
+
if (!config) {
|
|
143
|
+
throw new Error(`Unknown mode: ${mode}`);
|
|
144
|
+
}
|
|
145
|
+
// 步骤ID转索引:减1
|
|
146
|
+
return config.archivableSteps.map(id => id - 1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ============ 格式化函数 ============
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 获取模式的显示标签(中文)
|
|
153
|
+
* @param {string} mode - 模式名称
|
|
154
|
+
* @returns {string} 格式化的标签,如 "完整模式 (7步)"
|
|
155
|
+
*/
|
|
156
|
+
export function getModeLabel(mode) {
|
|
157
|
+
const config = MODE_CONFIG[mode];
|
|
158
|
+
if (!config) {
|
|
159
|
+
return '未知模式';
|
|
160
|
+
}
|
|
161
|
+
const stepCount = config.steps.length;
|
|
162
|
+
return `${config.label} (${stepCount}步)`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 获取模式的详细描述
|
|
167
|
+
* @param {string} mode - 模式名称
|
|
168
|
+
* @returns {string}
|
|
169
|
+
*/
|
|
170
|
+
export function getModeDescription(mode) {
|
|
171
|
+
const config = MODE_CONFIG[mode];
|
|
172
|
+
return config?.description || '无描述';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 格式化模式信息为多行文本(用于终端输出)
|
|
177
|
+
* @param {string} mode - 模式名称
|
|
178
|
+
* @returns {string}
|
|
179
|
+
*/
|
|
180
|
+
export function formatModeInfo(mode) {
|
|
181
|
+
const config = MODE_CONFIG[mode];
|
|
182
|
+
if (!config) {
|
|
183
|
+
return '未知模式';
|
|
184
|
+
}
|
|
185
|
+
const lines = [
|
|
186
|
+
`${config.label} (${config.steps.length}步)`,
|
|
187
|
+
`描述: ${config.description}`,
|
|
188
|
+
`步骤: ${config.steps.join(' → ')}`
|
|
189
|
+
];
|
|
190
|
+
if (config.skippedSteps.length > 0) {
|
|
191
|
+
lines.push(`跳过: 步骤 ${config.skippedSteps.join(', ')}`);
|
|
192
|
+
}
|
|
193
|
+
return lines.join('\n');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ============ 模式转换函数 ============
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 验证模式升级是否合法
|
|
200
|
+
* @param {string} fromMode - 当前模式
|
|
201
|
+
* @param {string} toMode - 目标模式
|
|
202
|
+
* @returns {ValidationResult}
|
|
203
|
+
*/
|
|
204
|
+
export function validateModeUpgrade(fromMode, toMode) {
|
|
205
|
+
if (!MODE_CONFIG[fromMode]) {
|
|
206
|
+
return { valid: false, reason: `未知的源模式: ${fromMode}` };
|
|
207
|
+
}
|
|
208
|
+
if (!MODE_CONFIG[toMode]) {
|
|
209
|
+
return { valid: false, reason: `未知的目标模式: ${toMode}` };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const fromIndex = MODE_UPGRADE_ORDER.indexOf(fromMode);
|
|
213
|
+
const toIndex = MODE_UPGRADE_ORDER.indexOf(toMode);
|
|
214
|
+
|
|
215
|
+
if (fromIndex === toIndex) {
|
|
216
|
+
return { valid: false, reason: '源模式和目标模式相同' };
|
|
217
|
+
}
|
|
218
|
+
if (fromIndex > toIndex) {
|
|
219
|
+
return { valid: false, reason: '只能从宽松模式升级到严格模式(minimal → quick → full)' };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return { valid: true };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 获取模式升级后需要补充的步骤ID
|
|
227
|
+
* @param {string} fromMode - 当前模式
|
|
228
|
+
* @param {string} toMode - 目标模式
|
|
229
|
+
* @returns {number[]} 需要补充的步骤ID数组
|
|
230
|
+
*/
|
|
231
|
+
export function getMissingStepsAfterUpgrade(fromMode, toMode) {
|
|
232
|
+
const fromSteps = new Set(getStepsForMode(fromMode));
|
|
233
|
+
const toSteps = getStepsForMode(toMode);
|
|
234
|
+
return toSteps.filter(step => !fromSteps.has(step));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ============ 文件路径函数 ============
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 获取 apply 命令的输入文件路径(相对于 projectRoot/incspec/)
|
|
241
|
+
* @param {string} mode - 模式名称
|
|
242
|
+
* @param {Object} workflow - 工作流状态(用于获取版本号)
|
|
243
|
+
* @returns {string} 相对路径
|
|
244
|
+
*/
|
|
245
|
+
export function getApplyInputFile(mode, workflow) {
|
|
246
|
+
if (mode === 'full') {
|
|
247
|
+
// 完整模式:使用增量设计文件
|
|
248
|
+
const moduleName = workflow.currentWorkflow?.replace('analyze-', '') || 'default';
|
|
249
|
+
const version = workflow.incrementVersion || 1;
|
|
250
|
+
return `increments/${moduleName}-increment-v${version}.md`;
|
|
251
|
+
} else {
|
|
252
|
+
// 快速/极简模式:使用结构化需求文件
|
|
253
|
+
return 'requirements/structured-requirements.md';
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 获取 merge 命令的输出基线文件名(不含路径)
|
|
259
|
+
* @param {string} moduleName - 模块名称
|
|
260
|
+
* @param {number} version - 版本号
|
|
261
|
+
* @returns {string} 文件名
|
|
262
|
+
*/
|
|
263
|
+
export function getMergeOutputFilename(moduleName, version) {
|
|
264
|
+
return `${moduleName}-baseline-v${version}.md`;
|
|
265
|
+
}
|
package/src/lib/workflow.mjs
CHANGED
|
@@ -9,6 +9,11 @@ import * as fs from 'fs';
|
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import { INCSPEC_DIR, FILES, getTemplatesDir } from './config.mjs';
|
|
11
11
|
import { formatLocalDateTime } from './terminal.mjs';
|
|
12
|
+
import {
|
|
13
|
+
getStepsForMode,
|
|
14
|
+
getSkippedStepsForMode,
|
|
15
|
+
isStepActiveInMode
|
|
16
|
+
} from './mode-utils.mjs';
|
|
12
17
|
|
|
13
18
|
/** Workflow steps definition */
|
|
14
19
|
export const STEPS = [
|
|
@@ -33,14 +38,9 @@ export const STATUS = {
|
|
|
33
38
|
export const MODE = {
|
|
34
39
|
FULL: 'full',
|
|
35
40
|
QUICK: 'quick',
|
|
41
|
+
MINIMAL: 'minimal',
|
|
36
42
|
};
|
|
37
43
|
|
|
38
|
-
/** Quick mode valid steps (1-based) */
|
|
39
|
-
export const QUICK_MODE_STEPS = [1, 2, 5, 6, 7];
|
|
40
|
-
|
|
41
|
-
/** Quick mode skipped steps (1-based) */
|
|
42
|
-
export const QUICK_MODE_SKIPPED = [3, 4];
|
|
43
|
-
|
|
44
44
|
function normalizeOutputName(outputFile) {
|
|
45
45
|
if (!outputFile || typeof outputFile !== 'string') {
|
|
46
46
|
return outputFile;
|
|
@@ -156,7 +156,13 @@ export function parseWorkflow(content) {
|
|
|
156
156
|
const modeMatch = content.match(/\*\*工作流模式\*\*:\s*(.+)/);
|
|
157
157
|
if (modeMatch) {
|
|
158
158
|
const modeValue = modeMatch[1].trim().toLowerCase();
|
|
159
|
-
|
|
159
|
+
if (modeValue === 'quick') {
|
|
160
|
+
workflow.mode = MODE.QUICK;
|
|
161
|
+
} else if (modeValue === 'minimal') {
|
|
162
|
+
workflow.mode = MODE.MINIMAL;
|
|
163
|
+
} else {
|
|
164
|
+
workflow.mode = MODE.FULL;
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
const startMatch = content.match(/\*\*开始时间\*\*:\s*(.+)/);
|
|
@@ -380,9 +386,10 @@ export function startWorkflow(projectRoot, workflowName, options = {}) {
|
|
|
380
386
|
workflow.mode = mode;
|
|
381
387
|
workflow.startTime = now;
|
|
382
388
|
|
|
383
|
-
// Initialize steps - mark skipped steps
|
|
389
|
+
// Initialize steps - mark skipped steps based on mode
|
|
390
|
+
const skippedSteps = getSkippedStepsForMode(mode);
|
|
384
391
|
workflow.steps = STEPS.map((step) => {
|
|
385
|
-
if (
|
|
392
|
+
if (skippedSteps.includes(step.id)) {
|
|
386
393
|
return {
|
|
387
394
|
status: STATUS.SKIPPED,
|
|
388
395
|
output: null,
|
|
@@ -529,10 +536,11 @@ export function resetToStep(projectRoot, targetStep) {
|
|
|
529
536
|
throw new Error(`目标步骤 ${targetStep} 尚未完成,无法回退到此步骤`);
|
|
530
537
|
}
|
|
531
538
|
|
|
532
|
-
// Handle
|
|
539
|
+
// Handle mode: cannot reset to skipped steps
|
|
533
540
|
const mode = workflow.mode || MODE.FULL;
|
|
534
|
-
|
|
535
|
-
|
|
541
|
+
const skippedSteps = getSkippedStepsForMode(mode);
|
|
542
|
+
if (skippedSteps.includes(targetStep)) {
|
|
543
|
+
throw new Error(`当前模式下步骤 ${targetStep} 被跳过,无法回退到此步骤`);
|
|
536
544
|
}
|
|
537
545
|
|
|
538
546
|
// Collect outputs from steps that will be reset (targetStep+1 to 7)
|
|
@@ -552,8 +560,8 @@ export function resetToStep(projectRoot, targetStep) {
|
|
|
552
560
|
const now = formatLocalDateTime(new Date());
|
|
553
561
|
for (let i = targetStep; i < STEPS.length; i++) {
|
|
554
562
|
const stepNumber = i + 1;
|
|
555
|
-
//
|
|
556
|
-
if (
|
|
563
|
+
// Keep skipped steps as skipped based on mode
|
|
564
|
+
if (skippedSteps.includes(stepNumber)) {
|
|
557
565
|
workflow.steps[i] = {
|
|
558
566
|
status: STATUS.SKIPPED,
|
|
559
567
|
output: null,
|
|
@@ -608,14 +616,16 @@ export function getWorkflowProgress(workflow) {
|
|
|
608
616
|
}
|
|
609
617
|
|
|
610
618
|
const mode = workflow.mode || MODE.FULL;
|
|
619
|
+
const skippedSteps = getSkippedStepsForMode(mode);
|
|
620
|
+
const activeSteps = getStepsForMode(mode);
|
|
611
621
|
let completed = 0;
|
|
612
622
|
let lastCompletedStep = null;
|
|
613
623
|
|
|
614
624
|
workflow.steps.forEach((step, index) => {
|
|
615
625
|
const stepNumber = index + 1;
|
|
616
626
|
|
|
617
|
-
// Skip counting skipped steps
|
|
618
|
-
if (
|
|
627
|
+
// Skip counting skipped steps
|
|
628
|
+
if (skippedSteps.includes(stepNumber)) {
|
|
619
629
|
return;
|
|
620
630
|
}
|
|
621
631
|
|
|
@@ -625,8 +635,7 @@ export function getWorkflowProgress(workflow) {
|
|
|
625
635
|
}
|
|
626
636
|
});
|
|
627
637
|
|
|
628
|
-
|
|
629
|
-
const total = mode === MODE.QUICK ? QUICK_MODE_STEPS.length : STEPS.length;
|
|
638
|
+
const total = activeSteps.length;
|
|
630
639
|
|
|
631
640
|
return {
|
|
632
641
|
completed,
|
|
@@ -707,15 +716,12 @@ export function isQuickMode(workflow) {
|
|
|
707
716
|
* @returns {number|null} - Next step number or null if complete
|
|
708
717
|
*/
|
|
709
718
|
export function getNextStep(currentStep, mode) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
return null; // Workflow complete
|
|
719
|
+
const activeSteps = getStepsForMode(mode);
|
|
720
|
+
const currentIndex = activeSteps.indexOf(currentStep);
|
|
721
|
+
if (currentIndex >= 0 && currentIndex < activeSteps.length - 1) {
|
|
722
|
+
return activeSteps[currentIndex + 1];
|
|
716
723
|
}
|
|
717
|
-
//
|
|
718
|
-
return currentStep < STEPS.length ? currentStep + 1 : null;
|
|
724
|
+
return null; // Workflow complete
|
|
719
725
|
}
|
|
720
726
|
|
|
721
727
|
/**
|
|
@@ -725,7 +731,8 @@ export function getNextStep(currentStep, mode) {
|
|
|
725
731
|
* @returns {boolean}
|
|
726
732
|
*/
|
|
727
733
|
export function shouldSkipStep(stepNumber, mode) {
|
|
728
|
-
|
|
734
|
+
const skippedSteps = getSkippedStepsForMode(mode);
|
|
735
|
+
return skippedSteps.includes(stepNumber);
|
|
729
736
|
}
|
|
730
737
|
|
|
731
738
|
/**
|
|
@@ -749,14 +756,11 @@ export function getPrerequisiteSteps(stepNumber, mode = MODE.FULL) {
|
|
|
749
756
|
return [];
|
|
750
757
|
}
|
|
751
758
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
}
|
|
756
|
-
return QUICK_MODE_STEPS.filter(step => step < stepNumber);
|
|
759
|
+
const activeSteps = getStepsForMode(mode);
|
|
760
|
+
if (!activeSteps.includes(stepNumber)) {
|
|
761
|
+
return null;
|
|
757
762
|
}
|
|
758
|
-
|
|
759
|
-
return Array.from({ length: stepNumber - 1 }, (_, i) => i + 1);
|
|
763
|
+
return activeSteps.filter(step => step < stepNumber);
|
|
760
764
|
}
|
|
761
765
|
|
|
762
766
|
/**
|
package/src/templates/AGENTS.md
CHANGED
|
@@ -4,11 +4,11 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
4
4
|
|
|
5
5
|
## 快速检查清单
|
|
6
6
|
|
|
7
|
-
**完整模式 (7步)**:
|
|
7
|
+
**完整模式 (FULL, 7步)**:
|
|
8
8
|
- 按顺序执行: analyze → collect-req → collect-dep → design → apply → merge → archive
|
|
9
9
|
- 适用于: 复杂 UI 功能、多组件交互、需要详细设计审查
|
|
10
10
|
|
|
11
|
-
**快速模式 (5步)**:
|
|
11
|
+
**快速模式 (QUICK, 5步)**:
|
|
12
12
|
- 启动: `incspec analyze <path> --quick`
|
|
13
13
|
- 按顺序执行:
|
|
14
14
|
- 步骤1: analyze (代码分析)
|
|
@@ -20,23 +20,55 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
20
20
|
- 步骤7: archive (归档)
|
|
21
21
|
- 适用于: Bug 修复、简单功能、不涉及复杂 UI 依赖的变更
|
|
22
22
|
|
|
23
|
+
**极简模式 (MINIMAL, 3步)**:
|
|
24
|
+
- 启动: `incspec analyze <path> --minimal`
|
|
25
|
+
- 按顺序执行:
|
|
26
|
+
- 步骤1: analyze (代码分析)
|
|
27
|
+
- [跳过步骤2: 需求收集]
|
|
28
|
+
- [跳过步骤3: UI依赖采集]
|
|
29
|
+
- [跳过步骤4: 增量设计]
|
|
30
|
+
- 步骤5: apply (直接应用代码变更)
|
|
31
|
+
- [跳过步骤6: 合并基线]
|
|
32
|
+
- 步骤7: archive (归档,用户自行决定是否先合并基线)
|
|
33
|
+
- 适用于: 紧急 Bug 修复、单文件小改动、快速实验
|
|
34
|
+
- 注意: 归档时会提醒用户是否需要先生成新基线快照(可选运行 `incspec merge`)
|
|
35
|
+
|
|
23
36
|
**核心约定**:
|
|
24
37
|
- 初始化: `incspec init`
|
|
25
38
|
- 检查状态: `incspec status`
|
|
26
39
|
- 编号引用: `[S1]` 时序步骤, `[D1]` 依赖, `[C1]` 变更
|
|
27
40
|
- 增量标记: `[N1]` 新增, `[S1-Modified]` 修改, `[S1-Deleted]` 删除
|
|
28
|
-
- 验证时机:
|
|
41
|
+
- 验证时机: 完整/快速模式在步骤 1/4/6 后、归档前执行 `incspec validate`;极简模式在步骤 1 和归档前执行,若先执行 merge 则在合并后验证
|
|
29
42
|
|
|
30
43
|
## 七步工作流
|
|
31
44
|
|
|
32
45
|
```
|
|
33
46
|
完整模式: [1分析] → [2需求] → [3UI依赖] → [4设计] → [5应用] → [6合并] → [7归档] → 循环
|
|
34
47
|
快速模式: [1分析] → [2需求] ─(跳过3,4)─→ [5应用] → [6合并] → [7归档] → 循环
|
|
48
|
+
极简模式: [1分析] ─(跳过2,3,4,6)─→ [5应用] → [7归档] → 循环
|
|
35
49
|
```
|
|
36
50
|
|
|
51
|
+
### 模式对比表
|
|
52
|
+
|
|
53
|
+
| 维度 | 完整模式 (FULL) | 快速模式 (QUICK) | 极简模式 (MINIMAL) |
|
|
54
|
+
|------|----------------|-----------------|-------------------|
|
|
55
|
+
| 步骤数 | 7 步 | 5 步 | 3 步 |
|
|
56
|
+
| 跳过步骤 | 无 | 步骤 3, 4 | 步骤 2, 3, 4, 6 |
|
|
57
|
+
| 需求收集 | ✓ 5 列结构化需求 | ✓ 5 列结构化需求 | ✗ 直接应用 |
|
|
58
|
+
| 增量设计 | ✓ 完整设计蓝图 | ✗ 直接应用 | ✗ 直接应用 |
|
|
59
|
+
| UI 依赖采集 | ✓ 6 维度分析 | ✗ 跳过 | ✗ 跳过 |
|
|
60
|
+
| 合并基线 | ✓ merge 命令 | ✓ merge 命令 | ✗ 可选(归档时提醒) |
|
|
61
|
+
| 适用场景 | 复杂功能、架构变更 | Bug 修复、简单功能 | 紧急修复、单文件改动 |
|
|
62
|
+
| 审批门禁 | 设计阶段 + 应用前 | 应用前 | 应用前 |
|
|
63
|
+
|
|
37
64
|
### 步骤 1: 分析代码工作流
|
|
38
65
|
|
|
39
|
-
**命令**: `incspec analyze <source-path> [--module=name] [--quick] [--baseline=file]`
|
|
66
|
+
**命令**: `incspec analyze <source-path> [--module=name] [--quick|--minimal] [--baseline=file]`
|
|
67
|
+
|
|
68
|
+
**选项**:
|
|
69
|
+
- `--quick`: 启动快速模式(跳过步骤 3, 4)
|
|
70
|
+
- `--minimal`: 启动极简模式(跳过步骤 2/3/4,步骤 6 可选)
|
|
71
|
+
- `--baseline=file`: 使用现有基线(跳过分析,直接进入步骤 2;极简模式直接进入 apply)
|
|
40
72
|
|
|
41
73
|
**目的**: 生成包含 API 调用时序图和依赖关系图的基线快照。
|
|
42
74
|
|
|
@@ -51,6 +83,7 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
51
83
|
**命令**: `incspec collect-req [--force]` (别名: `cr`)
|
|
52
84
|
|
|
53
85
|
**目的**: 交互式需求收集,转换为 5 列格式。
|
|
86
|
+
**极简模式**: 跳过此步骤。
|
|
54
87
|
|
|
55
88
|
**输出**: `incspec/requirements/structured-requirements.md`
|
|
56
89
|
|
|
@@ -61,6 +94,7 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
61
94
|
**命令**: `incspec collect-dep [--force]` (别名: `cd`)
|
|
62
95
|
|
|
63
96
|
**目的**: 映射新增/修改 UI 组件的所有上下文依赖。
|
|
97
|
+
**极简模式**: 跳过此步骤。
|
|
64
98
|
|
|
65
99
|
**输出**: `incspec/requirements/ui-dependencies.md`
|
|
66
100
|
|
|
@@ -71,6 +105,7 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
71
105
|
**命令**: `incspec design [--feature=name] [--force]` (别名: `d`)
|
|
72
106
|
|
|
73
107
|
**目的**: 创建全面的增量设计蓝图。
|
|
108
|
+
**极简模式**: 跳过此步骤。
|
|
74
109
|
|
|
75
110
|
**输出**: `incspec/increments/{feature}-increment-v{n}.md`
|
|
76
111
|
|
|
@@ -93,13 +128,14 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
93
128
|
|
|
94
129
|
**执行顺序**: Types → Utils → APIs → Store → Components
|
|
95
130
|
|
|
96
|
-
**审批门禁**:
|
|
131
|
+
**审批门禁**: 完整/快速模式需审批增量设计;极简模式在 apply 前确认改动范围。
|
|
97
132
|
|
|
98
133
|
### 步骤 6: 合并到基线
|
|
99
134
|
|
|
100
135
|
**命令**: `incspec merge [increment-path] [--force]` (别名: `m`)
|
|
101
136
|
|
|
102
137
|
**目的**: 将增量整合到新的基线快照中。
|
|
138
|
+
**极简模式**: 可选执行(通常在归档前按需生成新基线)。
|
|
103
139
|
|
|
104
140
|
**处理**: 移除增量标记 → 合并新节点 → 重新编号为干净序列 → 输出新基线 v{n+1}
|
|
105
141
|
|
|
@@ -143,15 +179,18 @@ incspec init [--force] # 初始化项目
|
|
|
143
179
|
incspec status / st # 查看工作流状态
|
|
144
180
|
incspec list / ls [-l] [-a] # 列出规格文件
|
|
145
181
|
|
|
146
|
-
# 7步工作流
|
|
147
|
-
incspec analyze <path> [--quick] [--module=name] [--baseline=file] # 步骤1
|
|
148
|
-
incspec collect-req / cr [--force] # 步骤2 (--force
|
|
149
|
-
incspec collect-dep / cd [--force] # 步骤3 (
|
|
150
|
-
incspec design / d [--feature=name] [--force] # 步骤4 (
|
|
182
|
+
# 7步工作流 (支持三种模式)
|
|
183
|
+
incspec analyze <path> [--quick|--minimal] [--module=name] [--baseline=file] # 步骤1
|
|
184
|
+
incspec collect-req / cr [--force] # 步骤2 (--force 跳过前置检查,极简模式跳过)
|
|
185
|
+
incspec collect-dep / cd [--force] # 步骤3 (快速/极简模式跳过)
|
|
186
|
+
incspec design / d [--feature=name] [--force] # 步骤4 (快速/极简模式跳过)
|
|
151
187
|
incspec apply / ap [path] [--force] # 步骤5
|
|
152
|
-
incspec merge / m [path] [--force] # 步骤6
|
|
188
|
+
incspec merge / m [path] [--force] # 步骤6 (极简模式可选)
|
|
153
189
|
incspec archive [--yes] [--keep] # 步骤7
|
|
154
190
|
|
|
191
|
+
# 模式管理
|
|
192
|
+
incspec upgrade <mode> / ug # 升级工作流模式 (minimal → quick → full)
|
|
193
|
+
|
|
155
194
|
# 验证与同步
|
|
156
195
|
incspec validate / v [--strict] # 验证完整性
|
|
157
196
|
incspec sync [--cursor|--claude|--all] [--global|--project] # IDE集成
|
|
@@ -159,6 +198,31 @@ incspec reset # 完全重置工作流(归档所有产出
|
|
|
159
198
|
incspec reset --to=<step> # 部分回退到指定步骤(保留1-N,重置N+1至7)
|
|
160
199
|
```
|
|
161
200
|
|
|
201
|
+
### 模式升级
|
|
202
|
+
|
|
203
|
+
**命令**: `incspec upgrade <mode>`
|
|
204
|
+
|
|
205
|
+
**升级路径**: minimal → quick → full (只能从宽松到严格)
|
|
206
|
+
|
|
207
|
+
**用法示例**:
|
|
208
|
+
```bash
|
|
209
|
+
# 从极简模式升级到快速模式
|
|
210
|
+
incspec upgrade quick
|
|
211
|
+
|
|
212
|
+
# 从快速模式升级到完整模式
|
|
213
|
+
incspec upgrade full
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**升级效果**:
|
|
217
|
+
- 极简 → 快速: 需补充步骤 2 (需求收集) 和步骤 6 (合并基线)
|
|
218
|
+
- 快速 → 完整: 需补充步骤 3 (UI依赖) 和步骤 4 (增量设计)
|
|
219
|
+
- 极简 → 完整: 需补充步骤 2 (需求收集)、步骤 3 (UI依赖)、步骤 4 (增量设计) 和步骤 6 (合并基线)
|
|
220
|
+
|
|
221
|
+
**注意事项**:
|
|
222
|
+
- 只有在活跃工作流中才能升级
|
|
223
|
+
- 升级后需按提示补充缺失的步骤
|
|
224
|
+
- 不支持降级(full → quick 或 quick → minimal)
|
|
225
|
+
|
|
162
226
|
## 文件格式示例
|
|
163
227
|
|
|
164
228
|
### 基线文件
|
|
@@ -211,6 +275,9 @@ baseline: home-baseline-v1
|
|
|
211
275
|
**快速模式流程**:
|
|
212
276
|
1. 人类提供简单需求 → AI 执行步骤 1-2 → 人类审批 → AI 执行步骤 5-7 → 循环
|
|
213
277
|
|
|
278
|
+
**极简模式流程**:
|
|
279
|
+
1. 人类提供紧急修复需求 → AI 执行步骤 1 (分析) → AI 执行步骤 5 (直接应用) → AI 执行步骤 7 (归档,提醒是否合并基线) → 循环
|
|
280
|
+
|
|
214
281
|
**核心原则**:
|
|
215
282
|
- 增量优于大爆炸 - 小的、经过验证的变更
|
|
216
283
|
- 规格驱动 - 需求先于代码
|
|
@@ -231,6 +298,9 @@ baseline: home-baseline-v1
|
|
|
231
298
|
- 步骤 2-6 执行前会自动检查前置步骤是否完成
|
|
232
299
|
- 若前置步骤未完成,命令会提示并阻止执行
|
|
233
300
|
- 添加 `--force` 可跳过此检查,强制执行当前步骤
|
|
301
|
+
**极简模式**:
|
|
302
|
+
- 默认仅要求步骤 1 完成后才允许执行 apply
|
|
303
|
+
- 若选择执行 merge,将在归档前补齐合并与验证
|
|
234
304
|
|
|
235
305
|
**工作流重置**:
|
|
236
306
|
- 完全重置: `incspec reset` - 归档所有产出,回到初始状态
|
|
@@ -29,6 +29,21 @@ incspec analyze <source-path> --module=<module> --quick
|
|
|
29
29
|
- 简单功能迭代
|
|
30
30
|
- 不涉及复杂 UI 依赖变更的任务
|
|
31
31
|
|
|
32
|
+
**启动极简模式工作流** (3步流程):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
incspec analyze <source-path> --module=<module> --minimal
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
极简模式跳过步骤 2 (需求收集)、步骤 3 (UI依赖采集)、步骤 4 (增量设计) 和步骤 6 (合并基线)。适用于:
|
|
39
|
+
- 紧急 Bug 修复
|
|
40
|
+
- 单文件小改动
|
|
41
|
+
- 快速实验和原型验证
|
|
42
|
+
|
|
43
|
+
注意:
|
|
44
|
+
- apply 时基于口头需求直接执行代码变更
|
|
45
|
+
- archive 时会提醒用户是否需要先运行 `incspec merge` 生成新基线(可选)
|
|
46
|
+
|
|
32
47
|
**使用现有基准报告** (跳过分析):
|
|
33
48
|
|
|
34
49
|
若已有基准报告文件,可直接使用:
|