@winspan/claude-forge 2.7.0 → 3.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.
Files changed (150) hide show
  1. package/README.md +4 -4
  2. package/dist/autopilot/intent-engine.js +5 -5
  3. package/dist/autopilot/intent-engine.js.map +1 -1
  4. package/dist/autopilot/issue-tracker.d.ts +1 -1
  5. package/dist/autopilot/issue-tracker.d.ts.map +1 -1
  6. package/dist/autopilot/issue-tracker.js +2 -2
  7. package/dist/autopilot/issue-tracker.js.map +1 -1
  8. package/dist/autopilot/phase-gap-detector.d.ts +2 -1
  9. package/dist/autopilot/phase-gap-detector.d.ts.map +1 -1
  10. package/dist/autopilot/phase-gap-detector.js +1 -1
  11. package/dist/autopilot/phase-gap-detector.js.map +1 -1
  12. package/dist/autopilot/quality-gate.d.ts +1 -1
  13. package/dist/autopilot/quality-gate.d.ts.map +1 -1
  14. package/dist/autopilot/quality-gate.js +4 -4
  15. package/dist/autopilot/quality-gate.js.map +1 -1
  16. package/dist/autopilot/task-completion-detector.d.ts +1 -1
  17. package/dist/autopilot/task-completion-detector.d.ts.map +1 -1
  18. package/dist/backup/index.d.ts +2 -2
  19. package/dist/backup/index.d.ts.map +1 -1
  20. package/dist/backup/index.js +5 -7
  21. package/dist/backup/index.js.map +1 -1
  22. package/dist/claudemd/writer.d.ts +1 -0
  23. package/dist/claudemd/writer.d.ts.map +1 -1
  24. package/dist/claudemd/writer.js +12 -0
  25. package/dist/claudemd/writer.js.map +1 -1
  26. package/dist/convention/convention-manager.d.ts +2 -4
  27. package/dist/convention/convention-manager.d.ts.map +1 -1
  28. package/dist/convention/convention-manager.js +6 -25
  29. package/dist/convention/convention-manager.js.map +1 -1
  30. package/dist/core/cache-registry.d.ts +53 -0
  31. package/dist/core/cache-registry.d.ts.map +1 -0
  32. package/dist/core/cache-registry.js +93 -0
  33. package/dist/core/cache-registry.js.map +1 -0
  34. package/dist/core/pending-prompt-sink.d.ts +14 -0
  35. package/dist/core/pending-prompt-sink.d.ts.map +1 -0
  36. package/dist/core/pending-prompt-sink.js +7 -0
  37. package/dist/core/pending-prompt-sink.js.map +1 -0
  38. package/dist/core/types.d.ts +24 -0
  39. package/dist/core/types.d.ts.map +1 -0
  40. package/dist/core/types.js +24 -0
  41. package/dist/core/types.js.map +1 -0
  42. package/dist/daemon/engine-registry/init-pipeline.d.ts.map +1 -1
  43. package/dist/daemon/engine-registry/init-pipeline.js +3 -1
  44. package/dist/daemon/engine-registry/init-pipeline.js.map +1 -1
  45. package/dist/daemon/engine-registry.js +2 -2
  46. package/dist/daemon/engine-registry.js.map +1 -1
  47. package/dist/daemon/handlers/post-tool-use-handler.d.ts.map +1 -1
  48. package/dist/daemon/handlers/post-tool-use-handler.js +4 -3
  49. package/dist/daemon/handlers/post-tool-use-handler.js.map +1 -1
  50. package/dist/daemon/handlers/pre-tool-use-handler.d.ts.map +1 -1
  51. package/dist/daemon/handlers/pre-tool-use-handler.js +18 -48
  52. package/dist/daemon/handlers/pre-tool-use-handler.js.map +1 -1
  53. package/dist/daemon/handlers/stages/13-template-route.js +2 -2
  54. package/dist/daemon/handlers/stages/13-template-route.js.map +1 -1
  55. package/dist/daemon/handlers/stages/18-complex-task.d.ts.map +1 -1
  56. package/dist/daemon/handlers/stages/18-complex-task.js +11 -3
  57. package/dist/daemon/handlers/stages/18-complex-task.js.map +1 -1
  58. package/dist/daemon/handlers/stop-handler.js +2 -2
  59. package/dist/daemon/handlers/stop-handler.js.map +1 -1
  60. package/dist/daemon/handlers/user-prompt-handler.js +6 -6
  61. package/dist/daemon/handlers/user-prompt-handler.js.map +1 -1
  62. package/dist/distill/trigger.js +2 -2
  63. package/dist/distill/trigger.js.map +1 -1
  64. package/dist/pipeline/artifact-generator.d.ts +5 -1
  65. package/dist/pipeline/artifact-generator.d.ts.map +1 -1
  66. package/dist/pipeline/artifact-generator.js +5 -1
  67. package/dist/pipeline/artifact-generator.js.map +1 -1
  68. package/dist/pipeline/artifact-validator.d.ts.map +1 -1
  69. package/dist/pipeline/artifact-validator.js +9 -0
  70. package/dist/pipeline/artifact-validator.js.map +1 -1
  71. package/dist/pipeline/completion-detector.d.ts.map +1 -1
  72. package/dist/pipeline/completion-detector.js +10 -0
  73. package/dist/pipeline/completion-detector.js.map +1 -1
  74. package/dist/pipeline/completion-gate.d.ts +56 -0
  75. package/dist/pipeline/completion-gate.d.ts.map +1 -0
  76. package/dist/pipeline/completion-gate.js +165 -0
  77. package/dist/pipeline/completion-gate.js.map +1 -0
  78. package/dist/pipeline/dynamic-node-executor.d.ts +10 -10
  79. package/dist/pipeline/dynamic-node-executor.d.ts.map +1 -1
  80. package/dist/pipeline/dynamic-node-executor.js +132 -202
  81. package/dist/pipeline/dynamic-node-executor.js.map +1 -1
  82. package/dist/pipeline/dynamic-node-types.d.ts +2 -0
  83. package/dist/pipeline/dynamic-node-types.d.ts.map +1 -1
  84. package/dist/pipeline/event-sourced-engine.d.ts.map +1 -1
  85. package/dist/pipeline/event-sourced-engine.js +6 -5
  86. package/dist/pipeline/event-sourced-engine.js.map +1 -1
  87. package/dist/pipeline/execution-plan-builder.d.ts +20 -0
  88. package/dist/pipeline/execution-plan-builder.d.ts.map +1 -0
  89. package/dist/pipeline/execution-plan-builder.js +100 -0
  90. package/dist/pipeline/execution-plan-builder.js.map +1 -0
  91. package/dist/pipeline/execution-plan.d.ts +64 -0
  92. package/dist/pipeline/execution-plan.d.ts.map +1 -0
  93. package/dist/pipeline/execution-plan.js +57 -0
  94. package/dist/pipeline/execution-plan.js.map +1 -0
  95. package/dist/pipeline/i-node-executor.d.ts +2 -0
  96. package/dist/pipeline/i-node-executor.d.ts.map +1 -1
  97. package/dist/pipeline/index.d.ts +22 -20
  98. package/dist/pipeline/index.d.ts.map +1 -1
  99. package/dist/pipeline/index.js +157 -284
  100. package/dist/pipeline/index.js.map +1 -1
  101. package/dist/pipeline/optimized-aggregator.d.ts.map +1 -1
  102. package/dist/pipeline/optimized-aggregator.js +1 -1
  103. package/dist/pipeline/optimized-aggregator.js.map +1 -1
  104. package/dist/pipeline/phase-manager.js +10 -10
  105. package/dist/pipeline/phase-manager.js.map +1 -1
  106. package/dist/pipeline/report-generator.d.ts +3 -3
  107. package/dist/pipeline/report-generator.d.ts.map +1 -1
  108. package/dist/pipeline/report-generator.js +4 -4
  109. package/dist/pipeline/report-generator.js.map +1 -1
  110. package/dist/pipeline/step-gate-keeper.d.ts +1 -1
  111. package/dist/pipeline/step-gate-keeper.d.ts.map +1 -1
  112. package/dist/pipeline/step-gate-keeper.js +2 -3
  113. package/dist/pipeline/step-gate-keeper.js.map +1 -1
  114. package/dist/pipeline/step-orchestrator.d.ts +6 -1
  115. package/dist/pipeline/step-orchestrator.d.ts.map +1 -1
  116. package/dist/pipeline/step-orchestrator.js +13 -5
  117. package/dist/pipeline/step-orchestrator.js.map +1 -1
  118. package/dist/pipeline/types.d.ts +5 -4
  119. package/dist/pipeline/types.d.ts.map +1 -1
  120. package/dist/pipeline/types.js +1 -17
  121. package/dist/pipeline/types.js.map +1 -1
  122. package/dist/storage/repositories/dynamic-pipeline-repository.d.ts.map +1 -1
  123. package/dist/storage/repositories/dynamic-pipeline-repository.js +11 -23
  124. package/dist/storage/repositories/dynamic-pipeline-repository.js.map +1 -1
  125. package/dist/storage/repositories/maintenance-repository.d.ts +1 -0
  126. package/dist/storage/repositories/maintenance-repository.d.ts.map +1 -1
  127. package/dist/storage/repositories/maintenance-repository.js +76 -130
  128. package/dist/storage/repositories/maintenance-repository.js.map +1 -1
  129. package/dist/storage/schema/migration-manager.d.ts +15 -0
  130. package/dist/storage/schema/migration-manager.d.ts.map +1 -0
  131. package/dist/storage/schema/migration-manager.js +868 -0
  132. package/dist/storage/schema/migration-manager.js.map +1 -0
  133. package/dist/storage/sqlite.d.ts +0 -5
  134. package/dist/storage/sqlite.d.ts.map +1 -1
  135. package/dist/storage/sqlite.js +6 -837
  136. package/dist/storage/sqlite.js.map +1 -1
  137. package/dist/utils/forge-resume-block.d.ts +2 -1
  138. package/dist/utils/forge-resume-block.d.ts.map +1 -1
  139. package/dist/utils/forge-resume-block.js +16 -2
  140. package/dist/utils/forge-resume-block.js.map +1 -1
  141. package/dist/utils/formatter.d.ts.map +1 -1
  142. package/dist/utils/formatter.js +3 -7
  143. package/dist/utils/formatter.js.map +1 -1
  144. package/dist/utils/mutex-lock.d.ts +1 -0
  145. package/dist/utils/mutex-lock.d.ts.map +1 -1
  146. package/dist/utils/mutex-lock.js +13 -0
  147. package/dist/utils/mutex-lock.js.map +1 -1
  148. package/dist/web-static/assets/{index-nmYJCpsl.js → index-BcPVkZqZ.js} +1 -1
  149. package/dist/web-static/index.html +1 -1
  150. package/package.json +1 -1
