@litmers/cursorflow-orchestrator 0.1.40 → 0.2.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.
Files changed (214) hide show
  1. package/CHANGELOG.md +0 -2
  2. package/README.md +8 -3
  3. package/commands/cursorflow-init.md +0 -4
  4. package/dist/cli/index.js +0 -6
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/logs.js +108 -9
  7. package/dist/cli/logs.js.map +1 -1
  8. package/dist/cli/models.js +20 -3
  9. package/dist/cli/models.js.map +1 -1
  10. package/dist/cli/monitor.d.ts +7 -10
  11. package/dist/cli/monitor.js +1103 -1239
  12. package/dist/cli/monitor.js.map +1 -1
  13. package/dist/cli/resume.js +21 -1
  14. package/dist/cli/resume.js.map +1 -1
  15. package/dist/cli/run.js +28 -9
  16. package/dist/cli/run.js.map +1 -1
  17. package/dist/cli/signal.d.ts +6 -1
  18. package/dist/cli/signal.js +99 -13
  19. package/dist/cli/signal.js.map +1 -1
  20. package/dist/cli/tasks.js +3 -46
  21. package/dist/cli/tasks.js.map +1 -1
  22. package/dist/core/agent-supervisor.d.ts +23 -0
  23. package/dist/core/agent-supervisor.js +42 -0
  24. package/dist/core/agent-supervisor.js.map +1 -0
  25. package/dist/core/auto-recovery.d.ts +3 -117
  26. package/dist/core/auto-recovery.js +4 -482
  27. package/dist/core/auto-recovery.js.map +1 -1
  28. package/dist/core/failure-policy.d.ts +0 -53
  29. package/dist/core/failure-policy.js +7 -175
  30. package/dist/core/failure-policy.js.map +1 -1
  31. package/dist/core/git-lifecycle-manager.d.ts +284 -0
  32. package/dist/core/git-lifecycle-manager.js +778 -0
  33. package/dist/core/git-lifecycle-manager.js.map +1 -0
  34. package/dist/core/git-pipeline-coordinator.d.ts +21 -0
  35. package/dist/core/git-pipeline-coordinator.js +205 -0
  36. package/dist/core/git-pipeline-coordinator.js.map +1 -0
  37. package/dist/core/intervention.d.ts +170 -0
  38. package/dist/core/intervention.js +408 -0
  39. package/dist/core/intervention.js.map +1 -0
  40. package/dist/core/lane-state-machine.d.ts +423 -0
  41. package/dist/core/lane-state-machine.js +890 -0
  42. package/dist/core/lane-state-machine.js.map +1 -0
  43. package/dist/core/orchestrator.d.ts +4 -1
  44. package/dist/core/orchestrator.js +39 -65
  45. package/dist/core/orchestrator.js.map +1 -1
  46. package/dist/core/runner/agent.d.ts +7 -1
  47. package/dist/core/runner/agent.js +54 -36
  48. package/dist/core/runner/agent.js.map +1 -1
  49. package/dist/core/runner/pipeline.js +283 -123
  50. package/dist/core/runner/pipeline.js.map +1 -1
  51. package/dist/core/runner/task.d.ts +4 -5
  52. package/dist/core/runner/task.js +6 -80
  53. package/dist/core/runner/task.js.map +1 -1
  54. package/dist/core/runner.js +8 -2
  55. package/dist/core/runner.js.map +1 -1
  56. package/dist/core/stall-detection.d.ts +11 -4
  57. package/dist/core/stall-detection.js +64 -27
  58. package/dist/core/stall-detection.js.map +1 -1
  59. package/dist/hooks/contexts/index.d.ts +104 -0
  60. package/dist/hooks/contexts/index.js +134 -0
  61. package/dist/hooks/contexts/index.js.map +1 -0
  62. package/dist/hooks/data-accessor.d.ts +86 -0
  63. package/dist/hooks/data-accessor.js +410 -0
  64. package/dist/hooks/data-accessor.js.map +1 -0
  65. package/dist/hooks/flow-controller.d.ts +136 -0
  66. package/dist/hooks/flow-controller.js +351 -0
  67. package/dist/hooks/flow-controller.js.map +1 -0
  68. package/dist/hooks/index.d.ts +68 -0
  69. package/dist/hooks/index.js +105 -0
  70. package/dist/hooks/index.js.map +1 -0
  71. package/dist/hooks/manager.d.ts +129 -0
  72. package/dist/hooks/manager.js +389 -0
  73. package/dist/hooks/manager.js.map +1 -0
  74. package/dist/hooks/types.d.ts +463 -0
  75. package/dist/hooks/types.js +45 -0
  76. package/dist/hooks/types.js.map +1 -0
  77. package/dist/services/logging/buffer.d.ts +2 -2
  78. package/dist/services/logging/buffer.js +95 -42
  79. package/dist/services/logging/buffer.js.map +1 -1
  80. package/dist/services/logging/console.js +6 -1
  81. package/dist/services/logging/console.js.map +1 -1
  82. package/dist/services/logging/formatter.d.ts +9 -4
  83. package/dist/services/logging/formatter.js +64 -18
  84. package/dist/services/logging/formatter.js.map +1 -1
  85. package/dist/services/logging/index.d.ts +0 -1
  86. package/dist/services/logging/index.js +0 -1
  87. package/dist/services/logging/index.js.map +1 -1
  88. package/dist/services/logging/paths.d.ts +8 -0
  89. package/dist/services/logging/paths.js +48 -0
  90. package/dist/services/logging/paths.js.map +1 -0
  91. package/dist/services/logging/raw-log.d.ts +6 -0
  92. package/dist/services/logging/raw-log.js +37 -0
  93. package/dist/services/logging/raw-log.js.map +1 -0
  94. package/dist/services/process/index.js +1 -1
  95. package/dist/services/process/index.js.map +1 -1
  96. package/dist/types/agent.d.ts +15 -0
  97. package/dist/types/config.d.ts +22 -1
  98. package/dist/types/event-categories.d.ts +601 -0
  99. package/dist/types/event-categories.js +233 -0
  100. package/dist/types/event-categories.js.map +1 -0
  101. package/dist/types/events.d.ts +0 -20
  102. package/dist/types/flow.d.ts +10 -6
  103. package/dist/types/index.d.ts +1 -1
  104. package/dist/types/index.js +17 -3
  105. package/dist/types/index.js.map +1 -1
  106. package/dist/types/lane.d.ts +1 -1
  107. package/dist/types/logging.d.ts +1 -1
  108. package/dist/types/task.d.ts +12 -1
  109. package/dist/ui/log-viewer.d.ts +3 -0
  110. package/dist/ui/log-viewer.js +3 -0
  111. package/dist/ui/log-viewer.js.map +1 -1
  112. package/dist/utils/config.js +10 -1
  113. package/dist/utils/config.js.map +1 -1
  114. package/dist/utils/cursor-agent.d.ts +11 -1
  115. package/dist/utils/cursor-agent.js +63 -16
  116. package/dist/utils/cursor-agent.js.map +1 -1
  117. package/dist/utils/enhanced-logger.d.ts +5 -1
  118. package/dist/utils/enhanced-logger.js +98 -19
  119. package/dist/utils/enhanced-logger.js.map +1 -1
  120. package/dist/utils/event-registry.d.ts +222 -0
  121. package/dist/utils/event-registry.js +463 -0
  122. package/dist/utils/event-registry.js.map +1 -0
  123. package/dist/utils/events.d.ts +1 -13
  124. package/dist/utils/events.js.map +1 -1
  125. package/dist/utils/flow.d.ts +10 -0
  126. package/dist/utils/flow.js +75 -0
  127. package/dist/utils/flow.js.map +1 -1
  128. package/dist/utils/log-constants.d.ts +1 -0
  129. package/dist/utils/log-constants.js +2 -1
  130. package/dist/utils/log-constants.js.map +1 -1
  131. package/dist/utils/log-formatter.d.ts +2 -1
  132. package/dist/utils/log-formatter.js +10 -10
  133. package/dist/utils/log-formatter.js.map +1 -1
  134. package/dist/utils/logger.d.ts +11 -0
  135. package/dist/utils/logger.js +82 -3
  136. package/dist/utils/logger.js.map +1 -1
  137. package/dist/utils/repro-thinking-logs.js +0 -13
  138. package/dist/utils/repro-thinking-logs.js.map +1 -1
  139. package/dist/utils/run-service.js +1 -1
  140. package/dist/utils/run-service.js.map +1 -1
  141. package/examples/README.md +0 -2
  142. package/examples/demo-project/README.md +1 -2
  143. package/package.json +13 -34
  144. package/scripts/setup-security.sh +0 -1
  145. package/scripts/test-log-parser.ts +171 -0
  146. package/scripts/verify-change.sh +272 -0
  147. package/src/cli/index.ts +0 -6
  148. package/src/cli/logs.ts +121 -10
  149. package/src/cli/models.ts +20 -3
  150. package/src/cli/monitor.ts +1273 -1342
  151. package/src/cli/resume.ts +27 -1
  152. package/src/cli/run.ts +29 -11
  153. package/src/cli/signal.ts +120 -18
  154. package/src/cli/tasks.ts +2 -59
  155. package/src/core/agent-supervisor.ts +64 -0
  156. package/src/core/auto-recovery.ts +14 -590
  157. package/src/core/failure-policy.ts +7 -229
  158. package/src/core/git-lifecycle-manager.ts +1011 -0
  159. package/src/core/git-pipeline-coordinator.ts +221 -0
  160. package/src/core/intervention.ts +463 -0
  161. package/src/core/lane-state-machine.ts +1097 -0
  162. package/src/core/orchestrator.ts +48 -64
  163. package/src/core/runner/agent.ts +77 -39
  164. package/src/core/runner/pipeline.ts +318 -138
  165. package/src/core/runner/task.ts +12 -97
  166. package/src/core/runner.ts +8 -2
  167. package/src/core/stall-detection.ts +74 -27
  168. package/src/hooks/contexts/index.ts +256 -0
  169. package/src/hooks/data-accessor.ts +488 -0
  170. package/src/hooks/flow-controller.ts +425 -0
  171. package/src/hooks/index.ts +154 -0
  172. package/src/hooks/manager.ts +434 -0
  173. package/src/hooks/types.ts +544 -0
  174. package/src/services/logging/buffer.ts +104 -43
  175. package/src/services/logging/console.ts +7 -1
  176. package/src/services/logging/formatter.ts +74 -18
  177. package/src/services/logging/index.ts +0 -2
  178. package/src/services/logging/paths.ts +14 -0
  179. package/src/services/logging/raw-log.ts +43 -0
  180. package/src/services/process/index.ts +1 -1
  181. package/src/types/agent.ts +15 -0
  182. package/src/types/config.ts +23 -1
  183. package/src/types/event-categories.ts +663 -0
  184. package/src/types/events.ts +0 -25
  185. package/src/types/flow.ts +10 -6
  186. package/src/types/index.ts +50 -4
  187. package/src/types/lane.ts +1 -2
  188. package/src/types/logging.ts +2 -1
  189. package/src/types/task.ts +12 -1
  190. package/src/ui/log-viewer.ts +3 -0
  191. package/src/utils/config.ts +11 -1
  192. package/src/utils/cursor-agent.ts +68 -16
  193. package/src/utils/enhanced-logger.ts +105 -19
  194. package/src/utils/event-registry.ts +595 -0
  195. package/src/utils/events.ts +0 -16
  196. package/src/utils/flow.ts +83 -0
  197. package/src/utils/log-constants.ts +2 -1
  198. package/src/utils/log-formatter.ts +10 -11
  199. package/src/utils/logger.ts +49 -3
  200. package/src/utils/repro-thinking-logs.ts +0 -15
  201. package/src/utils/run-service.ts +1 -1
  202. package/dist/cli/prepare.d.ts +0 -7
  203. package/dist/cli/prepare.js +0 -690
  204. package/dist/cli/prepare.js.map +0 -1
  205. package/dist/services/logging/file-writer.d.ts +0 -71
  206. package/dist/services/logging/file-writer.js +0 -516
  207. package/dist/services/logging/file-writer.js.map +0 -1
  208. package/dist/types/review.d.ts +0 -17
  209. package/dist/types/review.js +0 -6
  210. package/dist/types/review.js.map +0 -1
  211. package/scripts/ai-security-check.js +0 -233
  212. package/src/cli/prepare.ts +0 -777
  213. package/src/services/logging/file-writer.ts +0 -526
  214. package/src/types/review.ts +0 -20
