@localsummer/incspec 0.0.1
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/LICENSE +15 -0
- package/README.md +540 -0
- package/commands/analyze.mjs +133 -0
- package/commands/apply.mjs +111 -0
- package/commands/archive.mjs +340 -0
- package/commands/collect-dep.mjs +85 -0
- package/commands/collect-req.mjs +80 -0
- package/commands/cursor-sync.mjs +116 -0
- package/commands/design.mjs +131 -0
- package/commands/help.mjs +235 -0
- package/commands/init.mjs +127 -0
- package/commands/list.mjs +111 -0
- package/commands/merge.mjs +112 -0
- package/commands/status.mjs +117 -0
- package/commands/update.mjs +189 -0
- package/commands/validate.mjs +181 -0
- package/index.mjs +236 -0
- package/lib/agents.mjs +163 -0
- package/lib/config.mjs +343 -0
- package/lib/cursor.mjs +307 -0
- package/lib/spec.mjs +300 -0
- package/lib/terminal.mjs +292 -0
- package/lib/workflow.mjs +563 -0
- package/package.json +40 -0
- package/templates/AGENTS.md +610 -0
- package/templates/INCSPEC_BLOCK.md +19 -0
- package/templates/WORKFLOW.md +22 -0
- package/templates/cursor-commands/analyze-codeflow.md +341 -0
- package/templates/cursor-commands/analyze-increment-codeflow.md +246 -0
- package/templates/cursor-commands/apply-increment-code.md +392 -0
- package/templates/cursor-commands/inc-archive.md +278 -0
- package/templates/cursor-commands/merge-to-baseline.md +329 -0
- package/templates/cursor-commands/structured-requirements-collection.md +123 -0
- package/templates/cursor-commands/ui-dependency-collection.md +143 -0
- package/templates/project.md +24 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cursor-sync command - Sync Cursor slash commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import {
|
|
7
|
+
findProjectRoot,
|
|
8
|
+
INCSPEC_DIR,
|
|
9
|
+
} from '../lib/config.mjs';
|
|
10
|
+
import {
|
|
11
|
+
syncToProject,
|
|
12
|
+
syncToGlobal,
|
|
13
|
+
checkCursorCommands,
|
|
14
|
+
} from '../lib/cursor.mjs';
|
|
15
|
+
import {
|
|
16
|
+
colors,
|
|
17
|
+
colorize,
|
|
18
|
+
print,
|
|
19
|
+
printSuccess,
|
|
20
|
+
printWarning,
|
|
21
|
+
printInfo,
|
|
22
|
+
confirm,
|
|
23
|
+
select,
|
|
24
|
+
} from '../lib/terminal.mjs';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Execute cursor-sync command
|
|
28
|
+
* @param {Object} ctx - Command context
|
|
29
|
+
*/
|
|
30
|
+
export async function cursorSyncCommand(ctx) {
|
|
31
|
+
const { cwd, options } = ctx;
|
|
32
|
+
|
|
33
|
+
print('');
|
|
34
|
+
print(colorize(' incspec Cursor 命令同步', colors.bold, colors.cyan));
|
|
35
|
+
print(colorize(' ──────────────────────', colors.dim));
|
|
36
|
+
print('');
|
|
37
|
+
|
|
38
|
+
// Determine sync target
|
|
39
|
+
let syncTarget = null;
|
|
40
|
+
|
|
41
|
+
if (options.project) {
|
|
42
|
+
syncTarget = 'project';
|
|
43
|
+
} else if (options.global) {
|
|
44
|
+
syncTarget = 'global';
|
|
45
|
+
} else {
|
|
46
|
+
// Interactive selection
|
|
47
|
+
const projectRoot = findProjectRoot(cwd);
|
|
48
|
+
|
|
49
|
+
const choices = [
|
|
50
|
+
{
|
|
51
|
+
name: '项目目录 (.cursor/commands/incspec/)',
|
|
52
|
+
value: 'project',
|
|
53
|
+
description: '仅对当前项目生效',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: '全局目录 (~/.cursor/commands/incspec/)',
|
|
57
|
+
value: 'global',
|
|
58
|
+
description: '对所有项目生效',
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
if (!projectRoot) {
|
|
63
|
+
// No project found, only allow global
|
|
64
|
+
printWarning('未检测到 incspec 项目,将同步到全局目录。');
|
|
65
|
+
syncTarget = 'global';
|
|
66
|
+
} else {
|
|
67
|
+
syncTarget = await select({
|
|
68
|
+
message: '选择同步目标:',
|
|
69
|
+
choices,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Execute sync
|
|
75
|
+
if (syncTarget === 'project') {
|
|
76
|
+
const projectRoot = findProjectRoot(cwd);
|
|
77
|
+
|
|
78
|
+
if (!projectRoot) {
|
|
79
|
+
printWarning('未检测到 incspec 项目。请先运行 incspec init 或使用 --global 选项。');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
print(colorize(`同步到项目: ${projectRoot}`, colors.dim));
|
|
84
|
+
print('');
|
|
85
|
+
|
|
86
|
+
const count = syncToProject(projectRoot);
|
|
87
|
+
|
|
88
|
+
printSuccess(`已同步 ${count} 个 Cursor 命令到 .cursor/commands/incspec/`);
|
|
89
|
+
print('');
|
|
90
|
+
print(colorize('已创建的命令:', colors.bold));
|
|
91
|
+
print(colorize(' /incspec/inc-analyze 步骤1: 分析代码流程', colors.dim));
|
|
92
|
+
print(colorize(' /incspec/inc-collect-req 步骤2: 收集结构化需求', colors.dim));
|
|
93
|
+
print(colorize(' /incspec/inc-collect-dep 步骤3: UI依赖采集', colors.dim));
|
|
94
|
+
print(colorize(' /incspec/inc-design 步骤4: 增量设计', colors.dim));
|
|
95
|
+
print(colorize(' /incspec/inc-apply 步骤5: 应用代码变更', colors.dim));
|
|
96
|
+
print(colorize(' /incspec/inc-merge 步骤6: 合并到基线', colors.dim));
|
|
97
|
+
print(colorize(' /incspec/inc-archive 归档规范文件', colors.dim));
|
|
98
|
+
print(colorize(' /incspec/inc-status 查看工作流状态', colors.dim));
|
|
99
|
+
print(colorize(' /incspec/inc-help 显示帮助', colors.dim));
|
|
100
|
+
|
|
101
|
+
} else if (syncTarget === 'global') {
|
|
102
|
+
print(colorize('同步到全局目录...', colors.dim));
|
|
103
|
+
print('');
|
|
104
|
+
|
|
105
|
+
const count = syncToGlobal();
|
|
106
|
+
|
|
107
|
+
printSuccess(`已同步 ${count} 个 Cursor 命令到 ~/.cursor/commands/incspec/`);
|
|
108
|
+
print('');
|
|
109
|
+
print(colorize('全局命令将对所有项目生效。', colors.dim));
|
|
110
|
+
print(colorize('在项目中运行 incspec cursor-sync --project 可覆盖全局命令。', colors.dim));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
print('');
|
|
114
|
+
printInfo('请重启 Cursor 以加载新命令。');
|
|
115
|
+
print('');
|
|
116
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design command - Step 4: Design increment
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import {
|
|
8
|
+
ensureInitialized,
|
|
9
|
+
INCSPEC_DIR,
|
|
10
|
+
DIRS,
|
|
11
|
+
} from '../lib/config.mjs';
|
|
12
|
+
import {
|
|
13
|
+
readWorkflow,
|
|
14
|
+
updateStep,
|
|
15
|
+
STATUS,
|
|
16
|
+
} from '../lib/workflow.mjs';
|
|
17
|
+
import { getNextVersion, listSpecs } from '../lib/spec.mjs';
|
|
18
|
+
import {
|
|
19
|
+
colors,
|
|
20
|
+
colorize,
|
|
21
|
+
print,
|
|
22
|
+
printSuccess,
|
|
23
|
+
printWarning,
|
|
24
|
+
printInfo,
|
|
25
|
+
prompt,
|
|
26
|
+
} from '../lib/terminal.mjs';
|
|
27
|
+
|
|
28
|
+
const STEP_NUMBER = 4;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute design command
|
|
32
|
+
* @param {Object} ctx - Command context
|
|
33
|
+
*/
|
|
34
|
+
export async function designCommand(ctx) {
|
|
35
|
+
const { cwd, options } = ctx;
|
|
36
|
+
|
|
37
|
+
// Ensure initialized
|
|
38
|
+
const projectRoot = ensureInitialized(cwd);
|
|
39
|
+
|
|
40
|
+
// Get workflow state
|
|
41
|
+
const workflow = readWorkflow(projectRoot);
|
|
42
|
+
|
|
43
|
+
if (!workflow?.currentWorkflow) {
|
|
44
|
+
printWarning('没有活跃的工作流。请先运行 incspec analyze 开始新工作流。');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Get feature name
|
|
49
|
+
let featureName = typeof options.feature === 'string' ? options.feature : '';
|
|
50
|
+
if (!featureName) {
|
|
51
|
+
featureName = workflow.currentWorkflow.replace(/^analyze-/, '');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Calculate output file
|
|
55
|
+
const version = getNextVersion(projectRoot, 'increments', featureName);
|
|
56
|
+
const outputFile = `${featureName}-increment-v${version}.md`;
|
|
57
|
+
const outputPath = path.join(INCSPEC_DIR, DIRS.increments, outputFile);
|
|
58
|
+
|
|
59
|
+
// Find input files
|
|
60
|
+
const baselines = listSpecs(projectRoot, 'baselines');
|
|
61
|
+
const latestBaseline = baselines[0]?.name || '[无基线文件]';
|
|
62
|
+
if (baselines.length === 0) {
|
|
63
|
+
printWarning('未找到基线文件。请先运行步骤 1 (analyze)。');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const reqFile = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
|
|
68
|
+
const depFile = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'ui-dependencies.md');
|
|
69
|
+
const missingInputs = [];
|
|
70
|
+
if (!fs.existsSync(reqFile)) {
|
|
71
|
+
missingInputs.push('structured-requirements.md');
|
|
72
|
+
}
|
|
73
|
+
if (!fs.existsSync(depFile)) {
|
|
74
|
+
missingInputs.push('ui-dependencies.md');
|
|
75
|
+
}
|
|
76
|
+
if (missingInputs.length > 0) {
|
|
77
|
+
printWarning(`缺少需求输入文件: ${missingInputs.join(', ')}`);
|
|
78
|
+
printWarning('请先完成步骤 2 (collect-req) 和步骤 3 (collect-dep)。');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
print('');
|
|
83
|
+
print(colorize('步骤 4: 增量设计', colors.bold, colors.cyan));
|
|
84
|
+
print(colorize('────────────────', colors.dim));
|
|
85
|
+
print('');
|
|
86
|
+
print(colorize(`当前工作流: ${workflow.currentWorkflow}`, colors.dim));
|
|
87
|
+
print(colorize(`功能名称: ${featureName}`, colors.dim));
|
|
88
|
+
print(colorize(`输出文件: ${outputPath}`, colors.dim));
|
|
89
|
+
print('');
|
|
90
|
+
print(colorize('输入文件:', colors.bold));
|
|
91
|
+
print(colorize(` 基线快照: ${INCSPEC_DIR}/${DIRS.baselines}/${latestBaseline}`, colors.dim));
|
|
92
|
+
print(colorize(` 结构化需求: ${INCSPEC_DIR}/${DIRS.requirements}/structured-requirements.md`, colors.dim));
|
|
93
|
+
print(colorize(` UI依赖: ${INCSPEC_DIR}/${DIRS.requirements}/ui-dependencies.md`, colors.dim));
|
|
94
|
+
print('');
|
|
95
|
+
|
|
96
|
+
// Update workflow status
|
|
97
|
+
updateStep(projectRoot, STEP_NUMBER, STATUS.IN_PROGRESS);
|
|
98
|
+
|
|
99
|
+
print(colorize('使用说明:', colors.bold));
|
|
100
|
+
print('');
|
|
101
|
+
print(colorize('请在 Cursor 中运行以下命令:', colors.cyan));
|
|
102
|
+
print('');
|
|
103
|
+
print(colorize(` /incspec/inc-design --feature=${featureName}`, colors.bold, colors.white));
|
|
104
|
+
print('');
|
|
105
|
+
print(colorize('或使用 Claude Code 命令:', colors.cyan));
|
|
106
|
+
print('');
|
|
107
|
+
const baselinePath = path.join(projectRoot, INCSPEC_DIR, DIRS.baselines, latestBaseline);
|
|
108
|
+
const reqPath = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
|
|
109
|
+
const depPath = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'ui-dependencies.md');
|
|
110
|
+
const outDir = path.join(projectRoot, INCSPEC_DIR, DIRS.increments);
|
|
111
|
+
print(colorize(` /ai-increment:analyze-increment-codeflow ${baselinePath} ${reqPath} ${depPath} ${outDir}`, colors.bold, colors.white));
|
|
112
|
+
print('');
|
|
113
|
+
print(colorize('该命令将生成包含 7 大模块的增量设计蓝图:', colors.dim));
|
|
114
|
+
print(colorize(' 1. 一句话摘要', colors.dim));
|
|
115
|
+
print(colorize(' 2. 变更链条设计表', colors.dim));
|
|
116
|
+
print(colorize(' 3. 规划后的 API 调用时序图', colors.dim));
|
|
117
|
+
print(colorize(' 4. 规划后的依赖关系图', colors.dim));
|
|
118
|
+
print(colorize(' 5. 文件清单', colors.dim));
|
|
119
|
+
print(colorize(' 6. 风险预警', colors.dim));
|
|
120
|
+
print(colorize(' 7. 测试用例', colors.dim));
|
|
121
|
+
print('');
|
|
122
|
+
printInfo(`完成后运行 'incspec status' 查看进度`);
|
|
123
|
+
print('');
|
|
124
|
+
|
|
125
|
+
// Handle --complete flag
|
|
126
|
+
if (options.complete) {
|
|
127
|
+
const output = typeof options.output === 'string' ? options.output : outputFile;
|
|
128
|
+
updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, output);
|
|
129
|
+
printSuccess(`步骤 4 已标记为完成: ${output}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* help command - Display help information
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
colors,
|
|
7
|
+
colorize,
|
|
8
|
+
print,
|
|
9
|
+
} from '../lib/terminal.mjs';
|
|
10
|
+
import { STEPS } from '../lib/workflow.mjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Command definitions for help
|
|
14
|
+
*/
|
|
15
|
+
const COMMANDS = {
|
|
16
|
+
init: {
|
|
17
|
+
usage: 'incspec init [--force]',
|
|
18
|
+
description: '初始化 incspec 项目结构',
|
|
19
|
+
options: [
|
|
20
|
+
['--force', '强制重新初始化'],
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
update: {
|
|
24
|
+
usage: 'incspec update [-y|--yes]',
|
|
25
|
+
aliases: ['up'],
|
|
26
|
+
description: '更新模板文件到最新版本',
|
|
27
|
+
options: [
|
|
28
|
+
['-y, --yes', '跳过确认提示'],
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
status: {
|
|
32
|
+
usage: 'incspec status',
|
|
33
|
+
aliases: ['st'],
|
|
34
|
+
description: '显示当前工作流状态',
|
|
35
|
+
},
|
|
36
|
+
analyze: {
|
|
37
|
+
usage: 'incspec analyze <source-path> [--module=name]',
|
|
38
|
+
aliases: ['a'],
|
|
39
|
+
description: '步骤1: 分析代码流程,生成基线快照',
|
|
40
|
+
options: [
|
|
41
|
+
['-m, --module=<name>', '指定模块名称'],
|
|
42
|
+
['-w, --workflow=<name>', '指定工作流名称(避免交互提示)'],
|
|
43
|
+
['--complete', '标记步骤完成'],
|
|
44
|
+
['-o, --output=<file>', '完成时指定输出文件'],
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
'collect-req': {
|
|
48
|
+
usage: 'incspec collect-req',
|
|
49
|
+
aliases: ['cr'],
|
|
50
|
+
description: '步骤2: 收集结构化需求',
|
|
51
|
+
options: [
|
|
52
|
+
['--complete', '标记步骤完成'],
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
'collect-dep': {
|
|
56
|
+
usage: 'incspec collect-dep',
|
|
57
|
+
aliases: ['cd'],
|
|
58
|
+
description: '步骤3: 采集 UI 依赖',
|
|
59
|
+
options: [
|
|
60
|
+
['--complete', '标记步骤完成'],
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
design: {
|
|
64
|
+
usage: 'incspec design [--feature=name]',
|
|
65
|
+
aliases: ['d'],
|
|
66
|
+
description: '步骤4: 生成增量设计蓝图',
|
|
67
|
+
options: [
|
|
68
|
+
['-f, --feature=<name>', '指定功能名称'],
|
|
69
|
+
['--complete', '标记步骤完成'],
|
|
70
|
+
['-o, --output=<file>', '完成时指定输出文件'],
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
apply: {
|
|
74
|
+
usage: 'incspec apply [increment-path]',
|
|
75
|
+
aliases: ['ap'],
|
|
76
|
+
description: '步骤5: 应用代码变更',
|
|
77
|
+
options: [
|
|
78
|
+
['-s, --source-dir=<path>', '指定源代码目录'],
|
|
79
|
+
['--complete', '标记步骤完成'],
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
merge: {
|
|
83
|
+
usage: 'incspec merge [increment-path]',
|
|
84
|
+
aliases: ['m'],
|
|
85
|
+
description: '步骤6: 合并到新基线',
|
|
86
|
+
options: [
|
|
87
|
+
['--complete', '标记步骤完成'],
|
|
88
|
+
['-o, --output=<file>', '完成时指定输出文件'],
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
list: {
|
|
92
|
+
usage: 'incspec list [type] [-l|--long] [-a|--all]',
|
|
93
|
+
aliases: ['ls'],
|
|
94
|
+
description: '列出规范文件',
|
|
95
|
+
options: [
|
|
96
|
+
['type', 'baselines | requirements | increments | archives'],
|
|
97
|
+
['-l, --long', '显示详细信息'],
|
|
98
|
+
['-a, --all', '包含归档文件'],
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
validate: {
|
|
102
|
+
usage: 'incspec validate [--strict]',
|
|
103
|
+
aliases: ['v'],
|
|
104
|
+
description: '验证规范完整性',
|
|
105
|
+
options: [
|
|
106
|
+
['--strict', '严格模式,有错误时返回非零退出码'],
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
archive: {
|
|
110
|
+
usage: 'incspec archive [file-path] [--workflow] [-k|--keep] [-y|--yes]',
|
|
111
|
+
aliases: ['ar'],
|
|
112
|
+
description: '归档规范文件 (默认归档当前工作流产出)',
|
|
113
|
+
options: [
|
|
114
|
+
['--workflow', '归档当前工作流全部产出文件'],
|
|
115
|
+
['-k, --keep', '复制而非移动'],
|
|
116
|
+
['-y, --yes', '跳过确认提示'],
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
'cursor-sync': {
|
|
120
|
+
usage: 'incspec cursor-sync [--project|--global]',
|
|
121
|
+
aliases: ['cs'],
|
|
122
|
+
description: '同步 Cursor slash commands',
|
|
123
|
+
options: [
|
|
124
|
+
['--project', '同步到项目目录'],
|
|
125
|
+
['--global', '同步到全局目录'],
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
help: {
|
|
129
|
+
usage: 'incspec help [command]',
|
|
130
|
+
aliases: ['h'],
|
|
131
|
+
description: '显示帮助信息',
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Execute help command
|
|
137
|
+
* @param {Object} ctx - Command context
|
|
138
|
+
*/
|
|
139
|
+
export async function helpCommand(ctx = {}) {
|
|
140
|
+
const { command } = ctx;
|
|
141
|
+
|
|
142
|
+
print('');
|
|
143
|
+
|
|
144
|
+
if (command && COMMANDS[command]) {
|
|
145
|
+
// Show specific command help
|
|
146
|
+
showCommandHelp(command);
|
|
147
|
+
} else if (command) {
|
|
148
|
+
print(colorize(`未知命令: ${command}`, colors.red));
|
|
149
|
+
print('');
|
|
150
|
+
showGeneralHelp();
|
|
151
|
+
} else {
|
|
152
|
+
showGeneralHelp();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Show general help
|
|
158
|
+
*/
|
|
159
|
+
function showGeneralHelp() {
|
|
160
|
+
print(colorize(' incspec - 增量规范驱动开发工具', colors.bold, colors.cyan));
|
|
161
|
+
print(colorize(' ────────────────────────────', colors.dim));
|
|
162
|
+
print('');
|
|
163
|
+
print(colorize('用法:', colors.bold));
|
|
164
|
+
print(colorize(' incspec <command> [options]', colors.white));
|
|
165
|
+
print('');
|
|
166
|
+
|
|
167
|
+
print(colorize('工作流命令:', colors.bold));
|
|
168
|
+
print('');
|
|
169
|
+
|
|
170
|
+
const workflowCommands = ['analyze', 'collect-req', 'collect-dep', 'design', 'apply', 'merge'];
|
|
171
|
+
workflowCommands.forEach((cmd, index) => {
|
|
172
|
+
const def = COMMANDS[cmd];
|
|
173
|
+
const aliases = def.aliases ? colorize(` (${def.aliases.join(', ')})`, colors.dim) : '';
|
|
174
|
+
print(` ${colorize(`${index + 1}.`, colors.cyan)} ${colorize(cmd, colors.white)}${aliases}`);
|
|
175
|
+
print(colorize(` ${def.description}`, colors.dim));
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
print('');
|
|
179
|
+
print(colorize('管理命令:', colors.bold));
|
|
180
|
+
print('');
|
|
181
|
+
|
|
182
|
+
const mgmtCommands = ['init', 'update', 'status', 'list', 'validate', 'archive', 'cursor-sync', 'help'];
|
|
183
|
+
mgmtCommands.forEach(cmd => {
|
|
184
|
+
const def = COMMANDS[cmd];
|
|
185
|
+
const aliases = def.aliases ? colorize(` (${def.aliases.join(', ')})`, colors.dim) : '';
|
|
186
|
+
print(` ${colorize(cmd, colors.white)}${aliases}`);
|
|
187
|
+
print(colorize(` ${def.description}`, colors.dim));
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
print('');
|
|
191
|
+
print(colorize('选项:', colors.bold));
|
|
192
|
+
print(colorize(' -h, --help 显示帮助', colors.dim));
|
|
193
|
+
print(colorize(' -v, --version 显示版本', colors.dim));
|
|
194
|
+
print('');
|
|
195
|
+
print(colorize('示例:', colors.bold));
|
|
196
|
+
print(colorize(' incspec init # 初始化项目', colors.dim));
|
|
197
|
+
print(colorize(' incspec update # 更新模板文件', colors.dim));
|
|
198
|
+
print(colorize(' incspec analyze src/views/Home # 分析代码流程', colors.dim));
|
|
199
|
+
print(colorize(' incspec status # 查看工作流状态', colors.dim));
|
|
200
|
+
print(colorize(' incspec cursor-sync # 同步 Cursor 命令', colors.dim));
|
|
201
|
+
print('');
|
|
202
|
+
print(colorize(`运行 'incspec help <command>' 查看命令详情。`, colors.dim));
|
|
203
|
+
print('');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Show specific command help
|
|
208
|
+
* @param {string} command
|
|
209
|
+
*/
|
|
210
|
+
function showCommandHelp(command) {
|
|
211
|
+
const def = COMMANDS[command];
|
|
212
|
+
|
|
213
|
+
print(colorize(`incspec ${command}`, colors.bold, colors.cyan));
|
|
214
|
+
print('');
|
|
215
|
+
print(colorize(def.description, colors.white));
|
|
216
|
+
print('');
|
|
217
|
+
print(colorize('用法:', colors.bold));
|
|
218
|
+
print(colorize(` ${def.usage}`, colors.white));
|
|
219
|
+
|
|
220
|
+
if (def.aliases && def.aliases.length > 0) {
|
|
221
|
+
print('');
|
|
222
|
+
print(colorize('别名:', colors.bold));
|
|
223
|
+
print(colorize(` ${def.aliases.join(', ')}`, colors.dim));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (def.options && def.options.length > 0) {
|
|
227
|
+
print('');
|
|
228
|
+
print(colorize('选项:', colors.bold));
|
|
229
|
+
def.options.forEach(([opt, desc]) => {
|
|
230
|
+
print(` ${colorize(opt.padEnd(20), colors.cyan)} ${colorize(desc, colors.dim)}`);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
print('');
|
|
235
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* init command - Initialize incspec in a project
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import {
|
|
8
|
+
isInitialized,
|
|
9
|
+
createIncspecStructure,
|
|
10
|
+
getDefaultConfig,
|
|
11
|
+
INCSPEC_DIR,
|
|
12
|
+
findProjectRoot,
|
|
13
|
+
} from '../lib/config.mjs';
|
|
14
|
+
import { initWorkflow } from '../lib/workflow.mjs';
|
|
15
|
+
import { updateProjectAgentsFile } from '../lib/agents.mjs';
|
|
16
|
+
import {
|
|
17
|
+
colors,
|
|
18
|
+
colorize,
|
|
19
|
+
print,
|
|
20
|
+
printSuccess,
|
|
21
|
+
printWarning,
|
|
22
|
+
printInfo,
|
|
23
|
+
prompt,
|
|
24
|
+
confirm,
|
|
25
|
+
} from '../lib/terminal.mjs';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Execute init command
|
|
29
|
+
* @param {Object} ctx - Command context
|
|
30
|
+
*/
|
|
31
|
+
export async function initCommand(ctx) {
|
|
32
|
+
const { cwd, options } = ctx;
|
|
33
|
+
|
|
34
|
+
// Check if already initialized
|
|
35
|
+
if (isInitialized(cwd) && !options.force) {
|
|
36
|
+
printWarning(`incspec 已在此目录初始化。`);
|
|
37
|
+
printInfo(`如需重新初始化,请使用 --force 选项。`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const existingRoot = findProjectRoot(cwd);
|
|
42
|
+
if (existingRoot && existingRoot !== cwd && !options.force) {
|
|
43
|
+
printWarning(`检测到上级目录已初始化 incspec: ${existingRoot}`);
|
|
44
|
+
printInfo('请在项目根目录执行,或使用 --force 在当前目录初始化。');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
print('');
|
|
49
|
+
print(colorize(' incspec 初始化向导', colors.bold, colors.cyan));
|
|
50
|
+
print(colorize(' ─────────────────', colors.dim));
|
|
51
|
+
print('');
|
|
52
|
+
|
|
53
|
+
// Collect project info
|
|
54
|
+
const projectName = await prompt('项目名称', path.basename(cwd));
|
|
55
|
+
|
|
56
|
+
// Select tech stack
|
|
57
|
+
const techStackStr = await prompt('技术栈 (逗号分隔)', 'React, TypeScript');
|
|
58
|
+
const techStack = techStackStr.split(',').map(s => s.trim()).filter(Boolean);
|
|
59
|
+
|
|
60
|
+
const sourceDir = await prompt('源代码目录', 'src');
|
|
61
|
+
|
|
62
|
+
// Create config
|
|
63
|
+
const config = getDefaultConfig({
|
|
64
|
+
name: projectName,
|
|
65
|
+
tech_stack: techStack,
|
|
66
|
+
source_dir: sourceDir,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
print('');
|
|
70
|
+
print(colorize('配置预览:', colors.bold));
|
|
71
|
+
print(colorize(` 项目名称: ${config.name}`, colors.dim));
|
|
72
|
+
print(colorize(` 技术栈: ${config.tech_stack.join(', ')}`, colors.dim));
|
|
73
|
+
print(colorize(` 源代码目录: ${config.source_dir}`, colors.dim));
|
|
74
|
+
print('');
|
|
75
|
+
|
|
76
|
+
const shouldProceed = await confirm('确认创建 incspec 目录结构?');
|
|
77
|
+
|
|
78
|
+
if (!shouldProceed) {
|
|
79
|
+
print(colorize('已取消初始化。', colors.dim));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If force mode and directory exists, remove it first
|
|
84
|
+
const incspecPath = path.join(cwd, INCSPEC_DIR);
|
|
85
|
+
if (options.force && fs.existsSync(incspecPath)) {
|
|
86
|
+
fs.rmSync(incspecPath, { recursive: true, force: true });
|
|
87
|
+
printInfo('已删除旧的 incspec 目录。');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Create structure
|
|
91
|
+
createIncspecStructure(cwd, config);
|
|
92
|
+
|
|
93
|
+
// Initialize workflow
|
|
94
|
+
initWorkflow(cwd);
|
|
95
|
+
|
|
96
|
+
// Update project AGENTS.md with incspec block
|
|
97
|
+
const agentsResult = updateProjectAgentsFile(cwd);
|
|
98
|
+
if (agentsResult.created) {
|
|
99
|
+
printInfo('已创建项目 AGENTS.md 文件。');
|
|
100
|
+
} else if (agentsResult.updated) {
|
|
101
|
+
printInfo('已更新项目 AGENTS.md 中的 incspec 指令块。');
|
|
102
|
+
} else {
|
|
103
|
+
printInfo('已添加 incspec 指令块到项目 AGENTS.md。');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
print('');
|
|
107
|
+
printSuccess('incspec 初始化完成!');
|
|
108
|
+
print('');
|
|
109
|
+
print(colorize('创建的目录结构:', colors.bold));
|
|
110
|
+
print(colorize(` ${INCSPEC_DIR}/`, colors.cyan));
|
|
111
|
+
print(colorize(` ├── project.md`, colors.dim));
|
|
112
|
+
print(colorize(` ├── WORKFLOW.md`, colors.dim));
|
|
113
|
+
print(colorize(` ├── AGENTS.md`, colors.dim));
|
|
114
|
+
print(colorize(` ├── baselines/`, colors.dim));
|
|
115
|
+
print(colorize(` ├── requirements/`, colors.dim));
|
|
116
|
+
print(colorize(` ├── increments/`, colors.dim));
|
|
117
|
+
print(colorize(` └── archives/`, colors.dim));
|
|
118
|
+
print('');
|
|
119
|
+
print(colorize(` AGENTS.md (项目根目录)`, colors.cyan));
|
|
120
|
+
print(colorize(` └── incspec 指令块已添加`, colors.dim));
|
|
121
|
+
print('');
|
|
122
|
+
print(colorize('下一步:', colors.bold));
|
|
123
|
+
print(colorize(` 1. 运行 'incspec status' 查看工作流状态`, colors.dim));
|
|
124
|
+
print(colorize(` 2. 运行 'incspec cursor-sync' 同步 Cursor 命令`, colors.dim));
|
|
125
|
+
print(colorize(` 3. 使用 /incspec/inc-analyze 开始第一个工作流`, colors.dim));
|
|
126
|
+
print('');
|
|
127
|
+
}
|