@winspan/claude-forge 1.16.15 → 1.17.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 (67) hide show
  1. package/README.md +11 -11
  2. package/dist/daemon/index.d.ts.map +1 -1
  3. package/dist/daemon/index.js +8 -0
  4. package/dist/daemon/index.js.map +1 -1
  5. package/dist/pipeline/aggregator.d.ts +118 -0
  6. package/dist/pipeline/aggregator.d.ts.map +1 -0
  7. package/dist/pipeline/aggregator.js +252 -0
  8. package/dist/pipeline/aggregator.js.map +1 -0
  9. package/dist/pipeline/event-sourced-engine.d.ts +77 -0
  10. package/dist/pipeline/event-sourced-engine.d.ts.map +1 -0
  11. package/dist/pipeline/event-sourced-engine.js +266 -0
  12. package/dist/pipeline/event-sourced-engine.js.map +1 -0
  13. package/dist/pipeline/event-store.d.ts +58 -0
  14. package/dist/pipeline/event-store.d.ts.map +1 -0
  15. package/dist/pipeline/event-store.js +184 -0
  16. package/dist/pipeline/event-store.js.map +1 -0
  17. package/dist/pipeline/events.d.ts +166 -0
  18. package/dist/pipeline/events.d.ts.map +1 -0
  19. package/dist/pipeline/events.js +29 -0
  20. package/dist/pipeline/events.js.map +1 -0
  21. package/dist/pipeline/optimized-aggregator.d.ts +36 -0
  22. package/dist/pipeline/optimized-aggregator.d.ts.map +1 -0
  23. package/dist/pipeline/optimized-aggregator.js +93 -0
  24. package/dist/pipeline/optimized-aggregator.js.map +1 -0
  25. package/dist/pipeline/progress-tracker.d.ts +29 -0
  26. package/dist/pipeline/progress-tracker.d.ts.map +1 -0
  27. package/dist/pipeline/progress-tracker.js +99 -0
  28. package/dist/pipeline/progress-tracker.js.map +1 -0
  29. package/dist/pipeline/snapshot-store.d.ts +45 -0
  30. package/dist/pipeline/snapshot-store.d.ts.map +1 -0
  31. package/dist/pipeline/snapshot-store.js +89 -0
  32. package/dist/pipeline/snapshot-store.js.map +1 -0
  33. package/dist/pipeline/state-machine-types.d.ts +156 -0
  34. package/dist/pipeline/state-machine-types.d.ts.map +1 -0
  35. package/dist/pipeline/state-machine-types.js +7 -0
  36. package/dist/pipeline/state-machine-types.js.map +1 -0
  37. package/dist/pipeline/state-machine.d.ts +44 -0
  38. package/dist/pipeline/state-machine.d.ts.map +1 -0
  39. package/dist/pipeline/state-machine.js +203 -0
  40. package/dist/pipeline/state-machine.js.map +1 -0
  41. package/dist/pipeline/state-query.d.ts +71 -0
  42. package/dist/pipeline/state-query.d.ts.map +1 -0
  43. package/dist/pipeline/state-query.js +192 -0
  44. package/dist/pipeline/state-query.js.map +1 -0
  45. package/dist/pipeline/store.d.ts +12 -17
  46. package/dist/pipeline/store.d.ts.map +1 -1
  47. package/dist/pipeline/store.js +214 -110
  48. package/dist/pipeline/store.js.map +1 -1
  49. package/dist/pipeline/store.legacy.d.ts +48 -0
  50. package/dist/pipeline/store.legacy.d.ts.map +1 -0
  51. package/dist/pipeline/store.legacy.js +163 -0
  52. package/dist/pipeline/store.legacy.js.map +1 -0
  53. package/dist/pipeline/transitions.d.ts +28 -0
  54. package/dist/pipeline/transitions.d.ts.map +1 -0
  55. package/dist/pipeline/transitions.js +336 -0
  56. package/dist/pipeline/transitions.js.map +1 -0
  57. package/dist/scripts/auto-migrate.d.ts +9 -0
  58. package/dist/scripts/auto-migrate.d.ts.map +1 -0
  59. package/dist/scripts/auto-migrate.js +161 -0
  60. package/dist/scripts/auto-migrate.js.map +1 -0
  61. package/dist/scripts/migrate-to-event-sourcing.d.ts +16 -0
  62. package/dist/scripts/migrate-to-event-sourcing.d.ts.map +1 -0
  63. package/dist/scripts/migrate-to-event-sourcing.js +179 -0
  64. package/dist/scripts/migrate-to-event-sourcing.js.map +1 -0
  65. package/dist/web-static/assets/{index-Tbfb5BBI.js → index-BmOm81pb.js} +1 -1
  66. package/dist/web-static/index.html +1 -1
  67. package/package.json +3 -1
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Pipeline 状态查询服务
3
+ *
4
+ * 职责:
5
+ * 1. 查询当前状态
6
+ * 2. 检查转换可行性
7
+ * 3. 查询状态历史
8
+ * 4. 提供状态分析
9
+ */
10
+ import { PipelineEventType } from './events.js';
11
+ export class PipelineStateQuery {
12
+ aggregator;
13
+ eventStore;
14
+ stateMachine;
15
+ constructor(aggregator, eventStore, stateMachine) {
16
+ this.aggregator = aggregator;
17
+ this.eventStore = eventStore;
18
+ this.stateMachine = stateMachine;
19
+ }
20
+ /**
21
+ * 获取当前状态
22
+ */
23
+ getCurrentState(pipelineId) {
24
+ const pipeline = this.aggregator.rebuild(pipelineId);
25
+ if (!pipeline)
26
+ return null;
27
+ return {
28
+ phase: pipeline.phase,
29
+ status: pipeline.status,
30
+ ...(pipeline.qualityFixAttempt !== undefined ? { fixAttempt: pipeline.qualityFixAttempt } : {}),
31
+ };
32
+ }
33
+ /**
34
+ * 检查是否可以执行转换
35
+ */
36
+ canTransition(pipelineId, trigger) {
37
+ return this.stateMachine.canTransition(pipelineId, trigger);
38
+ }
39
+ /**
40
+ * 获取可用的转换列表
41
+ */
42
+ getAvailableTransitions(pipelineId) {
43
+ return this.stateMachine.getAvailableTransitions(pipelineId);
44
+ }
45
+ /**
46
+ * 获取状态历史
47
+ */
48
+ getStateHistory(pipelineId) {
49
+ const events = this.eventStore.getEvents(pipelineId);
50
+ const history = [];
51
+ let currentState = { phase: 'analyze', status: 'in_progress' };
52
+ for (const event of events) {
53
+ let stateChanged = false;
54
+ let trigger;
55
+ switch (event.type) {
56
+ case PipelineEventType.PIPELINE_CREATED:
57
+ currentState = { phase: 'analyze', status: 'in_progress' };
58
+ stateChanged = true;
59
+ trigger = 'PIPELINE_CREATED';
60
+ break;
61
+ case PipelineEventType.PHASE_ADVANCED:
62
+ const payload = event.payload;
63
+ currentState = {
64
+ phase: payload.toPhase,
65
+ status: payload.toPhase === 'done' ? 'completed' : 'in_progress',
66
+ };
67
+ stateChanged = true;
68
+ trigger = 'PHASE_ADVANCED';
69
+ break;
70
+ case PipelineEventType.QUALITY_CHECK_STARTED:
71
+ currentState = { ...currentState, status: 'quality_checking' };
72
+ stateChanged = true;
73
+ trigger = 'QUALITY_CHECK_STARTED';
74
+ break;
75
+ case PipelineEventType.QUALITY_CHECK_PASSED:
76
+ currentState = { ...currentState, status: 'in_progress' };
77
+ stateChanged = true;
78
+ trigger = 'QUALITY_CHECK_PASSED';
79
+ break;
80
+ case PipelineEventType.QUALITY_CHECK_FAILED:
81
+ const failPayload = event.payload;
82
+ currentState = {
83
+ ...currentState,
84
+ status: 'quality_blocked',
85
+ fixAttempt: failPayload.fixAttempt,
86
+ };
87
+ stateChanged = true;
88
+ trigger = 'QUALITY_CHECK_FAILED';
89
+ break;
90
+ case PipelineEventType.QUALITY_FORCED_PASS:
91
+ currentState = { ...currentState, status: 'quality_forced_pass' };
92
+ stateChanged = true;
93
+ trigger = 'QUALITY_FORCED_PASS';
94
+ break;
95
+ case PipelineEventType.PIPELINE_CLOSED:
96
+ currentState = { phase: 'done', status: 'completed' };
97
+ stateChanged = true;
98
+ trigger = 'PIPELINE_CLOSED';
99
+ break;
100
+ }
101
+ if (stateChanged) {
102
+ history.push({
103
+ state: currentState,
104
+ timestamp: event.timestamp,
105
+ trigger,
106
+ eventId: event.id,
107
+ });
108
+ }
109
+ }
110
+ return history;
111
+ }
112
+ /**
113
+ * 获取阶段停留时长
114
+ */
115
+ getPhaseDuration(pipelineId, phase) {
116
+ const history = this.getStateHistory(pipelineId);
117
+ const phaseEntries = history.filter(h => h.state.phase === phase);
118
+ if (phaseEntries.length === 0)
119
+ return null;
120
+ const startTime = phaseEntries[0].timestamp;
121
+ const endTime = phaseEntries[phaseEntries.length - 1].timestamp;
122
+ return endTime - startTime;
123
+ }
124
+ /**
125
+ * 获取质量门禁统计
126
+ */
127
+ getQualityGateStats(pipelineId) {
128
+ const events = this.eventStore.getEvents(pipelineId, {
129
+ types: [
130
+ PipelineEventType.QUALITY_CHECK_PASSED,
131
+ PipelineEventType.QUALITY_CHECK_FAILED,
132
+ PipelineEventType.QUALITY_FORCED_PASS,
133
+ ],
134
+ });
135
+ return {
136
+ totalChecks: events.length,
137
+ passed: events.filter(e => e.type === PipelineEventType.QUALITY_CHECK_PASSED).length,
138
+ failed: events.filter(e => e.type === PipelineEventType.QUALITY_CHECK_FAILED).length,
139
+ forcedPass: events.filter(e => e.type === PipelineEventType.QUALITY_FORCED_PASS).length,
140
+ };
141
+ }
142
+ /**
143
+ * 获取阶段事件统计
144
+ */
145
+ getPhaseEventStats(pipelineId, phase) {
146
+ const events = this.eventStore.getEvents(pipelineId);
147
+ // 找到该阶段的开始和结束时间
148
+ const phaseHistory = this.getStateHistory(pipelineId);
149
+ const phaseEntries = phaseHistory.filter(h => h.state.phase === phase);
150
+ if (phaseEntries.length === 0) {
151
+ return { totalEvents: 0, toolTracked: 0, tasksCompleted: 0 };
152
+ }
153
+ const startTime = phaseEntries[0].timestamp;
154
+ const endTime = phaseEntries[phaseEntries.length - 1]?.timestamp || Date.now();
155
+ const phaseEvents = events.filter(e => e.timestamp >= startTime && e.timestamp <= endTime);
156
+ return {
157
+ totalEvents: phaseEvents.length,
158
+ toolTracked: phaseEvents.filter(e => e.type === PipelineEventType.TOOL_TRACKED).length,
159
+ tasksCompleted: phaseEvents.filter(e => e.type === PipelineEventType.TASK_COMPLETED).length,
160
+ };
161
+ }
162
+ /**
163
+ * 判断是否处于阻塞状态
164
+ */
165
+ isBlocked(pipelineId) {
166
+ const state = this.getCurrentState(pipelineId);
167
+ if (!state)
168
+ return false;
169
+ return state.status === 'quality_blocked' || state.status === 'quality_forced_pass';
170
+ }
171
+ /**
172
+ * 获取阻塞原因
173
+ */
174
+ getBlockReason(pipelineId) {
175
+ const state = this.getCurrentState(pipelineId);
176
+ if (!state)
177
+ return null;
178
+ if (state.status === 'quality_blocked') {
179
+ const lastFailEvent = this.eventStore.getLatestEventByType(pipelineId, PipelineEventType.QUALITY_CHECK_FAILED);
180
+ if (lastFailEvent) {
181
+ const payload = lastFailEvent.payload;
182
+ return `质量检查失败(第${payload.fixAttempt}次):${payload.checks.length} 个问题待修复`;
183
+ }
184
+ return '质量检查失败';
185
+ }
186
+ if (state.status === 'quality_forced_pass') {
187
+ return '质量强制放行,需要手动确认后推进';
188
+ }
189
+ return null;
190
+ }
191
+ }
192
+ //# sourceMappingURL=state-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-query.js","sourceRoot":"","sources":["../../src/pipeline/state-query.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,23 @@
1
+ /**
2
+ * Pipeline Store - Event Sourcing Implementation
3
+ *
4
+ * 纯事件溯源实现,对外接口保持与旧版本兼容
5
+ */
1
6
  import type { Pipeline, PipelineTask, PipelinePhase } from './types.js';