@@ -1,16 +1,16 @@
1
1
  import { PipelineStore } from './store.js';
2
2
  import { PipelineAnalyzer } from './analyzer.js';
3
- import { PhaseManager } from './phase-manager.js';
4
3
  import { DynamicNodeExecutor } from './dynamic-node-executor.js';
5
- import { PhaseArtifactGenerator } from './artifact-generator.js';
6
4
  import { PipelineReportGenerator } from './report-generator.js';
7
5
  import { PHASE_LABELS } from './types.js';
8
6
  import { PIPELINE, TIME } from '../constants.js';
9
7
  import { logger } from '../utils/logger.js';
10
8
  import { ArtifactManager } from '../utils/artifact-manager.js';
11
- import { memoryManager } from '../utils/memory-manager.js';
9
+ import { cacheRegistry } from '../core/cache-registry.js';
12
10
  import { MutexLock } from '../utils/mutex-lock.js';
13
11
  import { buildForgeResumeEnvelope, stripForgeResumeBlocks } from '../utils/forge-resume-block.js';
12
+ import { getPlanPhaseLabels, stringifyExecutionPlanMeta, } from './execution-plan.js';
13
+ import { ExecutionPlanBuilder } from './execution-plan-builder.js';
14
14
  import fsPromises from 'fs/promises';
15
15
  import path from 'path';
16
16
  export { TemplateRegistry } from './template-registry.js';
