@localsummer/incspec 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  # IncSpec
12
12
 
13
+ ![IncSpec 全局介绍](./assets/incspec.jpeg)
14
+
13
15
  IncSpec 通过**增量规范驱动开发**让人类与 AI 编程助手保持一致 - 这是一个 6+1 步工作流(6 步开发 + 归档),在修改代码前先捕获代码流程基线。**无需 API 密钥。**
14
16
 
15
17
  ## 为什么选择 IncSpec?
@@ -89,6 +91,8 @@ AI 编程助手在处理复杂前端代码库时常常力不从心,因为 API
89
91
  └───────────┘
90
92
  ```
91
93
 
94
+ > **提示**: 如果已有基准报告,可使用 `incspec analyze --baseline=<file>` 直接跳过分析步骤,快速进入后续工作流。
95
+
92
96
  ## 快速开始
93
97
 
94
98
  ### 支持的 AI 工具
@@ -124,6 +128,9 @@ AI 编程助手在处理复杂前端代码库时常常力不从心,因为 API
124
128
  #### 步骤 1:安装 CLI
125
129
 
126
130
  ```bash
131
+ # 从 Npm 安装(推荐)
132
+ npm install -g @localsummer/incspec
133
+
127
134
  # 从 GitHub 克隆并安装
128
135
  git clone https://github.com/localSummer/IncSpec.git
129
136
  cd IncSpec
@@ -186,6 +193,17 @@ $ incspec status # 检查当前工作流状态
186
193
  $ incspec analyze src/views/Home --complete # 标记步骤 1 完成