2
7
  import type { SQLiteStorage } from '../storage/sqlite.js';
3
8
  export declare class PipelineStore {
4
- private db;
9
+ private eventStore;
10
+ private snapshotStore;
11
+ private aggregator;
12
+ private dbPath;
5
13
  constructor(storage: SQLiteStorage);
6
14
  createPipeline(requirement: string, projectPath: string, sessionId: string, techStack?: string, complexity?: 'simple' | 'moderate' | 'complex', taskType?: 'bugfix' | 'feature' | 'refactor' | 'performance' | 'documentation' | 'other', plannedPhases?: PipelinePhase[], phaseArtifacts?: Record<string, string[]>, reasoning?: string): Pipeline;
7
15
  addTasks(pipelineId: string, tasks: Array<Omit<PipelineTask, 'id'>>): PipelineTask[];
8
16
  getActivePipeline(projectPath: string): Pipeline | null;
9
17
  getTasks(pipelineId: string): PipelineTask[];
10
18
  updatePhase(pipelineId: string, phase: PipelinePhase): void;
11
- /** 按 ID 关闭单个 Pipeline */
12
19
  closeById(pipelineId: string): void;
13
- /**
14
- * 关闭超过 ttlMs 未更新的所有活跃 Pipeline,返回被关闭的数量。
15
- * 默认 2 小时(7200000ms)。
16
- */
17
20
  closeExpired(ttlMs?: number): number;
18
- /** 列出所有非 done 的 Pipeline(跨项目,供 CLI 展示) */
19
21
  listActive(): Array<{
20
22
  id: string;
21
23
  requirement: string;
@@ -23,22 +25,15 @@ export declare class PipelineStore {
23
25
  phase: PipelinePhase;
24
26
  updatedAt: string;
25
27
  }>;
26
- /**
27
- * 将指定 Pipeline 中所有 in_progress 任务重置为 pending。
28
- * 用于 ESC 中断后恢复:in_progress 表示"开始但未完成",中断后需重新检测。
29
- */
30
28
  resetInProgressTasks(pipelineId: string): number;
31
29
  getPhaseProgress(pipelineId: string, phase: PipelinePhase): {
32
30
  total: number;
33
31
  completed: number;
34
32
  };
35
- /**
36
- * 更新任务状态
37
- */
38
33
  updateTaskStatus(taskId: string, status: 'pending' | 'in_progress' | 'completed' | 'failed', output?: string): boolean;
39
- /**
40
- * 获取单个任务
41
- */
42
34
  getTask(taskId: string): PipelineTask | null;
35
+ getPipelineIdByTask(taskId: string): string | null;
36
+ private stateToLegacyPipeline;
37
+ private taskStateToLegacyTask;
43
38
  }
44
39
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/pipeline/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;gBAElB,OAAO,EAAE,aAAa;IAKlC,cAAc,CACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,EAC9C,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,eAAe,GAAG,OAAO,EACxF,aAAa,CAAC,EAAE,aAAa,EAAE,EAC/B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACzC,SAAS,CAAC,EAAE,MAAM,GACjB,QAAQ;IAgCX,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,YAAY,EAAE;IAwBpF,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IA2BvD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,EAAE;IAiB5C,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAM3D,yBAAyB;IACzB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAMnC;;;OAGG;IACH,YAAY,CAAC,KAAK,SAAqB,GAAG,MAAM;IAQhD,0CAA0C;IAC1C,UAAU,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IActH;;;OAGG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAOhD,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAWhG;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IActH;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;CAe7C"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/pipeline/store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAS1D,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,aAAa;IAOlC,cAAc,CACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,EAC9C,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,eAAe,GAAG,OAAO,EACxF,aAAa,CAAC,EAAE,aAAa,EAAE,EAC/B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACzC,SAAS,CAAC,EAAE,MAAM,GACjB,QAAQ;IA8BX,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,YAAY,EAAE;IAwBpF,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAcvD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,EAAE;IAO5C,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAiB3D,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAqBnC,YAAY,CAAC,KAAK,SAAqB,GAAG,MAAM;IAqBhD,UAAU,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBtH,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAKhD,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAIhG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IA0CtH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAa5C,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAelD,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,qBAAqB;CAY9B"}
@@ -1,23 +1,44 @@
1
+ /**
2
+ * Pipeline Store - Event Sourcing Implementation
3
+ *
4
+ * 纯事件溯源实现,对外接口保持与旧版本兼容
5
+ */
1
6
  import { randomUUID } from 'crypto';