@@ -0,0 +1,595 @@
1
+ /**
2
+ * Event Registry - 타입화된 이벤트 버스
3
+ *
4
+ * 기존 events.ts를 확장하여 타입 안전한 이벤트 발행/구독을 제공합니다.
5
+ *
6
+ * 특징:
7
+ * - 타입 안전한 이벤트 발행/구독
8
+ * - 카테고리별 이벤트 필터링
9
+ * - 이벤트 히스토리 관리
10
+ * - 이벤트 직렬화/역직렬화
11
+ */
12
+
13
+ import { EventEmitter } from 'events';
14
+ import {
15
+ EventCategory,
16
+ AllEventTypes,
17
+ EventPayloadMap,
18
+ TypedCursorFlowEvent,
19
+ TypedEventHandler,
20
+ GenericEventHandler,
21
+ getCategoryFromEventType,
22
+
23
+ // Event Types
24
+ OrchestrationEventType,
25
+ LaneEventType,
26
+ TaskEventType,
27
+ GitEventType,
28
+ RecoveryEventType,
29
+ AgentEventType,
30
+ StateEventType,
31
+ SystemEventType,
32
+ } from '../types/event-categories';
33
+
34
+ // ============================================================================
35
+ // Event Registry Configuration
36
+ // ============================================================================
37
+
38
+ /**
39
+ * 이벤트 레지스트리 설정
40
+ */
41
+ export interface EventRegistryConfig {
42
+ /** 이벤트 히스토리 최대 크기 (0 = 무제한) */
43
+ maxHistorySize: number;
44
+ /** 이벤트 히스토리 유지 시간 (ms, 0 = 영구) */
45
+ historyTtlMs: number;
46
+ /** 디버그 모드 */
47
+ debug: boolean;
48
+ /** 이벤트 발행 시 콘솔 출력 */
49
+ logEvents: boolean;
50
+ /** 로그할 이벤트 카테고리 (빈 배열 = 모두) */
51
+ logCategories: EventCategory[];
52
+ }
53
+
54
+ const DEFAULT_CONFIG: EventRegistryConfig = {
55
+ maxHistorySize: 1000,
56
+ historyTtlMs: 30 * 60 * 1000, // 30분
57
+ debug: false,
58
+ logEvents: false,
59
+ logCategories: [],
60
+ };
61
+
62
+ // ============================================================================
63
+ // Event Registry
64
+ // ============================================================================
65
+
66
+ /**
67
+ * 타입화된 이벤트 레지스트리
68
+ *
69
+ * 사용 예:
70
+ * ```typescript
71
+ * const registry = EventRegistry.getInstance();
72
+ *
73
+ * // 타입 안전한 이벤트 발행
74
+ * registry.emit(OrchestrationEventType.STARTED, {
75
+ * runId: 'run-123',
76
+ * tasksDir: '/path/to/tasks',
77
+ * laneCount: 3,
78
+ * runRoot: '/path/to/run'
79
+ * });
80
+ *
81
+ * // 타입 안전한 이벤트 구독
82
+ * registry.on(LaneEventType.COMPLETED, (event) => {
83
+ * console.log(event.payload.laneName, event.payload.exitCode);
84
+ * });
85
+ *
86
+ * // 카테고리별 구독
87
+ * registry.onCategory(EventCategory.GIT, (event) => {
88
+ * console.log('Git event:', event.type);
89
+ * });
90
+ *
91
+ * // 와일드카드 구독
92
+ * registry.onAny((event) => {
93
+ * console.log('Any event:', event.type);
94
+ * });
95
+ * ```
96
+ */
97
+ export class EventRegistry extends EventEmitter {
98
+ private static instance: EventRegistry | null = null;
99
+
100
+ private config: EventRegistryConfig;
101
+ private runId: string = '';
102
+ private eventHistory: TypedCursorFlowEvent[] = [];
103
+ private categoryHandlers: Map<EventCategory, GenericEventHandler[]> = new Map();
104
+
105
+ private constructor(config: Partial<EventRegistryConfig> = {}) {
106
+ super();
107
+ this.config = { ...DEFAULT_CONFIG, ...config };
108
+ this.setMaxListeners(100); // 많은 리스너 허용
109
+ }
110
+
111
+ /**
112
+ * 싱글톤 인스턴스 획득
113
+ */
114
+ static getInstance(config?: Partial<EventRegistryConfig>): EventRegistry {
115
+ if (!EventRegistry.instance) {
116
+ EventRegistry.instance = new EventRegistry(config);
117
+ } else if (config) {
118
+ EventRegistry.instance.updateConfig(config);
119
+ }
120
+ return EventRegistry.instance;
121
+ }
122
+
123
+ /**
124
+ * 인스턴스 리셋 (테스트용)
125
+ */
126
+ static resetInstance(): void {
127
+ EventRegistry.instance = null;
128
+ }
129
+
130
+ /**
131
+ * 설정 업데이트
132
+ */
133
+ updateConfig(config: Partial<EventRegistryConfig>): void {
134
+ this.config = { ...this.config, ...config };
135
+ }
136
+
137
+ /**
138
+ * Run ID 설정
139
+ */
140
+ setRunId(id: string): void {
141
+ this.runId = id;
142
+ }
143
+
144
+ /**
145
+ * Run ID 조회
146
+ */
147
+ getRunId(): string {
148
+ return this.runId;
149
+ }
150
+
151
+ // --------------------------------------------------------------------------
152
+ // Type-safe Event Emission
153
+ // --------------------------------------------------------------------------
154
+
155
+ /**
156
+ * 타입 안전한 이벤트 발행
157
+ */
158
+ emit<T extends keyof EventPayloadMap>(
159
+ type: T,
160
+ payload: EventPayloadMap[T],
161
+ options: { laneName?: string } = {}
162
+ ): boolean {
163
+ const category = getCategoryFromEventType(type as string);
164
+
165
+ const event: TypedCursorFlowEvent<T> = {
166
+ id: this.generateEventId(),
167
+ type,
168
+ category,
169
+ timestamp: new Date().toISOString(),
170
+ runId: this.runId,
171
+ laneName: options.laneName || this.extractLaneName(payload),
172
+ payload,
173
+ };
174
+
175
+ // 히스토리에 추가
176
+ this.addToHistory(event as TypedCursorFlowEvent);
177
+
178
+ // 디버그 로깅
179
+ if (this.config.logEvents && this.shouldLogEvent(category)) {
180
+ this.logEvent(event as TypedCursorFlowEvent);
181
+ }
182
+
183
+ // 이벤트 발행
184
+ super.emit(type as string, event);
185
+
186
+ // 카테고리별 핸들러 호출
187
+ const categoryHandlers = this.categoryHandlers.get(category);
188
+ if (categoryHandlers) {
189
+ for (const handler of categoryHandlers) {
190
+ try {
191
+ handler(event as TypedCursorFlowEvent);
192
+ } catch (error) {
193
+ console.error(`Event handler error for ${type}:`, error);
194
+ }
195
+ }
196
+ }
197
+
198
+ // 와일드카드 패턴 발행
199
+ super.emit(`${category}.*`, event);
200
+ super.emit('*', event);
201
+
202
+ return true;
203
+ }
204
+
205
+ /**
206
+ * 이벤트 ID 생성
207
+ */
208
+ private generateEventId(): string {
209
+ return `evt_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
210
+ }
211
+
212
+ /**
213
+ * 페이로드에서 laneName 추출
214
+ */
215
+ private extractLaneName(payload: any): string | undefined {
216
+ if (typeof payload === 'object' && payload !== null) {
217
+ return payload.laneName;
218
+ }
219
+ return undefined;
220
+ }
221
+
222
+ // --------------------------------------------------------------------------
223
+ // Type-safe Event Subscription
224
+ // --------------------------------------------------------------------------
225
+
226
+ /**
227
+ * 타입 안전한 이벤트 구독
228
+ */
229
+ on<T extends keyof EventPayloadMap>(
230
+ type: T,
231
+ handler: TypedEventHandler<T>
232
+ ): this {
233
+ return super.on(type as string, handler);
234
+ }
235
+
236
+ /**
237
+ * 일회성 이벤트 구독
238
+ */
239
+ once<T extends keyof EventPayloadMap>(
240
+ type: T,
241
+ handler: TypedEventHandler<T>
242
+ ): this {
243
+ return super.once(type as string, handler);
244
+ }
245
+
246
+ /**
247
+ * 이벤트 구독 해제
248
+ */
249
+ off<T extends keyof EventPayloadMap>(
250
+ type: T,
251
+ handler: TypedEventHandler<T>
252
+ ): this {
253
+ return super.off(type as string, handler);
254
+ }
255
+
256
+ /**
257
+ * 카테고리별 이벤트 구독
258
+ */
259
+ onCategory(category: EventCategory, handler: GenericEventHandler): () => void {
260
+ if (!this.categoryHandlers.has(category)) {
261
+ this.categoryHandlers.set(category, []);
262
+ }
263
+ this.categoryHandlers.get(category)!.push(handler);
264
+
265
+ // 와일드카드 패턴도 등록
266
+ super.on(`${category}.*`, handler);
267
+
268
+ // 구독 해제 함수 반환
269
+ return () => {
270
+ const handlers = this.categoryHandlers.get(category);
271
+ if (handlers) {
272
+ const index = handlers.indexOf(handler);
273
+ if (index > -1) {
274
+ handlers.splice(index, 1);
275
+ }
276
+ }
277
+ super.off(`${category}.*`, handler);
278
+ };
279
+ }
280
+
281
+ /**
282
+ * 모든 이벤트 구독
283
+ */
284
+ onAny(handler: GenericEventHandler): () => void {
285
+ super.on('*', handler);
286
+
287
+ return () => {
288
+ super.off('*', handler);
289
+ };
290
+ }
291
+
292
+ // --------------------------------------------------------------------------
293
+ // Event History
294
+ // --------------------------------------------------------------------------
295
+
296
+ /**
297
+ * 히스토리에 이벤트 추가
298
+ */
299
+ private addToHistory(event: TypedCursorFlowEvent): void {
300
+ this.eventHistory.push(event);
301
+
302
+ // 크기 제한 적용
303
+ if (this.config.maxHistorySize > 0 && this.eventHistory.length > this.config.maxHistorySize) {
304
+ this.eventHistory = this.eventHistory.slice(-this.config.maxHistorySize);
305
+ }
306
+
307
+ // TTL 적용
308
+ if (this.config.historyTtlMs > 0) {
309
+ const cutoffTime = Date.now() - this.config.historyTtlMs;
310
+ this.eventHistory = this.eventHistory.filter(
311
+ e => new Date(e.timestamp).getTime() > cutoffTime
312
+ );
313
+ }
314
+ }
315
+
316
+ /**
317
+ * 이벤트 히스토리 조회
318
+ */
319
+ getHistory(options: {
320
+ category?: EventCategory;
321
+ laneName?: string;
322
+ type?: string;
323
+ since?: number;
324
+ limit?: number;
325
+ } = {}): TypedCursorFlowEvent[] {
326
+ let result = this.eventHistory;
327
+
328
+ if (options.category) {
329
+ result = result.filter(e => e.category === options.category);
330
+ }
331
+
332
+ if (options.laneName) {
333
+ result = result.filter(e => e.laneName === options.laneName);
334
+ }
335
+
336
+ if (options.type) {
337
+ result = result.filter(e => e.type === options.type);
338
+ }
339
+
340
+ if (options.since) {
341
+ result = result.filter(e => new Date(e.timestamp).getTime() >= options.since!);
342
+ }
343
+
344
+ if (options.limit) {
345
+ result = result.slice(-options.limit);
346
+ }
347
+
348
+ return result;
349
+ }
350
+
351
+ /**
352
+ * Lane별 이벤트 히스토리 조회
353
+ */
354
+ getLaneHistory(laneName: string, limit?: number): TypedCursorFlowEvent[] {
355
+ return this.getHistory({ laneName, limit });
356
+ }
357
+
358
+ /**
359
+ * 카테고리별 이벤트 히스토리 조회
360
+ */
361
+ getCategoryHistory(category: EventCategory, limit?: number): TypedCursorFlowEvent[] {
362
+ return this.getHistory({ category, limit });
363
+ }
364
+
365
+ /**
366
+ * 히스토리 초기화
367
+ */
368
+ clearHistory(): void {
369
+ this.eventHistory = [];
370
+ }
371
+
372
+ // --------------------------------------------------------------------------
373
+ // Event Logging
374
+ // --------------------------------------------------------------------------
375
+
376
+ /**
377
+ * 이벤트 로깅 여부 결정
378
+ */
379
+ private shouldLogEvent(category: EventCategory): boolean {
380
+ if (this.config.logCategories.length === 0) {
381
+ return true;
382
+ }
383
+ return this.config.logCategories.includes(category);
384
+ }
385
+
386
+ /**
387
+ * 이벤트 로깅
388
+ */
389
+ private logEvent(event: TypedCursorFlowEvent): void {
390
+ const { type, category, laneName, timestamp } = event;
391
+ const laneLabel = laneName ? `[${laneName}]` : '';
392
+ console.log(`[Event] ${timestamp} ${category}.${type.split('.')[1]} ${laneLabel}`);
393
+
394
+ if (this.config.debug) {
395
+ console.log(' Payload:', JSON.stringify(event.payload, null, 2));
396
+ }
397
+ }
398
+
399
+ // --------------------------------------------------------------------------
400
+ // Event Serialization
401
+ // --------------------------------------------------------------------------
402
+
403
+ /**
404
+ * 이벤트를 JSON으로 직렬화
405
+ */
406
+ serializeEvent(event: TypedCursorFlowEvent): string {
407
+ return JSON.stringify(event);
408
+ }
409
+
410
+ /**
411
+ * JSON에서 이벤트 역직렬화
412
+ */
413
+ deserializeEvent(json: string): TypedCursorFlowEvent | null {
414
+ try {
415
+ return JSON.parse(json) as TypedCursorFlowEvent;
416
+ } catch {
417
+ return null;
418
+ }
419
+ }
420
+
421
+ /**
422
+ * 히스토리를 JSONL 형식으로 내보내기
423
+ */
424
+ exportHistory(): string {
425
+ return this.eventHistory.map(e => JSON.stringify(e)).join('\n');
426
+ }
427
+
428
+ /**
429
+ * JSONL에서 히스토리 가져오기
430
+ */
431
+ importHistory(jsonl: string): number {
432
+ const lines = jsonl.split('\n').filter(l => l.trim());
433
+ let imported = 0;
434
+
435
+ for (const line of lines) {
436
+ const event = this.deserializeEvent(line);
437
+ if (event) {
438
+ this.eventHistory.push(event);
439
+ imported++;
440
+ }
441
+ }
442
+
443
+ return imported;
444
+ }
445
+
446
+ // --------------------------------------------------------------------------
447
+ // Convenience Methods
448
+ // --------------------------------------------------------------------------
449
+
450
+ /**
451
+ * 마지막 이벤트 조회
452
+ */
453
+ getLastEvent(laneName?: string): TypedCursorFlowEvent | undefined {
454
+ if (laneName) {
455
+ const laneHistory = this.getLaneHistory(laneName, 1);
456
+ return laneHistory[0];
457
+ }
458
+ return this.eventHistory[this.eventHistory.length - 1];
459
+ }
460
+
461
+ /**
462
+ * 이벤트 카운트 조회
463
+ */
464
+ getEventCount(options: {
465
+ category?: EventCategory;
466
+ laneName?: string;
467
+ } = {}): number {
468
+ return this.getHistory(options).length;
469
+ }
470
+
471
+ /**
472
+ * 특정 이벤트 대기 (Promise)
473
+ */
474
+ waitFor<T extends keyof EventPayloadMap>(
475
+ type: T,
476
+ options: {
477
+ timeout?: number;
478
+ filter?: (event: TypedCursorFlowEvent<T>) => boolean;
479
+ } = {}
480
+ ): Promise<TypedCursorFlowEvent<T>> {
481
+ return new Promise((resolve, reject) => {
482
+ const timeout = options.timeout || 30000;
483
+
484
+ const timer = setTimeout(() => {
485
+ this.off(type, handler);
486
+ reject(new Error(`Timeout waiting for event: ${type}`));
487
+ }, timeout);
488
+
489
+ const handler: TypedEventHandler<T> = (event) => {
490
+ if (!options.filter || options.filter(event)) {
491
+ clearTimeout(timer);
492
+ this.off(type, handler);
493
+ resolve(event);
494
+ }
495
+ };
496
+
497
+ this.on(type, handler);
498
+ });
499
+ }
500
+ }
501
+
502
+ // ============================================================================
503
+ // Event Type Guards
504
+ // ============================================================================
505
+
506
+ /**
507
+ * Orchestration 이벤트인지 확인
508
+ */
509
+ export function isOrchestrationEvent(event: TypedCursorFlowEvent): boolean {
510
+ return event.category === EventCategory.ORCHESTRATION;
511
+ }
512
+
513
+ /**
514
+ * Lane 이벤트인지 확인
515
+ */
516
+ export function isLaneEvent(event: TypedCursorFlowEvent): boolean {
517
+ return event.category === EventCategory.LANE;
518
+ }
519
+
520
+ /**
521
+ * Task 이벤트인지 확인
522
+ */
523
+ export function isTaskEvent(event: TypedCursorFlowEvent): boolean {
524
+ return event.category === EventCategory.TASK;
525
+ }
526
+
527
+ /**
528
+ * Git 이벤트인지 확인
529
+ */
530
+ export function isGitEvent(event: TypedCursorFlowEvent): boolean {
531
+ return event.category === EventCategory.GIT;
532
+ }
533
+
534
+ /**
535
+ * Recovery 이벤트인지 확인
536
+ */
537
+ export function isRecoveryEvent(event: TypedCursorFlowEvent): boolean {
538
+ return event.category === EventCategory.RECOVERY;
539
+ }
540
+
541
+ /**
542
+ * 오류 이벤트인지 확인
543
+ */
544
+ export function isErrorEvent(event: TypedCursorFlowEvent): boolean {
545
+ const errorTypes = [
546
+ OrchestrationEventType.FAILED,
547
+ LaneEventType.FAILED,
548
+ TaskEventType.FAILED,
549
+ GitEventType.ERROR,
550
+ GitEventType.MERGE_CONFLICT,
551
+ GitEventType.PUSH_REJECTED,
552
+ AgentEventType.CONNECTION_ERROR,
553
+ AgentEventType.AUTH_ERROR,
554
+ AgentEventType.TIMEOUT,
555
+ StateEventType.TRANSITION_FAILED,
556
+ StateEventType.CORRUPTED,
557
+ ];
558
+
559
+ return errorTypes.includes(event.type as any);
560
+ }
561
+
562
+ // ============================================================================
563
+ // Convenience Functions
564
+ // ============================================================================
565
+
566
+ /**
567
+ * 싱글톤 인스턴스 획득
568
+ */
569
+ export function getEventRegistry(config?: Partial<EventRegistryConfig>): EventRegistry {
570
+ return EventRegistry.getInstance(config);
571
+ }
572
+
573
+ /**
574
+ * 인스턴스 리셋 (테스트용)
575
+ */
576
+ export function resetEventRegistry(): void {
577
+ EventRegistry.resetInstance();
578
+ }
579
+
580
+ // ============================================================================
581
+ // Re-exports for convenience
582
+ // ============================================================================
583
+
584
+ export {
585
+ EventCategory,
586
+ OrchestrationEventType,
587
+ LaneEventType,
588
+ TaskEventType,
589
+ GitEventType,
590
+ RecoveryEventType,
591
+ AgentEventType,
592
+ StateEventType,
593
+ SystemEventType,
594
+ };
595
+
@@ -14,10 +14,6 @@ import {
14
14
  TaskFailedPayload,
15
15
  AgentPromptSentPayload,
16
16
  AgentResponseReceivedPayload,
17
- ReviewStartedPayload,
18
- ReviewCompletedPayload,
19
- ReviewApprovedPayload,
20
- ReviewRejectedPayload
21
17
  } from './types';
22
18
 
23
19
  class CursorFlowEvents extends EventEmitter {
@@ -40,10 +36,6 @@ class CursorFlowEvents extends EventEmitter {
40
36
  emit(type: 'task.failed', payload: TaskFailedPayload): boolean;
41
37
  emit(type: 'agent.prompt_sent', payload: AgentPromptSentPayload): boolean;
42
38
  emit(type: 'agent.response_received', payload: AgentResponseReceivedPayload): boolean;
43
- emit(type: 'review.started', payload: ReviewStartedPayload): boolean;
44
- emit(type: 'review.completed', payload: ReviewCompletedPayload): boolean;
45
- emit(type: 'review.approved', payload: ReviewApprovedPayload): boolean;
46
- emit(type: 'review.rejected', payload: ReviewRejectedPayload): boolean;
47
39
  emit(type: string, payload: any): boolean;
48
40
  emit(type: string, payload: any): boolean {
49
41
  const event: CursorFlowEvent = {
@@ -82,10 +74,6 @@ class CursorFlowEvents extends EventEmitter {
82
74
  on(pattern: 'task.failed', handler: EventHandler<TaskFailedPayload>): this;
83
75
  on(pattern: 'agent.prompt_sent', handler: EventHandler<AgentPromptSentPayload>): this;
84
76
  on(pattern: 'agent.response_received', handler: EventHandler<AgentResponseReceivedPayload>): this;
85
- on(pattern: 'review.started', handler: EventHandler<ReviewStartedPayload>): this;
86
- on(pattern: 'review.completed', handler: EventHandler<ReviewCompletedPayload>): this;
87
- on(pattern: 'review.approved', handler: EventHandler<ReviewApprovedPayload>): this;
88
- on(pattern: 'review.rejected', handler: EventHandler<ReviewRejectedPayload>): this;
89
77
  on(pattern: string, handler: EventHandler): this;
90
78
  on(pattern: string, handler: EventHandler): this {
91
79
  return super.on(pattern, handler);
@@ -103,10 +91,6 @@ class CursorFlowEvents extends EventEmitter {
103
91
  once(pattern: 'task.failed', handler: EventHandler<TaskFailedPayload>): this;
104
92
  once(pattern: 'agent.prompt_sent', handler: EventHandler<AgentPromptSentPayload>): this;
105
93
  once(pattern: 'agent.response_received', handler: EventHandler<AgentResponseReceivedPayload>): this;
106
- once(pattern: 'review.started', handler: EventHandler<ReviewStartedPayload>): this;
107
- once(pattern: 'review.completed', handler: EventHandler<ReviewCompletedPayload>): this;
108
- once(pattern: 'review.approved', handler: EventHandler<ReviewApprovedPayload>): this;
109
- once(pattern: 'review.rejected', handler: EventHandler<ReviewRejectedPayload>): this;
110
94
  once(pattern: string, handler: EventHandler): this;
111
95
  once(pattern: string, handler: EventHandler): this {
112
96
  return super.once(pattern, handler);