@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,434 @@
1
+ /**
2
+ * CursorFlow Hook System - Hook Manager
3
+ *
4
+ * Hook 등록 및 실행을 관리하는 중앙 매니저입니다.
5
+ * 외부 개발자가 Hook을 등록하고 CursorFlow가 적절한 시점에 실행합니다.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { hooks, HookPoint } from '@litmers/cursorflow-orchestrator';
10
+ *
11
+ * hooks.register({
12
+ * point: HookPoint.AFTER_TASK,
13
+ * mode: 'sync',
14
+ * handler: async (ctx) => {
15
+ * // Your logic here
16
+ * },
17
+ * });
18
+ * ```
19
+ */
20
+
21
+ import * as logger from '../utils/logger';
22
+ import {
23
+ HookPoint,
24
+ HookMode,
25
+ HookRegistration,
26
+ HookExecutionResult,
27
+ HookContext,
28
+ BeforeTaskContext,
29
+ AfterTaskContext,
30
+ OnErrorContext,
31
+ OnStallContext,
32
+ OnLaneEndContext,
33
+ HooksConfig,
34
+ } from './types';
35
+
36
+ // ============================================================================
37
+ // Hook Manager
38
+ // ============================================================================
39
+
40
+ /**
41
+ * Hook Manager 클래스
42
+ *
43
+ * 싱글톤 패턴으로 구현되어 전역에서 접근 가능합니다.
44
+ */
45
+ export class HookManager {
46
+ private static instance: HookManager | null = null;
47
+
48
+ /** 등록된 Hook 목록 (Hook Point별로 분류) */
49
+ private hooks: Map<HookPoint, HookRegistration[]> = new Map();
50
+
51
+ /** 설정 */
52
+ private config: HooksConfig = {
53
+ timeout: 30000,
54
+ continueOnError: false,
55
+ debug: false,
56
+ };
57
+
58
+ private constructor() {
59
+ // 각 Hook Point에 대해 빈 배열 초기화
60
+ for (const point of Object.values(HookPoint)) {
61
+ this.hooks.set(point, []);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * 싱글톤 인스턴스 획득
67
+ */
68
+ static getInstance(): HookManager {
69
+ if (!HookManager.instance) {
70
+ HookManager.instance = new HookManager();
71
+ }
72
+ return HookManager.instance;
73
+ }
74
+
75
+ /**
76
+ * 인스턴스 리셋 (테스트용)
77
+ */
78
+ static resetInstance(): void {
79
+ HookManager.instance = null;
80
+ }
81
+
82
+ // ==========================================================================
83
+ // Configuration
84
+ // ==========================================================================
85
+
86
+ /**
87
+ * 설정 업데이트
88
+ */
89
+ configure(config: Partial<HooksConfig>): void {
90
+ this.config = { ...this.config, ...config };
91
+ }
92
+
93
+ /**
94
+ * 현재 설정 조회
95
+ */
96
+ getConfig(): HooksConfig {
97
+ return { ...this.config };
98
+ }
99
+
100
+ // ==========================================================================
101
+ // Hook Registration
102
+ // ==========================================================================
103
+
104
+ /**
105
+ * Hook 등록
106
+ *
107
+ * @param registration Hook 등록 정보
108
+ * @returns 등록 해제 함수
109
+ */
110
+ register<T extends HookPoint>(registration: HookRegistration<T>): () => void {
111
+ const { point, priority = 50, name, enabled = true } = registration;
112
+
113
+ if (!enabled) {
114
+ if (this.config.debug) {
115
+ logger.debug(`[HookManager] Skipping disabled hook: ${name || 'unnamed'}`);
116
+ }
117
+ return () => {};
118
+ }
119
+
120
+ const hooks = this.hooks.get(point) || [];
121
+
122
+ // 우선순위에 따라 정렬된 위치에 삽입
123
+ const insertIndex = hooks.findIndex(h => (h.priority || 50) > priority);
124
+ if (insertIndex === -1) {
125
+ hooks.push(registration);
126
+ } else {
127
+ hooks.splice(insertIndex, 0, registration);
128
+ }
129
+
130
+ this.hooks.set(point, hooks);
131
+
132
+ if (this.config.debug) {
133
+ logger.debug(`[HookManager] Registered hook "${name || 'unnamed'}" at ${point} (priority: ${priority})`);
134
+ }
135
+
136
+ // 등록 해제 함수 반환
137
+ return () => {
138
+ this.unregister(point, registration);
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Hook 등록 해제
144
+ */
145
+ private unregister<T extends HookPoint>(point: T, registration: HookRegistration<T>): void {
146
+ const hooks = this.hooks.get(point) || [];
147
+ const index = hooks.indexOf(registration as any);
148
+
149
+ if (index !== -1) {
150
+ hooks.splice(index, 1);
151
+ this.hooks.set(point, hooks);
152
+
153
+ if (this.config.debug) {
154
+ logger.debug(`[HookManager] Unregistered hook "${registration.name || 'unnamed'}" from ${point}`);
155
+ }
156
+ }
157
+ }
158
+
159
+ /**
160
+ * 특정 Hook Point의 모든 Hook 제거
161
+ */
162
+ clearHooks(point?: HookPoint): void {
163
+ if (point) {
164
+ this.hooks.set(point, []);
165
+ } else {
166
+ for (const p of Object.values(HookPoint)) {
167
+ this.hooks.set(p, []);
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * 등록된 Hook 수 조회
174
+ */
175
+ getHookCount(point?: HookPoint): number {
176
+ if (point) {
177
+ return this.hooks.get(point)?.length || 0;
178
+ }
179
+
180
+ let total = 0;
181
+ for (const hooks of this.hooks.values()) {
182
+ total += hooks.length;
183
+ }
184
+ return total;
185
+ }
186
+
187
+ /**
188
+ * Hook 등록 여부 확인
189
+ */
190
+ hasHooks(point: HookPoint): boolean {
191
+ return (this.hooks.get(point)?.length || 0) > 0;
192
+ }
193
+
194
+ // ==========================================================================
195
+ // Hook Execution
196
+ // ==========================================================================
197
+
198
+ /**
199
+ * beforeTask Hook 실행
200
+ */
201
+ async executeBeforeTask(context: BeforeTaskContext): Promise<HookExecutionResult[]> {
202
+ return this.execute(HookPoint.BEFORE_TASK, context);
203
+ }
204
+
205
+ /**
206
+ * afterTask Hook 실행
207
+ */
208
+ async executeAfterTask(context: AfterTaskContext): Promise<HookExecutionResult[]> {
209
+ return this.execute(HookPoint.AFTER_TASK, context);
210
+ }
211
+
212
+ /**
213
+ * onError Hook 실행
214
+ */
215
+ async executeOnError(context: OnErrorContext): Promise<HookExecutionResult[]> {
216
+ return this.execute(HookPoint.ON_ERROR, context);
217
+ }
218
+
219
+ /**
220
+ * onStall Hook 실행
221
+ */
222
+ async executeOnStall(context: OnStallContext): Promise<HookExecutionResult[]> {
223
+ return this.execute(HookPoint.ON_STALL, context);
224
+ }
225
+
226
+ /**
227
+ * onLaneEnd Hook 실행
228
+ */
229
+ async executeOnLaneEnd(context: OnLaneEndContext): Promise<HookExecutionResult[]> {
230
+ return this.execute(HookPoint.ON_LANE_END, context);
231
+ }
232
+
233
+ /**
234
+ * 일반 Hook 실행
235
+ */
236
+ async execute<T extends HookPoint>(
237
+ point: T,
238
+ context: HookContext
239
+ ): Promise<HookExecutionResult[]> {
240
+ const hooks = this.hooks.get(point) || [];
241
+
242
+ if (hooks.length === 0) {
243
+ return [];
244
+ }
245
+
246
+ if (this.config.debug) {
247
+ logger.debug(`[HookManager] Executing ${hooks.length} hooks for ${point}`);
248
+ }
249
+
250
+ const results: HookExecutionResult[] = [];
251
+ const syncHooks = hooks.filter(h => h.mode === 'sync');
252
+ const asyncHooks = hooks.filter(h => h.mode === 'async');
253
+
254
+ // 동기 Hook 순차 실행 (블로킹)
255
+ for (const hook of syncHooks) {
256
+ const result = await this.executeHook(hook, context);
257
+ results.push(result);
258
+
259
+ // 에러 발생 시 중단 여부 결정
260
+ if (!result.success && !this.config.continueOnError) {
261
+ logger.error(`[HookManager] Hook "${hook.name || 'unnamed'}" failed, stopping execution`);
262
+ break;
263
+ }
264
+ }
265
+
266
+ // 비동기 Hook 병렬 실행 (논블로킹)
267
+ if (asyncHooks.length > 0) {
268
+ // 비동기 Hook은 백그라운드에서 실행 (결과를 기다리지 않음)
269
+ Promise.all(
270
+ asyncHooks.map(hook => this.executeHook(hook, context))
271
+ ).then(asyncResults => {
272
+ for (const result of asyncResults) {
273
+ if (!result.success) {
274
+ logger.warn(`[HookManager] Async hook "${result.handlerName || 'unnamed'}" failed: ${result.error?.message}`);
275
+ }
276
+ }
277
+ }).catch(error => {
278
+ logger.error(`[HookManager] Async hooks error: ${error.message}`);
279
+ });
280
+ }
281
+
282
+ return results;
283
+ }
284
+
285
+ /**
286
+ * 단일 Hook 실행
287
+ */
288
+ private async executeHook(
289
+ hook: HookRegistration,
290
+ context: HookContext
291
+ ): Promise<HookExecutionResult> {
292
+ const startTime = Date.now();
293
+ const handlerName = hook.name || 'unnamed';
294
+
295
+ try {
296
+ // 타임아웃 설정
297
+ const timeout = this.config.timeout || 30000;
298
+
299
+ const result = await Promise.race([
300
+ (hook.handler as any)(context),
301
+ new Promise((_, reject) =>
302
+ setTimeout(() => reject(new Error(`Hook timeout after ${timeout}ms`)), timeout)
303
+ ),
304
+ ]);
305
+
306
+ const duration = Date.now() - startTime;
307
+
308
+ if (this.config.debug) {
309
+ logger.debug(`[HookManager] Hook "${handlerName}" completed in ${duration}ms`);
310
+ }
311
+
312
+ return {
313
+ success: true,
314
+ duration,
315
+ handlerName,
316
+ };
317
+ } catch (error: any) {
318
+ const duration = Date.now() - startTime;
319
+
320
+ // FlowAbortError와 FlowRetryError는 정상적인 플로우 제어이므로 다시 throw
321
+ if (error.name === 'FlowAbortError' || error.name === 'FlowRetryError') {
322
+ throw error;
323
+ }
324
+
325
+ logger.error(`[HookManager] Hook "${handlerName}" error: ${error.message}`);
326
+
327
+ return {
328
+ success: false,
329
+ error,
330
+ duration,
331
+ handlerName,
332
+ };
333
+ }
334
+ }
335
+
336
+ // ==========================================================================
337
+ // Hook Loading
338
+ // ==========================================================================
339
+
340
+ /**
341
+ * 파일에서 Hook 로드
342
+ */
343
+ async loadHooksFromFile(filePath: string): Promise<number> {
344
+ try {
345
+ // TypeScript/JavaScript 파일 동적 로드
346
+ const resolved = require.resolve(filePath);
347
+
348
+ // 캐시 삭제 (개발 중 핫 리로드를 위해)
349
+ delete require.cache[resolved];
350
+
351
+ const module = await import(resolved);
352
+
353
+ // 모듈이 HookManager를 반환하거나 register를 호출했으면 성공
354
+ if (this.config.debug) {
355
+ logger.debug(`[HookManager] Loaded hooks from ${filePath}`);
356
+ }
357
+
358
+ return this.getHookCount();
359
+ } catch (error: any) {
360
+ logger.error(`[HookManager] Failed to load hooks from ${filePath}: ${error.message}`);
361
+ throw error;
362
+ }
363
+ }
364
+
365
+ // ==========================================================================
366
+ // Debug & Inspection
367
+ // ==========================================================================
368
+
369
+ /**
370
+ * 등록된 Hook 목록 조회
371
+ */
372
+ listHooks(point?: HookPoint): Array<{ point: HookPoint; name: string; mode: HookMode; priority: number }> {
373
+ const result: Array<{ point: HookPoint; name: string; mode: HookMode; priority: number }> = [];
374
+
375
+ const points = point ? [point] : Object.values(HookPoint);
376
+
377
+ for (const p of points) {
378
+ const hooks = this.hooks.get(p) || [];
379
+ for (const hook of hooks) {
380
+ result.push({
381
+ point: p,
382
+ name: hook.name || 'unnamed',
383
+ mode: hook.mode,
384
+ priority: hook.priority || 50,
385
+ });
386
+ }
387
+ }
388
+
389
+ return result;
390
+ }
391
+
392
+ /**
393
+ * 디버그 정보 출력
394
+ */
395
+ debug(): void {
396
+ logger.info('=== HookManager Debug ===');
397
+ logger.info(`Config: ${JSON.stringify(this.config)}`);
398
+ logger.info(`Total hooks: ${this.getHookCount()}`);
399
+
400
+ for (const point of Object.values(HookPoint)) {
401
+ const hooks = this.hooks.get(point) || [];
402
+ if (hooks.length > 0) {
403
+ logger.info(` ${point}: ${hooks.length} hooks`);
404
+ for (const hook of hooks) {
405
+ logger.info(` - ${hook.name || 'unnamed'} (${hook.mode}, priority: ${hook.priority || 50})`);
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+
412
+ // ============================================================================
413
+ // Singleton Instance & Convenience API
414
+ // ============================================================================
415
+
416
+ /**
417
+ * 전역 HookManager 인스턴스
418
+ */
419
+ export const hooks = HookManager.getInstance();
420
+
421
+ /**
422
+ * HookManager 인스턴스 획득
423
+ */
424
+ export function getHookManager(): HookManager {
425
+ return HookManager.getInstance();
426
+ }
427
+
428
+ /**
429
+ * HookManager 인스턴스 리셋 (테스트용)
430
+ */
431
+ export function resetHookManager(): void {
432
+ HookManager.resetInstance();
433
+ }
434
+