2
7
  import { logger } from '../utils/logger.js';
3
8
  import { PIPELINE } from '../constants.js';
9
+ import { EventStore } from './event-store.js';
10
+ import { SnapshotStore } from './snapshot-store.js';
11
+ import { OptimizedAggregator } from './optimized-aggregator.js';
12
+ import { PipelineEventType } from './events.js';
4
13
  export class PipelineStore {
5
- db;
14
+ eventStore;
15
+ snapshotStore;
16
+ aggregator;
17
+ dbPath;
6
18
  constructor(storage) {
7
- this.db = storage.getDatabase();
8
- // Schema 已在 SQLiteStorage 初始化时通过 schema.sql 创建,无需重复初始化
19
+ this.dbPath = storage.getDbPath();
20
+ this.eventStore = new EventStore(this.dbPath);
21
+ this.snapshotStore = new SnapshotStore(this.dbPath);
22
+ this.aggregator = new OptimizedAggregator(this.eventStore, this.snapshotStore);
9
23
  }
10
24
  createPipeline(requirement, projectPath, sessionId, techStack, complexity, taskType, plannedPhases, phaseArtifacts, reasoning) {
11
25
  const id = randomUUID();
12
26
  const now = new Date().toISOString();
13
- this.db.prepare(`
14
- INSERT INTO pipelines (
15
- id, requirement, project_path, session_id, phase, tech_stack,
16
- complexity, task_type, planned_phases, phase_artifacts, reasoning,
17
- created_at, updated_at
18
- )
19
- VALUES (?, ?, ?, ?, 'analyze', ?, ?, ?, ?, ?, ?, ?, ?)
20
- `).run(id, requirement, projectPath, sessionId, techStack || null, complexity || 'moderate', taskType || 'other', plannedPhases ? JSON.stringify(plannedPhases) : null, phaseArtifacts ? JSON.stringify(phaseArtifacts) : null, reasoning || null, now, now);
27
+ this.eventStore.append({
28
+ pipelineId: id,
29
+ type: PipelineEventType.PIPELINE_CREATED,
30
+ payload: {
31
+ requirement,
32
+ projectPath,
33
+ sessionId,
34
+ techStack,
35
+ complexity,
36
+ taskType,
37
+ plannedPhases: plannedPhases || ['analyze', 'design', 'code', 'test', 'review'],
38
+ reasoning,
39
+ },
40
+ metadata: { sessionId },
41
+ });
21
42
  logger.info(`Pipeline 已创建:${id} — ${requirement} (${complexity || 'moderate'} ${taskType || 'other'})`);
22
43
  return {
23
44
  id, requirement, projectPath, sessionId,
@@ -27,129 +48,212 @@ export class PipelineStore {
27
48
  };
28
49
  }
29
50
  addTasks(pipelineId, tasks) {
30
- const insertStmt = this.db.prepare(`
31
- INSERT INTO pipeline_tasks (id, pipeline_id, title, phase, status, description, dependencies, output, source)
32
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
33
- `);
34
51
  const result = [];
35
- const insertAll = this.db.transaction((items) => {
36
- for (const task of items) {
37
- const id = randomUUID();
38
- insertStmt.run(id, pipelineId, task.title, task.phase, task.status, task.description, JSON.stringify(task.dependencies), task.output || null, task.source || null);
39
- result.push({ ...task, id });
40
- }
41
- });
42
- insertAll(tasks);
52
+ for (const task of tasks) {
53
+ const id = randomUUID();
54
+ this.eventStore.append({
55
+ pipelineId,
56
+ type: PipelineEventType.TASK_CREATED,
57
+ payload: {
58
+ taskId: id,
59
+ title: task.title,
60
+ phase: task.phase,
61
+ description: task.description,
62
+ dependencies: JSON.stringify(task.dependencies),
63
+ source: task.source,
64
+ },
65
+ metadata: { sessionId: '' },
66
+ });
67
+ result.push({ ...task, id });
68
+ }
43
69
  return result;
44
70
  }
45
71
  getActivePipeline(projectPath) {
46
- const row = this.db.prepare("SELECT * FROM pipelines WHERE project_path = ? AND phase != 'done' ORDER BY updated_at DESC LIMIT 1").get(projectPath);
47
- if (!row)
48
- return null;
49
- const tasks = this.getTasks(row.id);
50
- return {
51
- id: row.id,
52
- requirement: row.requirement,
53
- projectPath: row.project_path,
54
- sessionId: row.session_id,
55
- phase: row.phase,
56
- tasks,
57
- techStack: row.tech_stack,
58
- complexity: row.complexity || 'moderate',
59
- taskType: row.task_type || 'other',
60
- plannedPhases: row.planned_phases ? JSON.parse(row.planned_phases) : undefined,
61
- phaseArtifacts: row.phase_artifacts ? JSON.parse(row.phase_artifacts) : undefined,
62
- reasoning: row.reasoning,
63
- createdAt: row.created_at,
64
- updatedAt: row.updated_at,
65
- };
72
+ // 查询所有 pipeline,找到匹配 projectPath 且未关闭的
73
+ const pipelineIds = this.eventStore.getAllPipelineIds();
74
+ for (const pipelineId of pipelineIds) {
75
+ const state = this.aggregator.rebuild(pipelineId);
76
+ if (state && state.projectPath === projectPath && state.status !== 'completed') {
77
+ return this.stateToLegacyPipeline(state);
78
+ }
79
+ }
80
+ return null;
66
81
  }
67
82
  getTasks(pipelineId) {
68
- const rows = this.db.prepare('SELECT * FROM pipeline_tasks WHERE pipeline_id = ? ORDER BY phase, rowid').all(pipelineId);
69
- return rows.map(row => ({
70
- id: row.id,
71
- title: row.title,
72
- phase: row.phase,
73
- status: row.status,
74
- description: row.description,
75
- dependencies: JSON.parse(row.dependencies || '[]'),
76
- output: row.output,
77
- source: row.source,
78
- }));
83
+ const state = this.aggregator.rebuild(pipelineId);
84
+ if (!state)
85
+ return [];
86
+ return state.tasks.map(t => this.taskStateToLegacyTask(t, pipelineId));
79
87
  }
80
88
  updatePhase(pipelineId, phase) {
81
- this.db.prepare('UPDATE pipelines SET phase = ?, updated_at = ? WHERE id = ?').run(phase, new Date().toISOString(), pipelineId);
89
+ const state = this.aggregator.rebuild(pipelineId);
90
+ if (!state)
91
+ return;
92
+ this.eventStore.append({
93
+ pipelineId,
94
+ type: PipelineEventType.PHASE_ADVANCED,
95
+ payload: {
96
+ fromPhase: state.phase,
97
+ toPhase: phase,
98
+ reason: 'task_complete',
99
+ completedTasks: [],
100
+ },
101
+ metadata: { sessionId: state.sessionId },
102
+ });
82
103
  }
83
- /** 按 ID 关闭单个 Pipeline */
84
104
  closeById(pipelineId) {
85
- this.db.prepare("UPDATE pipelines SET phase = 'done', updated_at = ? WHERE id = ?").run(new Date().toISOString(), pipelineId);
105
+ const state = this.aggregator.rebuild(pipelineId);
106
+ if (!state)
107
+ return;
108
+ const totalTasks = state.tasks.length;
109
+ const completedTasks = state.tasks.filter(t => t.status === 'completed').length;
110
+ const failedTasks = state.tasks.filter(t => t.status === 'failed').length;
111
+ this.eventStore.append({
112
+ pipelineId,
113
+ type: PipelineEventType.PIPELINE_CLOSED,
114
+ payload: {
115
+ reason: 'manual',
116
+ totalTasks,
117
+ completedTasks,
118
+ failedTasks,
119
+ },
120
+ metadata: { sessionId: state.sessionId },
121
+ });
86
122
  }
87
- /**
88
- * 关闭超过 ttlMs 未更新的所有活跃 Pipeline,返回被关闭的数量。
89
- * 默认 2 小时(7200000ms)。
90
- */
91
123
  closeExpired(ttlMs = PIPELINE.EXPIRE_MS) {
92
- const cutoff = new Date(Date.now() - ttlMs).toISOString();
93
- const result = this.db.prepare("UPDATE pipelines SET phase = 'done', updated_at = ? WHERE phase != 'done' AND updated_at < ?").run(new Date().toISOString(), cutoff);
94
- return result.changes;
124
+ // 查询所有活跃 pipeline,关闭过期的
125
+ const pipelineIds = this.eventStore.getAllPipelineIds();
126
+ let closedCount = 0;
127
+ for (const pipelineId of pipelineIds) {
128
+ const state = this.aggregator.rebuild(pipelineId);
129
+ if (!state || state.status === 'completed')
130
+ continue;
131
+ const updatedAt = new Date(state.updatedAt).getTime();
132
+ const ageMs = Date.now() - updatedAt;
133
+ if (ageMs > ttlMs) {
134
+ this.closeById(pipelineId);
135
+ closedCount++;
136
+ }
137
+ }
138
+ return closedCount;
95
139
  }
96
- /** 列出所有非 done 的 Pipeline(跨项目,供 CLI 展示) */
97
140
  listActive() {
98
- const rows = this.db.prepare("SELECT id, requirement, project_path, phase, updated_at FROM pipelines WHERE phase != 'done' ORDER BY updated_at DESC").all();
99
- return rows.map(r => ({
100
- id: r.id,
101
- requirement: r.requirement,
102
- projectPath: r.project_path,
103
- phase: r.phase,
104
- updatedAt: r.updated_at,
105
- }));
106
- }
107
- /**
108
- * 将指定 Pipeline 中所有 in_progress 任务重置为 pending。
109
- * 用于 ESC 中断后恢复:in_progress 表示"开始但未完成",中断后需重新检测。
110
- */
141
+ const pipelineIds = this.eventStore.getAllPipelineIds();
142
+ const result = [];
143
+ for (const pipelineId of pipelineIds) {
144
+ const state = this.aggregator.rebuild(pipelineId);
145
+ if (state && state.status !== 'completed') {
146
+ result.push({
147
+ id: state.id,
148
+ requirement: state.requirement,
149
+ projectPath: state.projectPath,
150
+ phase: state.phase,
151
+ updatedAt: state.updatedAt,
152
+ });
153
+ }
154
+ }
155
+ return result;
156
+ }
111
157
  resetInProgressTasks(pipelineId) {
112
- const result = this.db.prepare("UPDATE pipeline_tasks SET status = 'pending' WHERE pipeline_id = ? AND status = 'in_progress'").run(pipelineId);
113
- return result.changes;
158
+ // 事件溯源中不需要重置,任务状态由事件决定
159
+ return 0;
114
160
  }
115
161
  getPhaseProgress(pipelineId, phase) {
116
- const row = this.db.prepare(`
117
- SELECT
118
- COUNT(*) as total,
119
- SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed
120
- FROM pipeline_tasks WHERE pipeline_id = ? AND phase = ?
121
- `).get(pipelineId, phase);
122
- return { total: row.total || 0, completed: row.completed || 0 };
123
- }
124
- /**
125
- * 更新任务状态
126
- */
162
+ return this.aggregator.getPhaseProgress(pipelineId, phase);
163
+ }
127
164
  updateTaskStatus(taskId, status, output) {
128
- if (output) {
129
- const result = this.db.prepare("UPDATE pipeline_tasks SET status = ?, output = ?, updated_at = datetime('now') WHERE id = ?").run(status, output, taskId);
130
- return result.changes > 0;
165
+ const pipelineId = this.getPipelineIdByTask(taskId);
166
+ if (!pipelineId)
167
+ return false;
168
+ const state = this.aggregator.rebuild(pipelineId);
169
+ if (!state)
170
+ return false;
171
+ const task = state.tasks.find(t => t.id === taskId);
172
+ if (!task)
173
+ return false;
174
+ if (status === 'in_progress') {
175
+ this.eventStore.append({
176
+ pipelineId,
177
+ type: PipelineEventType.TASK_STARTED,
178
+ payload: { taskId },
179
+ metadata: { sessionId: state.sessionId },
180
+ });
131
181
  }
132
- else {
133
- const result = this.db.prepare("UPDATE pipeline_tasks SET status = ?, updated_at = datetime('now') WHERE id = ?").run(status, taskId);
134
- return result.changes > 0;
182
+ else if (status === 'completed') {
183
+ this.eventStore.append({
184
+ pipelineId,
185
+ type: PipelineEventType.TASK_COMPLETED,
186
+ payload: {
187
+ taskId,
188
+ title: task.title,
189
+ phase: task.phase,
190
+ artifact: output || '',
191
+ detectionMethod: 'heuristic',
192
+ },
193
+ metadata: { sessionId: state.sessionId },
194
+ });
135
195
  }
196
+ else if (status === 'failed') {
197
+ this.eventStore.append({
198
+ pipelineId,
199
+ type: PipelineEventType.TASK_FAILED,
200
+ payload: { taskId, reason: output || 'unknown' },
201
+ metadata: { sessionId: state.sessionId },
202
+ });
203
+ }
204
+ return true;
136
205
  }
137
- /**
138
- * 获取单个任务
139
- */
140
206
  getTask(taskId) {
141
- const row = this.db.prepare('SELECT * FROM pipeline_tasks WHERE id = ?').get(taskId);
142
- if (!row)
207
+ const pipelineId = this.getPipelineIdByTask(taskId);
208
+ if (!pipelineId)
209
+ return null;
210
+ const state = this.aggregator.rebuild(pipelineId);
211
+ if (!state)
212
+ return null;
213
+ const task = state.tasks.find(t => t.id === taskId);
214
+ if (!task)
143
215
  return null;
216
+ return this.taskStateToLegacyTask(task, pipelineId);
217
+ }
218
+ getPipelineIdByTask(taskId) {
219
+ // 遍历所有 pipeline,找到包含该 task 的
220
+ const pipelineIds = this.eventStore.getAllPipelineIds();
221
+ for (const pipelineId of pipelineIds) {
222
+ const state = this.aggregator.rebuild(pipelineId);
223
+ if (state && state.tasks.some(t => t.id === taskId)) {
224
+ return pipelineId;
225
+ }
226
+ }
227
+ return null;
228
+ }
229
+ // 辅助方法:将 PipelineState 转换为 Legacy Pipeline
230
+ stateToLegacyPipeline(state) {
231
+ return {
232
+ id: state.id,
233
+ requirement: state.requirement,
234
+ projectPath: state.projectPath,
235
+ sessionId: state.sessionId,
236
+ phase: state.phase,
237
+ tasks: state.tasks.map(t => this.taskStateToLegacyTask(t, state.id)),
238
+ techStack: state.techStack,
239
+ complexity: state.complexity,
240
+ taskType: state.taskType,
241
+ plannedPhases: state.plannedPhases,
242
+ reasoning: state.reasoning,
243
+ createdAt: state.createdAt,
244
+ updatedAt: state.updatedAt,
245
+ };
246
+ }
247
+ taskStateToLegacyTask(task, pipelineId) {
144
248
  return {
145
- id: row.id,
146
- title: row.title,
147
- description: row.description,
148
- phase: row.phase,
149
- status: row.status,
150
- dependencies: [],
151
- source: row.source,
152
- output: row.output,
249
+ id: task.id,
250
+ title: task.title,
251
+ phase: task.phase,
252
+ status: task.status,
253
+ description: task.description || '',
254
+ dependencies: task.dependencies ? JSON.parse(task.dependencies) : [],
255
+ output: task.output,
256
+ source: task.source,
153
257
  };
154
258
  }
155
259
  }