prd-workflow-cli 1.4.0 → 2.0.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.
@@ -1,8 +1,11 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
- const confirm = require('./confirm');
5
4
 
5
+ /**
6
+ * 基线管理命令 (v2.0.0)
7
+ * 支持中文参数:产品定义、代码快照、用户反馈
8
+ */
6
9
  module.exports = async function (action, type, options = {}) {
7
10
  const configPath = path.join(process.cwd(), '.prd-config.json');
8
11
 
@@ -12,7 +15,13 @@ module.exports = async function (action, type, options = {}) {
12
15
  }
13
16
 
14
17
  const config = await fs.readJSON(configPath);
15
- const baselineDir = path.join(process.cwd(), '01_产品基线');
18
+
19
+ // 支持新旧两种目录名
20
+ let baselineDir = path.join(process.cwd(), '01_基线');
21
+ if (!await fs.pathExists(baselineDir)) {
22
+ baselineDir = path.join(process.cwd(), '01_产品基线');
23
+ }
24
+ await fs.ensureDir(baselineDir);
16
25
 
17
26
  if (action === 'create') {
18
27
  await createBaselineDoc(type, baselineDir, config, configPath, options);
@@ -21,21 +30,35 @@ module.exports = async function (action, type, options = {}) {
21
30
  }
22
31
  };
23
32
 
33
+ // 中文名称到内部类型的映射
34
+ const typeMap = {
35
+ '产品定义': 'product',
36
+ '代码快照': 'codebase',
37
+ '用户反馈': 'feedback',
38
+ // 兼容旧版
39
+ 'A0': 'product',
40
+ 'A1': 'codebase',
41
+ 'A2': 'feedback'
42
+ };
43
+
44
+ // 类型到文件名的映射
45
+ const fileNameMap = {
46
+ 'product': '产品定义.md',
47
+ 'codebase': '代码快照.md',
48
+ 'feedback': '用户反馈.md'
49
+ };
50
+
24
51
  async function createBaselineDoc(type, baselineDir, config, configPath, options = {}) {
25
- const templates = {
26
- 'A0': getA0Template(),
27
- 'A1': getA1Template(),
28
- 'A2': getA2Template(),
29
- 'R0': getR0Template()
30
- };
31
-
32
- if (!templates[type]) {
52
+ const internalType = typeMap[type];
53
+
54
+ if (!internalType) {
33
55
  console.log(chalk.red(`✗ 未知的文档类型: ${type}`));
34
- console.log('可用类型: A0, A1, A2, R0');
56
+ console.log('可用类型: 产品定义, 代码快照, 用户反馈');
57
+ console.log(chalk.gray('(兼容旧版: A0, A1, A2)'));
35
58
  return;
36
59
  }
37
60
 
38
- const fileName = getFileName(type);
61
+ const fileName = fileNameMap[internalType];
39
62
  const filePath = path.join(baselineDir, fileName);
40
63
 
41
64
  if (await fs.pathExists(filePath)) {
@@ -43,428 +66,286 @@ async function createBaselineDoc(type, baselineDir, config, configPath, options
43
66
  return;
44
67
  }
45
68
 
46
- // ⭐ R0 创建需要特殊处理:前置条件检查 + PM 确认
47
- if (type === 'R0') {
48
- console.log(chalk.bold.blue('\n=== R0 基线审视创建 ===\n'));
49
-
50
- // 1. 前置条件检查
51
- const projectDir = path.join(process.cwd(), '00_项目总览');
52
- const p0Path = path.join(projectDir, 'P0_项目基本信息.md');
53
- const a0Path = path.join(baselineDir, 'A0_产品基础与范围说明.md');
54
- const a1Path = path.join(baselineDir, 'A1_已上线功能与流程清单.md');
55
- const a2Path = path.join(baselineDir, 'A2_存量反馈与数据汇总.md');
56
-
57
- console.log(chalk.yellow('📋 前置条件检查:\n'));
58
-
59
- const p0Exists = await fs.pathExists(p0Path);
60
- const a0Exists = await fs.pathExists(a0Path);
61
- const a1Exists = await fs.pathExists(a1Path);
62
- const a2Exists = await fs.pathExists(a2Path);
63
-
64
- console.log(` ${p0Exists ? '✅' : '❌'} P0_项目基本信息.md`);
65
- console.log(` ${a0Exists ? '✅' : '❌'} A0_产品基础与范围说明.md`);
66
- console.log(` ${a1Exists ? '✅' : '❌'} A1_已上线功能与流程清单.md`);
67
- console.log(` ${a2Exists ? '✅' : '⚠️ (可选)'} A2_存量反馈与数据汇总.md`);
68
- console.log('');
69
-
70
- // P0、A0、A1 是必需的
71
- if (!p0Exists || !a0Exists || !a1Exists) {
72
- console.log(chalk.red('❌ 前置条件检查未通过!\n'));
73
- console.log(chalk.yellow('R0 基线审视必须基于完整的 A 类基线文档。\n'));
74
- console.log(chalk.bold('请先完成缺失的文档:'));
75
- if (!p0Exists) console.log(' - 完善 P0(00_项目总览/P0_项目基本信息.md)');
76
- if (!a0Exists) console.log(' - 创建 A0:prd baseline create A0');
77
- if (!a1Exists) console.log(' - 创建 A1:prd baseline create A1');
78
- console.log('');
79
- console.log(chalk.gray('提示:A2 是可选的,但建议创建'));
80
-
81
- // 在测试模式下抛出错误
82
- if (process.env.PRD_TEST_MODE === 'true') {
83
- throw new Error('R0 前置条件检查未通过');
84
- }
85
- process.exit(1);
86
- }
87
-
88
- console.log(chalk.green('✅ 前置条件检查通过!\n'));
89
-
90
- // 2. PM 确认
91
- if (options.pmConfirmed) {
92
- console.log(chalk.green('✓ PM 已在对话中确认创建 R0 基线审视'));
93
- } else if (process.env.PRD_TEST_MODE === 'true') {
94
- // 测试模式:跳过交互式确认
95
- console.log(chalk.yellow('⚠️ 测试模式:跳过交互式确认'));
96
- } else {
97
- // 交互式确认
98
- console.log(chalk.yellow('⚠️ R0 基线审视将:'));
99
- console.log(' 1. 系统性审视产品基线(基于 A0/A1/A2)');
100
- console.log(' 2. 梳理用户路径和问题');
101
- console.log(' 3. 识别关键成功因素');
102
- console.log(' 4. 给出基线稳定性判定\n');
103
-
104
- const confirmed = await confirm.confirmR0Creation();
105
- if (!confirmed) {
106
- console.log(chalk.yellow('\n已取消创建 R0'));
107
- return;
108
- }
109
- console.log(chalk.green('\n✓ PM 确认创建 R0\n'));
110
- }
69
+ // 根据类型获取模板
70
+ let template;
71
+ switch (internalType) {
72
+ case 'product':
73
+ template = getProductTemplate();
74
+ break;
75
+ case 'codebase':
76
+ template = getCodebaseTemplate();
77
+ break;
78
+ case 'feedback':
79
+ template = getFeedbackTemplate();
80
+ break;
111
81
  }
112
82
 
113
- await fs.writeFile(filePath, templates[type]);
83
+ await fs.writeFile(filePath, template);
114
84
 
115
85
  // 更新配置
116
- config.stages.baseline.documents.push(type);
86
+ config.stages.baseline.documents.push(internalType);
117
87
  await fs.writeJSON(configPath, config, { spaces: 2 });
118
88
 
119
89
  console.log(chalk.green(`✓ 已创建: ${fileName}`));
120
90
  console.log(chalk.cyan(`\n文件位置: ${filePath}\n`));
121
91
 
122
92
  // 给出下一步提示
123
- if (type === 'A0') {
124
- console.log(chalk.bold('下一步建议:'));
125
- console.log('1. 填写 A0 产品基础与范围说明');
126
- console.log('2. 创建 A1: prd baseline create A1');
127
- } else if (type === 'A1') {
128
- console.log(chalk.bold('下一步建议:'));
129
- console.log('1. 填写 A1 已上线功能与流程清单');
130
- console.log('2. 创建 A2: prd baseline create A2');
131
- } else if (type === 'A2') {
93
+ if (internalType === 'product') {
132
94
  console.log(chalk.bold('下一步建议:'));
133
- console.log('1. 填写 A2 存量反馈与数据汇总');
134
- console.log('2. 创建 R0 基线审视: prd baseline create R0');
135
- } else if (type === 'R0') {
95
+ console.log('1. 填写产品定义(与 AI 对话完成)');
96
+ console.log('2. 创建代码快照: prd baseline create 代码快照');
97
+ console.log(chalk.yellow('\n💡 提示: 使用 /prd-代码快照 工作流让 AI 自动扫描代码生成'));
98
+ } else if (internalType === 'codebase') {
99
+ console.log(chalk.bold('⚠️ 重要提醒:'));
100
+ console.log(chalk.yellow('代码快照应由 AI 扫描代码自动生成,而非手动填写!'));
101
+ console.log('\n使用 /prd-代码快照 工作流让 AI 扫描代码。');
102
+ console.log('\n下一步建议:');
103
+ console.log('1. 创建用户反馈: prd baseline create 用户反馈');
104
+ } else if (internalType === 'feedback') {
136
105
  console.log(chalk.bold('下一步建议:'));
137
- console.log('1. 完成 R0 基线审视(与 AI 协作填写)');
106
+ console.log('1. 整理用户反馈(可让 AI 协助)');
138
107
  console.log('2. 开始第一轮迭代: prd iteration new');
139
- console.log('');
140
- console.log(chalk.yellow('⚠️ 重要提醒:'));
141
- console.log(' R0 完成后,请勿自动创建后续文档!');
142
- console.log(' 必须由 PM 明确指示才能进入下一阶段。');
143
108
  }
144
109
  console.log('');
145
110
  }
146
111
 
147
- function getFileName(type) {
148
- const nameMap = {
149
- 'A0': 'A0_产品基础与范围说明.md',
150
- 'A1': 'A1_已上线功能与流程清单.md',
151
- 'A2': 'A2_存量反馈与数据汇总.md',
152
- 'R0': 'R0_基线审视报告.md'
153
- };
154
- return nameMap[type];
155
- }
156
-
157
- function getA0Template() {
158
- return `# A0_产品基础与范围说明
112
+ function getProductTemplate() {
113
+ return `# 产品定义
159
114
 
160
- **文档创建时间**: ${new Date().toLocaleString('zh-CN')}
115
+ **创建时间**: ${new Date().toLocaleString('zh-CN')}
161
116
 
162
117
  ---
163
118
 
164
- ## 一、产品背景与定位
119
+ ## 1. 产品是什么
165
120
 
166
- ### 产品是什么
167
121
  <!-- 用一句话描述此产品 -->
168
122
 
169
- ### 产品定位
123
+
124
+ ## 2. 产品定位
125
+
170
126
  <!-- 在整个业务体系中的角色 -->
171
127
 
128
+
172
129
  ---
173
130
 
174
- ## 二、目标用户定义
131
+ ## 3. 目标用户
175
132
 
176
133
  ### 主要用户群体
134
+
177
135
  <!-- 列出主要用户类型 -->
178
136
 
179
- ### 用户画像
180
- <!-- 描述典型用户特征 -->
181
137
 
182
- ---
183
-
184
- ## 三、核心使用场景
138
+ ### 用户画像
185
139
 
186
- ### 场景一:
187
- <!-- 场景描述 -->
140
+ <!-- 描述典型用户特征 -->
188
141
 
189
- ### 场景二:
190
- <!-- 场景描述 -->
191
142
 
192
143
  ---
193
144
 
194
- ## 四、当前版本范围与边界
145
+ ## 4. 核心使用场景
195
146
 
196
- ### 当前包含的能力
197
- <!-- 列出已有的核心功能 -->
147
+ ### 场景一: [场景名称]
198
148
 
199
- ### 当前的技术架构
200
- <!-- 简要说明技术实现方式 -->
149
+ <!-- 场景描述 -->
201
150
 
202
- ---
203
151
 
204
- ## 五、明确不覆盖的内容
152
+ ### 场景二: [场景名称]
205
153
 
206
- ### 当前不支持的场景
207
- <!-- 明确说明哪些场景不支持 -->
154
+ <!-- 场景描述 -->
208
155
 
209
- ### 已知限制
210
- <!-- 列出当前的限制条件 -->
211
156
 
212
157
  ---
213
158
 
214
- ## 填写说明
215
-
216
- ⚠️ **重要约束**:
217
- - 不写规划、不写愿景
218
- - 只描述"现在这个产品是什么样"
219
- - 边界要写清楚(哪些能力没有、哪些不支持)
220
-
221
- **目的**:
222
- - 给 AI 和人一个统一的"现状语境"
223
- - 防止后续规划"假设一个不存在的产品"
224
- - 作为所有 B 规划的前置事实引用源
225
- `;
226
- }
159
+ ## 5. 当前能力范围
227
160
 
228
- function getA1Template() {
229
- return `# A1_已上线功能与流程清单
161
+ ### 已有的核心功能
230
162
 
231
- **文档创建时间**: ${new Date().toLocaleString('zh-CN')}
163
+ <!-- 列出已有的核心功能 -->
232
164
 
233
- ---
234
165
 
235
- ## 一、功能列表(按模块)
166
+ ### 当前技术架构
236
167
 
237
- ### 模块一: [模块名称]
238
- - 功能 1.1:
239
- - 功能 1.2:
168
+ <!-- 简要说明技术实现方式 -->
240
169
 
241
- ### 模块二: [模块名称]
242
- - 功能 2.1:
243
- - 功能 2.2:
244
170
 
245
171
  ---
246
172
 
247
- ## 二、核心用户路径
173
+ ## 6. 明确不做的事情
248
174
 
249
- ### 路径一: [路径名称]
250
- 1. 步骤 1
251
- 2. 步骤 2
252
- 3. 步骤 3
253
-
254
- ### 路径二: [路径名称]
255
- 1. 步骤 1
256
- 2. 步骤 2
175
+ ### 不支持的场景
257
176
 
258
- ---
177
+ <!-- 明确说明哪些场景不支持 -->
259
178
 
260
- ## 三、关键业务流程节点
261
179
 
262
- ### 流程一:
263
- <!-- 描述业务流程的关键节点 -->
180
+ ### 已知限制
264
181
 
265
- ---
182
+ <!-- 列出当前的限制条件 -->
266
183
 
267
- ## 四、功能之间的依赖关系
268
-
269
- ### 依赖关系图
270
- <!-- 描述功能间的依赖 -->
271
184
 
272
185
  ---
273
186
 
274
187
  ## 填写说明
275
188
 
276
189
  ⚠️ **重要约束**:
277
- - 功能是"客观存在的",不是"设计过的"
278
- - 用户路径用真实使用顺序,不用理想流程
279
- - 不评价好坏,只陈述事实
190
+ - 不写规划、不写愿景
191
+ - 只描述"现在这个产品是什么样"
192
+ - 边界要写清楚(哪些能力没有、哪些不支持)
280
193
 
281
194
  **目的**:
282
- - 让审视与规划基于真实系统
283
- - 防止 AI 反复"重建已有能力"
284
- - 为 R0 / R1 提供审视对象
195
+ - 给 AI 和人一个统一的"现状语境"
196
+ - 防止后续规划"假设一个不存在的产品"
197
+ - 作为所有规划的前置事实引用源
285
198
  `;
286
199
  }
287
200
 
288
- function getA2Template() {
289
- return `# A2_存量反馈与数据输入汇总
201
+ function getCodebaseTemplate() {
202
+ return `# 代码快照
290
203
 
291
- **文档创建时间**: ${new Date().toLocaleString('zh-CN')}
204
+ **创建时间**: ${new Date().toLocaleString('zh-CN')}
292
205
 
293
206
  ---
294
207
 
295
- ## 一、用户反馈摘要
296
-
297
- ### 反馈类型一:
298
- <!-- 摘要用户反馈内容 -->
299
- - 来源:
300
- - 时间:
301
-
302
- ### 反馈类型二:
303
- <!-- 摘要用户反馈内容 -->
208
+ > ⚠️ **本文件应由 AI 扫描代码自动生成,请勿手动维护!**
209
+ >
210
+ > 使用 /prd-代码快照 工作流让 AI 扫描代码。
304
211
 
305
212
  ---
306
213
 
307
- ## 二、数据异常或指标变化
214
+ ## 1. 项目概览
308
215
 
309
- ### 异常一:
310
- <!-- 描述数据异常情况 -->
216
+ **项目类型**: [前端/后端/全栈/CLI]
217
+ **技术栈**: [React/Vue/Express/...]
218
+ **入口文件**: [...]
311
219
 
312
220
  ---
313
221
 
314
- ## 三、内部问题/投诉
222
+ ## 2. 功能清单
315
223
 
316
- ### 问题一:
317
- <!-- 描述问题 -->
318
- - 来源:
319
- - 影响范围:
224
+ ### 2.1 [模块A]
320
225
 
321
- ---
226
+ | 功能 | 路径/入口 | 说明 |
227
+ |-----|----------|------|
228
+ | 功能1 | \`src/xxx\` | ... |
229
+ | 功能2 | \`src/yyy\` | ... |
322
230
 
323
- ## 四、已知未解决事项
231
+ ### 2.2 [模块B]
324
232
 
325
- ### 事项一:
326
- <!-- 描述未解决的问题 -->
327
- - 原因:
328
- - 优先级:
233
+ ...
329
234
 
330
235
  ---
331
236
 
332
- ## 五、待下版事项(C 阶段产生的新需求)
333
-
334
- **用途说明**:
335
- 当 C1/C2 讨论过程中产生了新需求,但超出当前版本(B3)的规划范围时,
336
- 应记录在此章节,等待下一轮迭代时纳入 B1 规划。
337
-
338
- ### 待下版事项 #1: [需求标题]
339
-
340
- **来源**:C1/C2 讨论过程(第 XX 轮迭代,YYYY-MM-DD)
341
- **原因**:超出 B3 首版范围,延后处理
237
+ ## 3. API 清单(如有)
342
238
 
343
- **优先级**:
344
- - [ ] P0 - 紧急
345
- - [ ] P1 - 重要
346
- - [ ] P2 - 一般
239
+ | 方法 | 路径 | 说明 |
240
+ |-----|------|------|
241
+ | GET | /api/xxx | ... |
242
+ | POST | /api/yyy | ... |
347
243
 
348
- **详细描述**:
349
- <!-- 需求的详细说明 -->
244
+ ---
350
245
 
351
- **PM 补充说明**:
352
- <!-- 保留 PM 原话 -->
246
+ ## 4. 核心用户路径
353
247
 
354
- **关联需求**:
355
- <!-- 与现有需求的关联 -->
248
+ ### 路径 1: [路径名称]
356
249
 
357
- **记录时间**:
358
- **记录人**:
250
+ 1. 步骤 1
251
+ 2. 步骤 2
252
+ 3. 步骤 3
359
253
 
360
254
  ---
361
255
 
362
- ## 填写说明
256
+ ## 5. 依赖关系
363
257
 
364
- ⚠️ **重要约束**:
365
- - 不做结论、不做方案
366
- - 可以是原始反馈的整理
367
- - 标注来源即可
258
+ ### 模块间依赖
368
259
 
369
- **目的**:
370
- - 为 B 规划提供动因素材
371
- - 防止规划"拍脑袋"
372
- - 为 R 审视提供"现实校验"
373
- - **暂存 C 阶段产生的超范围需求(待下版处理)**
260
+ <!-- 描述功能间的依赖 -->
374
261
 
375
262
  ---
376
263
 
377
- ## 📋 使用流程
378
-
379
- ### 何时写入本文档?
380
-
381
- | 场景 | 写入章节 |
382
- |------|----------|
383
- | 收到用户反馈 | 一、用户反馈摘要 |
384
- | 发现数据异常 | 二、数据异常或指标变化 |
385
- | 内部发现问题 | 三、内部问题/投诉 |
386
- | 已知但未解决的问题 | 四、已知未解决事项 |
387
- | **C1/C2 讨论中产生的新需求** | **五、待下版事项** |
264
+ ## 扫描日志
388
265
 
389
- ### 何时从本文档提取?
390
-
391
- - **开始新一轮迭代时**:从第四、五章节提取问题/需求到 B1
392
- - **B1 规划时**:引用第一~三章节作为需求来源依据
266
+ - 最后扫描时间: ___
267
+ - 扫描范围: ___
268
+ - 识别功能点: ___ 个
269
+ - 识别 API: ___ 个
393
270
  `;
394
271
  }
395
272
 
396
- function getR0Template() {
397
- return `# R0_基线审视报告
273
+ function getFeedbackTemplate() {
274
+ return `# 用户反馈
398
275
 
399
- **审视时间**: ${new Date().toLocaleString('zh-CN')}
276
+ **创建时间**: ${new Date().toLocaleString('zh-CN')}
400
277
 
401
278
  ---
402
279
 
403
- ## 一、审视范围说明
280
+ ## 1. 用户反馈摘要
281
+
282
+ ### 反馈 1: [标题]
283
+
284
+ - **来源**:
285
+ - **时间**:
286
+ - **内容**:
404
287
 
405
- **审视对象**:
406
- - A0_产品基础与范围说明.md
407
- - A1_已上线功能与流程清单.md
408
- - A2_存量反馈与数据汇总.md
288
+ ### 反馈 2: [标题]
409
289
 
410
- **审视目标**:
411
- 建立产品基线,为后续迭代规划提供稳定的起点。
290
+ - **来源**:
291
+ - **时间**:
292
+ - **内容**:
412
293
 
413
294
  ---
414
295
 
415
- ## 二、实际用户路径审视
296
+ ## 2. 数据异常或指标变化
416
297
 
417
- ### 主要用户路径梳理
418
- <!-- 从头到尾走一遍系统,描述实际使用情况 -->
298
+ ### 异常 1: [标题]
419
299
 
420
- ### 发现的路径问题
421
- <!-- 列出用户路径中的断点、痛点 -->
300
+ - **发现时间**:
301
+ - **具体表现**:
302
+ - **影响范围**:
422
303
 
423
304
  ---
424
305
 
425
- ## 三、主要问题与机会
306
+ ## 3. 内部问题/投诉
426
307
 
427
- ### 问题清单
428
- 1.
429
- 2.
308
+ ### 问题 1: [标题]
430
309
 
431
- ### 机会点
432
- 1.
433
- 2.
310
+ - **来源**:
311
+ - **描述**:
312
+ - **影响范围**:
434
313
 
435
314
  ---
436
315
 
437
- ## 四、风险与隐患
316
+ ## 4. 已知未解决事项
438
317
 
439
- ### 技术风险
440
- <!-- 列出技术层面的风险 -->
318
+ ### 事项 1: [标题]
441
319
 
442
- ### 业务风险
443
- <!-- 列出业务层面的风险 -->
320
+ - **原因**:
321
+ - **优先级**: P0 / P1 / P2
444
322
 
445
323
  ---
446
324
 
447
- ## 五、总体判断结论
325
+ ## 5. 待下版事项
448
326
 
449
- **基线稳定性评估**:
450
- - [ ] 可以作为稳定基线
451
- - [ ] 需要先解决关键问题
327
+ > 当规划/版本讨论过程中产生了新需求,但超出当前版本范围时,
328
+ > 记录在此章节,等待下一轮迭代时纳入规划。
452
329
 
453
- **下一步建议**:
454
- <!-- 给出后续规划建议 -->
330
+ ### 待下版 #1: [需求标题]
331
+
332
+ **来源**: 第 XX 轮迭代讨论
333
+ **原因**: 超出首版范围,延后处理
334
+ **优先级**: P0 / P1 / P2
335
+ **详细描述**:
455
336
 
456
337
  ---
457
338
 
458
339
  ## 填写说明
459
340
 
460
341
  ⚠️ **重要约束**:
461
- - 必须"从头到尾走一遍系统"
462
- - 问题基于事实,不基于偏好
463
- - 结论是"是否适合作为稳定基线"
342
+ - 不做结论、不做方案
343
+ - 可以是原始反馈的整理
344
+ - 标注来源即可
464
345
 
465
346
  **目的**:
466
- - 给存量系统建立一个起点基线
467
- - 为第一次 B 规划提供"共识事实"
468
- - 防止一上来就大改而不知问题在哪
347
+ - 为规划提供动因素材
348
+ - 防止规划"拍脑袋"
349
+ - 暂存超范围需求(待下版处理)
469
350
  `;
470
351
  }