@litmers/cursorflow-orchestrator 0.1.39 → 0.2.2

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 +20 -16
  3. package/commands/cursorflow-init.md +0 -4
  4. package/dist/cli/logs.js +108 -9
  5. package/dist/cli/logs.js.map +1 -1
  6. package/dist/cli/models.js +20 -3
  7. package/dist/cli/models.js.map +1 -1
  8. package/dist/cli/monitor.d.ts +7 -10
  9. package/dist/cli/monitor.js +1088 -1240
  10. package/dist/cli/monitor.js.map +1 -1
  11. package/dist/cli/prepare.js +0 -1
  12. package/dist/cli/prepare.js.map +1 -1
  13. package/dist/cli/resume.js +23 -5
  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 +94 -12
  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 +2 -1
  26. package/dist/core/auto-recovery.js +6 -1
  27. package/dist/core/auto-recovery.js.map +1 -1
  28. package/dist/core/failure-policy.d.ts +0 -1
  29. package/dist/core/failure-policy.js +0 -1
  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 +176 -0
  38. package/dist/core/intervention.js +424 -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 +38 -63
  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 +45 -30
  48. package/dist/core/runner/agent.js.map +1 -1
  49. package/dist/core/runner/pipeline.js +283 -109
  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 -77
  53. package/dist/core/runner/task.js.map +1 -1
  54. package/dist/core/runner.js +11 -2
  55. package/dist/core/runner.js.map +1 -1
  56. package/dist/core/stall-detection.d.ts +27 -4
  57. package/dist/core/stall-detection.js +116 -28
  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 +8 -5
  81. package/dist/services/logging/console.js.map +1 -1
  82. package/dist/services/logging/formatter.d.ts +9 -3
  83. package/dist/services/logging/formatter.js +64 -17
  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 +24 -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 +13 -2
  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 +15 -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 +99 -20
  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/git.d.ts +12 -1
  129. package/dist/utils/git.js +54 -1
  130. package/dist/utils/git.js.map +1 -1
  131. package/dist/utils/log-constants.d.ts +1 -0
  132. package/dist/utils/log-constants.js +2 -1
  133. package/dist/utils/log-constants.js.map +1 -1
  134. package/dist/utils/log-formatter.d.ts +3 -2
  135. package/dist/utils/log-formatter.js +11 -11
  136. package/dist/utils/log-formatter.js.map +1 -1
  137. package/dist/utils/logger.d.ts +11 -0
  138. package/dist/utils/logger.js +82 -3
  139. package/dist/utils/logger.js.map +1 -1
  140. package/dist/utils/repro-thinking-logs.js +0 -13
  141. package/dist/utils/repro-thinking-logs.js.map +1 -1
  142. package/dist/utils/run-service.js +1 -1
  143. package/dist/utils/run-service.js.map +1 -1
  144. package/examples/README.md +0 -2
  145. package/examples/demo-project/README.md +1 -2
  146. package/package.json +18 -28
  147. package/scripts/setup-security.sh +0 -1
  148. package/scripts/test-log-parser.ts +171 -0
  149. package/scripts/verify-change.sh +272 -0
  150. package/src/cli/logs.ts +121 -10
  151. package/src/cli/models.ts +20 -3
  152. package/src/cli/monitor.ts +1257 -1342
  153. package/src/cli/prepare.ts +0 -1
  154. package/src/cli/resume.ts +29 -5
  155. package/src/cli/run.ts +29 -11
  156. package/src/cli/signal.ts +115 -17
  157. package/src/cli/tasks.ts +2 -59
  158. package/src/core/agent-supervisor.ts +64 -0
  159. package/src/core/auto-recovery.ts +7 -1
  160. package/src/core/failure-policy.ts +0 -1
  161. package/src/core/git-lifecycle-manager.ts +1011 -0
  162. package/src/core/git-pipeline-coordinator.ts +221 -0
  163. package/src/core/intervention.ts +481 -0
  164. package/src/core/lane-state-machine.ts +1097 -0
  165. package/src/core/orchestrator.ts +45 -62
  166. package/src/core/runner/agent.ts +66 -33
  167. package/src/core/runner/pipeline.ts +318 -122
  168. package/src/core/runner/task.ts +12 -93
  169. package/src/core/runner.ts +12 -2
  170. package/src/core/stall-detection.ts +145 -28
  171. package/src/hooks/contexts/index.ts +256 -0
  172. package/src/hooks/data-accessor.ts +488 -0
  173. package/src/hooks/flow-controller.ts +425 -0
  174. package/src/hooks/index.ts +154 -0
  175. package/src/hooks/manager.ts +434 -0
  176. package/src/hooks/types.ts +544 -0
  177. package/src/services/logging/buffer.ts +104 -43
  178. package/src/services/logging/console.ts +9 -5
  179. package/src/services/logging/formatter.ts +74 -17
  180. package/src/services/logging/index.ts +0 -2
  181. package/src/services/logging/paths.ts +14 -0
  182. package/src/services/logging/raw-log.ts +43 -0
  183. package/src/services/process/index.ts +1 -1
  184. package/src/types/agent.ts +15 -0
  185. package/src/types/config.ts +25 -1
  186. package/src/types/event-categories.ts +663 -0
  187. package/src/types/events.ts +0 -25
  188. package/src/types/flow.ts +10 -6
  189. package/src/types/index.ts +50 -4
  190. package/src/types/lane.ts +1 -2
  191. package/src/types/logging.ts +2 -1
  192. package/src/types/task.ts +13 -2
  193. package/src/ui/log-viewer.ts +3 -0
  194. package/src/utils/config.ts +17 -1
  195. package/src/utils/cursor-agent.ts +68 -16
  196. package/src/utils/enhanced-logger.ts +106 -20
  197. package/src/utils/event-registry.ts +595 -0
  198. package/src/utils/events.ts +0 -16
  199. package/src/utils/flow.ts +84 -0
  200. package/src/utils/git.ts +59 -1
  201. package/src/utils/log-constants.ts +2 -1
  202. package/src/utils/log-formatter.ts +11 -12
  203. package/src/utils/logger.ts +49 -3
  204. package/src/utils/repro-thinking-logs.ts +0 -15
  205. package/src/utils/run-service.ts +1 -1
  206. package/dist/services/logging/file-writer.d.ts +0 -71
  207. package/dist/services/logging/file-writer.js +0 -516
  208. package/dist/services/logging/file-writer.js.map +0 -1
  209. package/dist/types/review.d.ts +0 -17
  210. package/dist/types/review.js +0 -6
  211. package/dist/types/review.js.map +0 -1
  212. package/scripts/ai-security-check.js +0 -233
  213. package/src/services/logging/file-writer.ts +0 -526
  214. package/src/types/review.ts +0 -20
