@yuaone/core 0.1.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.
- package/LICENSE +663 -0
- package/README.md +15 -0
- package/dist/__tests__/context-manager.test.d.ts +6 -0
- package/dist/__tests__/context-manager.test.d.ts.map +1 -0
- package/dist/__tests__/context-manager.test.js +220 -0
- package/dist/__tests__/context-manager.test.js.map +1 -0
- package/dist/__tests__/governor.test.d.ts +6 -0
- package/dist/__tests__/governor.test.d.ts.map +1 -0
- package/dist/__tests__/governor.test.js +210 -0
- package/dist/__tests__/governor.test.js.map +1 -0
- package/dist/__tests__/model-router.test.d.ts +6 -0
- package/dist/__tests__/model-router.test.d.ts.map +1 -0
- package/dist/__tests__/model-router.test.js +329 -0
- package/dist/__tests__/model-router.test.js.map +1 -0
- package/dist/agent-logger.d.ts +384 -0
- package/dist/agent-logger.d.ts.map +1 -0
- package/dist/agent-logger.js +820 -0
- package/dist/agent-logger.js.map +1 -0
- package/dist/agent-loop.d.ts +163 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +609 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/agent-modes.d.ts +85 -0
- package/dist/agent-modes.d.ts.map +1 -0
- package/dist/agent-modes.js +418 -0
- package/dist/agent-modes.js.map +1 -0
- package/dist/approval.d.ts +137 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +299 -0
- package/dist/approval.js.map +1 -0
- package/dist/async-completion-queue.d.ts +56 -0
- package/dist/async-completion-queue.d.ts.map +1 -0
- package/dist/async-completion-queue.js +77 -0
- package/dist/async-completion-queue.js.map +1 -0
- package/dist/auto-fix.d.ts +174 -0
- package/dist/auto-fix.d.ts.map +1 -0
- package/dist/auto-fix.js +319 -0
- package/dist/auto-fix.js.map +1 -0
- package/dist/codebase-context.d.ts +396 -0
- package/dist/codebase-context.d.ts.map +1 -0
- package/dist/codebase-context.js +1260 -0
- package/dist/codebase-context.js.map +1 -0
- package/dist/conflict-resolver.d.ts +191 -0
- package/dist/conflict-resolver.d.ts.map +1 -0
- package/dist/conflict-resolver.js +524 -0
- package/dist/conflict-resolver.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +141 -0
- package/dist/constants.js.map +1 -0
- package/dist/context-budget.d.ts +435 -0
- package/dist/context-budget.d.ts.map +1 -0
- package/dist/context-budget.js +903 -0
- package/dist/context-budget.js.map +1 -0
- package/dist/context-compressor.d.ts +143 -0
- package/dist/context-compressor.d.ts.map +1 -0
- package/dist/context-compressor.js +511 -0
- package/dist/context-compressor.js.map +1 -0
- package/dist/context-manager.d.ts +112 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +247 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/continuous-reflection.d.ts +267 -0
- package/dist/continuous-reflection.d.ts.map +1 -0
- package/dist/continuous-reflection.js +338 -0
- package/dist/continuous-reflection.js.map +1 -0
- package/dist/cross-file-refactor.d.ts +352 -0
- package/dist/cross-file-refactor.d.ts.map +1 -0
- package/dist/cross-file-refactor.js +1544 -0
- package/dist/cross-file-refactor.js.map +1 -0
- package/dist/dag-orchestrator.d.ts +138 -0
- package/dist/dag-orchestrator.d.ts.map +1 -0
- package/dist/dag-orchestrator.js +379 -0
- package/dist/dag-orchestrator.js.map +1 -0
- package/dist/debate-orchestrator.d.ts +301 -0
- package/dist/debate-orchestrator.d.ts.map +1 -0
- package/dist/debate-orchestrator.js +719 -0
- package/dist/debate-orchestrator.js.map +1 -0
- package/dist/dependency-analyzer.d.ts +113 -0
- package/dist/dependency-analyzer.d.ts.map +1 -0
- package/dist/dependency-analyzer.js +444 -0
- package/dist/dependency-analyzer.js.map +1 -0
- package/dist/design-loop.d.ts +59 -0
- package/dist/design-loop.d.ts.map +1 -0
- package/dist/design-loop.js +344 -0
- package/dist/design-loop.js.map +1 -0
- package/dist/doc-intelligence.d.ts +383 -0
- package/dist/doc-intelligence.d.ts.map +1 -0
- package/dist/doc-intelligence.js +1307 -0
- package/dist/doc-intelligence.js.map +1 -0
- package/dist/dynamic-role-generator.d.ts +76 -0
- package/dist/dynamic-role-generator.d.ts.map +1 -0
- package/dist/dynamic-role-generator.js +194 -0
- package/dist/dynamic-role-generator.js.map +1 -0
- package/dist/errors.d.ts +69 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +102 -0
- package/dist/errors.js.map +1 -0
- package/dist/event-bus.d.ts +159 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +305 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/execution-engine.d.ts +425 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/execution-engine.js +1555 -0
- package/dist/execution-engine.js.map +1 -0
- package/dist/git-intelligence.d.ts +306 -0
- package/dist/git-intelligence.d.ts.map +1 -0
- package/dist/git-intelligence.js +1099 -0
- package/dist/git-intelligence.js.map +1 -0
- package/dist/governor.d.ts +77 -0
- package/dist/governor.d.ts.map +1 -0
- package/dist/governor.js +161 -0
- package/dist/governor.js.map +1 -0
- package/dist/hierarchical-planner.d.ts +313 -0
- package/dist/hierarchical-planner.d.ts.map +1 -0
- package/dist/hierarchical-planner.js +981 -0
- package/dist/hierarchical-planner.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/intent-inference.d.ts +103 -0
- package/dist/intent-inference.d.ts.map +1 -0
- package/dist/intent-inference.js +605 -0
- package/dist/intent-inference.js.map +1 -0
- package/dist/interrupt-manager.d.ts +143 -0
- package/dist/interrupt-manager.d.ts.map +1 -0
- package/dist/interrupt-manager.js +196 -0
- package/dist/interrupt-manager.js.map +1 -0
- package/dist/kernel.d.ts +564 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +1419 -0
- package/dist/kernel.js.map +1 -0
- package/dist/language-support.d.ts +232 -0
- package/dist/language-support.d.ts.map +1 -0
- package/dist/language-support.js +1134 -0
- package/dist/language-support.js.map +1 -0
- package/dist/llm-client.d.ts +82 -0
- package/dist/llm-client.d.ts.map +1 -0
- package/dist/llm-client.js +475 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/mcp-client.d.ts +232 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +718 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/memory-manager.d.ts +200 -0
- package/dist/memory-manager.d.ts.map +1 -0
- package/dist/memory-manager.js +568 -0
- package/dist/memory-manager.js.map +1 -0
- package/dist/memory.d.ts +87 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +341 -0
- package/dist/memory.js.map +1 -0
- package/dist/model-router.d.ts +245 -0
- package/dist/model-router.d.ts.map +1 -0
- package/dist/model-router.js +632 -0
- package/dist/model-router.js.map +1 -0
- package/dist/parallel-executor.d.ts +125 -0
- package/dist/parallel-executor.d.ts.map +1 -0
- package/dist/parallel-executor.js +201 -0
- package/dist/parallel-executor.js.map +1 -0
- package/dist/perf-optimizer.d.ts +212 -0
- package/dist/perf-optimizer.d.ts.map +1 -0
- package/dist/perf-optimizer.js +721 -0
- package/dist/perf-optimizer.js.map +1 -0
- package/dist/persona.d.ts +305 -0
- package/dist/persona.d.ts.map +1 -0
- package/dist/persona.js +887 -0
- package/dist/persona.js.map +1 -0
- package/dist/planner.d.ts +70 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +264 -0
- package/dist/planner.js.map +1 -0
- package/dist/qa-pipeline.d.ts +365 -0
- package/dist/qa-pipeline.d.ts.map +1 -0
- package/dist/qa-pipeline.js +1352 -0
- package/dist/qa-pipeline.js.map +1 -0
- package/dist/reasoning-adapter.d.ts +116 -0
- package/dist/reasoning-adapter.d.ts.map +1 -0
- package/dist/reasoning-adapter.js +187 -0
- package/dist/reasoning-adapter.js.map +1 -0
- package/dist/role-registry.d.ts +55 -0
- package/dist/role-registry.d.ts.map +1 -0
- package/dist/role-registry.js +192 -0
- package/dist/role-registry.js.map +1 -0
- package/dist/sandbox-tiers.d.ts +327 -0
- package/dist/sandbox-tiers.d.ts.map +1 -0
- package/dist/sandbox-tiers.js +928 -0
- package/dist/sandbox-tiers.js.map +1 -0
- package/dist/security-scanner.d.ts +222 -0
- package/dist/security-scanner.d.ts.map +1 -0
- package/dist/security-scanner.js +1129 -0
- package/dist/security-scanner.js.map +1 -0
- package/dist/security.d.ts +93 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +393 -0
- package/dist/security.js.map +1 -0
- package/dist/self-reflection.d.ts +397 -0
- package/dist/self-reflection.d.ts.map +1 -0
- package/dist/self-reflection.js +908 -0
- package/dist/self-reflection.js.map +1 -0
- package/dist/session-persistence.d.ts +191 -0
- package/dist/session-persistence.d.ts.map +1 -0
- package/dist/session-persistence.js +395 -0
- package/dist/session-persistence.js.map +1 -0
- package/dist/speculative-executor.d.ts +210 -0
- package/dist/speculative-executor.d.ts.map +1 -0
- package/dist/speculative-executor.js +618 -0
- package/dist/speculative-executor.js.map +1 -0
- package/dist/state-machine.d.ts +289 -0
- package/dist/state-machine.d.ts.map +1 -0
- package/dist/state-machine.js +695 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/sub-agent.d.ts +177 -0
- package/dist/sub-agent.d.ts.map +1 -0
- package/dist/sub-agent.js +303 -0
- package/dist/sub-agent.js.map +1 -0
- package/dist/system-prompt.d.ts +26 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +84 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/test-intelligence.d.ts +439 -0
- package/dist/test-intelligence.d.ts.map +1 -0
- package/dist/test-intelligence.js +1165 -0
- package/dist/test-intelligence.js.map +1 -0
- package/dist/types.d.ts +632 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/vector-index.d.ts +314 -0
- package/dist/vector-index.d.ts.map +1 -0
- package/dist/vector-index.js +618 -0
- package/dist/vector-index.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module event-bus
|
|
3
|
+
* @description HybridEventBus — 3계층 이벤트 전파 시스템.
|
|
4
|
+
*
|
|
5
|
+
* Layer 1: Process EventEmitter (CLI/Desktop, 0ms 레이턴시)
|
|
6
|
+
* Layer 2: Session EventBus (Web/Mobile, ~1ms)
|
|
7
|
+
* Layer 3: Team Broadcast (팀 모드, Redis Pub/Sub, ~5ms)
|
|
8
|
+
*
|
|
9
|
+
* 기능:
|
|
10
|
+
* - EventEmitter 기반 로컬 이벤트 (Layer 1+2)
|
|
11
|
+
* - 선택적 Redis 연동 (Layer 3, 팀 모드)
|
|
12
|
+
* - 시퀀스 번호 기반 이벤트 버퍼링 (SSE replay)
|
|
13
|
+
* - subscribe/emit/replay/broadcast
|
|
14
|
+
* - 최대 버퍼 500 이벤트
|
|
15
|
+
* - 팀 이벤트 필터 (progress:* 와 team:* 만 Redis로 전파)
|
|
16
|
+
*/
|
|
17
|
+
import type { BusEvent } from "./types.js";
|
|
18
|
+
/** HybridEventBus 생성 설정 */
|
|
19
|
+
export interface EventBusConfig {
|
|
20
|
+
/** 세션별 이벤트 버퍼 최대 크기 (기본 500) */
|
|
21
|
+
maxBuffer?: number;
|
|
22
|
+
/** Redis URL (팀 모드에서만 필요, 미지정 시 로컬 전용) */
|
|
23
|
+
redisUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
/** 시퀀스 번호 + 타임스탬프가 추가된 이벤트 */
|
|
26
|
+
export type StampedEvent = BusEvent & {
|
|
27
|
+
/** 세션 내 순서 번호 (1부터 시작) */
|
|
28
|
+
seq: number;
|
|
29
|
+
/** 이벤트 발행 시각 (epoch ms) */
|
|
30
|
+
ts: number;
|
|
31
|
+
};
|
|
32
|
+
/** 이벤트 리스너 함수 시그니처 */
|
|
33
|
+
export interface EventListener {
|
|
34
|
+
(event: StampedEvent): void;
|
|
35
|
+
}
|
|
36
|
+
/** 구독 해제 함수 */
|
|
37
|
+
export type Unsubscribe = () => void;
|
|
38
|
+
/**
|
|
39
|
+
* 3계층 하이브리드 이벤트 버스.
|
|
40
|
+
*
|
|
41
|
+
* - 로컬 EventEmitter로 Layer 1+2 처리 (0ms)
|
|
42
|
+
* - 선택적 Redis Pub/Sub로 Layer 3 팀 브로드캐스트 (~5ms)
|
|
43
|
+
* - 세션별 이벤트 버퍼로 SSE 재연결 시 replay 지원
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const bus = new HybridEventBus({ maxBuffer: 500 });
|
|
48
|
+
* await bus.init();
|
|
49
|
+
*
|
|
50
|
+
* const unsub = bus.subscribe("session-1", (event) => {
|
|
51
|
+
* console.log(event.kind, event.seq);
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* bus.emit("session-1", { kind: "agent:start", goal: "Fix bug" });
|
|
55
|
+
*
|
|
56
|
+
* // SSE 재연결 시 replay
|
|
57
|
+
* const missed = bus.replay("session-1", 5); // seq > 5인 이벤트
|
|
58
|
+
*
|
|
59
|
+
* unsub(); // 구독 해제
|
|
60
|
+
* await bus.destroy();
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare class HybridEventBus {
|
|
64
|
+
private readonly local;
|
|
65
|
+
private redis;
|
|
66
|
+
private readonly redisUrl;
|
|
67
|
+
private readonly maxBuffer;
|
|
68
|
+
/** 세션별 이벤트 버퍼 (replay용) */
|
|
69
|
+
private readonly buffers;
|
|
70
|
+
/** 세션별 시퀀스 카운터 */
|
|
71
|
+
private readonly seqCounters;
|
|
72
|
+
private initialized;
|
|
73
|
+
constructor(config?: EventBusConfig);
|
|
74
|
+
/**
|
|
75
|
+
* 이벤트 버스 초기화.
|
|
76
|
+
* Redis URL이 설정된 경우 연결을 시도한다.
|
|
77
|
+
* Redis 연결 실패 시에도 로컬 모드로 동작한다.
|
|
78
|
+
*/
|
|
79
|
+
init(): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* 이벤트 버스 종료.
|
|
82
|
+
* Redis 연결 해제 + 버퍼 클리어.
|
|
83
|
+
*/
|
|
84
|
+
destroy(): Promise<void>;
|
|
85
|
+
/** 팀 모드(Redis) 활성화 여부 */
|
|
86
|
+
get isTeamMode(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* 세션에 이벤트를 발행한다.
|
|
89
|
+
*
|
|
90
|
+
* 1. 시퀀스 번호 + 타임스탬프 부여
|
|
91
|
+
* 2. 로컬 EventEmitter로 즉시 전파 (Layer 1+2)
|
|
92
|
+
* 3. 버퍼에 저장 (SSE replay용)
|
|
93
|
+
* 4. 팀 이벤트 필터 통과 시 Redis 발행 (Layer 3)
|
|
94
|
+
*
|
|
95
|
+
* @param sessionId 세션 ID
|
|
96
|
+
* @param event 발행할 BusEvent
|
|
97
|
+
* @returns 부여된 시퀀스 번호
|
|
98
|
+
*/
|
|
99
|
+
emit(sessionId: string, event: BusEvent): number;
|
|
100
|
+
/**
|
|
101
|
+
* 세션의 이벤트를 구독한다 (Layer 1+2 로컬).
|
|
102
|
+
*
|
|
103
|
+
* @param sessionId 구독할 세션 ID
|
|
104
|
+
* @param listener 이벤트 리스너
|
|
105
|
+
* @returns 구독 해제 함수
|
|
106
|
+
*/
|
|
107
|
+
subscribe(sessionId: string, listener: EventListener): Unsubscribe;
|
|
108
|
+
/**
|
|
109
|
+
* SSE 재연결 시 놓친 이벤트를 재전송한다.
|
|
110
|
+
*
|
|
111
|
+
* @param sessionId 세션 ID
|
|
112
|
+
* @param fromSeq 이 시퀀스 이후의 이벤트만 반환 (exclusive)
|
|
113
|
+
* @returns 놓친 이벤트 배열
|
|
114
|
+
*/
|
|
115
|
+
replay(sessionId: string, fromSeq: number): StampedEvent[];
|
|
116
|
+
/**
|
|
117
|
+
* 워크스페이스 채널을 구독한다 (팀 모드, Redis 기반).
|
|
118
|
+
*
|
|
119
|
+
* @param workspaceId 워크스페이스 ID
|
|
120
|
+
* @param listener 이벤트 리스너
|
|
121
|
+
* @returns 구독 해제 함수
|
|
122
|
+
* @throws Redis가 활성화되지 않은 경우 에러
|
|
123
|
+
*/
|
|
124
|
+
subscribeWorkspace(workspaceId: string, listener: EventListener): Unsubscribe;
|
|
125
|
+
/**
|
|
126
|
+
* 팀 채널로 이벤트를 브로드캐스트한다 (Redis Pub/Sub).
|
|
127
|
+
* 로컬 세션 이벤트와 별도로, 워크스페이스 전체에 발행.
|
|
128
|
+
*
|
|
129
|
+
* @param workspaceId 워크스페이스 ID
|
|
130
|
+
* @param event 브로드캐스트할 이벤트
|
|
131
|
+
*/
|
|
132
|
+
broadcast(workspaceId: string, event: BusEvent): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* 세션의 버퍼와 시퀀스 카운터를 정리한다.
|
|
135
|
+
* 세션 종료 시 호출하여 메모리를 해제한다.
|
|
136
|
+
*
|
|
137
|
+
* @param sessionId 정리할 세션 ID
|
|
138
|
+
*/
|
|
139
|
+
clearSession(sessionId: string): void;
|
|
140
|
+
/**
|
|
141
|
+
* 현재 버퍼에 저장된 세션의 이벤트 수를 반환한다.
|
|
142
|
+
*
|
|
143
|
+
* @param sessionId 세션 ID
|
|
144
|
+
* @returns 버퍼된 이벤트 수
|
|
145
|
+
*/
|
|
146
|
+
getBufferSize(sessionId: string): number;
|
|
147
|
+
/**
|
|
148
|
+
* 세션의 현재 시퀀스 번호를 반환한다.
|
|
149
|
+
*
|
|
150
|
+
* @param sessionId 세션 ID
|
|
151
|
+
* @returns 현재 시퀀스 번호 (이벤트가 없으면 0)
|
|
152
|
+
*/
|
|
153
|
+
getCurrentSeq(sessionId: string): number;
|
|
154
|
+
/** 세션의 다음 시퀀스 번호를 발급한다 */
|
|
155
|
+
private nextSeq;
|
|
156
|
+
/** 이벤트를 세션 버퍼에 저장한다 (maxBuffer 초과 시 오래된 이벤트 삭제) */
|
|
157
|
+
private bufferEvent;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8BAA8B;AAC9B,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7B;AAED,eAAe;AACf,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAiGrC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,kBAAkB;IAClB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,GAAE,cAAmB;IAUvC;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,yBAAyB;IACzB,IAAI,UAAU,IAAI,OAAO,CAExB;IAID;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM;IA8BhD;;;;;;OAMG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,WAAW;IASlE;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAQ1D;;;;;;;OAOG;IACH,kBAAkB,CAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,aAAa,GACtB,WAAW;IAkBd;;;;;;OAMG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBpE;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMrC;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIxC;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAMxC,0BAA0B;IAC1B,OAAO,CAAC,OAAO;IAOf,mDAAmD;IACnD,OAAO,CAAC,WAAW;CAepB"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module event-bus
|
|
3
|
+
* @description HybridEventBus — 3계층 이벤트 전파 시스템.
|
|
4
|
+
*
|
|
5
|
+
* Layer 1: Process EventEmitter (CLI/Desktop, 0ms 레이턴시)
|
|
6
|
+
* Layer 2: Session EventBus (Web/Mobile, ~1ms)
|
|
7
|
+
* Layer 3: Team Broadcast (팀 모드, Redis Pub/Sub, ~5ms)
|
|
8
|
+
*
|
|
9
|
+
* 기능:
|
|
10
|
+
* - EventEmitter 기반 로컬 이벤트 (Layer 1+2)
|
|
11
|
+
* - 선택적 Redis 연동 (Layer 3, 팀 모드)
|
|
12
|
+
* - 시퀀스 번호 기반 이벤트 버퍼링 (SSE replay)
|
|
13
|
+
* - subscribe/emit/replay/broadcast
|
|
14
|
+
* - 최대 버퍼 500 이벤트
|
|
15
|
+
* - 팀 이벤트 필터 (progress:* 와 team:* 만 Redis로 전파)
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from "node:events";
|
|
18
|
+
// ─── Redis 팩토리 (동적 import) ───
|
|
19
|
+
/**
|
|
20
|
+
* ioredis가 설치된 환경에서만 Redis 어댑터를 생성.
|
|
21
|
+
* 설치되지 않은 경우 null을 반환하며, 팀 모드는 비활성화된다.
|
|
22
|
+
*/
|
|
23
|
+
async function createRedisAdapter(redisUrl) {
|
|
24
|
+
try {
|
|
25
|
+
const ioredis = await import("ioredis");
|
|
26
|
+
// ioredis exports vary between CJS/ESM — handle both shapes
|
|
27
|
+
const RedisClass = (typeof ioredis.default === "function"
|
|
28
|
+
? ioredis.default
|
|
29
|
+
: ioredis);
|
|
30
|
+
const pub = new RedisClass(redisUrl);
|
|
31
|
+
const sub = new RedisClass(redisUrl);
|
|
32
|
+
const subscriptions = new Map();
|
|
33
|
+
return {
|
|
34
|
+
async publish(channel, message) {
|
|
35
|
+
await pub.publish(channel, message);
|
|
36
|
+
},
|
|
37
|
+
subscribe(channel, listener) {
|
|
38
|
+
const handler = (ch, msg) => {
|
|
39
|
+
if (ch === channel)
|
|
40
|
+
listener(msg);
|
|
41
|
+
};
|
|
42
|
+
subscriptions.set(channel, handler);
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
44
|
+
sub.subscribe(channel);
|
|
45
|
+
sub.on("message", handler);
|
|
46
|
+
return () => {
|
|
47
|
+
sub.off("message", handler);
|
|
48
|
+
subscriptions.delete(channel);
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
50
|
+
sub.unsubscribe(channel);
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
async disconnect() {
|
|
54
|
+
subscriptions.clear();
|
|
55
|
+
await Promise.all([pub.quit(), sub.quit()]);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// ioredis가 설치되지 않은 환경 — 팀 모드 비활성화
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ─── 팀 이벤트 필터 ───
|
|
65
|
+
/** Redis로 전파할 이벤트 종류 prefix 목록 */
|
|
66
|
+
const TEAM_EVENT_PREFIXES = [
|
|
67
|
+
"progress:",
|
|
68
|
+
"team:",
|
|
69
|
+
"agent:completed",
|
|
70
|
+
"agent:error",
|
|
71
|
+
];
|
|
72
|
+
/** 해당 이벤트가 팀 채널로 전파되어야 하는지 판별 */
|
|
73
|
+
function isTeamEvent(kind) {
|
|
74
|
+
return TEAM_EVENT_PREFIXES.some((prefix) => kind.startsWith(prefix));
|
|
75
|
+
}
|
|
76
|
+
// ─── HybridEventBus ───
|
|
77
|
+
/**
|
|
78
|
+
* 3계층 하이브리드 이벤트 버스.
|
|
79
|
+
*
|
|
80
|
+
* - 로컬 EventEmitter로 Layer 1+2 처리 (0ms)
|
|
81
|
+
* - 선택적 Redis Pub/Sub로 Layer 3 팀 브로드캐스트 (~5ms)
|
|
82
|
+
* - 세션별 이벤트 버퍼로 SSE 재연결 시 replay 지원
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const bus = new HybridEventBus({ maxBuffer: 500 });
|
|
87
|
+
* await bus.init();
|
|
88
|
+
*
|
|
89
|
+
* const unsub = bus.subscribe("session-1", (event) => {
|
|
90
|
+
* console.log(event.kind, event.seq);
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* bus.emit("session-1", { kind: "agent:start", goal: "Fix bug" });
|
|
94
|
+
*
|
|
95
|
+
* // SSE 재연결 시 replay
|
|
96
|
+
* const missed = bus.replay("session-1", 5); // seq > 5인 이벤트
|
|
97
|
+
*
|
|
98
|
+
* unsub(); // 구독 해제
|
|
99
|
+
* await bus.destroy();
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export class HybridEventBus {
|
|
103
|
+
local = new EventEmitter();
|
|
104
|
+
redis = null;
|
|
105
|
+
redisUrl;
|
|
106
|
+
maxBuffer;
|
|
107
|
+
/** 세션별 이벤트 버퍼 (replay용) */
|
|
108
|
+
buffers = new Map();
|
|
109
|
+
/** 세션별 시퀀스 카운터 */
|
|
110
|
+
seqCounters = new Map();
|
|
111
|
+
initialized = false;
|
|
112
|
+
constructor(config = {}) {
|
|
113
|
+
this.maxBuffer = config.maxBuffer ?? 500;
|
|
114
|
+
this.redisUrl = config.redisUrl;
|
|
115
|
+
// EventEmitter 리스너 한도를 넉넉하게 설정 (세션별 구독자)
|
|
116
|
+
this.local.setMaxListeners(100);
|
|
117
|
+
}
|
|
118
|
+
// ─── Lifecycle ───
|
|
119
|
+
/**
|
|
120
|
+
* 이벤트 버스 초기화.
|
|
121
|
+
* Redis URL이 설정된 경우 연결을 시도한다.
|
|
122
|
+
* Redis 연결 실패 시에도 로컬 모드로 동작한다.
|
|
123
|
+
*/
|
|
124
|
+
async init() {
|
|
125
|
+
if (this.initialized)
|
|
126
|
+
return;
|
|
127
|
+
if (this.redisUrl) {
|
|
128
|
+
this.redis = await createRedisAdapter(this.redisUrl);
|
|
129
|
+
}
|
|
130
|
+
this.initialized = true;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 이벤트 버스 종료.
|
|
134
|
+
* Redis 연결 해제 + 버퍼 클리어.
|
|
135
|
+
*/
|
|
136
|
+
async destroy() {
|
|
137
|
+
if (this.redis) {
|
|
138
|
+
await this.redis.disconnect();
|
|
139
|
+
this.redis = null;
|
|
140
|
+
}
|
|
141
|
+
this.buffers.clear();
|
|
142
|
+
this.seqCounters.clear();
|
|
143
|
+
this.local.removeAllListeners();
|
|
144
|
+
this.initialized = false;
|
|
145
|
+
}
|
|
146
|
+
/** 팀 모드(Redis) 활성화 여부 */
|
|
147
|
+
get isTeamMode() {
|
|
148
|
+
return this.redis !== null;
|
|
149
|
+
}
|
|
150
|
+
// ─── Emit ───
|
|
151
|
+
/**
|
|
152
|
+
* 세션에 이벤트를 발행한다.
|
|
153
|
+
*
|
|
154
|
+
* 1. 시퀀스 번호 + 타임스탬프 부여
|
|
155
|
+
* 2. 로컬 EventEmitter로 즉시 전파 (Layer 1+2)
|
|
156
|
+
* 3. 버퍼에 저장 (SSE replay용)
|
|
157
|
+
* 4. 팀 이벤트 필터 통과 시 Redis 발행 (Layer 3)
|
|
158
|
+
*
|
|
159
|
+
* @param sessionId 세션 ID
|
|
160
|
+
* @param event 발행할 BusEvent
|
|
161
|
+
* @returns 부여된 시퀀스 번호
|
|
162
|
+
*/
|
|
163
|
+
emit(sessionId, event) {
|
|
164
|
+
const seq = this.nextSeq(sessionId);
|
|
165
|
+
const stamped = {
|
|
166
|
+
...event,
|
|
167
|
+
seq,
|
|
168
|
+
ts: Date.now(),
|
|
169
|
+
};
|
|
170
|
+
// Layer 1+2: 로컬 즉시 전파
|
|
171
|
+
this.local.emit(`session:${sessionId}`, stamped);
|
|
172
|
+
// 버퍼에 저장
|
|
173
|
+
this.bufferEvent(sessionId, stamped);
|
|
174
|
+
// Layer 3: 팀 모드 — 필터된 이벤트만 Redis로
|
|
175
|
+
if (this.redis && isTeamEvent(event.kind)) {
|
|
176
|
+
// fire-and-forget (Redis 발행 실패가 로컬 전파를 막지 않음)
|
|
177
|
+
this.redis.publish(`team:${sessionId}`, JSON.stringify(stamped)).catch(() => {
|
|
178
|
+
// Redis 발행 실패는 무시 (로컬 전파는 이미 완료)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return seq;
|
|
182
|
+
}
|
|
183
|
+
// ─── Subscribe ───
|
|
184
|
+
/**
|
|
185
|
+
* 세션의 이벤트를 구독한다 (Layer 1+2 로컬).
|
|
186
|
+
*
|
|
187
|
+
* @param sessionId 구독할 세션 ID
|
|
188
|
+
* @param listener 이벤트 리스너
|
|
189
|
+
* @returns 구독 해제 함수
|
|
190
|
+
*/
|
|
191
|
+
subscribe(sessionId, listener) {
|
|
192
|
+
this.local.on(`session:${sessionId}`, listener);
|
|
193
|
+
return () => {
|
|
194
|
+
this.local.off(`session:${sessionId}`, listener);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// ─── Replay ───
|
|
198
|
+
/**
|
|
199
|
+
* SSE 재연결 시 놓친 이벤트를 재전송한다.
|
|
200
|
+
*
|
|
201
|
+
* @param sessionId 세션 ID
|
|
202
|
+
* @param fromSeq 이 시퀀스 이후의 이벤트만 반환 (exclusive)
|
|
203
|
+
* @returns 놓친 이벤트 배열
|
|
204
|
+
*/
|
|
205
|
+
replay(sessionId, fromSeq) {
|
|
206
|
+
const buffer = this.buffers.get(sessionId);
|
|
207
|
+
if (!buffer)
|
|
208
|
+
return [];
|
|
209
|
+
return buffer.filter((e) => e.seq > fromSeq);
|
|
210
|
+
}
|
|
211
|
+
// ─── Team Broadcast (Layer 3) ───
|
|
212
|
+
/**
|
|
213
|
+
* 워크스페이스 채널을 구독한다 (팀 모드, Redis 기반).
|
|
214
|
+
*
|
|
215
|
+
* @param workspaceId 워크스페이스 ID
|
|
216
|
+
* @param listener 이벤트 리스너
|
|
217
|
+
* @returns 구독 해제 함수
|
|
218
|
+
* @throws Redis가 활성화되지 않은 경우 에러
|
|
219
|
+
*/
|
|
220
|
+
subscribeWorkspace(workspaceId, listener) {
|
|
221
|
+
if (!this.redis) {
|
|
222
|
+
throw new Error("Team mode requires Redis — provide redisUrl in config");
|
|
223
|
+
}
|
|
224
|
+
return this.redis.subscribe(`workspace:${workspaceId}`, (message) => {
|
|
225
|
+
try {
|
|
226
|
+
const event = JSON.parse(message);
|
|
227
|
+
listener(event);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// 파싱 실패한 메시지는 무시
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 팀 채널로 이벤트를 브로드캐스트한다 (Redis Pub/Sub).
|
|
236
|
+
* 로컬 세션 이벤트와 별도로, 워크스페이스 전체에 발행.
|
|
237
|
+
*
|
|
238
|
+
* @param workspaceId 워크스페이스 ID
|
|
239
|
+
* @param event 브로드캐스트할 이벤트
|
|
240
|
+
*/
|
|
241
|
+
async broadcast(workspaceId, event) {
|
|
242
|
+
if (!this.redis) {
|
|
243
|
+
throw new Error("Team mode requires Redis — provide redisUrl in config");
|
|
244
|
+
}
|
|
245
|
+
const stamped = {
|
|
246
|
+
...event,
|
|
247
|
+
seq: 0, // 워크스페이스 브로드캐스트는 세션 seq 없음
|
|
248
|
+
ts: Date.now(),
|
|
249
|
+
};
|
|
250
|
+
await this.redis.publish(`workspace:${workspaceId}`, JSON.stringify(stamped));
|
|
251
|
+
}
|
|
252
|
+
// ─── Session Cleanup ───
|
|
253
|
+
/**
|
|
254
|
+
* 세션의 버퍼와 시퀀스 카운터를 정리한다.
|
|
255
|
+
* 세션 종료 시 호출하여 메모리를 해제한다.
|
|
256
|
+
*
|
|
257
|
+
* @param sessionId 정리할 세션 ID
|
|
258
|
+
*/
|
|
259
|
+
clearSession(sessionId) {
|
|
260
|
+
this.buffers.delete(sessionId);
|
|
261
|
+
this.seqCounters.delete(sessionId);
|
|
262
|
+
this.local.removeAllListeners(`session:${sessionId}`);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 현재 버퍼에 저장된 세션의 이벤트 수를 반환한다.
|
|
266
|
+
*
|
|
267
|
+
* @param sessionId 세션 ID
|
|
268
|
+
* @returns 버퍼된 이벤트 수
|
|
269
|
+
*/
|
|
270
|
+
getBufferSize(sessionId) {
|
|
271
|
+
return this.buffers.get(sessionId)?.length ?? 0;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 세션의 현재 시퀀스 번호를 반환한다.
|
|
275
|
+
*
|
|
276
|
+
* @param sessionId 세션 ID
|
|
277
|
+
* @returns 현재 시퀀스 번호 (이벤트가 없으면 0)
|
|
278
|
+
*/
|
|
279
|
+
getCurrentSeq(sessionId) {
|
|
280
|
+
return this.seqCounters.get(sessionId) ?? 0;
|
|
281
|
+
}
|
|
282
|
+
// ─── Private Helpers ───
|
|
283
|
+
/** 세션의 다음 시퀀스 번호를 발급한다 */
|
|
284
|
+
nextSeq(sessionId) {
|
|
285
|
+
const current = this.seqCounters.get(sessionId) ?? 0;
|
|
286
|
+
const next = current + 1;
|
|
287
|
+
this.seqCounters.set(sessionId, next);
|
|
288
|
+
return next;
|
|
289
|
+
}
|
|
290
|
+
/** 이벤트를 세션 버퍼에 저장한다 (maxBuffer 초과 시 오래된 이벤트 삭제) */
|
|
291
|
+
bufferEvent(sessionId, event) {
|
|
292
|
+
let buffer = this.buffers.get(sessionId);
|
|
293
|
+
if (!buffer) {
|
|
294
|
+
buffer = [];
|
|
295
|
+
this.buffers.set(sessionId, buffer);
|
|
296
|
+
}
|
|
297
|
+
buffer.push(event);
|
|
298
|
+
// 버퍼 크기 제한 — 초과분 앞에서 삭제
|
|
299
|
+
if (buffer.length > this.maxBuffer) {
|
|
300
|
+
const excess = buffer.length - this.maxBuffer;
|
|
301
|
+
buffer.splice(0, excess);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"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"}
|