@@ -18,7 +18,7 @@ export { TemplateRouter } from './template-router.js';
18
18
  export class PipelineEngine {
19
19
  store;
20
20
  analyzer;
21
- phaseManager;
21
+ planBuilder;
22
22
  dynamicNodeExecutor;
23
23
  api;
24
24
  storage;
@@ -27,7 +27,7 @@ export class PipelineEngine {
27
27
  /** 上次注入的指令指纹(pipelineId:phase:completed/total),相同则跳过重复注入 */
28
28
  lastInstructionKey;
29
29
  /** 0/0 状态已通知的 key(projectPath:phase),避免每次 PreToolUse 重复注入空阶段提示(1小时 TTL 自动清理) */
30
- emptyPhaseNotified = memoryManager.register('pipeline:emptyNotified', {
30
+ emptyPhaseNotified = cacheRegistry.register('pipeline:emptyNotified', {
31
31
  max: 100,
32
32
  ttl: TIME.HOUR
33
33
  });
@@ -35,24 +35,24 @@ export class PipelineEngine {
35
35
  pipelineLock = new MutexLock('Pipeline');
36
36
  /** CLAUDE.md 写入器(可选,用于统一加锁写入) */
37
37
  claudeMdWriter;
38
- constructor(storage, api, conventionManager, claudeMdWriter) {
38
+ constructor(storage, api, conventionManager, claudeMdWriter, pendingPromptSink) {
39
39
  this.store = new PipelineStore(storage);
40
40
  this.analyzer = new PipelineAnalyzer(api, conventionManager);
41
- this.phaseManager = new PhaseManager(this.store);
42
- this.dynamicNodeExecutor = new DynamicNodeExecutor(api);
41
+ this.planBuilder = new ExecutionPlanBuilder(this.analyzer);
42
+ this.dynamicNodeExecutor = new DynamicNodeExecutor(api, pendingPromptSink);
43
43
  this.api = api;
44
44
  this.storage = storage;
45
- this.activePipelines = memoryManager.register('pipeline:active', { max: 50 });
46
- this.lastInstructionKey = memoryManager.register('pipeline:instruction', { max: 50 });
45
+ this.activePipelines = cacheRegistry.register('pipeline:active', { max: 50 });
46
+ this.lastInstructionKey = cacheRegistry.register('pipeline:instruction', { max: 50 });
47
47
  this.claudeMdWriter = claudeMdWriter;
48
48
  }
49
49
  /** 检测到 ESC 中断、等待用户确认意图的项目路径集合(2小时 TTL,用户可能长时间不确认) */
50
- interruptedProjects = memoryManager.register('pipeline:interrupted', {
50
+ interruptedProjects = cacheRegistry.register('pipeline:interrupted', {
51
51
  max: 50,
52
52
  ttl: TIME.TWO_HOURS
53
53
  });
54
54
  /** 硬阻断状态(key=projectPath):用于 PreToolUse 拦截后续工具调用 */
55
- blockedProjects = memoryManager.register('pipeline:blocked', {
55
+ blockedProjects = cacheRegistry.register('pipeline:blocked', {
56
56
  max: 50,
57
57
  ttl: TIME.TWO_HOURS
58
58
  });
@@ -123,12 +123,11 @@ export class PipelineEngine {
123
123
  }
124
124
  if (!pipeline || pipeline.phase === 'done')
125
125
  return null;
126
- // 刷新任务列表
127
- pipeline.tasks = this.store.getTasks(pipeline.id);
128
126
  // 计算当前进度指纹,相同时跳过注入(避免每次 PreToolUse 重复输出相同进度)
129
127
  // 注意:动态流水线(dp_)禁用去重,保证持续注入节点执行指令,避免 Claude 丢失上下文后停写
130
128
  const isDynamicPipeline = pipeline.id.startsWith('dp_');
131
129
  if (!isDynamicPipeline) {
130
+ pipeline.tasks = this.store.getTasks(pipeline.id);
132
131
  // total=0 时使用 emptyPhaseNotified 去重:首次注入后标记,状态变化时清除
133
132
  const progress = this.store.getPhaseProgress(pipeline.id, pipeline.phase);
134
133
  const instrKey = `${pipeline.id}:${pipeline.phase}:${progress.completed}/${progress.total}`;
@@ -151,9 +150,13 @@ export class PipelineEngine {
151
150
  const dynPipeline = await this.storage.repositories.dynamicPipelines.getById(pipeline.id);
152
151
  if (!dynPipeline)
153
152
  return null;
153
+ pipeline = this.dynamicPipelineToBridge(dynPipeline);
154
+ this.activePipelines.set(projectPath, pipeline);
154
155
  return this.dynamicNodeExecutor.getInstruction(dynPipeline);
155
156
  }
156
- return this.phaseManager.getPhaseInstruction(pipeline);
157
+ // Legacy Pipeline 不再处理(所有新 Pipeline 均为 dp_ 前缀)
158
+ logger.warn(`[Pipeline] Legacy Pipeline ${pipeline.id} 不再支持,请重新创建`);
159
+ return null;
157
160
  }
158
161
  /**
159
162
  * PostToolUse 处理:跟踪进度,检查阶段推进
@@ -209,85 +212,9 @@ export class PipelineEngine {
209
212
  }
210
213
  return dynamicResult;
211
214
  }
212
- // 刷新任务列表
213
- pipeline.tasks = this.store.getTasks(pipeline.id);
214
- const result = await this.phaseManager.checkAndAdvance(pipeline, event, qualityGate);
215
- // 持久化阶段推进状态(重启后可恢复)
216
- this.persistPhaseState(pipeline.id, pipeline.phase);
217
- if (result.qualityBlocked) {
218
- if (result.blocking) {
219
- this.markBlocked(event.project_path, pipeline.id, result.systemMessage || '[Pipeline 已阻断] 质量门禁 must 规范违反,必须修复后重启 Pipeline');
220
- }
221
- return { message: null, qualityBlocked: true, qualityIssues: result.qualityIssues, systemMessage: result.systemMessage, qualityLevel: result.qualityLevel, fixAttempts: result.fixAttempts, blocking: result.blocking };
222
- }
223
- if (result.advanced && result.newPhase) {
224
- const completedPhase = pipeline.phase; // 推进前的阶段
225
- // 阶段产物生成:异步非阻塞,失败只记录质量问题,不阻断推进
226
- const pipelineSnapshot = { ...pipeline };
227
- const artifactQualityIssues = [];
228
- try {
229
- await new PhaseArtifactGenerator(pipeline.projectPath, this.api, this.storage, pipelineSnapshot)
230
- .generateForPhase(completedPhase, pipelineSnapshot, event.session_id);
231
- }
232
- catch (err) {
233
- const issueMsg = `[阶段产物] ${PHASE_LABELS[completedPhase]} 产物生成失败:${err}`;
234
- logger.warn(`[Forge:阶段产物] ${issueMsg}`);
235
- artifactQualityIssues.push(issueMsg);
236
- // 产物失败不阻断推进,继续执行
237
- }
238
- pipeline.phase = result.newPhase;
239
- // 阶段推进后清除指纹缓存和空阶段标记,确保新阶段指令能正常注入
240
- this.lastInstructionKey.delete(event.project_path);
241
- this.emptyPhaseNotified.delete(`${event.project_path}:${completedPhase}`);
242
- // 阶段推进时更新 CLAUDE.md 续接状态,确保跨会话后 Claude 能快速恢复上下文
243
- this.persistPipelineStateToClaude(pipeline, event.project_path);
244
- if (result.newPhase === 'done') {
245
- this.activePipelines.delete(event.project_path);
246
- this.clearBlocked(event.project_path);
247
- // 统计数据
248
- const totalTasks = pipeline.tasks.length;
249
- const completedTasks = pipeline.tasks.filter(t => t.status === 'completed').length;
250
- const failedTasks = pipeline.tasks.filter(t => t.status === 'failed').length;
251
- const completedPhases = pipeline.plannedPhases?.filter(p => {
252
- const phaseTasks = pipeline.tasks.filter(t => t.phase === p);
253
- return phaseTasks.length > 0 && phaseTasks.every(t => t.status === 'completed');
254
- }) || [];
255
- // Pipeline 完成报告
256
- let reportMessage = `[Forge Pipeline] ✅ 项目已完成所有阶段!
257
- 📋 需求:${pipeline.requirement}
258
- 📊 统计:
259
- • 总任务数:${totalTasks}
260
- • 已完成:${completedTasks}
261
- • 失败:${failedTasks}
262
- • 完成阶段:${completedPhases.map(p => PHASE_LABELS[p]).join('、')}`;
263
- if (qualityGate) {
264
- try {
265
- const reportGenerator = new PipelineReportGenerator(qualityGate.getIssueTracker(), this.phaseManager);
266
- const markdown = reportGenerator.generate(pipeline);
267
- reportGenerator.persist(pipeline.projectPath, markdown);
268
- reportMessage = `${reportMessage}\n\n${markdown}`;
269
- }
270
- catch (err) {
271
- logger.warn(`[Pipeline] 完成报告生成失败:${err}`);
272
- }
273
- }
274
- return { message: reportMessage };
275
- }
276
- return {
277
- message: `[Forge Pipeline] 阶段推进:${PHASE_LABELS[result.newPhase]}`,
278
- gapMessage: result.gapMessage,
279
- qualityLevel: result.qualityLevel,
280
- advanceReason: result.advanceReason,
281
- systemMessage: result.systemMessage,
282
- qualityIssues: artifactQualityIssues.length > 0 ? artifactQualityIssues : undefined,
283
- };
284
- }
285
- // 非阶段推进时,也定期更新 CLAUDE.md(每 20 次工具调用一次)
286
- const eventCount = this.phaseManager.exportPhaseState(`${pipeline.id}:${pipeline.phase}`)?.eventCount ?? 0;
287
- if (eventCount > 0 && eventCount % 20 === 0) {
288
- this.persistPipelineStateToClaude(pipeline, event.project_path);
289
- }
290
- return { message: null, qualityLevel: result.qualityLevel };
215
+ // Legacy Pipeline 不再处理(所有新 Pipeline 均为 dp_ 前缀)
216
+ logger.warn(`[Pipeline] Legacy Pipeline ${pipeline.id} 不再支持,请重新创建`);
217
+ return { message: null };
291
218
  }
292
219
  /**
293
220
  * 动态流水线 PostToolUse 处理
@@ -366,7 +293,7 @@ export class PipelineEngine {
366
293
  • 已完成:${completedNodes}`;
367
294
  if (qualityGate) {
368
295
  try {
369
- const reportGenerator = new PipelineReportGenerator(qualityGate.getIssueTracker(), this.phaseManager);
296
+ const reportGenerator = new PipelineReportGenerator(qualityGate.getIssueTracker(), this.dynamicNodeExecutor);
370
297
  const markdown = reportGenerator.generate(pipeline);
371
298
  reportGenerator.persist(pipeline.projectPath, markdown);
372
299
  reportMessage = `${reportMessage}\n\n${markdown}`;
@@ -442,81 +369,107 @@ ${taskSummary}
442
369
  /**
443
370
  * 启动新 Pipeline
444
371
  */
445
- async startPipeline(requirement, projectPath, sessionId) {
372
+ async startPipeline(requirement, projectPath, sessionId, analysis) {
446
373
  logger.info(`[Pipeline] 启动中(模式:dynamic):"${requirement}"`);
447
- this.clearBlocked(projectPath); // 清理旧的阻断状态
448
- return this.startDynamicPipeline(requirement, projectPath, sessionId);
374
+ this.clearBlocked(projectPath);
375
+ const fallbackAnalysis = analysis ?? {
376
+ complexity: 'moderate',
377
+ requiresPipeline: true,
378
+ requirement,
379
+ reasoning: 'PipelineEngine 启动时未提供显式意图分析,使用默认编排分析',
380
+ estimatedFiles: 1,
381
+ suggestedPhases: [],
382
+ };
383
+ const plan = await this.buildExecutionPlan(requirement, projectPath, sessionId, fallbackAnalysis);
384
+ return this.startPipelineFromPlan(plan);
385
+ }
386
+ /**
387
+ * 生成统一执行计划(动态流水线唯一事实来源)
388
+ */
389
+ async buildExecutionPlan(requirement, projectPath, sessionId, analysis, template, templateRoute) {
390
+ return this.planBuilder.build({
391
+ requirement,
392
+ projectPath,
393
+ sessionId,
394
+ analysis,
395
+ template,
396
+ templateRoute: templateRoute ?? null,
397
+ });
449
398
  }
450
399
  /**
451
- * 启动动态节点 Pipeline(Dynamic 模式)
452
- *
453
- * 使用 DynamicPipelineRepository 创建流水线记录,
454
- * 通过 analyzer.decompose 分析需求,生成顺序依赖的 DynamicNode 列表,
455
- * 并以 Bridge Pattern 返回兼容 Pipeline 接口的对象。
400
+ * 从统一执行计划启动动态 Pipeline
456
401
  */
457
- async startDynamicPipeline(requirement, projectPath, sessionId) {
458
- logger.info(`[Pipeline:Dynamic] 🚀 启动动态流水线:"${requirement}" | 项目=${projectPath}`);
459
- // 1. 使用 analyzer 分析需求,获取规划阶段和复杂度
460
- const analysis = await this.analyzer.decompose(requirement, projectPath);
461
- const { plannedPhases, complexity, taskType, techStack, reasoning, phaseArtifacts } = analysis;
462
- // 2. 生成 Pipeline ID
402
+ async startPipelineFromPlan(plan) {
403
+ logger.info(`[Pipeline:Dynamic] 🚀 启动动态流水线:"${plan.requirement}" | 项目=${plan.projectPath} | source=${plan.source}`);
404
+ this.clearBlocked(plan.projectPath);
405
+ return this.materializeDynamicPipeline(plan);
406
+ }
407
+ async materializeDynamicPipeline(plan) {
463
408
  const pipelineId = `dp_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
464
- // 3. plannedPhases 转换为 DynamicNode 列表(顺序依赖)
465
- const nodes = plannedPhases.map((phaseId, index) => ({
409
+ const nodes = plan.stages.map((stage, index) => ({
466
410
  id: `${pipelineId}_node_${index}`,
467
- nodeTypeId: phaseId,
411
+ nodeTypeId: stage.nodeTypeId,
468
412
  status: (index === 0 ? 'in_progress' : 'pending'),
469
413
  dependencies: index > 0 ? [`${pipelineId}_node_${index - 1}`] : [],
470
414
  }));
471
- // 4. 创建 DynamicPipeline 记录
415
+ const reasoningMeta = stringifyExecutionPlanMeta({
416
+ currentNodeId: nodes[0]?.id,
417
+ originalReasoning: plan.reasoning,
418
+ executionPlan: plan,
419
+ templateId: plan.templateId,
420
+ templateName: plan.templateName,
421
+ source: plan.source,
422
+ });
472
423
  await this.storage.repositories.dynamicPipelines.create({
473
424
  id: pipelineId,
474
- requirement,
475
- projectPath,
476
- sessionId,
477
- complexity,
478
- reasoning: JSON.stringify({ currentNodeId: nodes[0]?.id, originalReasoning: reasoning }),
425
+ requirement: plan.requirement,
426
+ projectPath: plan.projectPath,
427
+ sessionId: plan.sessionId,
428
+ templateId: plan.templateId,
429
+ complexity: plan.complexity,
430
+ reasoning: reasoningMeta,
479
431
  status: 'in_progress',
432
+ executionPlan: plan,
480
433
  });
481
- // 5. 存储节点
482
434
  if (nodes.length > 0) {
483
435
  await this.storage.repositories.dynamicPipelines.createNodes(pipelineId, nodes);
484
436
  }
485
- // 6. 设置 currentNodeId
486
437
  if (nodes[0]) {
487
438
  await this.storage.repositories.dynamicPipelines.updateCurrentNode(pipelineId, nodes[0].id);
488
439
  }
489
- // 7. 构建 Pipeline 兼容对象(Bridge Pattern:DynamicPipeline → Pipeline)
490
440
  const now = new Date().toISOString();
491
- const legacyPipeline = {
441
+ const pipeline = {
492
442
  id: pipelineId,
493
- requirement,
494
- projectPath,
495
- sessionId,
443
+ requirement: plan.requirement,
444
+ projectPath: plan.projectPath,
445
+ sessionId: plan.sessionId,
496
446
  phase: nodes[0]?.nodeTypeId ?? 'code',
497
- tasks: nodes.map(node => ({
447
+ tasks: nodes.map((node, index) => ({
498
448
  id: node.id,
499
- title: PHASE_LABELS[node.nodeTypeId] || node.nodeTypeId,
449
+ title: plan.stages[index]?.name ?? (PHASE_LABELS[node.nodeTypeId] || node.nodeTypeId),
500
450
  phase: node.nodeTypeId,
501
451
  status: node.status === 'in_progress' ? 'in_progress' : node.status === 'completed' ? 'completed' : 'pending',
502
- description: `动态节点:${node.nodeTypeId}`,
452
+ description: plan.tasks[index]?.description ?? `动态节点:${node.nodeTypeId}`,
503
453
  dependencies: node.dependencies,
454
+ source: plan.source,
504
455
  })),
505
- techStack,
506
- complexity,
507
- taskType,
508
- plannedPhases,
509
- phaseArtifacts,
510
- reasoning,
456
+ techStack: plan.techStack,
457
+ complexity: plan.complexity,
458
+ taskType: plan.taskType,
459
+ plannedPhases: plan.stages.map(stage => stage.phase),
460
+ phaseArtifacts: Object.fromEntries(plan.stages.map(stage => [stage.phase, stage.derivedReports])),
461
+ reasoning: plan.reasoning,
462
+ templateId: plan.templateId,
463
+ executionPlan: plan,
511
464
  createdAt: now,
512
465
  updatedAt: now,
513
466
  };
514
- // 8. 缓存到内存,重置质量门禁计数
515
- this.activePipelines.set(projectPath, legacyPipeline);
516
- this.phaseManager.resetFixAttempts(pipelineId);
517
- const nodeFlow = plannedPhases.map(p => PHASE_LABELS[p] || p).join(' → ');
518
- logger.info(`[Pipeline:Dynamic] ✅ 动态流水线已创建\n📋 需求:${requirement}\n📊 统计:${nodes.length} 个节点 | 复杂度:${complexity}\n🗺️ 节点规划:${nodeFlow}`);
519
- return legacyPipeline;
467
+ this.activePipelines.set(plan.projectPath, pipeline);
468
+ this.dynamicNodeExecutor.resetFixAttempts(pipelineId);
469
+ this.writeExecutionPlanArtifact(plan, pipeline);
470
+ const nodeFlow = getPlanPhaseLabels(plan).join(' → ');
471
+ logger.info(`[Pipeline:Dynamic] ✅ 动态流水线已创建\n📋 需求:${plan.requirement}\n📊 统计:${nodes.length} 个节点 | 复杂度:${plan.complexity}\n🗺️ 节点规划:${nodeFlow}`);
472
+ return pipeline;
520
473
  }
521
474
  /**
522
475
  * 将 DynamicPipeline 转换为 Pipeline 兼容对象(冷缓存恢复时使用)
@@ -527,7 +480,8 @@ ${taskSummary}
527
480
  : dynPipeline.nodes.find(n => n.status === 'in_progress');
528
481
  const phase = currentNode?.nodeTypeId ??
529
482
  dynPipeline.nodes[0]?.nodeTypeId ?? 'code';
530
- const plannedPhases = dynPipeline.nodes.map(n => n.nodeTypeId);
483
+ const plannedPhases = dynPipeline.executionPlan?.stages.map(stage => stage.phase)
484
+ ?? dynPipeline.nodes.map(n => n.nodeTypeId);
531
485
  return {
532
486
  id: dynPipeline.id,
533
487
  requirement: dynPipeline.requirement,
@@ -545,6 +499,7 @@ ${taskSummary}
545
499
  complexity: dynPipeline.complexity,
546
500
  plannedPhases,
547
501
  reasoning: dynPipeline.reasoning,
502
+ executionPlan: dynPipeline.executionPlan,
548
503
  createdAt: dynPipeline.createdAt,
549
504
  updatedAt: dynPipeline.updatedAt,
550
505
  };
@@ -552,87 +507,29 @@ ${taskSummary}
552
507
  /**
553
508
  * 从 PipelineTemplate 启动 Pipeline(Batch 4:模板驱动,跳过 AI 分解)
554
509
  */
555
- async startPipelineFromTemplate(requirement, projectPath, sessionId, template) {
556
- logger.info(`[Pipeline:Template] 🚀 从模板启动:"${requirement}" | 模板=${template.id}`);
557
- // 从模板阶段构建任务列表
558
- const validPhases = template.phases
559
- .map(p => p.id)
560
- .filter((id) => ['analyze', 'design', 'profile', 'code', 'test', 'review'].includes(id));
561
- const plannedPhases = validPhases.length > 0 ? validPhases : ['code', 'test'];
562
- const complexity = (template.trigger?.complexity?.[0] || 'moderate');
563
- const taskType = template.taskType || 'other';
564
- // 生成 Pipeline ID
565
- const pipelineId = `dp_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
566
- // 将模板 phases 转换为 DynamicNode 列表(顺序依赖)
567
- const nodes = plannedPhases.map((phaseId, index) => ({
568
- id: `${pipelineId}_node_${index}`,
569
- nodeTypeId: phaseId,
570
- status: (index === 0 ? 'in_progress' : 'pending'),
571
- dependencies: index > 0 ? [`${pipelineId}_node_${index - 1}`] : [],
572
- }));
573
- // 创建 DynamicPipeline 记录
574
- await this.storage.repositories.dynamicPipelines.create({
575
- id: pipelineId,
576
- requirement,
577
- projectPath,
578
- sessionId,
579
- complexity,
580
- reasoning: JSON.stringify({
581
- currentNodeId: nodes[0]?.id,
582
- templateId: template.id,
583
- templateName: template.name,
584
- source: template.source
585
- }),
586
- status: 'in_progress',
587
- });
588
- // 存储节点
589
- if (nodes.length > 0) {
590
- await this.storage.repositories.dynamicPipelines.createNodes(pipelineId, nodes);
591
- }
592
- // 设置 currentNodeId
593
- if (nodes[0]) {
594
- await this.storage.repositories.dynamicPipelines.updateCurrentNode(pipelineId, nodes[0].id);
595
- }
596
- // 构建 Pipeline 兼容对象
597
- const now = new Date().toISOString();
598
- const pipeline = {
599
- id: pipelineId,
510
+ async startPipelineFromTemplate(requirement, projectPath, sessionId, template, analysis, templateRoute) {
511
+ const fallbackAnalysis = analysis ?? {
512
+ complexity: 'moderate',
513
+ requiresPipeline: true,
600
514
  requirement,
601
- projectPath,
602
- sessionId,
603
- phase: nodes[0]?.nodeTypeId ?? 'code',
604
- tasks: nodes.map(node => ({
605
- id: node.id,
606
- title: PHASE_LABELS[node.nodeTypeId] || node.nodeTypeId,
607
- phase: node.nodeTypeId,
608
- status: node.status === 'in_progress' ? 'in_progress' : node.status === 'completed' ? 'completed' : 'pending',
609
- description: `模板节点:${node.nodeTypeId}`,
610
- dependencies: node.dependencies,
611
- })),
612
- complexity,
613
- taskType,
614
- plannedPhases,
615
- reasoning: `来源模板:${template.name}(${template.id})`,
616
- createdAt: now,
617
- updatedAt: now,
515
+ reasoning: `模板 ${template.id} 启动时未提供显式意图分析,使用默认编排分析`,
516
+ estimatedFiles: 1,
517
+ suggestedPhases: template.phases.map(phase => phase.id),
618
518
  };
619
- this.activePipelines.set(projectPath, pipeline);
620
- // 新 Pipeline 启动时重置质量门禁修复计数(防止旧计数污染)
621
- this.phaseManager.resetFixAttempts(pipeline.id);
622
- // 写入执行计划文档
519
+ const plan = await this.buildExecutionPlan(requirement, projectPath, sessionId, fallbackAnalysis, template, templateRoute);
520
+ return this.startPipelineFromPlan(plan);
521
+ }
522
+ writeExecutionPlanArtifact(plan, pipeline) {
623
523
  try {
624
- const artifactManager = new ArtifactManager(projectPath);
625
- const phases = plannedPhases.map(p => PHASE_LABELS[p] || p).join(' → ');
626
- const taskLines = pipeline.tasks.map(t => `- [${PHASE_LABELS[t.phase] || t.phase}] ${t.title}${t.description ? `:${t.description}` : ''}`).join('\n');
627
- const planContent = `# 执行计划(模板驱动)\n\n**需求**:${requirement}\n\n**模板**:${template.name}(${template.id})\n\n**阶段规划**:${phases}\n\n## 任务清单\n\n${taskLines}\n`;
628
- artifactManager.writeArtifact('plan', '执行计划.md', planContent, requirement.slice(0, 50), '执行计划');
524
+ const artifactManager = new ArtifactManager(plan.projectPath);
525
+ const phases = getPlanPhaseLabels(plan).join(' → ');
526
+ const taskLines = pipeline.tasks.map(task => `- [${PHASE_LABELS[task.phase] || task.phase}] ${task.title}${task.description ? `:${task.description}` : ''}`).join('\n');
527
+ const planContent = `# 执行计划\n\n**需求**:${plan.requirement}\n\n**来源**:${plan.source}${plan.templateName ? `(${plan.templateName})` : ''}\n\n**阶段规划**:${phases}\n\n## 任务清单\n\n${taskLines}\n`;
528
+ artifactManager.writeArtifact('plan', '执行计划.md', planContent, plan.requirement.slice(0, 50), '执行计划');
629
529
  }
630
530
  catch (err) {
631
- logger.warn(`[Pipeline] 模板执行计划文档写入失败:${err}`);
531
+ logger.warn(`[Pipeline] 执行计划文档写入失败:${err}`);
632
532
  }
633
- const phaseFlow = plannedPhases.map(p => PHASE_LABELS[p] || p).join(' → ');
634
- logger.info(`[Pipeline:Template] ✅ 模板驱动启动完成\n📋 需求:${requirement}\n📊 统计:${pipeline.tasks.length} 个节点 | ${plannedPhases.length} 个阶段 | 模板:${template.name}\n🗺️ 阶段规划:${phaseFlow}`);
635
- return pipeline;
636
533
  }
637
534
  /**
638
535
  * 检查项目是否有活跃 Pipeline
@@ -641,7 +538,9 @@ ${taskSummary}
641
538
  if (this.activePipelines.has(projectPath))
642
539
  return true;
643
540
  const db = this.store.getActivePipeline(projectPath);
644
- return db !== null;
541
+ if (db !== null)
542
+ return true;
543
+ return this.storage.repositories.dynamicPipelines.getActiveByProjectPath(projectPath) !== null;
645
544
  }
646
545
  /**
647
546
  * 获取 Pipeline 状态摘要(用于 resume 注入)
@@ -722,12 +621,6 @@ ${taskSummary}
722
621
  }
723
622
  return progressLine + gateLine;
724
623
  }
725
- /**
726
- * 获取 PhaseManager 引用(用于注入知识上下文)
727
- */
728
- getPhaseManager() {
729
- return this.phaseManager;
730
- }
731
624
  /**
732
625
  * 获取 DynamicNodeExecutor 引用
733
626
  */
@@ -738,38 +631,35 @@ ${taskSummary}
738
631
  * 获取活跃 Pipeline 对象
739
632
  */
740
633
  getActivePipelineForProject(projectPath) {
741
- return this.activePipelines.get(projectPath) || this.store.getActivePipeline(projectPath);
634
+ const cached = this.activePipelines.get(projectPath);
635
+ if (cached)
636
+ return cached;
637
+ const legacy = this.store.getActivePipeline(projectPath);
638
+ if (legacy)
639
+ return legacy;
640
+ const dynamic = this.storage.repositories.dynamicPipelines.getActiveByProjectPath(projectPath);
641
+ return dynamic ? this.dynamicPipelineToBridge(dynamic) : null;
742
642
  }
743
643
  /**
744
- * ESC 中断后从 DB 恢复时,重建 PhaseManager 的内存状态。
745
- * - phaseToolsSeen:已完成任务的阶段标记为"已见过 write"(允许后续任务正常检测)
746
- * - totalPhaseEventCounts:按已完成任务数估算(保守值,避免立刻触发兜底推进)
644
+ * ESC 中断后从 DB 恢复时,重建执行器的内存状态。
747
645
  */
748
646
  restorePhaseState(pipeline) {
749
647
  const phase = pipeline.phase;
750
648
  if (phase === 'done')
751
649
  return;
752
- const key = `${pipeline.id}:${phase}`;
753
- const completedCount = pipeline.tasks.filter(t => t.phase === phase && t.status === 'completed').length;
754
- // 跨会话恢复时清理质量门禁修复计数,避免残留计数导致"第N次"误报
755
- this.phaseManager.resetFixAttempts(pipeline.id);
756
- // 优先从 daemon_state 恢复完整状态
757
- if (this.loadPhaseState(pipeline.id, phase)) {
758
- logger.debug(`[Pipeline] 从 daemon_state 恢复阶段状态:${phase}`);
650
+ // 动态 Pipeline 使用 DynamicNodeExecutor 的状态恢复
651
+ if (pipeline.id.startsWith('dp_')) {
652
+ this.dynamicNodeExecutor.resetFixAttempts(pipeline.id);
653
+ logger.debug(`[Pipeline] 动态 Pipeline 状态已恢复:${phase}`);
759
654
  return;
760
655
  }
761
- // 回退:已有已完成任务 恢复 toolsSeen 为"已做过 explore + write",避免卡死
762
- if (completedCount > 0) {
763
- this.phaseManager.restoreToolsSeen(key, new Set(['explore', 'write', 'bash']));
764
- }
765
- // 回退:事件计数按已完成任务数 × 5(保守估算,不触发兜底推进)
766
- this.phaseManager.restoreEventCount(key, completedCount * 5);
767
- logger.debug(`[Pipeline] 回退恢复阶段状态:${phase} | 已完成=${completedCount}`);
656
+ // Legacy Pipeline 不再支持状态恢复
657
+ logger.warn(`[Pipeline] Legacy Pipeline ${pipeline.id} 状态恢复已跳过`);
768
658
  }
769
659
  /** 将当前阶段推进状态持久化到 daemon_state */
770
660
  persistPhaseState(pipelineId, phase) {
771
661
  const key = `${pipelineId}:${phase}`;
772
- const state = this.phaseManager.exportPhaseState(key);
662
+ const state = this.dynamicNodeExecutor.exportState(key);
773
663
  this.storage.setDaemonState(`pipeline:phase-state:${key}`, JSON.stringify(state));
774
664
  }
775
665
  /** 从 daemon_state 加载阶段推进状态,成功返回 true */
@@ -780,7 +670,7 @@ ${taskSummary}
780
670
  return false;
781
671
  try {
782
672
  const parsed = JSON.parse(raw);
783
- this.phaseManager.restorePhaseState(key, parsed);
673
+ this.dynamicNodeExecutor.restoreState(key, parsed);
784
674
  return true;
785
675
  }
786
676
  catch (err) {
@@ -823,7 +713,7 @@ ${taskSummary}
823
713
  this.dynamicNodeExecutor.cleanup(interrupted.pipelineId);
824
714
  }
825
715
  else {
826
- this.phaseManager.cleanup(interrupted.pipelineId);
716
+ this.dynamicNodeExecutor.cleanup(interrupted.pipelineId);
827
717
  }
828
718
  this.activePipelines.delete(projectPath);
829
719
  this.lastInstructionKey.delete(projectPath);
@@ -842,7 +732,7 @@ ${taskSummary}
842
732
  this.dynamicNodeExecutor.cleanup(projectPathOrId);
843
733
  }
844
734
  else {
845
- this.phaseManager.cleanup(projectPathOrId);
735
+ this.dynamicNodeExecutor.cleanup(projectPathOrId);
846
736
  }
847
737
  this.store.closeById(projectPathOrId);
848
738
  // 清理内存缓存(遍历找到对应条目)
@@ -863,7 +753,7 @@ ${taskSummary}
863
753
  this.dynamicNodeExecutor.cleanup(pipeline.id);
864
754
  }
865
755
  else {
866
- this.phaseManager.cleanup(pipeline.id);
756
+ this.dynamicNodeExecutor.cleanup(pipeline.id);
867
757
  }
868
758
  this.store.closeById(pipeline.id);
869
759
  }
@@ -886,7 +776,7 @@ ${taskSummary}
886
776
  this.dynamicNodeExecutor.cleanup(pipelineId);
887
777
  }
888
778
  else {
889
- this.phaseManager.cleanup(pipelineId);
779
+ this.dynamicNodeExecutor.cleanup(pipelineId);
890
780
  }
891
781
  }
892
782
  logger.info(`[Pipeline] 已自动关闭 ${closedIds.length} 个过期 Pipeline(超过 ${ttlMs / 60000} 分钟未更新)`);
@@ -923,32 +813,17 @@ ${taskSummary}
923
813
  return false;
924
814
  return this.dynamicNodeExecutor.hasArtifactRetry(pipeline.id);
925
815
  }
816
+ evaluatePreToolGate(event) {
817
+ const pipeline = this.getActiveDynamicPipelineForProject(event.project_path);
818
+ if (!pipeline)
819
+ return null;
820
+ return this.dynamicNodeExecutor.evaluatePreToolGate(pipeline, event);
821
+ }
926
822
  /**
927
823
  * 检查 Step 级工具白名单(Step 模式启用时生效)
928
824
  */
929
825
  checkStepGate(event) {
930
- const pipeline = this.getActiveDynamicPipelineForProject(event.project_path);
931
- if (!pipeline)
932
- return null;
933
- const currentNode = pipeline.nodes.find(n => n.id === pipeline.currentNodeId);
934
- if (!currentNode)
935
- return null;
936
- // 检查是否启用 Step 模式
937
- const stepOrchestrator = this.dynamicNodeExecutor.getStepOrchestrator();
938
- if (!stepOrchestrator.isStepModeEnabled(currentNode)) {
939
- return null; // 未启用 Step 模式,跳过检查
940
- }
941
- // 获取当前 Step
942
- const currentStep = stepOrchestrator.getCurrentStep(pipeline, currentNode);
943
- if (!currentStep)
944
- return null;
945
- // 加载 Step 定义
946
- const stepDef = stepOrchestrator.loadStepDefinition(currentNode.nodeTypeId, currentStep.stepDefinitionId);
947
- if (!stepDef)
948
- return null;
949
- // 使用 StepGateKeeper 检查工具
950
- const stepGateKeeper = this.dynamicNodeExecutor.getStepGateKeeper();
951
- return stepGateKeeper.checkTool(event, currentStep, stepDef);
826
+ return this.evaluatePreToolGate(event);
952
827
  }
953
828
  /** 标记项目进入硬阻断状态 */
954
829
  markBlocked(projectPath, pipelineId, reason) {
@@ -1006,11 +881,12 @@ ${taskSummary}
1006
881
  * 使用与 PreToolUse 相同的进度指纹缓存机制,避免相同进度下重复注入
1007
882
  */
1008
883
  async getCurrentPhaseDirective(projectPath) {
1009
- const pipeline = this.activePipelines.get(projectPath) || this.store.getActivePipeline(projectPath);
884
+ const pipeline = this.getActivePipelineForProject(projectPath);
1010
885
  if (!pipeline || pipeline.phase === 'done')
1011
886
  return null;
1012
- // 刷新任务列表
1013
- pipeline.tasks = this.store.getTasks(pipeline.id);
887
+ if (!pipeline.id.startsWith('dp_')) {
888
+ pipeline.tasks = this.store.getTasks(pipeline.id);
889
+ }
1014
890
  // 进度指纹去重:与 PreToolUse 共享 lastInstructionKey 缓存
1015
891
  const progress = this.store.getPhaseProgress(pipeline.id, pipeline.phase);
1016
892
  const instrKey = `${pipeline.id}:${pipeline.phase}:${progress.completed}/${progress.total}:user`;
@@ -1033,7 +909,9 @@ ${taskSummary}
1033
909
  return null;
1034
910
  return this.dynamicNodeExecutor.getInstruction(dynPipeline);
1035
911
  }
1036
- return this.phaseManager.getPhaseInstruction(pipeline);
912
+ // Legacy Pipeline 不再支持
913
+ logger.warn(`[Pipeline] Legacy Pipeline ${pipeline.id} 不再支持`);
914
+ return null;
1037
915
  }
1038
916
  /**
1039
917
  * 获取任务进度摘要(Stage 09 增强上下文使用)
@@ -1056,20 +934,15 @@ ${taskSummary}
1056
934
  /**
1057
935
  * 获取产物门禁提示(供 stage-scheduler 注入到 AI 上下文)
1058
936
  */
1059
- getArtifactGateReminder(projectPath) {
1060
- const pipeline = this.activePipelines.get(projectPath) || this.store.getActivePipeline(projectPath);
1061
- if (!pipeline || pipeline.phase === 'done')
1062
- return null;
1063
- return this.phaseManager.getArtifactGateReminder(pipeline.id, pipeline.phase);
937
+ getArtifactGateReminder(_projectPath) {
938
+ // Legacy 功能,动态 Pipeline 不使用产物门禁提示
939
+ return null;
1064
940
  }
1065
941
  /**
1066
942
  * 清除产物门禁提示
1067
943
  */
1068
- clearArtifactGateReminder(projectPath) {
1069
- const pipeline = this.activePipelines.get(projectPath) || this.store.getActivePipeline(projectPath);
1070
- if (!pipeline || pipeline.phase === 'done')
1071
- return;
1072
- this.phaseManager.clearArtifactGateReminder(pipeline.id, pipeline.phase);
944
+ clearArtifactGateReminder(_projectPath) {
945
+ // Legacy 功能,动态 Pipeline 不使用产物门禁提示
1073
946
  }
1074
947
  /**
1075
948
  * 获取当前阶段名称(用于失败信号上下文)
@@ -1084,7 +957,7 @@ ${taskSummary}
1084
957
  * 获取 Pipeline 阶段快照(用于复盘分析)
1085
958
  */
1086
959
  getSessionSnapshot(pipelineId) {
1087
- return this.phaseManager.getSessionSnapshot(pipelineId);
960
+ return this.dynamicNodeExecutor.getSessionSnapshot(pipelineId);
1088
961
  }
1089
962
  /**
1090
963
  * 发射 Step 级别的事件(STEP_STARTED/COMPLETED/FAILED/VALIDATED/RETRYING/NEED_HUMAN)