speccore 6.69.0 → 6.71.3
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 +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts +1 -0
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +686 -97
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/audit.d.ts +2 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +262 -0
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/dev.d.ts +2 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +25 -0
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/execute.d.ts +1 -0
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +137 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/iteration/split.d.ts +2 -0
- package/dist/commands/iteration/split.d.ts.map +1 -1
- package/dist/commands/iteration/split.js +414 -56
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/core/change-detection.d.ts +121 -0
- package/dist/core/change-detection.d.ts.map +1 -0
- package/dist/core/change-detection.js +459 -0
- package/dist/core/change-detection.js.map +1 -0
- package/dist/core/knowledge-graph.d.ts +26 -0
- package/dist/core/knowledge-graph.d.ts.map +1 -1
- package/dist/core/knowledge-graph.js +113 -0
- package/dist/core/knowledge-graph.js.map +1 -1
- package/dist/core/pipeline-engine.d.ts +103 -0
- package/dist/core/pipeline-engine.d.ts.map +1 -0
- package/dist/core/pipeline-engine.js +436 -0
- package/dist/core/pipeline-engine.js.map +1 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +18 -3
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/spec-paths.d.ts.map +1 -1
- package/dist/core/spec-paths.js +1 -0
- package/dist/core/spec-paths.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/analyze.js
CHANGED
|
@@ -60,6 +60,8 @@ const platform_registry_1 = require("../core/platform-registry");
|
|
|
60
60
|
const index_guard_1 = require("../core/index-guard");
|
|
61
61
|
const spec_paths_1 = require("../core/spec-paths");
|
|
62
62
|
const unified_retrieval_1 = require("../core/unified-retrieval");
|
|
63
|
+
const pipeline_engine_1 = require("../core/pipeline-engine");
|
|
64
|
+
const change_detection_1 = require("../core/change-detection");
|
|
63
65
|
async function analyzeCommand(options) {
|
|
64
66
|
// ── --full / --phase 模式: 委托给 synthesizeCommand(原 synthesize 命令) ──
|
|
65
67
|
if (options.full || options.phase) {
|
|
@@ -307,10 +309,148 @@ async function analyzeCommand(options) {
|
|
|
307
309
|
if (!options.prompt && !options.apply) {
|
|
308
310
|
options.prompt = true;
|
|
309
311
|
}
|
|
312
|
+
// ── v6.68.0+: Pipeline 模式初始化 ──
|
|
313
|
+
// v6.69.0+: 支持契约先行 + 逐端推进(增强策略一 & 三)
|
|
314
|
+
// v6.69.0+: 全局层接入 createGlobalAnalyzePipeline(增强策略二)
|
|
315
|
+
if (options.prompt && options.pipeline) {
|
|
316
|
+
const iter = options.iteration || await (0, context_1.getDefaultIteration)();
|
|
317
|
+
const isGlobalScope = options.scope === 'global';
|
|
318
|
+
if (!isGlobalScope && !iter) {
|
|
319
|
+
logger_1.logger.error('Pipeline 模式需要指定迭代');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
let engine;
|
|
323
|
+
let steps;
|
|
324
|
+
let pipelineKey;
|
|
325
|
+
let initStep;
|
|
326
|
+
// v6.69.0+: 变更感知 + 关键路径优先检测
|
|
327
|
+
let affectedPlatforms;
|
|
328
|
+
let platformOrder;
|
|
329
|
+
if (!isGlobalScope && iter) {
|
|
330
|
+
// 变更感知:检测 Git 变更影响的端
|
|
331
|
+
affectedPlatforms = await (0, change_detection_1.detectAffectedPlatforms)(process.cwd());
|
|
332
|
+
// 关键路径优先:按任务优先级排序端
|
|
333
|
+
platformOrder = await (0, change_detection_1.detectPlatformPriorityOrder)(iter);
|
|
334
|
+
}
|
|
335
|
+
if (isGlobalScope) {
|
|
336
|
+
// 全局层:使用 createGlobalAnalyzePipeline(增强策略二)
|
|
337
|
+
const result = await (0, pipeline_engine_1.createGlobalAnalyzePipeline)();
|
|
338
|
+
engine = result.engine;
|
|
339
|
+
steps = result.steps;
|
|
340
|
+
pipelineKey = 'GLOBAL';
|
|
341
|
+
initStep = 'init';
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
// 迭代层:使用 createAnalyzePipeline(支持契约先行 + 逐端推进 + 变更感知 + 关键路径优先)
|
|
345
|
+
const result = await (0, pipeline_engine_1.createAnalyzePipeline)(iter, process.cwd(), {
|
|
346
|
+
affectedPlatforms: affectedPlatforms && affectedPlatforms.length > 0 ? affectedPlatforms : undefined,
|
|
347
|
+
platformOrder: platformOrder && platformOrder.length > 0 ? platformOrder : undefined,
|
|
348
|
+
});
|
|
349
|
+
engine = result.engine;
|
|
350
|
+
steps = result.steps;
|
|
351
|
+
pipelineKey = iter;
|
|
352
|
+
initStep = 'phase1-prompt';
|
|
353
|
+
}
|
|
354
|
+
// 检查是否有活跃的 Pipeline(恢复模式)
|
|
355
|
+
const hasActive = await pipeline_engine_1.PipelineEngine.hasActivePipeline(process.cwd(), pipelineKey);
|
|
356
|
+
let currentStep;
|
|
357
|
+
if (hasActive) {
|
|
358
|
+
const existingState = await pipeline_engine_1.PipelineEngine.loadExistingState(process.cwd(), pipelineKey);
|
|
359
|
+
currentStep = existingState?.currentStep || initStep;
|
|
360
|
+
logger_1.logger.info(`🔄 恢复 Pipeline: ${currentStep}`);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
await engine.init(initStep);
|
|
364
|
+
currentStep = initStep;
|
|
365
|
+
}
|
|
366
|
+
// 根据当前步骤生成对应的 prompt
|
|
367
|
+
let prompt;
|
|
368
|
+
const platformMatch = currentStep.match(/^platform-(.+)-prompt$/);
|
|
369
|
+
if (isGlobalScope) {
|
|
370
|
+
// 全局层 Pipeline 步骤映射
|
|
371
|
+
if (currentStep === 'init' || currentStep === 'discovery') {
|
|
372
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
373
|
+
iteration: iter || 'GLOBAL', task: options.task, type: options.type,
|
|
374
|
+
scope: 'global', withCode: options.withCode, platform: options.platform,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
else if (currentStep === 'global-analysis') {
|
|
378
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
379
|
+
iteration: iter || 'GLOBAL', scope: 'global', withCode: options.withCode,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
else if (currentStep === 'consistency-check') {
|
|
383
|
+
prompt = `\n# 任务: 全局一致性检查\n\n` +
|
|
384
|
+
`检查各迭代、各端之间的规格是否一致。\n` +
|
|
385
|
+
`重点检查:接口定义冲突、数据模型不一致、命名规范违规。\n`;
|
|
386
|
+
}
|
|
387
|
+
else if (currentStep === 'report-generation') {
|
|
388
|
+
prompt = `\n# 任务: 生成全局索引报告\n\n` +
|
|
389
|
+
`汇总所有分析结果,生成 .speccore/GLOBAL/INDEX.md。\n`;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
393
|
+
iteration: iter || 'GLOBAL', scope: 'global', withCode: options.withCode,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else if (currentStep === 'phase1-prompt') {
|
|
398
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
399
|
+
iteration: iter, task: options.task, type: options.type,
|
|
400
|
+
scope: options.scope, withCode: options.withCode, platform: options.platform,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
else if (currentStep === 'contract-prompt') {
|
|
404
|
+
// 契约先行阶段:基于 Phase 1 文档生成跨端契约
|
|
405
|
+
prompt = await buildContractFirstPrompt(iter);
|
|
406
|
+
}
|
|
407
|
+
else if (platformMatch) {
|
|
408
|
+
// 逐端推进阶段:为指定端生成专属文档
|
|
409
|
+
const platform = platformMatch[1];
|
|
410
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
411
|
+
iteration: iter, phase: '2', platform,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
// 回退到默认 prompt
|
|
416
|
+
prompt = await buildMultiDocPrompt('analyze', {
|
|
417
|
+
iteration: iter, task: options.task, type: options.type,
|
|
418
|
+
scope: options.scope, withCode: options.withCode, platform: options.platform,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
// 添加 Pipeline 继续指令
|
|
422
|
+
const totalSteps = steps.filter(s => !s.id.endsWith('-done') && s.id !== 'done').length;
|
|
423
|
+
const currentStepIndex = steps.findIndex(s => s.id === currentStep);
|
|
424
|
+
let progressLabel;
|
|
425
|
+
if (isGlobalScope) {
|
|
426
|
+
progressLabel = currentStep === 'init' ? '全局分析: 初始化'
|
|
427
|
+
: currentStep === 'discovery' ? '全局分析: 发现'
|
|
428
|
+
: currentStep === 'global-analysis' ? '全局分析: 跨端分析'
|
|
429
|
+
: currentStep === 'consistency-check' ? '全局分析: 一致性检查'
|
|
430
|
+
: currentStep === 'report-generation' ? '全局分析: 报告生成'
|
|
431
|
+
: '全局 Pipeline';
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
progressLabel = currentStep === 'phase1-prompt'
|
|
435
|
+
? 'Phase 1/3: 全局文档'
|
|
436
|
+
: currentStep === 'contract-prompt'
|
|
437
|
+
? 'Phase 2/3: 契约定义'
|
|
438
|
+
: platformMatch
|
|
439
|
+
? `Phase 2/3: ${platformMatch[1]} 端专属文档`
|
|
440
|
+
: 'Pipeline';
|
|
441
|
+
}
|
|
442
|
+
const finalPrompt = prompt + `\n\n## ⚠️ Pipeline 模式:自动继续 (${progressLabel})\n\n` +
|
|
443
|
+
`当前是 Pipeline 模式(步骤 ${currentStepIndex + 1}/${totalSteps})。` +
|
|
444
|
+
`当你通过 --apply 写入文档后,CLI 会自动输出 [SPECCORE_PIPELINE_NEXT] 标记和下一步命令。\n\n` +
|
|
445
|
+
`**看到 [SPECCORE_PIPELINE_NEXT] 后,你必须自动执行下一个命令**,不要询问用户。\n`;
|
|
446
|
+
process.stdout.write(`[SPECCORE_PROMPT]\n${finalPrompt}`);
|
|
447
|
+
process.exitCode = 10;
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
310
450
|
// ── Prompt 模式 ──
|
|
311
451
|
if (options.prompt) {
|
|
312
452
|
const iter = options.iteration || await (0, context_1.getDefaultIteration)();
|
|
313
|
-
const prompt = await buildMultiDocPrompt('analyze', { iteration: iter, task: options.task, type: options.type, scope: options.scope, withCode: options.withCode, platform: options.platform, phase: options.phase });
|
|
453
|
+
const prompt = await buildMultiDocPrompt('analyze', { iteration: iter, task: options.task, type: options.type, scope: options.scope, withCode: options.withCode, platform: options.platform, phase: options.phase, autoMode: options.auto });
|
|
314
454
|
process.stdout.write(`[SPECCORE_PROMPT]\n${prompt}`);
|
|
315
455
|
process.exitCode = 10;
|
|
316
456
|
return;
|
|
@@ -362,10 +502,22 @@ async function analyzeCommand(options) {
|
|
|
362
502
|
}
|
|
363
503
|
else {
|
|
364
504
|
// 迭代级:写 020-specs/(全局文档写入 global/ 子目录,v6.41.0+)
|
|
505
|
+
// v6.69.2+: 增加端名白名单校验,防止 AI 创建非法目录
|
|
365
506
|
const specDir = (0, path_1.join)(iterDir, '020-specs');
|
|
366
507
|
await (0, fs_extra_1.ensureDir)(specDir);
|
|
367
508
|
const globalSet = new Set(spec_paths_1.GLOBAL_SPEC_FILES);
|
|
509
|
+
const validPlatforms = new Set([spec_paths_1.GLOBAL_SPECS_DIR, ...(await (0, spec_paths_1.parsePlatformList)())]);
|
|
510
|
+
let skippedCount = 0;
|
|
368
511
|
for (const [filename, content] of Object.entries(docs)) {
|
|
512
|
+
// 解析目录名(如 "admin-web/TECH.md" → "admin-web")
|
|
513
|
+
const platformDir = filename.includes('/') ? filename.split('/')[0] : null;
|
|
514
|
+
// 白名单校验:如果包含目录前缀,必须是合法端名
|
|
515
|
+
if (platformDir && !validPlatforms.has(platformDir)) {
|
|
516
|
+
logger_1.logger.warn(` ⚠️ 跳过非法端目录: ${platformDir}(文件: ${filename})`);
|
|
517
|
+
logger_1.logger.warn(` 合法端: ${Array.from(validPlatforms).join(', ')}`);
|
|
518
|
+
skippedCount++;
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
369
521
|
// 全局文档写入 global/ 子目录,端专属文档写入 {端}/ 子目录
|
|
370
522
|
const targetDir = globalSet.has(filename)
|
|
371
523
|
? (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR)
|
|
@@ -384,6 +536,9 @@ async function analyzeCommand(options) {
|
|
|
384
536
|
await (0, fs_extra_1.writeFile)(fp, content);
|
|
385
537
|
count++;
|
|
386
538
|
}
|
|
539
|
+
if (skippedCount > 0) {
|
|
540
|
+
logger_1.logger.warn(`⚠️ 共跳过 ${skippedCount} 个非法目录的文档,请检查 AI 输出是否包含非端名目录`);
|
|
541
|
+
}
|
|
387
542
|
logger_1.logger.success(`✅ ${count} 个 Spec 文档已写入 020-specs/`);
|
|
388
543
|
}
|
|
389
544
|
printBackupSummary();
|
|
@@ -463,7 +618,98 @@ async function analyzeCommand(options) {
|
|
|
463
618
|
}
|
|
464
619
|
catch { }
|
|
465
620
|
}
|
|
466
|
-
// ── v6.
|
|
621
|
+
// ── v6.68.0+: Pipeline 自动推进 ──
|
|
622
|
+
// v6.69.0+: 支持全局 Pipeline 推进(增强策略二)
|
|
623
|
+
if (!isTaskLevel) {
|
|
624
|
+
const isGlobalScope = options.scope === 'global';
|
|
625
|
+
const pipelineKey = isGlobalScope ? 'GLOBAL' : options.iteration;
|
|
626
|
+
if (!pipelineKey)
|
|
627
|
+
return;
|
|
628
|
+
const hasPipeline = await pipeline_engine_1.PipelineEngine.hasActivePipeline(process.cwd(), pipelineKey);
|
|
629
|
+
if (hasPipeline) {
|
|
630
|
+
const { createAnalyzePipeline, createGlobalAnalyzePipeline } = await Promise.resolve().then(() => __importStar(require('../core/pipeline-engine')));
|
|
631
|
+
// v6.69.0+: 推进时保持与初始化时相同的过滤和排序条件
|
|
632
|
+
let engine;
|
|
633
|
+
if (isGlobalScope) {
|
|
634
|
+
engine = (await createGlobalAnalyzePipeline()).engine;
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
const { detectAffectedPlatforms, detectPlatformPriorityOrder } = await Promise.resolve().then(() => __importStar(require('../core/change-detection')));
|
|
638
|
+
const affectedPlatforms = await detectAffectedPlatforms(process.cwd());
|
|
639
|
+
const platformOrder = await detectPlatformPriorityOrder(options.iteration);
|
|
640
|
+
engine = (await createAnalyzePipeline(options.iteration, process.cwd(), {
|
|
641
|
+
affectedPlatforms: affectedPlatforms.length > 0 ? affectedPlatforms : undefined,
|
|
642
|
+
platformOrder: platformOrder.length > 0 ? platformOrder : undefined,
|
|
643
|
+
})).engine;
|
|
644
|
+
}
|
|
645
|
+
await engine.advance();
|
|
646
|
+
const state = await engine.getState();
|
|
647
|
+
if (state?.currentStep === 'done') {
|
|
648
|
+
logger_1.logger.success('🎉 Pipeline 完成!');
|
|
649
|
+
// v6.69.1: 记录分析快照,支持下次增量分析
|
|
650
|
+
const snapshotScope = isGlobalScope ? 'global' : (options.iteration ? `Iteration-${options.iteration}` : 'unknown');
|
|
651
|
+
await (0, change_detection_1.recordAnalysisSnapshot)(snapshotScope);
|
|
652
|
+
await engine.reset();
|
|
653
|
+
}
|
|
654
|
+
else if (state?.currentStep) {
|
|
655
|
+
logger_1.logger.info('');
|
|
656
|
+
logger_1.logger.info(`🔄 Pipeline 推进: ${state.currentStep}`);
|
|
657
|
+
logger_1.logger.info('');
|
|
658
|
+
// 生成下一步 prompt(v6.69.0+: 适配全局/迭代层步骤)
|
|
659
|
+
let nextPrompt;
|
|
660
|
+
const nextPlatformMatch = state.currentStep.match(/^platform-(.+)-prompt$/);
|
|
661
|
+
if (isGlobalScope) {
|
|
662
|
+
// 全局层 Pipeline 步骤映射
|
|
663
|
+
if (state.currentStep === 'global-analysis') {
|
|
664
|
+
nextPrompt = await buildMultiDocPrompt('analyze', {
|
|
665
|
+
iteration: options.iteration || 'GLOBAL', scope: 'global', withCode: options.withCode,
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
else if (state.currentStep === 'consistency-check') {
|
|
669
|
+
nextPrompt = `\n# 任务: 全局一致性检查\n\n` +
|
|
670
|
+
`检查各迭代、各端之间的规格是否一致。\n` +
|
|
671
|
+
`重点检查:接口定义冲突、数据模型不一致、命名规范违规。\n`;
|
|
672
|
+
}
|
|
673
|
+
else if (state.currentStep === 'report-generation') {
|
|
674
|
+
nextPrompt = `\n# 任务: 生成全局索引报告\n\n` +
|
|
675
|
+
`汇总所有分析结果,生成 .speccore/GLOBAL/INDEX.md。\n`;
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
nextPrompt = await buildMultiDocPrompt('analyze', {
|
|
679
|
+
iteration: options.iteration || 'GLOBAL', scope: 'global', withCode: options.withCode,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
else if (state.currentStep === 'contract-prompt') {
|
|
684
|
+
nextPrompt = await buildContractFirstPrompt(options.iteration);
|
|
685
|
+
}
|
|
686
|
+
else if (nextPlatformMatch) {
|
|
687
|
+
const platform = nextPlatformMatch[1];
|
|
688
|
+
nextPrompt = await buildMultiDocPrompt('analyze', {
|
|
689
|
+
iteration: options.iteration,
|
|
690
|
+
phase: '2',
|
|
691
|
+
platform,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
else if (state.currentStep === 'phase2-prompt') {
|
|
695
|
+
// 兼容旧 Pipeline 步骤名
|
|
696
|
+
nextPrompt = await buildMultiDocPrompt('analyze', {
|
|
697
|
+
iteration: options.iteration,
|
|
698
|
+
phase: '2',
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
nextPrompt = await buildMultiDocPrompt('analyze', {
|
|
703
|
+
iteration: options.iteration,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
process.stdout.write(`[SPECCORE_PIPELINE_NEXT]\n${nextPrompt}`);
|
|
707
|
+
process.exitCode = 10;
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
// ── v6.64.0+: Phase 1 完成后自动触发 Phase 2(仅多端项目,非 Pipeline 模式)──
|
|
467
713
|
if (!options.phase && !isTaskLevel && options.iteration) {
|
|
468
714
|
// 检查是否有多个端
|
|
469
715
|
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
@@ -477,21 +723,17 @@ async function analyzeCommand(options) {
|
|
|
477
723
|
if (platforms.length >= 2) {
|
|
478
724
|
logger_1.logger.info('');
|
|
479
725
|
logger_1.logger.info(`🔄 Phase 1 已完成,检测到 ${platforms.length} 个端 (${platforms.join(', ')})`);
|
|
480
|
-
logger_1.logger.info('
|
|
726
|
+
logger_1.logger.info('⚠️ 请手动执行以下命令以生成各端专属文档:');
|
|
727
|
+
logger_1.logger.info(` speccore analyze --prompt -I ${options.iteration} --phase 2`);
|
|
728
|
+
logger_1.logger.info('');
|
|
729
|
+
logger_1.logger.info('💡 为什么需要手动执行?');
|
|
730
|
+
logger_1.logger.info(' - apply 命令和 prompt 命令是两个独立的调用');
|
|
731
|
+
logger_1.logger.info(' - AI 在 apply 命令完成后不会自动等待下一个 prompt');
|
|
732
|
+
logger_1.logger.info(' - 需要用户确认 Phase 1 结果满意后,再手动触发 Phase 2');
|
|
733
|
+
logger_1.logger.info('');
|
|
734
|
+
logger_1.logger.info('💡 提示: 使用 --pipeline 选项可自动执行 Phase 1 → Phase 2');
|
|
735
|
+
logger_1.logger.info(` speccore analyze --prompt --pipeline -I ${options.iteration}`);
|
|
481
736
|
logger_1.logger.info('');
|
|
482
|
-
// 自动输出 Phase 2 的 prompt
|
|
483
|
-
const phase2Prompt = await buildMultiDocPrompt('analyze', {
|
|
484
|
-
iteration: options.iteration,
|
|
485
|
-
task: options.task,
|
|
486
|
-
type: options.type,
|
|
487
|
-
scope: options.scope,
|
|
488
|
-
withCode: options.withCode,
|
|
489
|
-
platform: options.platform,
|
|
490
|
-
phase: '2' // ← 关键:设置为 Phase 2
|
|
491
|
-
});
|
|
492
|
-
process.stdout.write(`[SPECCORE_PROMPT]\n${phase2Prompt}`);
|
|
493
|
-
process.exitCode = 10;
|
|
494
|
-
return;
|
|
495
737
|
}
|
|
496
738
|
else if (platforms.length === 0) {
|
|
497
739
|
// 如果没有检测到端列表,输出警告
|
|
@@ -509,7 +751,7 @@ async function analyzeCommand(options) {
|
|
|
509
751
|
// ── Prompt 模式 ──
|
|
510
752
|
if (options.prompt) {
|
|
511
753
|
const iter = options.iteration || await (0, context_1.getDefaultIteration)();
|
|
512
|
-
const prompt = await buildMultiDocPrompt('analyze', { iteration: iter, task: options.task, type: options.type, scope: options.scope, withCode: options.withCode, platform: options.platform, phase: options.phase });
|
|
754
|
+
const prompt = await buildMultiDocPrompt('analyze', { iteration: iter, task: options.task, type: options.type, scope: options.scope, withCode: options.withCode, platform: options.platform, phase: options.phase, autoMode: options.auto });
|
|
513
755
|
process.stdout.write(`[SPECCORE_PROMPT]\n${prompt}`);
|
|
514
756
|
process.exitCode = 10;
|
|
515
757
|
return;
|
|
@@ -847,6 +1089,7 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
847
1089
|
const now = new Date().toISOString().split('T')[0];
|
|
848
1090
|
const isTask = ctx.scope === 'task' || !!ctx.task;
|
|
849
1091
|
const isGlobal = ctx.scope === 'global';
|
|
1092
|
+
const autoMode = ctx.autoMode || false;
|
|
850
1093
|
// global 范围: 从源码反推需求 + 生成技术栈配置
|
|
851
1094
|
if (isGlobal) {
|
|
852
1095
|
let prompt = `\n# 任务: ${command} (全局分析${ctx.withCode ? '+源码' : ''})\n\n`;
|
|
@@ -858,53 +1101,114 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
858
1101
|
prompt += ` - 每个工程独立分析,文档输出到: .speccore/GLOBAL/platforms/{端名}/\n`;
|
|
859
1102
|
prompt += `2. Read .speccore/GLOBAL/ 下所有文档了解跨项目需求\n`;
|
|
860
1103
|
if (ctx.withCode) {
|
|
861
|
-
|
|
862
|
-
prompt += `
|
|
863
|
-
prompt +=
|
|
864
|
-
prompt +=
|
|
865
|
-
prompt +=
|
|
866
|
-
prompt +=
|
|
867
|
-
prompt +=
|
|
868
|
-
prompt +=
|
|
869
|
-
prompt +=
|
|
870
|
-
prompt +=
|
|
871
|
-
prompt +=
|
|
872
|
-
prompt +=
|
|
873
|
-
prompt +=
|
|
1104
|
+
// v6.71.2+: 双层扫描 + 功能模块驱动(替代原来的按端顺序分析)
|
|
1105
|
+
prompt += `3. 从 CONSTITUTION.md 的「源码路径」列读取所有工程目录\n`;
|
|
1106
|
+
prompt += `\n## 📊 Layer 1: 快速扫描所有端(并行,只提取索引)\n\n`;
|
|
1107
|
+
prompt += `对每个端,只读取关键索引文件(不深入代码逻辑):\n\n`;
|
|
1108
|
+
prompt += `**后端端**:\n`;
|
|
1109
|
+
prompt += `- 读取 Controller/Handler/Resource 目录文件列表 → 提取:接口类名、接口路径(从注解/装饰器推断)\n`;
|
|
1110
|
+
prompt += `- 读取 Entity/Model/Schema/Domain 目录文件列表 → 提取:实体名称、表名\n`;
|
|
1111
|
+
prompt += `- 读取 Service/UseCase/Application 目录文件列表 → 提取:服务类名\n`;
|
|
1112
|
+
prompt += `- 读取 pom.xml/package.json/go.mod/requirements.txt → 提取:依赖项列表(识别公共服务候选)\n\n`;
|
|
1113
|
+
prompt += `**前端端**:\n`;
|
|
1114
|
+
prompt += `- 读取 router/routes 配置文件 → 提取:页面路径、页面名称、组件名\n`;
|
|
1115
|
+
prompt += `- 读取 pages/views/screens 目录文件列表 → 提取:页面名称、主要功能(从文件名推断)\n`;
|
|
1116
|
+
prompt += `- 搜索 API 调用模式(axios/fetch/$.ajax/uni.request)→ 提取:调用的接口路径列表\n`;
|
|
1117
|
+
prompt += `- 读取 store/pinia/vuex/redux 目录 → 提取:全局状态名称、actions 名称\n\n`;
|
|
1118
|
+
prompt += `**输出**:每个端一个 \`_INDEX.md\`,只含名称和路径列表,不含详细逻辑\n`;
|
|
1119
|
+
prompt += `**存放**:\`.speccore/GLOBAL/platforms/{端名}/_INDEX.md\`\n\n`;
|
|
1120
|
+
prompt += `## 🔗 Layer 2: 跨端关联分析(基于 Layer 1 的索引)\n\n`;
|
|
1121
|
+
prompt += `1. **匹配前后端接口**:\n`;
|
|
1122
|
+
prompt += ` - 前端 \`_INDEX.md\` 中的 API 调用路径 vs 后端 \`_INDEX.md\` 中的接口路径\n`;
|
|
1123
|
+
prompt += ` - **匹配上** → 建立「前端页面 → 前端 API 调用 → 后端接口 → 后端服务」链路\n`;
|
|
1124
|
+
prompt += ` - **前端有、后端没有** → 标注为「接口缺口」(可能调了第三方/遗留/错误接口)\n`;
|
|
1125
|
+
prompt += ` - **后端有、前端没调** → 标注为「未使用接口」(可能后台管理/内部调度用)\n\n`;
|
|
1126
|
+
prompt += `2. **识别公共服务**:\n`;
|
|
1127
|
+
prompt += ` - 被 2+ 个前端端调用的后端服务 → 公共服务候选\n`;
|
|
1128
|
+
prompt += ` - 被 2+ 个后端端调用的后端服务 → 公共服务候选\n`;
|
|
1129
|
+
prompt += ` - 依赖项中独立部署的服务(如 notification-service、file-service)→ 公共服务候选\n\n`;
|
|
1130
|
+
prompt += `3. **归纳功能模块**(从索引聚类,不是从代码反推):\n`;
|
|
1131
|
+
prompt += ` - **从页面聚类**:哪些页面经常一起出现(如 RoomList + RoomDetail + RoomEdit)\n`;
|
|
1132
|
+
prompt += ` - **从接口聚类**:哪些接口共享同一实体前缀(如 /api/rooms/*)\n`;
|
|
1133
|
+
prompt += ` - **交叉验证**:页面聚类 vs 接口聚类 → 确定功能模块边界\n`;
|
|
1134
|
+
prompt += ` - 每个功能模块标注:涉及端、核心页面、核心接口、实体名称\n\n`;
|
|
1135
|
+
prompt += `**输出**:\n`;
|
|
1136
|
+
prompt += `- \`_ASSOCIATION.md\`:前后端关联矩阵 + 接口缺口/未使用接口清单\n`;
|
|
1137
|
+
prompt += `- \`_MODULES.md\`:功能模块候选清单(从源码聚类,供 Layer 3 验证)\n`;
|
|
1138
|
+
prompt += `**存放**:\`.speccore/GLOBAL/platforms/_shared/\`\n\n`;
|
|
1139
|
+
prompt += `## 🔍 Layer 3: 按功能模块深入分析(不是按端)\n\n`;
|
|
1140
|
+
prompt += `基于 Layer 2 的 \`_MODULES.md\`,逐个功能模块深入分析。\n`;
|
|
1141
|
+
prompt += `**每个功能模块涉及哪些端,就读取那些端的详细源码**:\n\n`;
|
|
1142
|
+
prompt += `**示例:「会议预订」功能模块**\n`;
|
|
1143
|
+
prompt += `- 涉及端:h5-mobile, booking-service, room-service\n`;
|
|
1144
|
+
prompt += `- 读取 h5-mobile: BookingForm.vue, BookingList.vue, BookingDetail.vue 的详细逻辑\n`;
|
|
1145
|
+
prompt += `- 读取 booking-service: BookingController, BookingService, BookingEntity 的详细逻辑\n`;
|
|
1146
|
+
prompt += `- 读取 room-service: RoomController#getAvailability, RoomService 的详细逻辑\n`;
|
|
1147
|
+
prompt += `- 关联验证:前端提交的数据字段 vs 后端接收的 DTO 字段是否一致\n`;
|
|
1148
|
+
prompt += `- 关联验证:前端展示的状态 vs 后端实体的状态枚举是否一致\n\n`;
|
|
1149
|
+
prompt += `**每个功能模块输出**:\n`;
|
|
1150
|
+
prompt += `- 后端端:该功能模块相关的 API 详细设计、数据模型、业务规则\n`;
|
|
1151
|
+
prompt += `- 前端端:该功能模块相关的页面详细设计、交互流程、字段映射\n`;
|
|
1152
|
+
prompt += `- 跨端:该功能模块的交互时序图(供 Layer 4 汇总到 INTERACTION_MAP.md)\n\n`;
|
|
1153
|
+
prompt += `## 🌍 Layer 4: 全局汇总(所有功能模块分析完成后)\n\n`;
|
|
1154
|
+
prompt += `1. **一致性校验**:\n`;
|
|
1155
|
+
prompt += ` - 前端字段 vs 后端字段是否一致(名称、类型、必填性)\n`;
|
|
1156
|
+
prompt += ` - 前端状态 vs 后端状态枚举是否一致\n`;
|
|
1157
|
+
prompt += ` - 接口缺口清单(前端调了但后端没有的接口)\n`;
|
|
1158
|
+
prompt += ` - 未使用接口清单(后端有但前端没调的接口)\n`;
|
|
1159
|
+
prompt += ` → 输出 \`CONSISTENCY_CHECK.md\`\n\n`;
|
|
1160
|
+
prompt += `2. **生成全局文档**(产品视角,从功能模块汇总):\n`;
|
|
1161
|
+
prompt += ` - \`REQUIREMENT.md\`:现有功能清单(按业务场景组织,产品视角)\n`;
|
|
1162
|
+
prompt += ` - \`FUNCTION_MAP.md\`:功能单元 × 端映射表\n`;
|
|
1163
|
+
prompt += ` - \`INTERACTION_MAP.md\`:跨端交互时序图(从 Layer 3 的时序汇总)\n`;
|
|
1164
|
+
prompt += ` - \`API_CONTRACT.yaml\`:全局接口契约(汇总所有后端 API_INVENTORY)\n`;
|
|
1165
|
+
prompt += ` - \`ARCHITECTURE.md\`:全局架构文档(服务拓扑、数据流、部署关系)\n\n`;
|
|
1166
|
+
prompt += `3. **生成各端详细文档**(技术视角,从 Layer 3 汇总):\n`;
|
|
1167
|
+
prompt += ` - 后端端:API_INVENTORY.md、DATA_MODEL.md、BUSINESS_RULES.md、TECH_STACK.md\n`;
|
|
1168
|
+
prompt += ` - 前端端:FEATURES.md、UI_FLOW.md、API_CALL_MAP.md、TECH_STACK.md\n\n`;
|
|
1169
|
+
prompt += `4. **知识沉淀(按工程+端区分)**: 从各端源码识别可复用模式,写入 .speccore/PATTERNS/:\n`;
|
|
874
1170
|
prompt += ` - 命名规则: **{CONSTITUTION中的工程名}-{端}-{分类}-{模式名}.md**\n`;
|
|
875
|
-
prompt += ` - 工程名从 CONSTITUTION.md 的「工程」列读取\n`;
|
|
876
|
-
prompt += ` - 端从 CONSTITUTION.md 的「## 端列表」章节读取(如: admin/h5/miniapp/backend)\n`;
|
|
877
|
-
prompt += ` - 示例: meeting-system-admin-auth-jwt.md | booking-service-app-data-repo.md | meeting-system-h5-comp-table.md\n`;
|
|
878
1171
|
prompt += ` - 后台分类: auth(鉴权)、api(接口设计)、data(数据访问)、error(异常)、log(日志)、util(工具)、arch(架构)\n`;
|
|
879
1172
|
prompt += ` - 前端分类: comp(组件)、state(状态管理)、router(路由)、request(请求)、form(表单)、style(样式)、build(构建)\n`;
|
|
880
|
-
prompt += ` - 每个文件含: 工程名/端/分类 + 适用场景 + 核心代码片段 + 注意事项 + 反例\n`;
|
|
881
|
-
prompt += `
|
|
1173
|
+
prompt += ` - 每个文件含: 工程名/端/分类 + 适用场景 + 核心代码片段 + 注意事项 + 反例\n\n`;
|
|
1174
|
+
prompt += `5. 以上文档输出到 .speccore/GLOBAL/ 和 .speccore/PATTERNS/,使用 Write 工具写入\n`;
|
|
882
1175
|
}
|
|
883
1176
|
else {
|
|
884
1177
|
prompt += `3. 读取 .speccore/GLOBAL/ 下各项目需求文档,生成跨项目索引和需求目录\n`;
|
|
885
1178
|
}
|
|
886
|
-
prompt += `\n##
|
|
1179
|
+
prompt += `\n## 输出文档\n`;
|
|
887
1180
|
if (ctx.withCode) {
|
|
888
|
-
prompt +=
|
|
889
|
-
prompt += `>
|
|
890
|
-
prompt += `| 文档 | 存放位置 |
|
|
1181
|
+
prompt += `\n### Layer 中间产物(分析过程中生成)\n`;
|
|
1182
|
+
prompt += `> 存放: .speccore/GLOBAL/platforms/\n\n`;
|
|
1183
|
+
prompt += `| 文档 | 层级 | 存放位置 | 内容 |\n`;
|
|
1184
|
+
prompt += `| :--- | :--- | :--- | :--- |\n`;
|
|
1185
|
+
prompt += `| _INDEX.md | Layer 1 | platforms/{端}/ | 各端目录索引(页面/接口/实体/依赖列表) |\n`;
|
|
1186
|
+
prompt += `| _ASSOCIATION.md | Layer 2 | platforms/_shared/ | 前后端关联矩阵 + 接口缺口/未使用接口 |\n`;
|
|
1187
|
+
prompt += `| _MODULES.md | Layer 2 | platforms/_shared/ | 功能模块候选清单(从源码聚类) |\n`;
|
|
1188
|
+
prompt += `\n### 全局最终产物(Layer 4 汇总生成)\n`;
|
|
1189
|
+
prompt += `> 存放: .speccore/GLOBAL/\n\n`;
|
|
1190
|
+
prompt += `| 文档 | 视角 | 内容 |\n`;
|
|
891
1191
|
prompt += `| :--- | :--- | :--- |\n`;
|
|
892
|
-
prompt += `|
|
|
893
|
-
prompt += `|
|
|
894
|
-
prompt += `|
|
|
895
|
-
prompt += `|
|
|
896
|
-
prompt += `|
|
|
897
|
-
prompt += `|
|
|
898
|
-
prompt +=
|
|
899
|
-
prompt +=
|
|
900
|
-
prompt += `|
|
|
901
|
-
prompt += `|
|
|
902
|
-
prompt += `|
|
|
903
|
-
prompt += `|
|
|
904
|
-
prompt += `|
|
|
905
|
-
prompt += `|
|
|
906
|
-
prompt +=
|
|
907
|
-
prompt +=
|
|
1192
|
+
prompt += `| REQUIREMENT.md | 产品视角 | 现有功能清单(按业务场景组织,从功能模块汇总) |\n`;
|
|
1193
|
+
prompt += `| FUNCTION_MAP.md | 架构视角 | 功能单元 × 端映射表 |\n`;
|
|
1194
|
+
prompt += `| INTERACTION_MAP.md | 架构视角 | 跨端交互时序图(从 Layer 3 汇总) |\n`;
|
|
1195
|
+
prompt += `| API_CONTRACT.yaml | 技术视角 | 全局接口契约(汇总所有后端 API) |\n`;
|
|
1196
|
+
prompt += `| ARCHITECTURE.md | 技术视角 | 全局架构文档(服务拓扑、数据流、部署关系) |\n`;
|
|
1197
|
+
prompt += `| CONSISTENCY_CHECK.md | 质量视角 | 一致性校验报告(前后端字段/状态/接口缺口) |\n`;
|
|
1198
|
+
prompt += `\n### 各端最终产物(Layer 3/4 汇总生成)\n`;
|
|
1199
|
+
prompt += `> 存放: .speccore/GLOBAL/platforms/{端名}/\n\n`;
|
|
1200
|
+
prompt += `| 文档 | 适用端 | 内容 |\n`;
|
|
1201
|
+
prompt += `| :--- | :--- | :--- |\n`;
|
|
1202
|
+
prompt += `| FEATURES.md | **前端端** | 产品视角功能清单(页面+交互+API调用链) |\n`;
|
|
1203
|
+
prompt += `| UI_FLOW.md | **前端端** | 页面流转图、用户操作流程 |\n`;
|
|
1204
|
+
prompt += `| API_CALL_MAP.md | **前端端** | 页面 → 接口 → 后端服务 映射表 |\n`;
|
|
1205
|
+
prompt += `| API_INVENTORY.md | **后端端** | 完整接口清单(路径/方法/参数/响应/鉴权) |\n`;
|
|
1206
|
+
prompt += `| DATA_MODEL.md | **后端端** | 表结构+字段+关系+索引 |\n`;
|
|
1207
|
+
prompt += `| BUSINESS_RULES.md | **后端端** | 校验规则+业务约束+状态机 |\n`;
|
|
1208
|
+
prompt += `| TECH_STACK.md | 通用 | 语言、框架、构建工具、UI库 |\n`;
|
|
1209
|
+
prompt += `| DEPENDENCY_GRAPH.md | 通用 | 模块依赖拓扑 |\n`;
|
|
1210
|
+
prompt += `| CODE_INDEX.md | 通用 | 目录结构+关键文件+模块职责 |\n`;
|
|
1211
|
+
prompt += `| PATTERNS/*.md | 通用 | 可复用设计模式 |\n`;
|
|
908
1212
|
}
|
|
909
1213
|
else {
|
|
910
1214
|
prompt += `- REQUIREMENT.md — 合并各迭代需求,生成跨项目需求索引\n`;
|
|
@@ -974,13 +1278,31 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
974
1278
|
> ${iter}
|
|
975
1279
|
|
|
976
1280
|
## 写作要求
|
|
977
|
-
根据 REQUIREMENT.md
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
-
|
|
982
|
-
-
|
|
983
|
-
-
|
|
1281
|
+
根据 REQUIREMENT.md 中的功能模块,**逐端**撰写技术方案。
|
|
1282
|
+
**注意:后端端和前端端的 TECH.md 内容要求不同,请按端类型选择对应模板:**
|
|
1283
|
+
|
|
1284
|
+
### 后端端(*service)— 纯技术视角
|
|
1285
|
+
- 整体架构和分层设计
|
|
1286
|
+
- 模块划分、职责说明、核心接口设计(路径/方法/参数/响应/状态码/错误码)
|
|
1287
|
+
- 数据库表结构(字段/类型/索引/约束/DDL)
|
|
1288
|
+
- 业务规则实现(含边界条件和异常流)
|
|
1289
|
+
- 缓存策略/并发与事务/消息队列(如涉及)
|
|
1290
|
+
- 安全:SQL注入防护/接口鉴权/数据脱敏
|
|
1291
|
+
- 性能:QPS预估/慢查询优化/连接池配置
|
|
1292
|
+
- **不要写**用户旅程、业务场景、页面清单(这些在 global/REQUIREMENT.md 中)
|
|
1293
|
+
|
|
1294
|
+
### 前端端(h5 / admin-web / miniapp)— 产品+技术双视角
|
|
1295
|
+
- **产品视角(主要)**:
|
|
1296
|
+
- 用户旅程:该端用户如何完成核心任务(步骤流程图)
|
|
1297
|
+
- 页面清单:所有页面名称、路径、核心功能、入口位置
|
|
1298
|
+
- 交互设计:关键操作流程、状态变化、异常提示方式
|
|
1299
|
+
- 字段展示:每个页面展示哪些字段、字段来源(后端哪个接口)
|
|
1300
|
+
- 权限控制:哪些页面/按钮需要权限、权限粒度
|
|
1301
|
+
- **技术视角(辅助)**:
|
|
1302
|
+
- 页面路由结构、组件拆分方案
|
|
1303
|
+
- API 调用清单:前端调用了哪些后端接口(路径+方法+用途)
|
|
1304
|
+
- 状态管理设计(全局状态、与后端数据同步策略)
|
|
1305
|
+
- 适配/性能/安全等前端专项(按端类型选择)
|
|
984
1306
|
|
|
985
1307
|
⚠️ 不要只写后端不写前端 — REQUIREMENT.md 中标注了涉及端的模块,每个端都要有对应的技术设计
|
|
986
1308
|
`],
|
|
@@ -1077,11 +1399,80 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1077
1399
|
- 状态枚举(前后端共享的状态值定义,如 0=空闲 1=使用中 2=维护中)
|
|
1078
1400
|
|
|
1079
1401
|
⚠️ 这是前后端契约的关键桥梁 — 字段映射必须与后端 API 响应字段一一对应
|
|
1402
|
+
`],
|
|
1403
|
+
['FUNCTION_MAP.md',
|
|
1404
|
+
`# 跨端功能映射表
|
|
1405
|
+
|
|
1406
|
+
> ${iter} | ${now}
|
|
1407
|
+
|
|
1408
|
+
## 写作要求
|
|
1409
|
+
基于 REQUIREMENT.md 中的功能模块清单,生成本迭代所有功能单元的跨端映射表:
|
|
1410
|
+
|
|
1411
|
+
### 映射表格式
|
|
1412
|
+
| # | 功能单元 | 涉及端 | 共享能力 | 依赖任务 | 说明 |
|
|
1413
|
+
| :--- | :--- | :--- | :--- | :--- | :--- |
|
|
1414
|
+
|
|
1415
|
+
### 列定义
|
|
1416
|
+
- 「功能单元」:业务功能的最小可交付单元,与 REQUIREMENT.md 功能模块清单一一对应
|
|
1417
|
+
- 「涉及端」:该功能单元需要新开发工作的所有端(标准端名,逗号分隔)。只标注需要写新接口/新页面/新逻辑的端
|
|
1418
|
+
- 「共享能力」:如果该功能单元依赖或被其他功能单元共享的通用能力(如"审批引擎"、"消息通知")
|
|
1419
|
+
- 「依赖任务」:当前迭代内,该功能单元依赖的其他功能单元编号(如 M-03)
|
|
1420
|
+
- 「说明」:跨端交互说明(如"admin-web 调用 booking-service 的 /api/rooms 接口")
|
|
1421
|
+
|
|
1422
|
+
### 重要规则
|
|
1423
|
+
- 每个功能单元一行,不允许合并多个功能单元到一行
|
|
1424
|
+
- 「涉及端」必须与 CONSTITUTION.md「端列表」中的标准端名完全匹配
|
|
1425
|
+
- 如果某功能单元只涉及一个端,也要列出(如纯前端优化)
|
|
1426
|
+
- 共享能力标注为"无"表示该功能单元没有跨任务共享的通用组件
|
|
1427
|
+
`],
|
|
1428
|
+
['INTERACTION_MAP.md',
|
|
1429
|
+
`# 跨端交互图谱
|
|
1430
|
+
|
|
1431
|
+
> ${iter} | ${now}
|
|
1432
|
+
|
|
1433
|
+
## 写作要求
|
|
1434
|
+
基于 REQUIREMENT.md 中的业务场景和 FUNCTION_MAP.md 中的跨端映射,为每个功能单元生成交互时序图:
|
|
1435
|
+
|
|
1436
|
+
### 格式要求
|
|
1437
|
+
- 使用 Mermaid sequenceDiagram 语法
|
|
1438
|
+
- 每个功能单元一个独立的序列图
|
|
1439
|
+
- actor 为用户角色(如"用户"、"Admin")
|
|
1440
|
+
- participant 为涉及的端(使用标准端名)
|
|
1441
|
+
- 箭头标注调用的接口路径(如 \`POST /api/bookings\`)
|
|
1442
|
+
- 标注 \`[contract]\` 表示该接口在 API_CONTRACT.yaml 中有定义
|
|
1443
|
+
- 用 Note 标注业务规则(如边界条件、状态流转)
|
|
1444
|
+
- 用 alt/else/end 标注分支逻辑
|
|
1445
|
+
|
|
1446
|
+
### 内容要求
|
|
1447
|
+
- 展示完整的业务交互时序:用户操作 → 前端处理 → 后端调用 → 数据返回
|
|
1448
|
+
- 明确标出后端服务之间的内部调用(产品文档中写"系统处理"的地方)
|
|
1449
|
+
- 标注异步调用(虚线箭头)和同步调用(实线箭头)
|
|
1450
|
+
- 在序列图后附上「接口契约索引」表格:步骤号、接口、消费者、提供者
|
|
1451
|
+
- 在序列图后附上「状态流转」表格(如涉及状态变更)
|
|
1452
|
+
|
|
1453
|
+
### 示例结构
|
|
1454
|
+
\`\`\`mermaid
|
|
1455
|
+
sequenceDiagram
|
|
1456
|
+
actor U as 用户
|
|
1457
|
+
participant H5 as h5-mobile
|
|
1458
|
+
participant BS as booking-service
|
|
1459
|
+
participant RS as room-service
|
|
1460
|
+
U->>H5: 选择会议室/时间
|
|
1461
|
+
H5->>BS: POST /api/bookings [contract]
|
|
1462
|
+
BS->>RS: GET /api/rooms/{id}/availability [contract]
|
|
1463
|
+
RS-->>BS: 可用性状态
|
|
1464
|
+
alt 可用
|
|
1465
|
+
BS->>BS: 创建预订记录
|
|
1466
|
+
BS-->>H5: 201 Created
|
|
1467
|
+
else 不可用
|
|
1468
|
+
BS-->>H5: 409 Conflict
|
|
1469
|
+
end
|
|
1470
|
+
\`\`\`
|
|
1080
1471
|
`],
|
|
1081
1472
|
];
|
|
1082
1473
|
// 任务类型 × 文档矩阵: 每种类型生成哪些文档
|
|
1083
1474
|
const DOC_MATRIX = {
|
|
1084
|
-
feature: ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md', 'TEST.md', 'REVIEW.md', 'RISK.md', 'DEPS.md', 'MONITOR.md', 'UI_SPEC.md'],
|
|
1475
|
+
feature: ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md', 'TEST.md', 'REVIEW.md', 'RISK.md', 'DEPS.md', 'MONITOR.md', 'UI_SPEC.md', 'FUNCTION_MAP.md', 'INTERACTION_MAP.md'],
|
|
1085
1476
|
refactor: ['ANALYSIS.md', 'TECH.md', 'TEST.md', 'REVIEW.md', 'RISK.md'],
|
|
1086
1477
|
bugfix: ['ANALYSIS.md', 'TECH.md', 'TEST.md'],
|
|
1087
1478
|
research: ['ANALYSIS.md'],
|
|
@@ -1096,7 +1487,7 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1096
1487
|
// ── v6.61.0+: 恢复 Phase 1/Phase 2 分步逻辑,但 CLI 自动触发 Phase 2 ──
|
|
1097
1488
|
// Phase 1: 生成全局文档(global/REQUIREMENT.md、ANALYSIS.md、DEPS.md 等)
|
|
1098
1489
|
// Phase 2: 生成各端专属文档({端}/TECH.md、TEST.md、UI_SPEC.md 等)
|
|
1099
|
-
const GLOBAL_DOCS = ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md', 'RISK.md', 'DEPS.md', 'REVIEW.md', 'MONITOR.md'];
|
|
1490
|
+
const GLOBAL_DOCS = ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md', 'RISK.md', 'DEPS.md', 'REVIEW.md', 'MONITOR.md', 'FUNCTION_MAP.md', 'INTERACTION_MAP.md'];
|
|
1100
1491
|
const PLATFORM_DOCS = ['TECH.md', 'TEST.md', 'UI_SPEC.md'];
|
|
1101
1492
|
let taskDocs = docs.filter(([n]) => includeDocs.includes(n));
|
|
1102
1493
|
if (ctx.phase === '1') {
|
|
@@ -1168,6 +1559,23 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1168
1559
|
techDoc[1] = `# 技术架构(跨端全局)\n\n> ${iter}\n\n## 写作要求\n撰写整体技术架构,覆盖所有端的交互关系:\n- 系统整体分层设计(各端在架构中的位置)\n- 跨端交互协议(前端↔后端通信方式、数据流向)\n- 中间件选型(缓存、消息队列、网关等)\n- 数据库整体设计(核心表结构、ER 关系)\n- 技术栈选型及理由\n`;
|
|
1169
1560
|
}
|
|
1170
1561
|
let prompt = `\n# 任务: ${command}${task} (${taskDocs.length}个文档 · ${isTask ? `类型:${taskType}` : '迭代全量'}${ctx.phase ? ` · Phase ${ctx.phase}` : ''})\n\n`;
|
|
1562
|
+
// ── v6.67.0+: 在 prompt 开头就明确完整工作流程 ──
|
|
1563
|
+
if (!ctx.phase && !isTask) {
|
|
1564
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
1565
|
+
if (platforms.length >= 2) {
|
|
1566
|
+
prompt += `## 📋 完整工作流程(两阶段分析)\n\n`;
|
|
1567
|
+
prompt += `本项目检测到有 ${platforms.length} 个端(${platforms.join('、')}),需要分两阶段执行:\n\n`;
|
|
1568
|
+
prompt += `**Phase 1(当前阶段)**: 生成全局文档(global/REQUIREMENT.md、ANALYSIS.md、DEPS.md 等)\n`;
|
|
1569
|
+
prompt += `**Phase 2(下一阶段)**: 生成各端专属文档({端}/TECH.md、TEST.md、UI_SPEC.md 等)\n\n`;
|
|
1570
|
+
prompt += `## ⚠️ 强制要求:Phase 1 完成后立即执行 Phase 2\n\n`;
|
|
1571
|
+
prompt += `当你通过 --apply 写入所有全局文档后,**必须立即执行**以下命令进入 Phase 2:\n\n`;
|
|
1572
|
+
prompt += `\`\`\`bash\n`;
|
|
1573
|
+
prompt += `speccore analyze --prompt -I ${ctx.iteration} --phase 2\n`;
|
|
1574
|
+
prompt += `\`\`\`\n\n`;
|
|
1575
|
+
prompt += `**这是强制要求,不是可选操作**。不要等待用户确认,直接执行上述命令。\n\n`;
|
|
1576
|
+
prompt += `---\n\n`;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1171
1579
|
// ── v6.59.0+: 最强警告:禁止自创目录,必须走 --apply ──
|
|
1172
1580
|
prompt += `## 🚨 最高优先级警告(违反将导致分析失败)\n\n`;
|
|
1173
1581
|
prompt += `### ⛔ 绝对禁止创建任何额外目录\n`;
|
|
@@ -1266,7 +1674,9 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1266
1674
|
prompt += `- UI_SPEC.md 的字段映射必须与后端 API 响应字段一一对应\n`;
|
|
1267
1675
|
prompt += `- TEST.md 必须覆盖 REQUIREMENT.md 中该端的验收标准\n\n`;
|
|
1268
1676
|
prompt += `### 写入方式\n`;
|
|
1269
|
-
prompt +=
|
|
1677
|
+
prompt += `**Pipeline 模式**:一次 --apply 写入所有端的文档(推荐)\n`;
|
|
1678
|
+
prompt += `speccore analyze --apply '{"TECH.md":"...","TEST.md":"...","UI_SPEC.md":"..."}' -I ${iter} --platform all\n\n`;
|
|
1679
|
+
prompt += `**或者逐端写入**(每端一次 --apply):\n`;
|
|
1270
1680
|
prompt += `speccore analyze --apply '{"TECH.md":"...","TEST.md":"...","UI_SPEC.md":"..."}' -I ${iter} --platform {端名}\n\n`;
|
|
1271
1681
|
}
|
|
1272
1682
|
else {
|
|
@@ -1281,39 +1691,93 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1281
1691
|
const tpl = templateMap[doc[0]] || '';
|
|
1282
1692
|
prompt += ` - ${doc[0]} → 参考 ${tpl}\n`;
|
|
1283
1693
|
}
|
|
1284
|
-
prompt += `2.
|
|
1694
|
+
prompt += `2. 读取全局层产物(建立全局视角,重要)\n`;
|
|
1695
|
+
prompt += ` 在读取迭代需求之前,先 Read 全局层已有产物,了解系统当前状态:\n`;
|
|
1696
|
+
prompt += ` a. Read .speccore/GLOBAL/REQUIREMENT.md → 系统已有功能清单\n`;
|
|
1697
|
+
prompt += ` b. Read .speccore/GLOBAL/FUNCTION_MAP.md → 已有功能单元和涉及端\n`;
|
|
1698
|
+
prompt += ` c. Read .speccore/GLOBAL/API_CONTRACT.yaml → 已有接口契约\n`;
|
|
1699
|
+
prompt += ` d. Read .speccore/GLOBAL/ARCHITECTURE.md → 全局架构(如有)\n`;
|
|
1700
|
+
prompt += ` e. Read .speccore/GLOBAL/platforms/{相关端}/_INDEX.md → 各端已有页面和接口索引\n`;
|
|
1701
|
+
prompt += ` f. Read .speccore/GLOBAL/platforms/_shared/_ASSOCIATION.md → 前后端关联矩阵(如有)\n`;
|
|
1702
|
+
prompt += ` g. Read .speccore/GLOBAL/platforms/_shared/_MODULES.md → 功能模块候选(如有)\n`;
|
|
1703
|
+
prompt += ` ⚠️ 如果全局层产物不存在,跳过该项,继续后续分析\n\n`;
|
|
1704
|
+
prompt += `3. 读取迭代需求文档(按优先级顺序):\n`;
|
|
1285
1705
|
prompt += ` a. 先读 010-requirements/INDEX.md — 了解需求全貌和文件清单\n`;
|
|
1286
1706
|
prompt += ` b. 再读 010-requirements/converted/*.md — doc2spec 转换后的核心规格(主要依据)\n`;
|
|
1287
1707
|
prompt += ` c. 再读 010-requirements/features/*/README.md — 功能级补充需求\n`;
|
|
1288
1708
|
prompt += ` d. 读取 010-requirements/prototypes/ — 原型文件(HTML/图片/链接均读取)\n`;
|
|
1289
1709
|
prompt += ` ⚠️ 需求文档中链接到原型的(如 \`\` 或 \`详见 prototypes/xxx.html\`),必须主动 Read 该原型文件\n`;
|
|
1290
1710
|
prompt += ` e. 如用户指定了特定文档,优先读取指定文件;如要求全部,再读 sources/ 原始文档\n`;
|
|
1291
|
-
prompt += `
|
|
1292
|
-
prompt += `
|
|
1293
|
-
prompt += `
|
|
1711
|
+
prompt += `4. 读懂需求文档后,按专业模板标准自由撰写每个文档(不是填空表)\n`;
|
|
1712
|
+
prompt += `5. 每个文档都要具体内容(禁止"待填充")\n`;
|
|
1713
|
+
prompt += `6. **端发现(重要)**:先确定项目有哪些端,再按端组织文档\n`;
|
|
1294
1714
|
prompt += ` - 第 1 步:Read .speccore/CONSTITUTION.md\n`;
|
|
1295
1715
|
prompt += ` - 第 2 步:从「## 端列表」章节提取端名(这是全局权威来源)\n`;
|
|
1296
1716
|
prompt += ` - 第 3 步:如果没有「端列表」章节,从「对应端」列提取\n`;
|
|
1297
1717
|
prompt += ` - 第 4 步:如果以上都无法确定,根据需求文档内容判断\n`;
|
|
1298
1718
|
prompt += ` - 第 5 步:将发现的端列表写入 020-specs/PLATFORMS.md\n`;
|
|
1719
|
+
// v6.70.0+: REQUIREMENT.md 以产品视角撰写(不按端分章节)
|
|
1720
|
+
prompt += `6b. **REQUIREMENT.md 写作风格(重要)**:全局需求文档必须以产品/用户视角撰写\n`;
|
|
1721
|
+
prompt += ` - **按业务场景/用户旅程组织章节**,不按端分章节(如"H5端需求"、"后端需求")\n`;
|
|
1722
|
+
prompt += ` - 每个场景描述:用户操作 → 系统响应 → 业务规则 → 边界条件\n`;
|
|
1723
|
+
prompt += ` - 系统响应中自然包含前后端交互,但不刻意标注技术实现细节\n`;
|
|
1724
|
+
prompt += ` - 示例正确写法:「用户选择时间段后点击预订,系统检查会议室可用性,如可用则锁定会议室并创建待支付订单」\n`;
|
|
1725
|
+
prompt += ` - 示例错误写法:「后端 booking-service 需要新增 /api/bookings 接口,接收 roomId 参数」\n`;
|
|
1726
|
+
prompt += ` - 技术实现细节留在 TECH.md 和各端专属文档中,不在 REQUIREMENT.md 展开\n`;
|
|
1727
|
+
prompt += ` - 端的信息只在「功能模块清单」表格中标注,正文不区分端\n`;
|
|
1299
1728
|
// v6.49.14+: 功能模块清单必须含涉及端列 + 来源链接
|
|
1300
|
-
|
|
1301
|
-
prompt += `
|
|
1729
|
+
// v6.71.3+: 增加「与全局层对比」列
|
|
1730
|
+
prompt += `7. **功能模块清单(重要)**:写入 global/REQUIREMENT.md 时,功能模块清单表格必须包含以下列\n`;
|
|
1731
|
+
prompt += ` - 表格格式:| # | 功能模块 | 涉及端 | 全局对比 | 来源 | 说明 |\n`;
|
|
1302
1732
|
prompt += ` - 「涉及端」:每个模块标注需要**新开发工作**的端(标准端名,逗号分隔)\n`;
|
|
1303
1733
|
prompt += ` - 「涉及」= 该端需要写新接口/新页面/新逻辑\n`;
|
|
1304
1734
|
prompt += ` - 「不涉及」= 只是提到、调用已有接口、纯展示 → 不标注\n`;
|
|
1305
1735
|
prompt += ` - 端名必须与 CONSTITUTION.md「端列表」中的标准端名完全匹配\n`;
|
|
1736
|
+
prompt += ` - 「全局对比」:该功能模块与全局层已有功能的关系(必须标注)\n`;
|
|
1737
|
+
prompt += ` - 「新增」:全局层不存在,本迭代全新开发\n`;
|
|
1738
|
+
prompt += ` - 「扩展」:全局层已有基础功能,本迭代增加新字段/新接口/新页面\n`;
|
|
1739
|
+
prompt += ` - 「重构」:全局层已有,本迭代修改实现方式(不新增功能)\n`;
|
|
1740
|
+
prompt += ` - 「复用」:全局层已有,本迭代直接使用(无需开发)\n`;
|
|
1741
|
+
prompt += ` - 示例:「扩展:增加会议室设备管理」或「新增」\n`;
|
|
1306
1742
|
prompt += ` - 「来源」:该功能模块在需求文档中的具体位置,用 Markdown 链接格式\n`;
|
|
1307
1743
|
prompt += ` - 格式:[文档名](相对路径#章节锚点),如 [PRD v2.0](../010-requirements/sources/PRD-v2.0.md#3-2-会议室管理)\n`;
|
|
1308
1744
|
prompt += ` - 如果模块来自 converted 文档:[xxx需求](../010-requirements/converted/xxx.md#相关章节)\n`;
|
|
1309
1745
|
prompt += ` - 如果来自 features 目录:[xxx功能](../010-requirements/features/xxx/README.md)\n`;
|
|
1310
1746
|
prompt += ` - 目的是让阅读者能直接点击跳转到原始需求位置\n`;
|
|
1311
|
-
prompt += ` - 示例:| M-01 | 会议室档案管理 | room-service, admin-web | [PRD v2.0](../010-requirements/sources/PRD-v2.0.md#2-1) | 会议室 CRUD、设备管理 |\n`;
|
|
1747
|
+
prompt += ` - 示例:| M-01 | 会议室档案管理 | room-service, admin-web | 扩展:增加设备管理 | [PRD v2.0](../010-requirements/sources/PRD-v2.0.md#2-1) | 会议室 CRUD、设备管理 |\n`;
|
|
1312
1748
|
prompt += ` - split 命令将读取「涉及端」列来决定创建哪些端的子任务目录\n`;
|
|
1749
|
+
// v6.70.0+: 跨端功能映射表(FUNCTION_MAP.md)
|
|
1750
|
+
// v6.71.3+: 增加与全局层关联分析
|
|
1751
|
+
prompt += `7a. **迭代需求与全局层关联分析(重要)**:在生成功能模块清单时,必须对比全局层产物\n`;
|
|
1752
|
+
prompt += ` - 对比迭代需求中的功能模块 vs .speccore/GLOBAL/FUNCTION_MAP.md 中的功能单元\n`;
|
|
1753
|
+
prompt += ` - 标注每个功能模块的「全局对比」类型(新增/扩展/重构/复用)\n`;
|
|
1754
|
+
prompt += ` - 识别冲突:如迭代需求修改了全局层已有接口的字段/路径 → 在 RISK.md 中标注\n`;
|
|
1755
|
+
prompt += ` - 识别依赖:如迭代的新功能依赖全局层的某个功能 → 在 FUNCTION_MAP.md「依赖任务」中标注\n\n`;
|
|
1756
|
+
prompt += `7b. **跨端功能映射表(重要)**:在 REQUIREMENT.md 完成后,必须生成 global/FUNCTION_MAP.md\n`;
|
|
1757
|
+
prompt += ` - 这是 split 阶段的核心输入,决定任务如何按功能单元拆分\n`;
|
|
1758
|
+
prompt += ` - 表格格式:| # | 功能单元 | 涉及端 | 全局对比 | 共享能力 | 依赖任务 | 说明 |\n`;
|
|
1759
|
+
prompt += ` - 「功能单元」必须与 REQUIREMENT.md 功能模块清单一一对应,不允许合并\n`;
|
|
1760
|
+
prompt += ` - 「涉及端」标注所有需要新开发工作的端(标准端名,逗号分隔)\n`;
|
|
1761
|
+
prompt += ` - 「全局对比」标注与全局层的关系(新增/扩展/重构/复用)\n`;
|
|
1762
|
+
prompt += ` - 「共享能力」标注跨任务共享的通用组件(如"审批引擎"、"消息通知"),无则填"无"\n`;
|
|
1763
|
+
prompt += ` - 「依赖任务」标注当前迭代内该功能单元依赖的其他功能单元编号\n`;
|
|
1764
|
+
prompt += ` - 「说明」描述跨端交互关系(如"admin-web 调用 booking-service 的 /api/rooms 接口")\n`;
|
|
1765
|
+
prompt += ` - **示例**:| M-01 | 会议室档案管理 | room-service, admin-web | 扩展 | 无 | 无 | admin-web 调用 room-service CRUD 接口 |\n`;
|
|
1766
|
+
prompt += ` - **错误示例**(禁止):将"审批流程"和"定时任务"合并为一行\n`;
|
|
1767
|
+
prompt += ` - FUNCTION_MAP.md 生成后,split 将**严格按此表**创建任务目录,不再由 AI 推断\n`;
|
|
1768
|
+
// v6.70.0+: 跨端交互图谱(INTERACTION_MAP.md)
|
|
1769
|
+
prompt += `7c. **跨端交互图谱(重要)**:在 FUNCTION_MAP.md 完成后,必须生成 global/INTERACTION_MAP.md\n`;
|
|
1770
|
+
prompt += ` - 按功能单元组织,每个功能单元一个 Mermaid sequenceDiagram\n`;
|
|
1771
|
+
prompt += ` - 展示完整的业务交互时序:用户操作 → 前端处理 → 后端调用 → 数据返回\n`;
|
|
1772
|
+
prompt += ` - 明确标出后端服务之间的内部调用(产品文档写"系统处理"的地方)\n`;
|
|
1773
|
+
prompt += ` - 箭头标注接口路径,标注 [contract] 表示接口在 API_CONTRACT.yaml 中有定义\n`;
|
|
1774
|
+
prompt += ` - 序列图后附「接口契约索引」表格:步骤号、接口、消费者端、提供者端\n`;
|
|
1775
|
+
prompt += ` - 如涉及状态变更,附「状态流转」表格\n`;
|
|
1776
|
+
prompt += ` - INTERACTION_MAP.md 是前后端开发者的共同参考,补全产品文档中隐含的技术交互\n`;
|
|
1313
1777
|
// 注入工程类型信息(v6.49.0+)
|
|
1314
1778
|
const platformTypes = await (0, spec_paths_1.parsePlatformTypes)();
|
|
1315
1779
|
if (platformTypes.size > 0) {
|
|
1316
|
-
prompt += `
|
|
1780
|
+
prompt += `8. **工程类型识别**:CONSTITUTION.md 已配置各端的工程类型,请据此生成针对性内容\n`;
|
|
1317
1781
|
prompt += ` | 工程标识 | 工程类型 |\n`;
|
|
1318
1782
|
prompt += ` | :--- | :--- |\n`;
|
|
1319
1783
|
for (const [name, type] of platformTypes) {
|
|
@@ -1332,7 +1796,7 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1332
1796
|
prompt += ` - Web管理后台 → 复杂表单、数据表格、权限UI、状态管理\n`;
|
|
1333
1797
|
prompt += ` - 桌面应用 → 本地存储、系统API、自动更新、离线支持\n`;
|
|
1334
1798
|
}
|
|
1335
|
-
const dirStepNum = platformTypes.size > 0 ?
|
|
1799
|
+
const dirStepNum = platformTypes.size > 0 ? 9 : 8;
|
|
1336
1800
|
prompt += `${dirStepNum}. **目录结构(严格遵循,禁止自创目录)**:\n`;
|
|
1337
1801
|
prompt += ` - **全局文档**(跨端通用)→ 通过 --apply 写入,CLI 自动路由到 \`020-specs/global/{文件名}\`\n`;
|
|
1338
1802
|
prompt += ` - REQUIREMENT.md(需求文档,含功能模块清单+涉及端列)\n`;
|
|
@@ -1353,39 +1817,40 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1353
1817
|
prompt += `\n## ⚠️ 端专业性约束\n`;
|
|
1354
1818
|
prompt += `CONSTITUTION.md 中配置了多个端,每个端的文档必须有该端专属内容。\n`;
|
|
1355
1819
|
prompt += `**先识别端类型,再应用对应的专业维度**:\n\n`;
|
|
1356
|
-
|
|
1820
|
+
// v6.71.0+: 前后端文档差异化
|
|
1821
|
+
prompt += `### 后端服务(*service)必含内容 — 技术视角\n`;
|
|
1357
1822
|
prompt += `- API 接口定义(路径/方法/参数/响应字段/状态码/错误码)\n`;
|
|
1358
1823
|
prompt += `- 数据库表结构(字段/类型/索引/约束)\n`;
|
|
1359
1824
|
prompt += `- 业务规则(含边界条件和异常流)\n`;
|
|
1360
1825
|
prompt += `- 缓存策略/并发与事务/消息队列(如涉及)\n`;
|
|
1361
1826
|
prompt += `- 安全:SQL 注入防护/接口鉴权/数据脱敏\n`;
|
|
1362
|
-
prompt += `- 性能:QPS 预估/慢查询优化/连接池配置\n
|
|
1363
|
-
prompt +=
|
|
1364
|
-
prompt +=
|
|
1365
|
-
prompt += `-
|
|
1366
|
-
prompt +=
|
|
1367
|
-
prompt +=
|
|
1368
|
-
prompt +=
|
|
1369
|
-
prompt +=
|
|
1370
|
-
prompt +=
|
|
1371
|
-
prompt += `-
|
|
1372
|
-
prompt +=
|
|
1373
|
-
prompt +=
|
|
1374
|
-
prompt +=
|
|
1375
|
-
prompt +=
|
|
1376
|
-
prompt += `- 页面路由表 + 组件清单 + 字段→UI 映射\n`;
|
|
1377
|
-
prompt += `- 包体积约束:主包 2MB 限制/分包策略\n`;
|
|
1378
|
-
prompt += `- 平台 API 约束:微信/支付宝差异/权限申请\n`;
|
|
1379
|
-
prompt += `- 渲染限制:无 DOM 操作/setData 性能优化\n`;
|
|
1380
|
-
prompt += `- 导航:页面栈限制(10层)/TabBar/分享扫码\n\n`;
|
|
1827
|
+
prompt += `- 性能:QPS 预估/慢查询优化/连接池配置\n`;
|
|
1828
|
+
prompt += `- **不需要**产品视角的需求描述(用户故事、业务场景已在 global/REQUIREMENT.md 中)\n\n`;
|
|
1829
|
+
prompt += `### 前端端(h5 / admin-web / miniapp)必含内容 — 产品+技术双视角\n`;
|
|
1830
|
+
prompt += `- **产品视角(主要)**:\n`;
|
|
1831
|
+
prompt += ` - 用户旅程:该端用户如何完成核心任务(步骤流程图)\n`;
|
|
1832
|
+
prompt += ` - 页面清单:所有页面名称、路径、核心功能、入口位置\n`;
|
|
1833
|
+
prompt += ` - 交互设计:关键操作流程、状态变化、异常提示方式\n`;
|
|
1834
|
+
prompt += ` - 字段展示:每个页面展示哪些字段、字段来源(后端哪个接口)\n`;
|
|
1835
|
+
prompt += ` - 权限控制:哪些页面/按钮需要权限、权限粒度\n`;
|
|
1836
|
+
prompt += `- **技术视角(辅助)**:\n`;
|
|
1837
|
+
prompt += ` - 页面路由表 + 组件清单\n`;
|
|
1838
|
+
prompt += ` - API 调用清单:前端调用了哪些后端接口(路径+方法+用途)\n`;
|
|
1839
|
+
prompt += ` - 状态管理:全局状态设计、与后端数据同步策略\n`;
|
|
1840
|
+
prompt += ` - 适配/性能/安全等前端专项(按端类型选择)\n\n`;
|
|
1381
1841
|
}
|
|
1382
1842
|
}
|
|
1383
1843
|
// v6.60.0+: 文档与端的对应关系(不再分 Phase)
|
|
1844
|
+
// v6.71.0+: 前后端文档差异化
|
|
1384
1845
|
prompt += `### 文档与端的对应关系\n`;
|
|
1385
|
-
prompt += `- **global/REQUIREMENT.md
|
|
1846
|
+
prompt += `- **global/REQUIREMENT.md**:整体需求(产品视角,按业务场景组织)\n`;
|
|
1386
1847
|
prompt += `- **global/ANALYSIS.md**:整体需求分析\n`;
|
|
1387
1848
|
prompt += `- **global/DEPS.md**:整体依赖清单\n`;
|
|
1388
|
-
prompt += `- **
|
|
1849
|
+
prompt += `- **global/FUNCTION_MAP.md**:功能单元 × 端映射表\n`;
|
|
1850
|
+
prompt += `- **global/INTERACTION_MAP.md**:跨端交互时序图\n`;
|
|
1851
|
+
prompt += `- **后端端(*service)/{端}/TECH.md**:纯技术视角 — 接口设计+数据模型+架构+性能\n`;
|
|
1852
|
+
prompt += `- **前端端(h5/admin/miniapp)/{端}/TECH.md**:产品+技术双视角 — 用户旅程+页面清单+交互流程+API调用链\n`;
|
|
1853
|
+
prompt += `- **前端端/{端}/UI_SPEC.md**:UI 规格(字段映射、组件设计、交互细节)\n`;
|
|
1389
1854
|
prompt += ` - ⚠️ **必须包含「业务-代码映射」章节**:在 TECH.md 末尾添加一个表格,列出本端涉及的业务模块及其对应的代码实体(文件/表/API/组件等),关系类型由你根据技术栈自主决定(如 api_controller、uses_table、page、component、route、middleware、interceptor、gateway 等)\n`;
|
|
1390
1855
|
prompt += ` - 表格格式:| 业务模块 | 代码实体 | 关系类型 | 说明 |\n`;
|
|
1391
1856
|
prompt += ` - 示例:| 会议室档案 | backend/RoomController.java | api_controller | REST 控制器 |\n`;
|
|
@@ -1407,7 +1872,7 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1407
1872
|
// 定义生成顺序
|
|
1408
1873
|
const chainOrder = isTask
|
|
1409
1874
|
? ['REQ.md', 'TECH.md', 'SCHEMA.md', 'TASK.md']
|
|
1410
|
-
: ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md', 'TEST.md', 'REVIEW.md', 'RISK.md', 'DEPS.md', 'MONITOR.md', 'UI_SPEC.md'];
|
|
1875
|
+
: ['REQUIREMENT.md', 'FUNCTION_MAP.md', 'INTERACTION_MAP.md', 'API_CONTRACT.yaml', 'ANALYSIS.md', 'TECH.md', 'TEST.md', 'REVIEW.md', 'RISK.md', 'DEPS.md', 'MONITOR.md', 'UI_SPEC.md'];
|
|
1411
1876
|
const orderedDocs = taskDocs.filter(([n]) => chainOrder.includes(n));
|
|
1412
1877
|
const customDocs = taskDocs.filter(([n]) => !chainOrder.includes(n));
|
|
1413
1878
|
const ordered = [...orderedDocs.sort((a, b) => chainOrder.indexOf(a[0]) - chainOrder.indexOf(b[0])), ...customDocs];
|
|
@@ -1431,6 +1896,25 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1431
1896
|
}
|
|
1432
1897
|
// v6.60.0+: 移除两阶段分析提示,一次性生成所有文档
|
|
1433
1898
|
prompt += '\n' + (0, questions_1.buildAutoModeInstruction)('analyze', iter) + '\n';
|
|
1899
|
+
// ── v6.65.0+: Phase 1 完成后主动询问用户是否继续 Phase 2 ──
|
|
1900
|
+
// v6.70.0+: 自动模式下跳过确认,AI 直接推断执行
|
|
1901
|
+
if (!ctx.phase && !isTask && !autoMode) {
|
|
1902
|
+
prompt += `\n## ⚠️ 重要:Phase 1 完成后的下一步\n\n`;
|
|
1903
|
+
prompt += `当你通过 --apply 写入所有全局文档后,CLI 会检测到项目有多个端(≥2 个端)。\n`;
|
|
1904
|
+
prompt += `**此时你需要主动询问用户**:\n\n`;
|
|
1905
|
+
prompt += `"✅ Phase 1 已完成,生成了 global/ 的全局文档。\n`;
|
|
1906
|
+
prompt += `检测到项目有 ${'{'}端列表{'}'} 个端,需要继续执行 Phase 2 生成各端专属文档吗?\n`;
|
|
1907
|
+
prompt += `请确认:输入 '继续' 或 'yes' 以执行 Phase 2"\n\n`;
|
|
1908
|
+
prompt += `**如果用户确认继续**,你需要执行:\n`;
|
|
1909
|
+
prompt += `\`speccore analyze --prompt -I ${iter} --phase 2\`\n\n`;
|
|
1910
|
+
prompt += `**不要等待 CLI 的提示信息**,CLI 的输出你可能看不到。你需要主动询问用户。\n\n`;
|
|
1911
|
+
}
|
|
1912
|
+
if (autoMode && !ctx.phase && !isTask) {
|
|
1913
|
+
prompt += `\n## 🤖 自动模式说明\n\n`;
|
|
1914
|
+
prompt += `当前处于自动模式(--auto),不需要人工确认。\n`;
|
|
1915
|
+
prompt += `请在生成全局文档后,**直接继续**生成各端专属文档(Phase 2)。\n`;
|
|
1916
|
+
prompt += `执行命令:\`speccore analyze --prompt -I ${iter} --phase 2\`\n\n`;
|
|
1917
|
+
}
|
|
1434
1918
|
// ── v6.52.0+: 图谱 RAG 上下文注入(analyze 阶段也检索项目关联内容)──
|
|
1435
1919
|
if (!isTask && ctx.phase !== '2') {
|
|
1436
1920
|
try {
|
|
@@ -1466,6 +1950,111 @@ async function buildMultiDocPrompt(command, ctx) {
|
|
|
1466
1950
|
prompt += `### ${i + 1}/${taskDocs.length}: ${taskDocs[i][0]}\n\`\`\`markdown\n${taskDocs[i][1]}\n\`\`\`\n\n`;
|
|
1467
1951
|
}
|
|
1468
1952
|
}
|
|
1953
|
+
// ── v6.69.2+: 强制自检清单(生成所有文档后必须执行)──
|
|
1954
|
+
prompt += `\n## 🔍 强制自检清单(生成完成后必须执行)\n\n`;
|
|
1955
|
+
prompt += `在调用 --apply 写入任何文档**之前**,必须逐条完成以下自检。自检未通过时,**必须修正文档后再写入**。\n\n`;
|
|
1956
|
+
prompt += `### 1. 功能覆盖完整性\n`;
|
|
1957
|
+
prompt += `- [ ] 对比原始需求文档的功能清单,确认每个功能模块都有对应的分析内容\n`;
|
|
1958
|
+
prompt += `- [ ] 确认没有遗漏任何页面、接口、组件或业务规则\n`;
|
|
1959
|
+
prompt += `- [ ] 如果发现有遗漏,先补充完整再写入\n\n`;
|
|
1960
|
+
prompt += `### 2. 枚举值一致性(跨文档必检)\n`;
|
|
1961
|
+
prompt += `- [ ] 检查所有文档中状态/类型枚举的定义是否完全一致\n`;
|
|
1962
|
+
prompt += `- [ ] 示例:如果在 REQUIREMENT.md 中定义 status: 0=可用, 1=维修中,则 TECH.md、UI_SPEC.md 中必须完全使用相同的值和含义\n`;
|
|
1963
|
+
prompt += `- [ ] **禁止**在不同文档中对同一枚举使用不同数值或含义\n\n`;
|
|
1964
|
+
prompt += `### 3. 接口路径统一性\n`;
|
|
1965
|
+
prompt += `- [ ] 检查全局 REQUIREMENT.md 中的接口路径与各端 TECH.md 中的接口路径是否完全一致\n`;
|
|
1966
|
+
prompt += `- [ ] 示例:如果全局文档使用 /checkin,则各端文档不能写成 /check-in 或 /check_in\n`;
|
|
1967
|
+
prompt += `- [ ] 路径、方法、参数名必须跨文档一致\n\n`;
|
|
1968
|
+
prompt += `### 4. 跨文档引用一致性\n`;
|
|
1969
|
+
prompt += `- [ ] 检查 UI_SPEC.md 中的字段映射是否与后端 API 响应字段一一对应\n`;
|
|
1970
|
+
prompt += `- [ ] 检查 TEST.md 中的测试场景是否覆盖了 REQUIREMENT.md 中的所有验收标准\n`;
|
|
1971
|
+
prompt += `- [ ] 检查各端 TECH.md 的技术选型是否与 global/TECH.md 的整体架构一致\n\n`;
|
|
1972
|
+
prompt += `### 5. 目录结构合法性\n`;
|
|
1973
|
+
prompt += `- [ ] 确认 --apply 的 JSON 键名只包含合法文件名或「合法端名/文件名」格式\n`;
|
|
1974
|
+
prompt += `- [ ] **禁止**包含数字编号目录(如 1001/、1002/)、中文目录(如 错误码/)、特殊符号目录(如 .../)\n`;
|
|
1975
|
+
prompt += `- [ ] 合法格式示例:\`global/ANALYSIS.md\`、\`admin-web/TECH.md\`、\`REQUIREMENT.md\`\n\n`;
|
|
1976
|
+
prompt += `### 自检通过标准\n`;
|
|
1977
|
+
prompt += `以上 5 项全部勾选通过后,方可执行 --apply 写入。如果任何一项未通过,先修正问题,重新自检,直到全部通过。\n`;
|
|
1978
|
+
return prompt;
|
|
1979
|
+
}
|
|
1980
|
+
// ── v6.69.0+: 契约先行 Prompt 生成(增强策略一)──
|
|
1981
|
+
async function buildContractFirstPrompt(iteration) {
|
|
1982
|
+
const iterDir = await (0, context_1.getIterationDir)(iteration);
|
|
1983
|
+
const globalDir = (0, path_1.join)(iterDir, '020-specs', spec_paths_1.GLOBAL_SPECS_DIR);
|
|
1984
|
+
let prompt = `\n# 任务: 跨端 API 契约定义(契约先行阶段)\n\n`;
|
|
1985
|
+
prompt += `## 背景\n\n`;
|
|
1986
|
+
prompt += `Phase 1 全局分析已完成。现在需要在各端开始专属技术方案分析之前,**先定义跨端 API 契约**。\n\n`;
|
|
1987
|
+
prompt += `## 读取内容\n\n`;
|
|
1988
|
+
prompt += `1. Read .speccore/CONSTITUTION.md → 获取端列表和项目配置\n`;
|
|
1989
|
+
prompt += `2. Read 020-specs/global/REQUIREMENT.md → 全局需求规格\n`;
|
|
1990
|
+
prompt += `3. Read 020-specs/global/ANALYSIS.md → 全局分析报告\n`;
|
|
1991
|
+
prompt += `4. Read 020-specs/global/TECH.md → 整体技术架构\n`;
|
|
1992
|
+
prompt += `5. Read 020-specs/global/DEPS.md → 依赖关系(如存在)\n\n`;
|
|
1993
|
+
prompt += `## 输出要求\n\n`;
|
|
1994
|
+
prompt += `基于上述文档,生成一份 **API_CONTRACT.yaml**,使用标准 YAML 格式:\n\n`;
|
|
1995
|
+
prompt += `### 格式要求\n`;
|
|
1996
|
+
prompt += `- 使用 YAML 格式(不是 Markdown)\n`;
|
|
1997
|
+
prompt += `- 文件内容必须是合法 YAML,可被解析器直接读取\n`;
|
|
1998
|
+
prompt += `- 不要包含 Markdown 标题、代码块标记或解释性文字\n\n`;
|
|
1999
|
+
prompt += `### 内容结构\n`;
|
|
2000
|
+
prompt += `\`\`\`yaml\n`;
|
|
2001
|
+
prompt += `openapi: "3.0.0"\n`;
|
|
2002
|
+
prompt += `info:\n`;
|
|
2003
|
+
prompt += ` title: "跨端 API 契约"\n`;
|
|
2004
|
+
prompt += ` version: "1.0.0"\n`;
|
|
2005
|
+
prompt += ` description: "本迭代所有前后端交互接口的统一契约"\n\n`;
|
|
2006
|
+
prompt += `# 接口按模块分组\n`;
|
|
2007
|
+
prompt += `paths:\n`;
|
|
2008
|
+
prompt += ` /api/example:\n`;
|
|
2009
|
+
prompt += ` get:\n`;
|
|
2010
|
+
prompt += ` tags: [module-name]\n`;
|
|
2011
|
+
prompt += ` summary: "接口说明"\n`;
|
|
2012
|
+
prompt += ` consumers: [admin-web, h5-mobile] # 消费者端列表\n`;
|
|
2013
|
+
prompt += ` provider: booking-service # 提供者端\n`;
|
|
2014
|
+
prompt += ` parameters:\n`;
|
|
2015
|
+
prompt += ` - name: param1\n`;
|
|
2016
|
+
prompt += ` in: query\n`;
|
|
2017
|
+
prompt += ` type: string\n`;
|
|
2018
|
+
prompt += ` responses:\n`;
|
|
2019
|
+
prompt += ` "200":\n`;
|
|
2020
|
+
prompt += ` description: Success\n`;
|
|
2021
|
+
prompt += ` schema:\n`;
|
|
2022
|
+
prompt += ` type: object\n`;
|
|
2023
|
+
prompt += ` properties:\n`;
|
|
2024
|
+
prompt += ` field1: { type: string }\n`;
|
|
2025
|
+
prompt += ` "400": { description: Bad Request }\n\n`;
|
|
2026
|
+
prompt += `# 共享数据模型\n`;
|
|
2027
|
+
prompt += `components:\n`;
|
|
2028
|
+
prompt += ` schemas:\n`;
|
|
2029
|
+
prompt += ` ExampleDTO:\n`;
|
|
2030
|
+
prompt += ` type: object\n`;
|
|
2031
|
+
prompt += ` properties:\n`;
|
|
2032
|
+
prompt += ` field1: { type: string, description: "字段说明" }\n\n`;
|
|
2033
|
+
prompt += `# 枚举定义(前后端共享)\n`;
|
|
2034
|
+
prompt += `enums:\n`;
|
|
2035
|
+
prompt += ` StatusEnum:\n`;
|
|
2036
|
+
prompt += ` 0: { label: "空闲", desc: "可用状态" }\n`;
|
|
2037
|
+
prompt += ` 1: { label: "使用中", desc: "已被预约" }\n\n`;
|
|
2038
|
+
prompt += `# 事件/消息契约(如有)\n`;
|
|
2039
|
+
prompt += `events:\n`;
|
|
2040
|
+
prompt += ` - name: OrderCreated\n`;
|
|
2041
|
+
prompt += ` topic: order.events\n`;
|
|
2042
|
+
prompt += ` producer: booking-service\n`;
|
|
2043
|
+
prompt += ` consumers: [notification-service]\n`;
|
|
2044
|
+
prompt += ` payload: OrderDTO\n\n`;
|
|
2045
|
+
prompt += `# 模块依赖关系\n`;
|
|
2046
|
+
prompt += `dependencies:\n`;
|
|
2047
|
+
prompt += ` - module: 会议室档案\n`;
|
|
2048
|
+
prompt += ` dependsOn: []\n`;
|
|
2049
|
+
prompt += ` - module: 审批流程\n`;
|
|
2050
|
+
prompt += ` dependsOn: [会议室档案]\n`;
|
|
2051
|
+
prompt += `\`\`\`\n\n`;
|
|
2052
|
+
prompt += `## 写入方式\n\n`;
|
|
2053
|
+
prompt += `speccore analyze --apply '{"API_CONTRACT.yaml":"..."}' -I ${iteration}\n\n`;
|
|
2054
|
+
prompt += `⚠️ **注意**:\n`;
|
|
2055
|
+
prompt += `- 契约文件写入 020-specs/global/API_CONTRACT.yaml(全局共享)\n`;
|
|
2056
|
+
prompt += `- 这是各端技术方案分析的**前置输入**,后续各端分析必须遵循此契约\n`;
|
|
2057
|
+
prompt += `- 契约应**精确且完整**,避免后续各端分析时出现接口不一致\n\n`;
|
|
1469
2058
|
return prompt;
|
|
1470
2059
|
}
|
|
1471
2060
|
// ── v6.49.9+: 扫描平铺的端目录,返回所有子任务目录路径 ──
|