@localsummer/incspec 0.0.6 → 0.0.8
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 +76 -15
- package/commands/analyze.mjs +28 -12
- package/commands/apply.mjs +78 -33
- package/commands/archive.mjs +25 -3
- package/commands/collect-dep.mjs +2 -2
- package/commands/collect-req.mjs +10 -2
- package/commands/design.mjs +2 -2
- package/commands/help.mjs +20 -11
- package/commands/list.mjs +2 -1
- package/commands/merge.mjs +64 -33
- package/commands/reset.mjs +166 -0
- package/commands/status.mjs +30 -7
- package/commands/sync.mjs +210 -0
- package/commands/update.mjs +2 -1
- package/index.mjs +13 -6
- package/lib/agents.mjs +1 -1
- package/lib/claude.mjs +144 -0
- package/lib/config.mjs +13 -10
- package/lib/cursor.mjs +20 -5
- package/lib/terminal.mjs +108 -0
- package/lib/workflow.mjs +123 -29
- package/package.json +1 -1
- package/templates/AGENTS.md +89 -36
- package/templates/INCSPEC_BLOCK.md +1 -1
- package/templates/WORKFLOW.md +1 -0
- package/templates/cursor-commands/analyze-codeflow.md +12 -1
- package/templates/cursor-commands/apply-increment-code.md +129 -1
- package/templates/cursor-commands/merge-to-baseline.md +87 -1
- package/templates/cursor-commands/structured-requirements-collection.md +6 -0
- package/templates/inc-spec-skill/SKILL.md +286 -0
- package/templates/inc-spec-skill/references/analyze-codeflow.md +368 -0
- package/templates/inc-spec-skill/references/analyze-increment-codeflow.md +246 -0
- package/templates/inc-spec-skill/references/apply-increment-code.md +520 -0
- package/templates/inc-spec-skill/references/inc-archive.md +278 -0
- package/templates/inc-spec-skill/references/merge-to-baseline.md +415 -0
- package/templates/inc-spec-skill/references/structured-requirements-collection.md +129 -0
- package/templates/inc-spec-skill/references/ui-dependency-collection.md +143 -0
- package/commands/cursor-sync.mjs +0 -116
package/lib/workflow.mjs
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import { INCSPEC_DIR, FILES, getTemplatesDir } from './config.mjs';
|
|
11
|
+
import { formatLocalDateTime } from './terminal.mjs';
|
|
11
12
|
|
|
12
13
|
/** Workflow steps definition */
|
|
13
14
|
export const STEPS = [
|
|
@@ -17,6 +18,7 @@ export const STEPS = [
|
|
|
17
18
|
{ id: 4, name: 'design-increment', label: '增量设计', command: 'design' },
|
|
18
19
|
{ id: 5, name: 'apply-code', label: '应用代码变更', command: 'apply' },
|
|
19
20
|
{ id: 6, name: 'merge-baseline', label: '合并到基线', command: 'merge' },
|
|
21
|
+
{ id: 7, name: 'archive-workflow', label: '归档工作流产出', command: 'archive' },
|
|
20
22
|
];
|
|
21
23
|
|
|
22
24
|
/** Step status */
|
|
@@ -24,8 +26,21 @@ export const STATUS = {
|
|
|
24
26
|
PENDING: 'pending',
|
|
25
27
|
IN_PROGRESS: 'in_progress',
|
|
26
28
|
COMPLETED: 'completed',
|
|
29
|
+
SKIPPED: 'skipped',
|
|
27
30
|
};
|
|
28
31
|
|
|
32
|
+
/** Workflow mode */
|
|
33
|
+
export const MODE = {
|
|
34
|
+
FULL: 'full',
|
|
35
|
+
QUICK: 'quick',
|
|
36
|
+
};
|
|
37
|
+
|
|
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
|
+
|
|
29
44
|
function normalizeOutputName(outputFile) {
|
|
30
45
|
if (!outputFile || typeof outputFile !== 'string') {
|
|
31
46
|
return outputFile;
|
|
@@ -116,6 +131,7 @@ export function parseWorkflow(content) {
|
|
|
116
131
|
const workflow = {
|
|
117
132
|
currentWorkflow: null,
|
|
118
133
|
currentStep: null,
|
|
134
|
+
mode: MODE.FULL,
|
|
119
135
|
startTime: null,
|
|
120
136
|
lastUpdate: null,
|
|
121
137
|
steps: [],
|
|
@@ -136,6 +152,13 @@ export function parseWorkflow(content) {
|
|
|
136
152
|
workflow.currentStep = parseInt(stepMatch[1], 10);
|
|
137
153
|
}
|
|
138
154
|
|
|
155
|
+
// Parse mode field
|
|
156
|
+
const modeMatch = content.match(/\*\*工作流模式\*\*:\s*(.+)/);
|
|
157
|
+
if (modeMatch) {
|
|
158
|
+
const modeValue = modeMatch[1].trim().toLowerCase();
|
|
159
|
+
workflow.mode = modeValue === 'quick' ? MODE.QUICK : MODE.FULL;
|
|
160
|
+
}
|
|
161
|
+
|
|
139
162
|
const startMatch = content.match(/\*\*开始时间\*\*:\s*(.+)/);
|
|
140
163
|
if (startMatch) {
|
|
141
164
|
workflow.startTime = startMatch[1].trim();
|
|
@@ -211,13 +234,15 @@ export function readWorkflow(projectRoot) {
|
|
|
211
234
|
* @returns {string}
|
|
212
235
|
*/
|
|
213
236
|
export function generateWorkflowContent(workflow) {
|
|
214
|
-
const now = new Date()
|
|
237
|
+
const now = formatLocalDateTime(new Date());
|
|
238
|
+
const mode = workflow.mode || MODE.FULL;
|
|
215
239
|
|
|
216
240
|
const lines = [
|
|
217
241
|
'# Workflow Status',
|
|
218
242
|
'',
|
|
219
243
|
`**当前工作流**: ${workflow.currentWorkflow || '-'}`,
|
|
220
244
|
`**当前步骤**: ${workflow.currentStep || '-'}`,
|
|
245
|
+
`**工作流模式**: ${mode}`,
|
|
221
246
|
`**开始时间**: ${workflow.startTime || '-'}`,
|
|
222
247
|
`**最后更新**: ${now}`,
|
|
223
248
|
'',
|
|
@@ -271,10 +296,11 @@ export function initWorkflow(projectRoot) {
|
|
|
271
296
|
const workflowPath = getWorkflowPath(projectRoot);
|
|
272
297
|
const content = generateInitialWorkflowContent();
|
|
273
298
|
fs.writeFileSync(workflowPath, content, 'utf-8');
|
|
274
|
-
|
|
299
|
+
|
|
275
300
|
return {
|
|
276
301
|
currentWorkflow: null,
|
|
277
302
|
currentStep: null,
|
|
303
|
+
mode: MODE.FULL,
|
|
278
304
|
startTime: null,
|
|
279
305
|
lastUpdate: null,
|
|
280
306
|
steps: STEPS.map(() => ({
|
|
@@ -292,14 +318,14 @@ export function initWorkflow(projectRoot) {
|
|
|
292
318
|
*/
|
|
293
319
|
function generateInitialWorkflowContent() {
|
|
294
320
|
const templatePath = path.join(getTemplatesDir(), 'WORKFLOW.md');
|
|
295
|
-
const now = new Date()
|
|
296
|
-
|
|
321
|
+
const now = formatLocalDateTime(new Date());
|
|
322
|
+
|
|
297
323
|
if (fs.existsSync(templatePath)) {
|
|
298
324
|
let content = fs.readFileSync(templatePath, 'utf-8');
|
|
299
325
|
content = content.replace(/\{\{last_update\}\}/g, now);
|
|
300
326
|
return content;
|
|
301
327
|
}
|
|
302
|
-
|
|
328
|
+
|
|
303
329
|
// Fallback to generated content
|
|
304
330
|
const workflow = {
|
|
305
331
|
currentWorkflow: null,
|
|
@@ -313,7 +339,7 @@ function generateInitialWorkflowContent() {
|
|
|
313
339
|
})),
|
|
314
340
|
history: [],
|
|
315
341
|
};
|
|
316
|
-
|
|
342
|
+
|
|
317
343
|
return generateWorkflowContent(workflow);
|
|
318
344
|
}
|
|
319
345
|
|
|
@@ -321,10 +347,12 @@ function generateInitialWorkflowContent() {
|
|
|
321
347
|
* Start a new workflow
|
|
322
348
|
* @param {string} projectRoot
|
|
323
349
|
* @param {string} workflowName
|
|
350
|
+
* @param {Object} options - { mode: 'full' | 'quick' }
|
|
324
351
|
* @returns {Object}
|
|
325
352
|
*/
|
|
326
|
-
export function startWorkflow(projectRoot, workflowName) {
|
|
327
|
-
const now = new Date()
|
|
353
|
+
export function startWorkflow(projectRoot, workflowName, options = {}) {
|
|
354
|
+
const now = formatLocalDateTime(new Date());
|
|
355
|
+
const mode = options.mode || MODE.FULL;
|
|
328
356
|
let workflow = readWorkflow(projectRoot);
|
|
329
357
|
|
|
330
358
|
if (!workflow) {
|
|
@@ -335,12 +363,12 @@ export function startWorkflow(projectRoot, workflowName) {
|
|
|
335
363
|
if (workflow.currentWorkflow) {
|
|
336
364
|
const progress = getWorkflowProgress(workflow);
|
|
337
365
|
const isComplete = progress.completed === progress.total;
|
|
338
|
-
|
|
366
|
+
|
|
339
367
|
// Format: "workflowName (completed/total)" for incomplete, just name for complete
|
|
340
|
-
const historyName = isComplete
|
|
341
|
-
? workflow.currentWorkflow
|
|
368
|
+
const historyName = isComplete
|
|
369
|
+
? workflow.currentWorkflow
|
|
342
370
|
: `${workflow.currentWorkflow} (${progress.completed}/${progress.total})`;
|
|
343
|
-
|
|
371
|
+
|
|
344
372
|
workflow.history.unshift({
|
|
345
373
|
name: historyName,
|
|
346
374
|
status: isComplete ? 'completed' : 'incomplete',
|
|
@@ -352,12 +380,24 @@ export function startWorkflow(projectRoot, workflowName) {
|
|
|
352
380
|
// Start new workflow
|
|
353
381
|
workflow.currentWorkflow = workflowName;
|
|
354
382
|
workflow.currentStep = 1;
|
|
383
|
+
workflow.mode = mode;
|
|
355
384
|
workflow.startTime = now;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
385
|
+
|
|
386
|
+
// Initialize steps - mark skipped steps in quick mode
|
|
387
|
+
workflow.steps = STEPS.map((step) => {
|
|
388
|
+
if (mode === MODE.QUICK && QUICK_MODE_SKIPPED.includes(step.id)) {
|
|
389
|
+
return {
|
|
390
|
+
status: STATUS.SKIPPED,
|
|
391
|
+
output: null,
|
|
392
|
+
completedAt: now,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
status: STATUS.PENDING,
|
|
397
|
+
output: null,
|
|
398
|
+
completedAt: null,
|
|
399
|
+
};
|
|
400
|
+
});
|
|
361
401
|
|
|
362
402
|
writeWorkflow(projectRoot, workflow);
|
|
363
403
|
return workflow;
|
|
@@ -381,8 +421,9 @@ export function updateStep(projectRoot, stepNumber, status, outputFile = null) {
|
|
|
381
421
|
throw new Error(`无效的步骤编号: ${stepNumber}`);
|
|
382
422
|
}
|
|
383
423
|
|
|
384
|
-
const now = new Date()
|
|
424
|
+
const now = formatLocalDateTime(new Date());
|
|
385
425
|
const normalizedOutput = normalizeOutputName(outputFile);
|
|
426
|
+
const mode = workflow.mode || MODE.FULL;
|
|
386
427
|
|
|
387
428
|
workflow.steps[index] = {
|
|
388
429
|
status,
|
|
@@ -390,11 +431,15 @@ export function updateStep(projectRoot, stepNumber, status, outputFile = null) {
|
|
|
390
431
|
completedAt: status === STATUS.COMPLETED ? now : null,
|
|
391
432
|
};
|
|
392
433
|
|
|
393
|
-
// Update current step
|
|
434
|
+
// Update current step based on mode
|
|
394
435
|
if (status === STATUS.IN_PROGRESS) {
|
|
395
436
|
workflow.currentStep = stepNumber;
|
|
396
|
-
} else if (status === STATUS.COMPLETED
|
|
397
|
-
|
|
437
|
+
} else if (status === STATUS.COMPLETED) {
|
|
438
|
+
const nextStep = getNextStep(stepNumber, mode);
|
|
439
|
+
if (nextStep) {
|
|
440
|
+
workflow.currentStep = nextStep;
|
|
441
|
+
}
|
|
442
|
+
// nextStep is null means workflow is complete
|
|
398
443
|
}
|
|
399
444
|
|
|
400
445
|
writeWorkflow(projectRoot, workflow);
|
|
@@ -411,7 +456,7 @@ export function completeWorkflow(projectRoot) {
|
|
|
411
456
|
throw new Error('工作流未初始化');
|
|
412
457
|
}
|
|
413
458
|
|
|
414
|
-
const now = new Date()
|
|
459
|
+
const now = formatLocalDateTime(new Date());
|
|
415
460
|
|
|
416
461
|
// Add to history
|
|
417
462
|
workflow.history.unshift({
|
|
@@ -440,7 +485,7 @@ export function archiveWorkflow(projectRoot) {
|
|
|
440
485
|
throw new Error('工作流未初始化');
|
|
441
486
|
}
|
|
442
487
|
|
|
443
|
-
const now = new Date()
|
|
488
|
+
const now = formatLocalDateTime(new Date());
|
|
444
489
|
|
|
445
490
|
workflow.history.unshift({
|
|
446
491
|
name: workflow.currentWorkflow,
|
|
@@ -483,27 +528,39 @@ export function getStepByCommand(command) {
|
|
|
483
528
|
/**
|
|
484
529
|
* Calculate workflow completion progress
|
|
485
530
|
* @param {Object} workflow
|
|
486
|
-
* @returns {{completed: number, total: number, lastCompletedStep: number|null}}
|
|
531
|
+
* @returns {{completed: number, total: number, lastCompletedStep: number|null, mode: string}}
|
|
487
532
|
*/
|
|
488
533
|
export function getWorkflowProgress(workflow) {
|
|
489
534
|
if (!workflow || !workflow.steps) {
|
|
490
|
-
return { completed: 0, total: STEPS.length, lastCompletedStep: null };
|
|
535
|
+
return { completed: 0, total: STEPS.length, lastCompletedStep: null, mode: MODE.FULL };
|
|
491
536
|
}
|
|
492
537
|
|
|
538
|
+
const mode = workflow.mode || MODE.FULL;
|
|
493
539
|
let completed = 0;
|
|
494
540
|
let lastCompletedStep = null;
|
|
495
541
|
|
|
496
542
|
workflow.steps.forEach((step, index) => {
|
|
543
|
+
const stepNumber = index + 1;
|
|
544
|
+
|
|
545
|
+
// Skip counting skipped steps in quick mode
|
|
546
|
+
if (mode === MODE.QUICK && QUICK_MODE_SKIPPED.includes(stepNumber)) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
497
550
|
if (step && step.status === STATUS.COMPLETED) {
|
|
498
551
|
completed++;
|
|
499
|
-
lastCompletedStep =
|
|
552
|
+
lastCompletedStep = stepNumber;
|
|
500
553
|
}
|
|
501
554
|
});
|
|
502
555
|
|
|
556
|
+
// Quick mode has 5 steps (1,2,5,6,7), full mode has 7 steps
|
|
557
|
+
const total = mode === MODE.QUICK ? QUICK_MODE_STEPS.length : STEPS.length;
|
|
558
|
+
|
|
503
559
|
return {
|
|
504
560
|
completed,
|
|
505
|
-
total
|
|
561
|
+
total,
|
|
506
562
|
lastCompletedStep,
|
|
563
|
+
mode,
|
|
507
564
|
};
|
|
508
565
|
}
|
|
509
566
|
|
|
@@ -533,7 +590,7 @@ export function isWorkflowIncomplete(workflow) {
|
|
|
533
590
|
*/
|
|
534
591
|
export function addToHistory(projectRoot, entry) {
|
|
535
592
|
let workflow = readWorkflow(projectRoot);
|
|
536
|
-
|
|
593
|
+
|
|
537
594
|
if (!workflow) {
|
|
538
595
|
workflow = {
|
|
539
596
|
currentWorkflow: null,
|
|
@@ -549,7 +606,7 @@ export function addToHistory(projectRoot, entry) {
|
|
|
549
606
|
};
|
|
550
607
|
}
|
|
551
608
|
|
|
552
|
-
const now = new Date()
|
|
609
|
+
const now = formatLocalDateTime(new Date());
|
|
553
610
|
|
|
554
611
|
workflow.history.unshift({
|
|
555
612
|
name: entry.name,
|
|
@@ -561,3 +618,40 @@ export function addToHistory(projectRoot, entry) {
|
|
|
561
618
|
writeWorkflow(projectRoot, workflow);
|
|
562
619
|
return workflow;
|
|
563
620
|
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Check if workflow is in quick mode
|
|
624
|
+
* @param {Object} workflow
|
|
625
|
+
* @returns {boolean}
|
|
626
|
+
*/
|
|
627
|
+
export function isQuickMode(workflow) {
|
|
628
|
+
return workflow?.mode === MODE.QUICK;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Get next valid step based on mode
|
|
633
|
+
* @param {number} currentStep - Current step number (1-based)
|
|
634
|
+
* @param {string} mode - Workflow mode
|
|
635
|
+
* @returns {number|null} - Next step number or null if complete
|
|
636
|
+
*/
|
|
637
|
+
export function getNextStep(currentStep, mode) {
|
|
638
|
+
if (mode === MODE.QUICK) {
|
|
639
|
+
const currentIndex = QUICK_MODE_STEPS.indexOf(currentStep);
|
|
640
|
+
if (currentIndex >= 0 && currentIndex < QUICK_MODE_STEPS.length - 1) {
|
|
641
|
+
return QUICK_MODE_STEPS[currentIndex + 1];
|
|
642
|
+
}
|
|
643
|
+
return null; // Workflow complete
|
|
644
|
+
}
|
|
645
|
+
// Full mode
|
|
646
|
+
return currentStep < STEPS.length ? currentStep + 1 : null;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Check if a step should be skipped based on mode
|
|
651
|
+
* @param {number} stepNumber - Step number (1-based)
|
|
652
|
+
* @param {string} mode - Workflow mode
|
|
653
|
+
* @returns {boolean}
|
|
654
|
+
*/
|
|
655
|
+
export function shouldSkipStep(stepNumber, mode) {
|
|
656
|
+
return mode === MODE.QUICK && QUICK_MODE_SKIPPED.includes(stepNumber);
|
|
657
|
+
}
|
package/package.json
CHANGED
package/templates/AGENTS.md
CHANGED
|
@@ -4,48 +4,69 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
|
|
|
4
4
|
|
|
5
5
|
## 快速检查清单
|
|
6
6
|
|
|
7
|
+
**完整模式 (7步):**
|
|
7
8
|
- 初始化项目: `incspec init` (创建 `incspec/` 目录结构)
|
|
8
9
|
- 检查状态: `incspec status` 或 `incspec st`
|
|
9
|
-
- 按顺序执行
|
|
10
|
+
- 按顺序执行7步工作流: analyze → collect-req → collect-dep → design → apply → merge -> archive
|
|
10
11
|
- 使用编号引用: `[S1]` 表示时序步骤, `[D1]` 表示依赖, `[C1]` 表示变更
|
|
11
12
|
- 标记增量: `[N1]` 新增, `[S1-Modified]` 修改, `[S1-Deleted]` 删除
|
|
12
13
|
- 继续前先验证: `incspec validate --strict`
|
|
13
14
|
- 合并后循环回到步骤1开始下一个增量周期
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
**快速模式 (5步):**
|
|
17
|
+
- 启动快速模式: `incspec analyze <path> --quick`
|
|
18
|
+
- 按顺序执行: analyze → collect-req → apply → merge -> archive
|
|
19
|
+
- 跳过步骤 3 (UI依赖采集) 和步骤 4 (增量设计)
|
|
20
|
+
- 适用于 Bug 修复、简单功能、不涉及复杂 UI 依赖的变更
|
|
21
|
+
|
|
22
|
+
## 七步工作流
|
|
16
23
|
|
|
17
24
|
### 概览
|
|
18
25
|
|
|
19
26
|
```
|
|
20
|
-
|
|
21
|
-
│
|
|
22
|
-
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
│
|
|
26
|
-
│ │
|
|
27
|
-
│ │
|
|
28
|
-
│
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
│
|
|
32
|
-
│
|
|
33
|
-
│ │
|
|
34
|
-
│ │
|
|
35
|
-
│
|
|
36
|
-
│
|
|
37
|
-
│
|
|
38
|
-
│
|
|
39
|
-
|
|
27
|
+
┌───────────────────────────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ IncSpec 工作流模式 │
|
|
29
|
+
├───────────────────────────────────────────────────────────────────────────────────┤
|
|
30
|
+
│ │
|
|
31
|
+
│ 完整模式 (7步): │
|
|
32
|
+
│ │
|
|
33
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
34
|
+
│ │ 步骤 1 │ │ 步骤 2 │ │ 步骤 3 │ │ 步骤 4 │ │
|
|
35
|
+
│ │ 分析 │───▶│ 收集 │───▶│ 收集 │───▶│ 设计 │ │
|
|
36
|
+
│ │ 代码流 │ │ 需求 │ │ UI依赖 │ │ 增量 │ │
|
|
37
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
38
|
+
│ ▲ │ │
|
|
39
|
+
│ │ ▼ │
|
|
40
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
41
|
+
│ │ │ │ 步骤 7 │ │ 步骤 6 │ │ 步骤 5 │ │
|
|
42
|
+
│ │ 循环 │◀───│ 归档 │◀───│ 合并到 │◀───│ 应用 │ │
|
|
43
|
+
│ │ │ │ 产出 │ │ 基线 │ │ 代码 │ │
|
|
44
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
45
|
+
│ │
|
|
46
|
+
│ 快速模式 (5步): │
|
|
47
|
+
│ │
|
|
48
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
49
|
+
│ │ 步骤 1 │ │ 步骤 2 │ │ 步骤 5 │ │ 步骤 6 │ │ 步骤 7 │ │
|
|
50
|
+
│ │ 分析 │───▶│ 收集 │───▶│ 应用 │───▶│ 合并到 │───▶│ 归档 │ │
|
|
51
|
+
│ │ 代码流 │ │ 需求 │ │ 代码 │ │ 基线 │ │ 产出 │ │
|
|
52
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
53
|
+
│ (跳过步骤 3 UI依赖采集 和 步骤 4 增量设计) │
|
|
54
|
+
│ │
|
|
55
|
+
└───────────────────────────────────────────────────────────────────────────────────┘
|
|
40
56
|
```
|
|
41
57
|
|
|
58
|
+
**模式选择:**
|
|
59
|
+
- **完整模式**: 复杂 UI 功能、多组件交互、需要详细设计审查
|
|
60
|
+
- **快速模式**: Bug 修复、简单功能、不涉及 UI 依赖变更
|
|
61
|
+
|
|
42
62
|
### 步骤 1: 分析代码工作流
|
|
43
63
|
|
|
44
|
-
**命令**: `incspec analyze <source-path> [--module=name] [--baseline=file]`
|
|
64
|
+
**命令**: `incspec analyze <source-path> [--module=name] [--quick] [--baseline=file]`
|
|
45
65
|
|
|
46
66
|
**目的**: 生成包含 API 调用时序图和依赖关系图的基线快照。
|
|
47
67
|
|
|
48
68
|
**选项**:
|
|
69
|
+
- `--quick`: 启动快速模式 (5步流程)
|
|
49
70
|
- `--baseline=<file>`: 使用现有基准报告,自动从 baselines/ 或 archives/ 目录恢复
|
|
50
71
|
|
|
51
72
|
**输出**: `incspec/baselines/{module}-baseline-v{n}.md`
|
|
@@ -186,6 +207,19 @@ graph TD
|
|
|
186
207
|
|
|
187
208
|
**结果**: 新基线成为下一个增量周期的起点。
|
|
188
209
|
|
|
210
|
+
### 步骤 7: 归档工作流产出
|
|
211
|
+
|
|
212
|
+
**命令**: `incspec archive [--yes] [<file>] [--keep]`
|
|
213
|
+
|
|
214
|
+
**目的**: 将已完成的工作流产出文件归档到历史记录目录。
|
|
215
|
+
|
|
216
|
+
**处理流程**:
|
|
217
|
+
1. 确定要归档的文件 (默认全部当前工作流产出)
|
|
218
|
+
2. 创建归档目录: `incspec/archives/YYYY-MM/{module}/`
|
|
219
|
+
3. 移动或复制文件到归档目录 (取决于 `--keep` 选项)
|
|
220
|
+
4. 更新工作流状态以反映归档
|
|
221
|
+
|
|
222
|
+
|
|
189
223
|
## 任务前准备
|
|
190
224
|
|
|
191
225
|
**上下文检查清单**:
|
|
@@ -199,7 +233,7 @@ graph TD
|
|
|
199
233
|
- 始终从最新基线开始
|
|
200
234
|
- 在开始新增量之前完成上一个增量
|
|
201
235
|
- 使用 `incspec validate` 检查完整性
|
|
202
|
-
- 严格按步骤顺序执行: 1 → 2 → 3 → 4 → 5 → 6
|
|
236
|
+
- 严格按步骤顺序执行: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
|
203
237
|
|
|
204
238
|
## 快速开始
|
|
205
239
|
|
|
@@ -217,13 +251,14 @@ incspec list baselines # 仅列出基线
|
|
|
217
251
|
incspec list -l # 长格式(含时间戳)
|
|
218
252
|
incspec list -a # 包含归档
|
|
219
253
|
|
|
220
|
-
#
|
|
221
|
-
incspec analyze <path> [--module=name] [--baseline=file] # 步骤1: 基线分析
|
|
254
|
+
# 7步工作流
|
|
255
|
+
incspec analyze <path> [--module=name] [--quick] [--baseline=file] # 步骤1: 基线分析
|
|
222
256
|
incspec collect-req / cr # 步骤2: 需求收集
|
|
223
|
-
incspec collect-dep / cd # 步骤3: 依赖收集
|
|
224
|
-
incspec design [--feature=name] / d # 步骤4: 增量设计
|
|
257
|
+
incspec collect-dep / cd # 步骤3: 依赖收集 (快速模式跳过)
|
|
258
|
+
incspec design [--feature=name] / d # 步骤4: 增量设计 (快速模式跳过)
|
|
225
259
|
incspec apply [path] / ap # 步骤5: 代码执行
|
|
226
260
|
incspec merge [path] / m # 步骤6: 基线合并
|
|
261
|
+
incspec archive --yes # 步骤7: 归档产出
|
|
227
262
|
|
|
228
263
|
# 验证与管理
|
|
229
264
|
incspec validate / v # 验证完整性
|
|
@@ -234,9 +269,12 @@ incspec archive <file> # 归档指定文件
|
|
|
234
269
|
incspec archive <file> --keep # 复制而非移动
|
|
235
270
|
|
|
236
271
|
# IDE 集成
|
|
237
|
-
incspec
|
|
238
|
-
incspec
|
|
239
|
-
incspec
|
|
272
|
+
incspec sync # 交互式选择同步目标
|
|
273
|
+
incspec sync --cursor # 同步 Cursor 斜杠命令
|
|
274
|
+
incspec sync --claude # 同步 Claude Code Skill
|
|
275
|
+
incspec sync --all # 同步全部
|
|
276
|
+
incspec sync --global # 同步到全局目录
|
|
277
|
+
incspec sync --project # 同步到当前目录
|
|
240
278
|
|
|
241
279
|
# 帮助
|
|
242
280
|
incspec help [command] # 显示帮助
|
|
@@ -245,7 +283,7 @@ incspec --version / -v # 显示版本
|
|
|
245
283
|
|
|
246
284
|
### Cursor 斜杠命令
|
|
247
285
|
|
|
248
|
-
运行 `incspec cursor
|
|
286
|
+
运行 `incspec sync --cursor` 后,以下命令可用:
|
|
249
287
|
|
|
250
288
|
| 命令 | 步骤 | 描述 |
|
|
251
289
|
|------|------|------|
|
|
@@ -255,6 +293,7 @@ incspec --version / -v # 显示版本
|
|
|
255
293
|
| `/incspec/inc-design` | 4 | 设计增量蓝图 |
|
|
256
294
|
| `/incspec/inc-apply` | 5 | 应用代码变更 |
|
|
257
295
|
| `/incspec/inc-merge` | 6 | 合并到基线 |
|
|
296
|
+
| `/incspec/inc-archive` | 7 | 归档工作流产出 |
|
|
258
297
|
| `/incspec/inc-status` | - | 检查工作流状态 |
|
|
259
298
|
| `/incspec/inc-help` | - | 显示帮助 |
|
|
260
299
|
|
|
@@ -481,7 +520,7 @@ updated: 2024-01-16T14:30:00Z
|
|
|
481
520
|
|
|
482
521
|
### 工作流纪律
|
|
483
522
|
|
|
484
|
-
1. **不要跳过步骤** -
|
|
523
|
+
1. **不要跳过步骤** - 完整模式按1-7顺序执行,快速模式按1-2-5-6-7执行
|
|
485
524
|
2. **一次一个增量** - 完成后再开始下一个
|
|
486
525
|
3. **频繁验证** - 继续前运行 `incspec validate`
|
|
487
526
|
4. **保持基线最新** - 实施成功后始终合并
|
|
@@ -585,13 +624,15 @@ incspec status
|
|
|
585
624
|
incspec status # 我在哪里?
|
|
586
625
|
incspec list # 有什么?
|
|
587
626
|
incspec validate --strict # 是否正确?
|
|
588
|
-
incspec
|
|
627
|
+
incspec sync # 设置IDE命令
|
|
589
628
|
```
|
|
590
629
|
|
|
591
630
|
## 与AI助手集成
|
|
592
631
|
|
|
593
632
|
### 推荐工作流
|
|
594
633
|
|
|
634
|
+
**完整模式 (7步):**
|
|
635
|
+
|
|
595
636
|
1. **人类**: 提供高层需求
|
|
596
637
|
2. **AI**: 运行步骤1 (analyze) 理解代码库
|
|
597
638
|
3. **AI**: 运行步骤2 (collect-req) 并提出澄清问题
|
|
@@ -601,7 +642,19 @@ incspec cursor-sync # 设置IDE命令
|
|
|
601
642
|
7. **AI**: 运行步骤5 (apply) 生成代码
|
|
602
643
|
8. **人类**: 测试并验证变更
|
|
603
644
|
9. **AI**: 运行步骤6 (merge) 更新基线
|
|
604
|
-
10.
|
|
645
|
+
10. **AI**: 运行步骤7 (archive) 归档产出
|
|
646
|
+
11. **循环**: 返回步骤1开始下一个增量
|
|
647
|
+
|
|
648
|
+
**快速模式 (5步):**
|
|
649
|
+
|
|
650
|
+
1. **人类**: 提供简单需求 (Bug修复/小功能)
|
|
651
|
+
2. **AI**: 运行步骤1 (analyze --quick) 理解代码库
|
|
652
|
+
3. **AI**: 运行步骤2 (collect-req) 收集需求
|
|
653
|
+
4. **AI**: 运行步骤5 (apply) 生成代码
|
|
654
|
+
5. **人类**: 测试并验证变更
|
|
655
|
+
6. **AI**: 运行步骤6 (merge) 更新基线
|
|
656
|
+
7. **AI**: 运行步骤7 (archive) 归档产出
|
|
657
|
+
8. **循环**: 返回步骤1开始下一个增量
|
|
605
658
|
|
|
606
659
|
### 核心原则
|
|
607
660
|
|
|
@@ -610,4 +663,4 @@ incspec cursor-sync # 设置IDE命令
|
|
|
610
663
|
- **可追溯** - 每个变更都关联到需求
|
|
611
664
|
- **可逆转** - 基线提供回滚点
|
|
612
665
|
|
|
613
|
-
记住: 基线是真相。增量是提案。通过
|
|
666
|
+
记住: 基线是真相。增量是提案。通过7步周期保持它们同步。
|
package/templates/WORKFLOW.md
CHANGED
|
@@ -18,6 +18,17 @@ incspec analyze <source-path> --module=<module> --workflow=analyze-<module>
|
|
|
18
18
|
incspec analyze <source-path> --module=<module> --workflow=analyze-<module> --complete --output=<output-file>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
**启动快速模式工作流** (5步流程):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
incspec analyze <source-path> --module=<module> --quick
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
快速模式跳过步骤 3 (UI依赖采集) 和步骤 4 (增量设计),直接从需求进入代码应用。适用于:
|
|
28
|
+
- Bug 修复
|
|
29
|
+
- 简单功能迭代
|
|
30
|
+
- 不涉及复杂 UI 依赖变更的任务
|
|
31
|
+
|
|
21
32
|
**使用现有基准报告** (跳过分析):
|
|
22
33
|
|
|
23
34
|
若已有基准报告文件,可直接使用:
|
|
@@ -27,7 +38,7 @@ incspec analyze --baseline=<baseline-file> [--module=<module>] [--workflow=<work
|
|
|
27
38
|
```
|
|
28
39
|
|
|
29
40
|
说明:
|
|
30
|
-
- `<baseline-file>`
|
|
41
|
+
- `<baseline-file>` 文件名,自动递归搜索 baselines/ 和 archives/ 目录
|
|
31
42
|
- 若文件在归档目录,自动移动到 baselines/ 目录
|
|
32
43
|
- `<module>` 默认从文件名推断 (xxx-baseline-vN.md -> xxx)
|
|
33
44
|
- `<workflow>` 默认为 analyze-<module>
|