@@ -0,0 +1,425 @@
1
+ /**
2
+ * CursorFlow Hook System - Flow Controller Implementation
3
+ *
4
+ * Hook 핸들러에서 실행 플로우를 제어하기 위한 구현체입니다.
5
+ * pause, resume, injectTask 등의 기능을 제공합니다.
6
+ */
7
+
8
+ import * as fs from 'fs';
9
+ import { safeJoin } from '../utils/path';
10
+ import * as logger from '../utils/logger';
11
+ import { events } from '../utils/events';
12
+ import {
13
+ FlowController,
14
+ TaskDefinition,
15
+ AICallOptions,
16
+ } from './types';
17
+
18
+ // ============================================================================
19
+ // Flow Controller Options
20
+ // ============================================================================
21
+
22
+ export interface FlowControllerOptions {
23
+ /** Lane 이름 */
24
+ laneName: string;
25
+ /** Run 디렉토리 */
26
+ runDir: string;
27
+ /** Worktree 디렉토리 */
28
+ worktreeDir: string;
29
+ /** 현재 태스크 인덱스 */
30
+ currentTaskIndex: number;
31
+ /** 태스크 목록 (수정 가능) */
32
+ tasks: TaskDefinition[];
33
+ /** 태스크 파일 경로 */
34
+ tasksFile: string;
35
+ /** Chat ID */
36
+ chatId: string;
37
+ /** AgentSupervisor 인스턴스 (AI 호출용) */
38
+ agentSupervisor?: any;
39
+ }
40
+
41
+ // ============================================================================
42
+ // Flow Control State
43
+ // ============================================================================
44
+
45
+ /**
46
+ * 플로우 제어 상태
47
+ */
48
+ export interface FlowControlState {
49
+ /** 일시 중지 여부 */
50
+ isPaused: boolean;
51
+ /** 중단 여부 */
52
+ isAborted: boolean;
53
+ /** 재시도 요청 여부 */
54
+ shouldRetry: boolean;
55
+ /** 재시도 시 사용할 수정된 프롬프트 */
56
+ retryPrompt?: string;
57
+ /** 수정된 현재 프롬프트 */
58
+ modifiedCurrentPrompt?: string;
59
+ /** 중지/중단 사유 */
60
+ reason?: string;
61
+ /** 재개 시 전달할 데이터 */
62
+ resumeData?: any;
63
+ }
64
+
65
+ // ============================================================================
66
+ // Flow Controller Implementation
67
+ // ============================================================================
68
+
69
+ /**
70
+ * FlowController 구현체
71
+ */
72
+ export class FlowControllerImpl implements FlowController {
73
+ private options: FlowControllerOptions;
74
+ private state: FlowControlState;
75
+ private pauseResolver: ((data?: any) => void) | null = null;
76
+
77
+ constructor(options: FlowControllerOptions) {
78
+ this.options = options;
79
+ this.state = {
80
+ isPaused: false,
81
+ isAborted: false,
82
+ shouldRetry: false,
83
+ };
84
+ }
85
+
86
+ // ==========================================================================
87
+ // Flow Control Methods
88
+ // ==========================================================================
89
+
90
+ /**
91
+ * 플로우 일시 중지
92
+ */
93
+ async pause(reason: string): Promise<void> {
94
+ if (this.state.isPaused) {
95
+ logger.warn(`[Hook] Already paused, ignoring duplicate pause request`);
96
+ return;
97
+ }
98
+
99
+ this.state.isPaused = true;
100
+ this.state.reason = reason;
101
+
102
+ logger.info(`[Hook] Flow paused: ${reason}`);
103
+
104
+ // 이벤트 발행
105
+ events.emit('lane.paused' as any, {
106
+ laneName: this.options.laneName,
107
+ reason,
108
+ });
109
+
110
+ // Pause 상태 파일 생성 (외부에서 확인 가능)
111
+ const pauseFile = safeJoin(this.options.runDir, 'paused.json');
112
+ fs.writeFileSync(pauseFile, JSON.stringify({
113
+ paused: true,
114
+ reason,
115
+ timestamp: Date.now(),
116
+ }, null, 2));
117
+
118
+ // resume이 호출될 때까지 대기
119
+ return new Promise((resolve) => {
120
+ this.pauseResolver = (data) => {
121
+ this.state.isPaused = false;
122
+ this.state.resumeData = data;
123
+
124
+ // Pause 파일 삭제
125
+ try {
126
+ fs.unlinkSync(pauseFile);
127
+ } catch {
128
+ // Ignore
129
+ }
130
+
131
+ resolve();
132
+ };
133
+ });
134
+ }
135
+
136
+ /**
137
+ * 플로우 재개
138
+ */
139
+ resume(data?: any): void {
140
+ if (!this.state.isPaused) {
141
+ logger.warn(`[Hook] Not paused, ignoring resume request`);
142
+ return;
143
+ }
144
+
145
+ logger.info(`[Hook] Flow resumed`);
146
+
147
+ // 이벤트 발행
148
+ events.emit('lane.resumed' as any, {
149
+ laneName: this.options.laneName,
150
+ });
151
+
152
+ if (this.pauseResolver) {
153
+ this.pauseResolver(data);
154
+ this.pauseResolver = null;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Lane 중단
160
+ */
161
+ abort(reason: string): void {
162
+ this.state.isAborted = true;
163
+ this.state.reason = reason;
164
+
165
+ logger.error(`[Hook] Flow aborted: ${reason}`);
166
+
167
+ // 이벤트 발행
168
+ events.emit('lane.failed' as any, {
169
+ laneName: this.options.laneName,
170
+ exitCode: 1,
171
+ error: reason,
172
+ });
173
+
174
+ // Abort 예외 던지기 (Runner에서 catch)
175
+ throw new FlowAbortError(reason);
176
+ }
177
+
178
+ /**
179
+ * 현재 태스크 재시도
180
+ */
181
+ retry(options?: { modifiedPrompt?: string }): void {
182
+ this.state.shouldRetry = true;
183
+ this.state.retryPrompt = options?.modifiedPrompt;
184
+
185
+ logger.info(`[Hook] Task retry requested${options?.modifiedPrompt ? ' with modified prompt' : ''}`);
186
+
187
+ throw new FlowRetryError(options?.modifiedPrompt);
188
+ }
189
+
190
+ // ==========================================================================
191
+ // Task Manipulation Methods
192
+ // ==========================================================================
193
+
194
+ /**
195
+ * 다음에 실행할 태스크 삽입
196
+ */
197
+ injectTask(task: TaskDefinition): void {
198
+ const insertIndex = this.options.currentTaskIndex + 1;
199
+
200
+ // 태스크 배열에 삽입
201
+ this.options.tasks.splice(insertIndex, 0, task);
202
+
203
+ logger.info(`[Hook] Injected task "${task.name}" at index ${insertIndex}`);
204
+
205
+ // tasks.json 파일 업데이트
206
+ this.persistTasks();
207
+ }
208
+
209
+ /**
210
+ * 현재 태스크 프롬프트 수정 (beforeTask에서만 유효)
211
+ */
212
+ modifyCurrentPrompt(newPrompt: string): void {
213
+ this.state.modifiedCurrentPrompt = newPrompt;
214
+
215
+ const currentTask = this.options.tasks[this.options.currentTaskIndex];
216
+ if (currentTask) {
217
+ logger.info(`[Hook] Modified prompt for task "${currentTask.name}"`);
218
+ }
219
+ }
220
+
221
+ /**
222
+ * 다음 태스크 수정
223
+ */
224
+ modifyNextTask(modifier: (task: TaskDefinition) => TaskDefinition): void {
225
+ const nextIndex = this.options.currentTaskIndex + 1;
226
+
227
+ if (nextIndex >= this.options.tasks.length) {
228
+ logger.warn(`[Hook] No next task to modify`);
229
+ return;
230
+ }
231
+
232
+ const nextTask = this.options.tasks[nextIndex];
233
+ const modifiedTask = modifier(nextTask);
234
+ this.options.tasks[nextIndex] = modifiedTask;
235
+
236
+ logger.info(`[Hook] Modified next task "${modifiedTask.name}"`);
237
+
238
+ // tasks.json 파일 업데이트
239
+ this.persistTasks();
240
+ }
241
+
242
+ /**
243
+ * 남은 태스크 전체 교체
244
+ */
245
+ replaceRemainingTasks(tasks: TaskDefinition[]): void {
246
+ const currentIndex = this.options.currentTaskIndex;
247
+
248
+ // 현재까지의 태스크 유지, 이후 교체
249
+ const completedTasks = this.options.tasks.slice(0, currentIndex + 1);
250
+ this.options.tasks.length = 0;
251
+ this.options.tasks.push(...completedTasks, ...tasks);
252
+
253
+ logger.info(`[Hook] Replaced remaining tasks with ${tasks.length} new tasks`);
254
+
255
+ // tasks.json 파일 업데이트
256
+ this.persistTasks();
257
+ }
258
+
259
+ /**
260
+ * tasks.json 파일에 변경사항 저장
261
+ */
262
+ private persistTasks(): void {
263
+ try {
264
+ const tasksFile = this.options.tasksFile;
265
+
266
+ if (fs.existsSync(tasksFile)) {
267
+ const config = JSON.parse(fs.readFileSync(tasksFile, 'utf8'));
268
+ config.tasks = this.options.tasks;
269
+ fs.writeFileSync(tasksFile, JSON.stringify(config, null, 2));
270
+ }
271
+ } catch (error) {
272
+ logger.warn(`[Hook] Failed to persist tasks: ${error}`);
273
+ }
274
+ }
275
+
276
+ // ==========================================================================
277
+ // Agent Communication Methods
278
+ // ==========================================================================
279
+
280
+ /**
281
+ * AI 에이전트에게 메시지 전송 (현재 세션)
282
+ */
283
+ async sendMessage(message: string): Promise<string> {
284
+ const { agentSupervisor, worktreeDir, chatId, laneName, runDir } = this.options;
285
+
286
+ if (!agentSupervisor) {
287
+ throw new Error('AgentSupervisor not available');
288
+ }
289
+
290
+ logger.info(`[Hook] Sending message to agent`);
291
+
292
+ try {
293
+ const result = await agentSupervisor.sendTaskPrompt({
294
+ workspaceDir: worktreeDir,
295
+ chatId,
296
+ prompt: message,
297
+ laneName,
298
+ signalDir: runDir,
299
+ taskName: 'hook-intervention',
300
+ });
301
+
302
+ return result.resultText || '';
303
+ } catch (error: any) {
304
+ logger.error(`[Hook] Failed to send message: ${error.message}`);
305
+ throw error;
306
+ }
307
+ }
308
+
309
+ /**
310
+ * 별도 AI 호출 (새 세션)
311
+ */
312
+ async callAI(prompt: string, options?: AICallOptions): Promise<string> {
313
+ const { agentSupervisor, worktreeDir, laneName, runDir } = this.options;
314
+
315
+ if (!agentSupervisor) {
316
+ throw new Error('AgentSupervisor not available');
317
+ }
318
+
319
+ logger.info(`[Hook] Calling AI with new session`);
320
+
321
+ try {
322
+ // 새 채팅 세션 생성
323
+ const newChatId = agentSupervisor.createChat(worktreeDir);
324
+
325
+ const result = await agentSupervisor.sendTaskPrompt({
326
+ workspaceDir: worktreeDir,
327
+ chatId: newChatId,
328
+ prompt,
329
+ model: options?.model,
330
+ laneName,
331
+ signalDir: runDir,
332
+ timeout: options?.timeout,
333
+ taskName: 'hook-ai-call',
334
+ });
335
+
336
+ return result.resultText || '';
337
+ } catch (error: any) {
338
+ logger.error(`[Hook] Failed to call AI: ${error.message}`);
339
+ throw error;
340
+ }
341
+ }
342
+
343
+ // ==========================================================================
344
+ // State Access Methods
345
+ // ==========================================================================
346
+
347
+ /**
348
+ * 현재 상태 조회
349
+ */
350
+ getState(): FlowControlState {
351
+ return { ...this.state };
352
+ }
353
+
354
+ /**
355
+ * 수정된 프롬프트 조회 (beforeTask에서 설정된 경우)
356
+ */
357
+ getModifiedPrompt(): string | undefined {
358
+ return this.state.modifiedCurrentPrompt;
359
+ }
360
+
361
+ /**
362
+ * 재개 데이터 조회
363
+ */
364
+ getResumeData(): any {
365
+ return this.state.resumeData;
366
+ }
367
+
368
+ /**
369
+ * 상태 리셋
370
+ */
371
+ resetState(): void {
372
+ this.state = {
373
+ isPaused: false,
374
+ isAborted: false,
375
+ shouldRetry: false,
376
+ };
377
+ this.pauseResolver = null;
378
+ }
379
+
380
+ /**
381
+ * 옵션 업데이트
382
+ */
383
+ updateOptions(updates: Partial<FlowControllerOptions>): void {
384
+ this.options = { ...this.options, ...updates };
385
+ }
386
+ }
387
+
388
+ // ============================================================================
389
+ // Custom Errors
390
+ // ============================================================================
391
+
392
+ /**
393
+ * Flow 중단 에러
394
+ */
395
+ export class FlowAbortError extends Error {
396
+ constructor(reason: string) {
397
+ super(`Flow aborted: ${reason}`);
398
+ this.name = 'FlowAbortError';
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Flow 재시도 에러
404
+ */
405
+ export class FlowRetryError extends Error {
406
+ public modifiedPrompt?: string;
407
+
408
+ constructor(modifiedPrompt?: string) {
409
+ super('Flow retry requested');
410
+ this.name = 'FlowRetryError';
411
+ this.modifiedPrompt = modifiedPrompt;
412
+ }
413
+ }
414
+
415
+ // ============================================================================
416
+ // Factory Function
417
+ // ============================================================================
418
+
419
+ /**
420
+ * FlowController 인스턴스 생성
421
+ */
422
+ export function createFlowController(options: FlowControllerOptions): FlowControllerImpl {
423
+ return new FlowControllerImpl(options);
424
+ }
425
+
@@ -0,0 +1,154 @@
1
+ /**
2
+ * CursorFlow Hook System
3
+ *
4
+ * 외부 개발자가 Supervisor AI, 모니터링 시스템, 커스텀 로직 등을
5
+ * 구현할 수 있도록 제공하는 Hook API입니다.
6
+ *
7
+ * ## Quick Start
8
+ *
9
+ * ```typescript
10
+ * import { hooks, HookPoint } from '@litmers/cursorflow-orchestrator';
11
+ *
12
+ * // 태스크 완료 후 결과 리뷰
13
+ * hooks.register({
14
+ * point: HookPoint.AFTER_TASK,
15
+ * mode: 'sync',
16
+ * name: 'my-reviewer',
17
+ * handler: async (ctx) => {
18
+ * // 수정된 파일 확인
19
+ * const files = await ctx.getData.git.getChangedFiles();
20
+ * console.log('Modified files:', files.map(f => f.path));
21
+ *
22
+ * // AI 응답 분석
23
+ * const response = await ctx.getData.conversation.getLastResponse();
24
+ *
25
+ * // 필요시 추가 태스크 삽입
26
+ * if (needsFix(response)) {
27
+ * ctx.flow.injectTask({
28
+ * name: 'Fix: ' + ctx.task.name,
29
+ * prompt: 'Fix the issues...',
30
+ * });
31
+ * }
32
+ * },
33
+ * });
34
+ * ```
35
+ *
36
+ * ## Hook Points
37
+ *
38
+ * | Hook Point | 트리거 시점 | 주요 용도 |
39
+ * |------------|------------|----------|
40
+ * | `beforeTask` | 태스크 실행 직전 | 프롬프트 검토/수정 |
41
+ * | `afterTask` | 태스크 완료 직후 | 결과 리뷰, 태스크 삽입 |
42
+ * | `onError` | 에러 발생 시 | 에러 분석, 복구 |
43
+ * | `onStall` | 응답 없음 감지 시 | 상황 분석, 개입 |
44
+ * | `onLaneEnd` | Lane 종료 시 | 최종 리뷰, 보고서 |
45
+ *
46
+ * ## Configuration
47
+ *
48
+ * `.cursorflow.json`에서 Hook 설정:
49
+ *
50
+ * ```json
51
+ * {
52
+ * "hooks": {
53
+ * "file": "./cursorflow.hooks.ts",
54
+ * "timeout": 30000,
55
+ * "continueOnError": false
56
+ * }
57
+ * }
58
+ * ```
59
+ *
60
+ * @module hooks
61
+ */
62
+
63
+ // ============================================================================
64
+ // Type Exports
65
+ // ============================================================================
66
+
67
+ export {
68
+ // Hook Points & Modes
69
+ HookPoint,
70
+ HookMode,
71
+
72
+ // Context Types
73
+ HookContext,
74
+ BeforeTaskContext,
75
+ AfterTaskContext,
76
+ OnErrorContext,
77
+ OnStallContext,
78
+ OnLaneEndContext,
79
+
80
+ // Data Types
81
+ ChangedFile,
82
+ Commit,
83
+ Message,
84
+ TaskResult,
85
+ TaskDefinition,
86
+ ToolCall,
87
+ ErrorLog,
88
+ DependencyResult,
89
+
90
+ // Interface Types
91
+ HookDataAccessor,
92
+ FlowController,
93
+ AICallOptions,
94
+
95
+ // Registration Types
96
+ HookRegistration,
97
+ HookExecutionResult,
98
+ HookHandlerMap,
99
+
100
+ // Config Types
101
+ HooksConfig,
102
+ } from './types';
103
+
104
+ // ============================================================================
105
+ // Manager Exports
106
+ // ============================================================================
107
+
108
+ export {
109
+ HookManager,
110
+ hooks,
111
+ getHookManager,
112
+ resetHookManager,
113
+ } from './manager';
114
+
115
+ // ============================================================================
116
+ // Implementation Exports (for advanced usage)
117
+ // ============================================================================
118
+
119
+ export {
120
+ HookDataAccessorImpl,
121
+ DataAccessorOptions,
122
+ createDataAccessor,
123
+ } from './data-accessor';
124
+
125
+ export {
126
+ FlowControllerImpl,
127
+ FlowControllerOptions,
128
+ FlowControlState,
129
+ FlowAbortError,
130
+ FlowRetryError,
131
+ createFlowController,
132
+ } from './flow-controller';
133
+
134
+ // ============================================================================
135
+ // Context Builder Exports (for internal/advanced usage)
136
+ // ============================================================================
137
+
138
+ export {
139
+ BaseContextOptions,
140
+ createBeforeTaskContext,
141
+ createAfterTaskContext,
142
+ createOnErrorContext,
143
+ createOnStallContext,
144
+ createOnLaneEndContext,
145
+ } from './contexts';
146
+
147
+ // ============================================================================
148
+ // Re-export for convenience
149
+ // ============================================================================
150
+
151
+ // Default export: hooks singleton
152
+ import { hooks as hooksSingleton } from './manager';
153
+ export default hooksSingleton;
154
+