187
194
  ```
188
195
 
196
+ **使用现有基准报告** (跳过分析):
197
+
198
+ 如果已有基准报告文件,可直接使用,跳过分析步骤:
199
+ ```bash
200
+ $ incspec analyze --baseline=home-baseline-v1.md # 直接使用现有基准报告
201
+ ```
202
+ - 自动搜索 `baselines/` 和 `archives/` 目录
203
+ - 若文件在归档目录,自动移动到 `baselines/` 目录
204
+ - 模块名自动从文件名推断 (`xxx-baseline-vN.md` -> `xxx`)
205
+ - 可通过 `--module` 覆盖模块名
206
+
189
207
  #### 2. 收集结构化需求
190
208
 
191
209
  定义你想要的变更:
@@ -422,6 +440,7 @@ incspec help <command> # 显示特定命令帮助
422
440
  incspec analyze <source-path> [--module=name] # 别名:a
423
441
  incspec a src/views/Home --module=home
424
442
  incspec analyze src/views/Home --complete -o baselines/home-baseline-v1.md
443
+ incspec analyze --baseline=home-baseline-v1.md # 使用现有基准(自动从归档恢复)
425
444
 
426
445
  # 步骤 2:收集结构化需求
427
446
  incspec collect-req # 别名:cr
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import * as path from 'path';
6
+ import * as fs from 'fs';
6
7
  import {
7
8
  ensureInitialized,
8
9
  INCSPEC_DIR,
@@ -32,6 +33,49 @@ import {
32
33
 
33
34
  const STEP_NUMBER = 1;
34
35
 
36
+ /**
37
+ * Search for a file in the archives directory
38
+ * @param {string} projectRoot - Project root path
39
+ * @param {string} fileName - File name to search
40
+ * @returns {string|null} - Full path if found, null otherwise
41
+ */
42
+ function findInArchives(projectRoot, fileName) {
43
+ const archivesDir = path.join(projectRoot, INCSPEC_DIR, DIRS.archives);
44
+ if (!fs.existsSync(archivesDir)) {
45
+ return null;
46
+ }
47
+
48
+ // Recursive search: archives/ -> YYYY-MM/ -> [module/] -> files
49
+ const monthDirs = fs.readdirSync(archivesDir, { withFileTypes: true })
50
+ .filter(d => d.isDirectory())
51
+ .map(d => d.name)
52
+ .sort()
53
+ .reverse(); // Prioritize recent months
54
+
55
+ for (const month of monthDirs) {
56
+ const monthPath = path.join(archivesDir, month);
57
+
58
+ // Check files directly in month directory
59
+ const directPath = path.join(monthPath, fileName);
60
+ if (fs.existsSync(directPath)) {
61
+ return directPath;
62
+ }
63
+
64
+ // Check module subdirectories
65
+ const subDirs = fs.readdirSync(monthPath, { withFileTypes: true })
66
+ .filter(d => d.isDirectory());
67
+
68
+ for (const subDir of subDirs) {
69
+ const subPath = path.join(monthPath, subDir.name, fileName);
70
+ if (fs.existsSync(subPath)) {
71
+ return subPath;
72
+ }
73
+ }
74
+ }
75
+
76
+ return null;
77
+ }
78
+
35
79
  /**
36
80
  * Execute analyze command
37
81
  * @param {Object} ctx - Command context
@@ -42,6 +86,57 @@ export async function analyzeCommand(ctx) {
42
86
  // Ensure initialized
43
87
  const projectRoot = ensureInitialized(cwd);
44
88
 
89
+ // Handle --baseline option: use existing baseline report
90
+ if (options.baseline) {
91
+ const baselineFile = typeof options.baseline === 'string' ? options.baseline : '';
92
+ if (!baselineFile) {
93
+ printError('请指定基准报告文件名');
94
+ process.exit(1);
95
+ }
96
+
97
+ const baselinesDir = path.join(projectRoot, INCSPEC_DIR, DIRS.baselines);
98
+ const baselinePath = path.join(baselinesDir, baselineFile);
99
+ let fromArchive = false;
100
+
101
+ // 1. First check baselines directory
102
+ if (!fs.existsSync(baselinePath)) {
103
+ // 2. Search in archives directory
104
+ const archivePath = findInArchives(projectRoot, baselineFile);
105
+ if (!archivePath) {
106
+ printError(`基准文件不存在: ${baselineFile}`);
107
+ printInfo('已搜索 baselines/ 和 archives/ 目录');
108
+ process.exit(1);
109
+ }
110
+
111
+ // 3. Move to baselines directory
112
+ fs.renameSync(archivePath, baselinePath);
113
+ fromArchive = true;
114
+ printInfo(`已从归档恢复: ${path.relative(projectRoot, archivePath)}`);
115
+ }
116
+
117
+ // Infer module name from filename (xxx-baseline-vN.md -> xxx)
118
+ let moduleName = typeof options.module === 'string' ? options.module : '';
119
+ if (!moduleName) {
120
+ const match = baselineFile.match(/^(.+)-baseline-v\d+\.md$/);
121
+ moduleName = match ? match[1] : path.basename(baselineFile, '.md');
122
+ }
123
+
124
+ // Handle workflow state
125
+ let workflow = readWorkflow(projectRoot);
126
+ if (!workflow?.currentWorkflow) {
127
+ const workflowName = typeof options.workflow === 'string' ? options.workflow : `analyze-${moduleName}`;
128
+ workflow = startWorkflow(projectRoot, workflowName);
129
+ printSuccess(`已创建新工作流: ${workflowName}`);
130
+ }
131
+
132
+ // Mark step as completed
133
+ updateStep(projectRoot, STEP_NUMBER, STATUS.COMPLETED, baselineFile);
134
+ print('');
135
+ printSuccess(`已使用现有基准报告: ${baselineFile}`);
136
+ printInfo(`运行 'incspec status' 查看进度`);
137
+ return;
138
+ }
139
+
45
140
  // Get source path
46
141
  let sourcePath = args[0];
47
142
  if (!sourcePath) {
package/commands/help.mjs CHANGED
@@ -34,12 +34,13 @@ const COMMANDS = {
34
34
  description: '显示当前工作流状态',
35
35
  },
36
36
  analyze: {
37
- usage: 'incspec analyze <source-path> [--module=name]',
37
+ usage: 'incspec analyze <source-path> [--module=name] [--baseline=file]',
38
38
  aliases: ['a'],
39
39
  description: '步骤1: 分析代码流程,生成基线快照',
40
40
  options: [
41
41
  ['-m, --module=<name>', '指定模块名称'],
42
42
  ['-w, --workflow=<name>', '指定工作流名称(避免交互提示)'],
43
+ ['-b, --baseline=<file>', '使用现有基准报告(自动从归档恢复)'],
43
44
  ['--complete', '标记步骤完成'],
44
45
  ['-o, --output=<file>', '完成时指定输出文件'],
45
46
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localsummer/incspec",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "面向 AI 编程助手的增量规范驱动开发工具",
5
5
  "bin": {
6
6
  "incspec": "index.mjs"
@@ -41,10 +41,13 @@ AI 编码助手使用 IncSpec 进行增量规格驱动开发的操作指南。
41
41
 
42
42
  ### 步骤 1: 分析代码工作流
43
43
 
44
- **命令**: `incspec analyze <source-path> [--module=name]`
44
+ **命令**: `incspec analyze <source-path> [--module=name] [--baseline=file]`
45
45
 
46
46
  **目的**: 生成包含 API 调用时序图和依赖关系图的基线快照。
47
47
 
48
+ **选项**:
49
+ - `--baseline=<file>`: 使用现有基准报告,自动从 baselines/ 或 archives/ 目录恢复
50
+
48
51
  **输出**: `incspec/baselines/{module}-baseline-v{n}.md`
49
52
 
50
53
  **关键交付物**:
@@ -215,7 +218,7 @@ incspec list -l # 长格式(含时间戳)
215
218
  incspec list -a # 包含归档
216
219
 
217
220
  # 6步工作流
218
- incspec analyze <path> [--module=name] # 步骤1: 基线分析
221
+ incspec analyze <path> [--module=name] [--baseline=file] # 步骤1: 基线分析
219
222
  incspec collect-req / cr # 步骤2: 需求收集
220
223
  incspec collect-dep / cd # 步骤3: 依赖收集
221
224
  incspec design [--feature=name] / d # 步骤4: 增量设计
@@ -18,6 +18,22 @@ 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
+ **使用现有基准报告** (跳过分析):
22
+
23
+ 若已有基准报告文件,可直接使用:
24
+
25
+ ```bash
26
+ incspec analyze --baseline=<baseline-file> [--module=<module>] [--workflow=<workflow>]
27
+ ```
28
+
29
+ 说明:
30
+ - `<baseline-file>` 文件名,自动搜索 baselines/ 和 archives/ 目录
31
+ - 若文件在归档目录,自动移动到 baselines/ 目录
32
+ - `<module>` 默认从文件名推断 (xxx-baseline-vN.md -> xxx)
33
+ - `<workflow>` 默认为 analyze-<module>
34
+
35
+ ---
36
+
21
37
  说明:
22
38
  - `<module>` 默认为 source_path 最后一级目录名,若用户显式指定模块名则使用该值
23
39
  - `<output-file>` 必须与最终写入的文件名一致