intent-hub 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.
Files changed (214) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.turbo/cache/019f5ae385027cb1-meta.json +1 -0
  3. package/.turbo/cache/019f5ae385027cb1.tar.zst +0 -0
  4. package/.turbo/cache/040af6112a552a64-meta.json +1 -0
  5. package/.turbo/cache/040af6112a552a64.tar.zst +0 -0
  6. package/.turbo/cache/11195eac3ca5c6ce-meta.json +1 -0
  7. package/.turbo/cache/11195eac3ca5c6ce.tar.zst +0 -0
  8. package/.turbo/cache/13d11166efdf11cf-meta.json +1 -0
  9. package/.turbo/cache/13d11166efdf11cf.tar.zst +0 -0
  10. package/.turbo/cache/19af1af3b136706c-meta.json +1 -0
  11. package/.turbo/cache/19af1af3b136706c.tar.zst +0 -0
  12. package/.turbo/cache/1d33efac91c05b50-meta.json +1 -0
  13. package/.turbo/cache/1d33efac91c05b50.tar.zst +0 -0
  14. package/.turbo/cache/200b85a612af2d13-meta.json +1 -0
  15. package/.turbo/cache/200b85a612af2d13.tar.zst +0 -0
  16. package/.turbo/cache/210308c9ea929858-meta.json +1 -0
  17. package/.turbo/cache/210308c9ea929858.tar.zst +0 -0
  18. package/.turbo/cache/38df8e44c617835e-meta.json +1 -0
  19. package/.turbo/cache/38df8e44c617835e.tar.zst +0 -0
  20. package/.turbo/cache/3e449de5ef60a7a0-meta.json +1 -0
  21. package/.turbo/cache/3e449de5ef60a7a0.tar.zst +0 -0
  22. package/.turbo/cache/51ff024a97c2b4f5-meta.json +1 -0
  23. package/.turbo/cache/51ff024a97c2b4f5.tar.zst +0 -0
  24. package/.turbo/cache/54bc756eeebb377a-meta.json +1 -0
  25. package/.turbo/cache/54bc756eeebb377a.tar.zst +0 -0
  26. package/.turbo/cache/5ed6a840acafc873-meta.json +1 -0
  27. package/.turbo/cache/5ed6a840acafc873.tar.zst +0 -0
  28. package/.turbo/cache/6702dc24e5ca3c2e-meta.json +1 -0
  29. package/.turbo/cache/6702dc24e5ca3c2e.tar.zst +0 -0
  30. package/.turbo/cache/725c72cf71ea854f-meta.json +1 -0
  31. package/.turbo/cache/725c72cf71ea854f.tar.zst +0 -0
  32. package/.turbo/cache/7344ca28d348037a-meta.json +1 -0
  33. package/.turbo/cache/7344ca28d348037a.tar.zst +0 -0
  34. package/.turbo/cache/748fb444cdc0b78c-meta.json +1 -0
  35. package/.turbo/cache/748fb444cdc0b78c.tar.zst +0 -0
  36. package/.turbo/cache/789677c36fe7fb98-meta.json +1 -0
  37. package/.turbo/cache/789677c36fe7fb98.tar.zst +0 -0
  38. package/.turbo/cache/89ff6c6f38dd4a18-meta.json +1 -0
  39. package/.turbo/cache/89ff6c6f38dd4a18.tar.zst +0 -0
  40. package/.turbo/cache/8dbc92d00de0c92e-meta.json +1 -0
  41. package/.turbo/cache/8dbc92d00de0c92e.tar.zst +0 -0
  42. package/.turbo/cache/8eb03f40082b9441-meta.json +1 -0
  43. package/.turbo/cache/8eb03f40082b9441.tar.zst +0 -0
  44. package/.turbo/cache/9157134d4b916017-meta.json +1 -0
  45. package/.turbo/cache/9157134d4b916017.tar.zst +0 -0
  46. package/.turbo/cache/94219ffd32b48e93-meta.json +1 -0
  47. package/.turbo/cache/94219ffd32b48e93.tar.zst +0 -0
  48. package/.turbo/cache/95c1d160b4fa84eb-meta.json +1 -0
  49. package/.turbo/cache/95c1d160b4fa84eb.tar.zst +0 -0
  50. package/.turbo/cache/998833ea02dfb225-meta.json +1 -0
  51. package/.turbo/cache/998833ea02dfb225.tar.zst +0 -0
  52. package/.turbo/cache/a5974ef6ade3eb90-meta.json +1 -0
  53. package/.turbo/cache/a5974ef6ade3eb90.tar.zst +0 -0
  54. package/.turbo/cache/aab811809257decb-meta.json +1 -0
  55. package/.turbo/cache/aab811809257decb.tar.zst +0 -0
  56. package/.turbo/cache/ab2f82a54da854fd-meta.json +1 -0
  57. package/.turbo/cache/ab2f82a54da854fd.tar.zst +0 -0
  58. package/.turbo/cache/abbf4d95d62a7303-meta.json +1 -0
  59. package/.turbo/cache/abbf4d95d62a7303.tar.zst +0 -0
  60. package/.turbo/cache/af4441f519f9ce50-meta.json +1 -0
  61. package/.turbo/cache/af4441f519f9ce50.tar.zst +0 -0
  62. package/.turbo/cache/b9b85aaaf03d00a6-meta.json +1 -0
  63. package/.turbo/cache/b9b85aaaf03d00a6.tar.zst +0 -0
  64. package/.turbo/cache/cd58ee8721bbfed7-meta.json +1 -0
  65. package/.turbo/cache/cd58ee8721bbfed7.tar.zst +0 -0
  66. package/.turbo/cache/d285e48b8afa30b5-meta.json +1 -0
  67. package/.turbo/cache/d285e48b8afa30b5.tar.zst +0 -0
  68. package/.turbo/cache/d33e90229142acce-meta.json +1 -0
  69. package/.turbo/cache/d33e90229142acce.tar.zst +0 -0
  70. package/.turbo/cache/d57839a0d3b04540-meta.json +1 -0
  71. package/.turbo/cache/d57839a0d3b04540.tar.zst +0 -0
  72. package/.turbo/cache/d8554ef2c8b6e5eb-meta.json +1 -0
  73. package/.turbo/cache/d8554ef2c8b6e5eb.tar.zst +0 -0
  74. package/.turbo/cache/dc7375b51290e102-meta.json +1 -0
  75. package/.turbo/cache/dc7375b51290e102.tar.zst +0 -0
  76. package/.turbo/cache/e5310fe547fdbf0a-meta.json +1 -0
  77. package/.turbo/cache/e5310fe547fdbf0a.tar.zst +0 -0
  78. package/.turbo/cache/f12bb5f2f188758d-meta.json +1 -0
  79. package/.turbo/cache/f12bb5f2f188758d.tar.zst +0 -0
  80. package/.turbo/cache/f2db5af0c0b4d23f-meta.json +1 -0
  81. package/.turbo/cache/f2db5af0c0b4d23f.tar.zst +0 -0
  82. package/.turbo/cache/f8935ade01a88cd7-meta.json +1 -0
  83. package/.turbo/cache/f8935ade01a88cd7.tar.zst +0 -0
  84. package/.turbo/cache/f982b8dd966f823a-meta.json +1 -0
  85. package/.turbo/cache/f982b8dd966f823a.tar.zst +0 -0
  86. package/.turbo/cache/f9d4036dd350ba1a-meta.json +1 -0
  87. package/.turbo/cache/f9d4036dd350ba1a.tar.zst +0 -0
  88. package/README.md +661 -0
  89. package/README_ko.md +577 -0
  90. package/bun.lock +135 -0
  91. package/package.json +26 -0
  92. package/packages/agent/.turbo/turbo-build.log +5 -0
  93. package/packages/agent/.turbo/turbo-typecheck.log +1 -0
  94. package/packages/agent/dist/connection/hub-client.d.ts +33 -0
  95. package/packages/agent/dist/connection/hub-client.d.ts.map +1 -0
  96. package/packages/agent/dist/connection/index.d.ts +2 -0
  97. package/packages/agent/dist/connection/index.d.ts.map +1 -0
  98. package/packages/agent/dist/hooks/index.d.ts +3 -0
  99. package/packages/agent/dist/hooks/index.d.ts.map +1 -0
  100. package/packages/agent/dist/hooks/intent-hub-hooks.d.ts +47 -0
  101. package/packages/agent/dist/hooks/intent-hub-hooks.d.ts.map +1 -0
  102. package/packages/agent/dist/index.d.ts +6 -0
  103. package/packages/agent/dist/index.d.ts.map +1 -0
  104. package/packages/agent/dist/index.js +3315 -0
  105. package/packages/agent/dist/plugin/index.d.ts +3 -0
  106. package/packages/agent/dist/plugin/index.d.ts.map +1 -0
  107. package/packages/agent/dist/plugin/intent-hub-plugin.d.ts +54 -0
  108. package/packages/agent/dist/plugin/intent-hub-plugin.d.ts.map +1 -0
  109. package/packages/agent/package.json +32 -0
  110. package/packages/agent/src/connection/hub-client.ts +152 -0
  111. package/packages/agent/src/connection/index.ts +1 -0
  112. package/packages/agent/src/hooks/index.ts +2 -0
  113. package/packages/agent/src/hooks/intent-hub-hooks.ts +245 -0
  114. package/packages/agent/src/index.ts +5 -0
  115. package/packages/agent/src/plugin/index.ts +2 -0
  116. package/packages/agent/src/plugin/intent-hub-plugin.ts +153 -0
  117. package/packages/agent/tsconfig.json +9 -0
  118. package/packages/hub/.turbo/turbo-build.log +6 -0
  119. package/packages/hub/.turbo/turbo-typecheck.log +1 -0
  120. package/packages/hub/dist/api/dashboard.d.ts +17 -0
  121. package/packages/hub/dist/api/dashboard.d.ts.map +1 -0
  122. package/packages/hub/dist/cli.d.ts +3 -0
  123. package/packages/hub/dist/cli.d.ts.map +1 -0
  124. package/packages/hub/dist/cli.js +7719 -0
  125. package/packages/hub/dist/core/conflict-detector.d.ts +36 -0
  126. package/packages/hub/dist/core/conflict-detector.d.ts.map +1 -0
  127. package/packages/hub/dist/core/index.d.ts +7 -0
  128. package/packages/hub/dist/core/index.d.ts.map +1 -0
  129. package/packages/hub/dist/core/intent-analyzer.d.ts +8 -0
  130. package/packages/hub/dist/core/intent-analyzer.d.ts.map +1 -0
  131. package/packages/hub/dist/core/lock-manager.d.ts +13 -0
  132. package/packages/hub/dist/core/lock-manager.d.ts.map +1 -0
  133. package/packages/hub/dist/core/orchestrator.d.ts +46 -0
  134. package/packages/hub/dist/core/orchestrator.d.ts.map +1 -0
  135. package/packages/hub/dist/index.d.ts +9 -0
  136. package/packages/hub/dist/index.d.ts.map +1 -0
  137. package/packages/hub/dist/index.js +4686 -0
  138. package/packages/hub/dist/llm/index.d.ts +7 -0
  139. package/packages/hub/dist/llm/index.d.ts.map +1 -0
  140. package/packages/hub/dist/llm/negotiation-engine.d.ts +40 -0
  141. package/packages/hub/dist/llm/negotiation-engine.d.ts.map +1 -0
  142. package/packages/hub/dist/llm/provider.d.ts +46 -0
  143. package/packages/hub/dist/llm/provider.d.ts.map +1 -0
  144. package/packages/hub/dist/llm/smart-analyzer.d.ts +20 -0
  145. package/packages/hub/dist/llm/smart-analyzer.d.ts.map +1 -0
  146. package/packages/hub/dist/server/hub-server.d.ts +35 -0
  147. package/packages/hub/dist/server/hub-server.d.ts.map +1 -0
  148. package/packages/hub/dist/server/index.d.ts +5 -0
  149. package/packages/hub/dist/server/index.d.ts.map +1 -0
  150. package/packages/hub/dist/server/message-handler.d.ts +18 -0
  151. package/packages/hub/dist/server/message-handler.d.ts.map +1 -0
  152. package/packages/hub/dist/server/smart-hub-server.d.ts +43 -0
  153. package/packages/hub/dist/server/smart-hub-server.d.ts.map +1 -0
  154. package/packages/hub/dist/state/index.d.ts +2 -0
  155. package/packages/hub/dist/state/index.d.ts.map +1 -0
  156. package/packages/hub/dist/state/session-manager.d.ts +19 -0
  157. package/packages/hub/dist/state/session-manager.d.ts.map +1 -0
  158. package/packages/hub/dist/tunnel/index.d.ts +14 -0
  159. package/packages/hub/dist/tunnel/index.d.ts.map +1 -0
  160. package/packages/hub/package.json +54 -0
  161. package/packages/hub/src/api/dashboard.ts +261 -0
  162. package/packages/hub/src/cli.ts +193 -0
  163. package/packages/hub/src/core/conflict-detector.ts +138 -0
  164. package/packages/hub/src/core/index.ts +6 -0
  165. package/packages/hub/src/core/intent-analyzer.ts +112 -0
  166. package/packages/hub/src/core/lock-manager.ts +95 -0
  167. package/packages/hub/src/core/orchestrator.ts +255 -0
  168. package/packages/hub/src/index.ts +8 -0
  169. package/packages/hub/src/llm/index.ts +17 -0
  170. package/packages/hub/src/llm/negotiation-engine.ts +297 -0
  171. package/packages/hub/src/llm/provider.ts +175 -0
  172. package/packages/hub/src/llm/smart-analyzer.ts +169 -0
  173. package/packages/hub/src/server/hub-server.ts +219 -0
  174. package/packages/hub/src/server/index.ts +4 -0
  175. package/packages/hub/src/server/message-handler.ts +111 -0
  176. package/packages/hub/src/server/smart-hub-server.ts +374 -0
  177. package/packages/hub/src/state/index.ts +1 -0
  178. package/packages/hub/src/state/session-manager.ts +59 -0
  179. package/packages/hub/src/tunnel/index.ts +153 -0
  180. package/packages/hub/tsconfig.json +9 -0
  181. package/packages/shared/.turbo/turbo-build.log +5 -0
  182. package/packages/shared/.turbo/turbo-typecheck.log +1 -0
  183. package/packages/shared/dist/index.d.ts +3 -0
  184. package/packages/shared/dist/index.d.ts.map +1 -0
  185. package/packages/shared/dist/index.js +50 -0
  186. package/packages/shared/dist/types/domain.d.ts +50 -0
  187. package/packages/shared/dist/types/domain.d.ts.map +1 -0
  188. package/packages/shared/dist/types/index.d.ts +4 -0
  189. package/packages/shared/dist/types/index.d.ts.map +1 -0
  190. package/packages/shared/dist/types/intent.d.ts +24 -0
  191. package/packages/shared/dist/types/intent.d.ts.map +1 -0
  192. package/packages/shared/dist/types/message.d.ts +151 -0
  193. package/packages/shared/dist/types/message.d.ts.map +1 -0
  194. package/packages/shared/dist/utils/id.d.ts +6 -0
  195. package/packages/shared/dist/utils/id.d.ts.map +1 -0
  196. package/packages/shared/dist/utils/index.d.ts +3 -0
  197. package/packages/shared/dist/utils/index.d.ts.map +1 -0
  198. package/packages/shared/dist/utils/message.d.ts +5 -0
  199. package/packages/shared/dist/utils/message.d.ts.map +1 -0
  200. package/packages/shared/package.json +33 -0
  201. package/packages/shared/src/index.ts +2 -0
  202. package/packages/shared/src/types/domain.ts +57 -0
  203. package/packages/shared/src/types/index.ts +3 -0
  204. package/packages/shared/src/types/intent.ts +34 -0
  205. package/packages/shared/src/types/message.ts +188 -0
  206. package/packages/shared/src/utils/id.ts +21 -0
  207. package/packages/shared/src/utils/index.ts +2 -0
  208. package/packages/shared/src/utils/message.ts +30 -0
  209. package/packages/shared/tsconfig.json +9 -0
  210. package/scripts/test-e2e.ts +194 -0
  211. package/scripts/test-mvp2.ts +167 -0
  212. package/scripts/test-mvp3.ts +405 -0
  213. package/tsconfig.json +19 -0
  214. package/turbo.json +22 -0
@@ -0,0 +1,405 @@
1
+ /**
2
+ * MVP 3 E2E Test - Full Integration Test
3
+ *
4
+ * Tests:
5
+ * 1. SmartHubServer with Dashboard API
6
+ * 2. Agent Hooks integration
7
+ * 3. WebSocket communication flow
8
+ * 4. Conflict detection and blocking
9
+ * 5. Dashboard API endpoints
10
+ */
11
+
12
+ import { SmartHubServer, DashboardApi } from "../packages/hub/dist/index.js";
13
+ import { HubClient } from "../packages/agent/dist/index.js";
14
+
15
+ const HUB_PORT = 19876;
16
+ const DASHBOARD_PORT = 19877;
17
+
18
+ console.log("🧪 MVP 3 - Full Integration E2E Test\n");
19
+ console.log("━".repeat(60));
20
+
21
+ // Simple mock LLM provider for testing
22
+ class TestMockProvider {
23
+ name = "test-mock";
24
+
25
+ async complete() {
26
+ return { content: "mock response", model: "test" };
27
+ }
28
+
29
+ async completeJSON<T>(messages: Array<{ role: string; content: string }>): Promise<T> {
30
+ const lastMessage = messages[messages.length - 1]?.content || "";
31
+
32
+ if (lastMessage.includes("OAuth") || lastMessage.includes("oauth") || lastMessage.includes("로그인")) {
33
+ return {
34
+ domain: "auth",
35
+ subdomain: "oauth",
36
+ affectedFiles: ["src/auth/oauth.ts"],
37
+ semanticTags: ["login", "oauth", "google"],
38
+ estimatedScope: "medium",
39
+ dependencies: [],
40
+ summary: "OAuth implementation",
41
+ } as T;
42
+ }
43
+
44
+ if (lastMessage.includes("결제") || lastMessage.includes("payment")) {
45
+ return {
46
+ domain: "payment",
47
+ subdomain: "checkout",
48
+ affectedFiles: ["src/payment/checkout.ts"],
49
+ semanticTags: ["payment", "checkout"],
50
+ estimatedScope: "medium",
51
+ dependencies: [],
52
+ summary: "Payment checkout",
53
+ } as T;
54
+ }
55
+
56
+ return {
57
+ domain: "general",
58
+ affectedFiles: [],
59
+ semanticTags: [],
60
+ estimatedScope: "small",
61
+ dependencies: [],
62
+ summary: "General task",
63
+ } as T;
64
+ }
65
+ }
66
+
67
+ function wait(ms: number): Promise<void> {
68
+ return new Promise((resolve) => setTimeout(resolve, ms));
69
+ }
70
+
71
+ function waitForConnection(client: HubClient, timeout = 5000): Promise<boolean> {
72
+ return new Promise((resolve) => {
73
+ const start = Date.now();
74
+ const check = () => {
75
+ if (client.isConnected()) {
76
+ resolve(true);
77
+ } else if (Date.now() - start > timeout) {
78
+ resolve(false);
79
+ } else {
80
+ setTimeout(check, 50);
81
+ }
82
+ };
83
+ check();
84
+ });
85
+ }
86
+
87
+ async function runTest() {
88
+ const results: { test: string; passed: boolean; error?: string }[] = [];
89
+
90
+ // ===========================================
91
+ // Setup: Start Hub Server with Dashboard
92
+ // ===========================================
93
+ console.log("\n📦 Starting SmartHubServer with Dashboard...\n");
94
+
95
+ const provider = new TestMockProvider() as any;
96
+
97
+ const hubServer = new SmartHubServer({
98
+ port: HUB_PORT,
99
+ host: "localhost",
100
+ llmProvider: provider,
101
+ orchestratorConfig: {
102
+ useLLMAnalysis: true,
103
+ autoNegotiate: false,
104
+ conflictThreshold: "medium",
105
+ },
106
+ });
107
+
108
+ const dashboardApi = new DashboardApi({
109
+ port: DASHBOARD_PORT,
110
+ hubServer,
111
+ });
112
+
113
+ hubServer.start();
114
+ dashboardApi.start();
115
+
116
+ await wait(500); // Wait for servers to start
117
+
118
+ // ===========================================
119
+ // Test 1: Dashboard API - Initial Status
120
+ // ===========================================
121
+ console.log("1️⃣ Test: Dashboard API - Initial Status\n");
122
+
123
+ try {
124
+ const res = await fetch(`http://localhost:${DASHBOARD_PORT}/api/status`);
125
+ const data = (await res.json()) as {
126
+ status: string;
127
+ connectedUsers: number;
128
+ orchestrator: { activeIntents: number };
129
+ };
130
+
131
+ const passed = data.status === "running" && data.connectedUsers === 0 && data.orchestrator.activeIntents === 0;
132
+
133
+ results.push({ test: "Dashboard API - Initial Status", passed });
134
+ console.log(` Status: ${data.status}`);
135
+ console.log(` Connected Users: ${data.connectedUsers}`);
136
+ console.log(` Active Intents: ${data.orchestrator.activeIntents}`);
137
+ console.log(` ${passed ? "✓" : "✗"} ${passed ? "Passed" : "Failed"}\n`);
138
+ } catch (error: any) {
139
+ results.push({ test: "Dashboard API - Initial Status", passed: false, error: error.message });
140
+ console.log(` ✗ Failed: ${error.message}\n`);
141
+ }
142
+
143
+ // ===========================================
144
+ // Test 2: Client Connection via HubClient
145
+ // ===========================================
146
+ console.log("2️⃣ Test: Client Connection via HubClient\n");
147
+
148
+ let aliceConnected = false;
149
+ let aliceSessionId = "";
150
+ const aliceMessages: any[] = [];
151
+
152
+ const aliceClient = new HubClient({
153
+ hubUrl: `ws://localhost:${HUB_PORT}`,
154
+ userId: "alice",
155
+ username: "Alice",
156
+ projectPath: "/test/project",
157
+ onConnected: (sessionId) => {
158
+ aliceConnected = true;
159
+ aliceSessionId = sessionId;
160
+ console.log(` Alice connected: ${sessionId}`);
161
+ },
162
+ onMessage: (msg) => {
163
+ aliceMessages.push(msg);
164
+ },
165
+ onDisconnected: () => {
166
+ console.log(" Alice disconnected");
167
+ },
168
+ onError: (err) => {
169
+ console.log(` Alice error: ${err.message}`);
170
+ },
171
+ reconnectInterval: 1000,
172
+ });
173
+
174
+ aliceClient.connect();
175
+
176
+ await wait(1000);
177
+ aliceConnected = aliceClient.isConnected();
178
+ aliceSessionId = aliceClient.getSessionId() || "";
179
+
180
+ results.push({
181
+ test: "Client Connection",
182
+ passed: aliceConnected && aliceSessionId.length > 0,
183
+ });
184
+ console.log(` ${aliceConnected ? "✓" : "✗"} Alice connected: ${aliceConnected}\n`);
185
+
186
+ // ===========================================
187
+ // Test 3: Dashboard shows connected user
188
+ // ===========================================
189
+ console.log("3️⃣ Test: Dashboard Shows Connected User\n");
190
+
191
+ try {
192
+ const res = await fetch(`http://localhost:${DASHBOARD_PORT}/api/clients`);
193
+ const data = (await res.json()) as { count: number; clients: { username: string }[] };
194
+
195
+ const passed = data.count === 1 && data.clients[0]?.username === "Alice";
196
+
197
+ results.push({ test: "Dashboard - Connected User", passed });
198
+ console.log(` Client count: ${data.count}`);
199
+ console.log(` First client: ${data.clients[0]?.username}`);
200
+ console.log(` ${passed ? "✓" : "✗"} ${passed ? "Passed" : "Failed"}\n`);
201
+ } catch (error: any) {
202
+ results.push({ test: "Dashboard - Connected User", passed: false, error: error.message });
203
+ console.log(` ✗ Failed: ${error.message}\n`);
204
+ }
205
+
206
+ // ===========================================
207
+ // Test 4: Intent Submission - Approval
208
+ // ===========================================
209
+ console.log("4️⃣ Test: Intent Submission - Alice Gets Approved\n");
210
+
211
+ aliceClient.submitIntent("Google OAuth 로그인 구현해줘");
212
+ await wait(500);
213
+
214
+ const aliceLockMsg = aliceMessages.find((m) => m.type === "hub:lock:acquired");
215
+ const aliceAnalyzedMsg = aliceMessages.find((m) => m.type === "hub:intent:analyzed");
216
+
217
+ const aliceApproved = !!aliceLockMsg;
218
+ results.push({ test: "Alice Intent - Approved", passed: aliceApproved });
219
+
220
+ console.log(` Intent analyzed: ${aliceAnalyzedMsg?.payload?.analysis?.domain || "N/A"}`);
221
+ console.log(` Lock acquired: ${aliceLockMsg?.payload?.domains?.join(", ") || "No"}`);
222
+ console.log(` ${aliceApproved ? "✓" : "✗"} ${aliceApproved ? "Passed" : "Failed"}\n`);
223
+
224
+ // ===========================================
225
+ // Test 5: Second Client - Conflict Detection
226
+ // ===========================================
227
+ console.log("5️⃣ Test: Bob Connects and Gets Blocked (Same Domain)\n");
228
+
229
+ let bobConnected = false;
230
+ const bobMessages: any[] = [];
231
+
232
+ const bobClient = new HubClient({
233
+ hubUrl: `ws://localhost:${HUB_PORT}`,
234
+ userId: "bob",
235
+ username: "Bob",
236
+ projectPath: "/test/project",
237
+ onConnected: () => {
238
+ bobConnected = true;
239
+ console.log(" Bob connected");
240
+ },
241
+ onMessage: (msg) => {
242
+ bobMessages.push(msg);
243
+ },
244
+ onError: (err) => {
245
+ console.log(` Bob error: ${err.message}`);
246
+ },
247
+ reconnectInterval: 1000,
248
+ });
249
+
250
+ bobClient.connect();
251
+ await wait(1000);
252
+ bobConnected = bobClient.isConnected();
253
+
254
+ // Bob tries to work on auth (same domain as Alice)
255
+ bobClient.submitIntent("OAuth 세션 관리 추가");
256
+ await wait(500);
257
+
258
+ const bobBlockedMsg = bobMessages.find((m) => m.type === "hub:lock:blocked");
259
+ const bobBlocked = !!bobBlockedMsg;
260
+
261
+ results.push({ test: "Bob Intent - Blocked", passed: bobBlocked });
262
+
263
+ if (bobBlockedMsg) {
264
+ console.log(` Blocked by: ${bobBlockedMsg.payload.blockedBy[0]?.username}`);
265
+ console.log(` Domain: ${bobBlockedMsg.payload.blockedBy[0]?.domain}`);
266
+ }
267
+ console.log(` ${bobBlocked ? "✓" : "✗"} ${bobBlocked ? "Passed" : "Failed"}\n`);
268
+
269
+ // ===========================================
270
+ // Test 6: Different Domain - No Conflict
271
+ // ===========================================
272
+ console.log("6️⃣ Test: Carol Works on Different Domain (No Conflict)\n");
273
+
274
+ let carolConnected = false;
275
+ const carolMessages: any[] = [];
276
+
277
+ const carolClient = new HubClient({
278
+ hubUrl: `ws://localhost:${HUB_PORT}`,
279
+ userId: "carol",
280
+ username: "Carol",
281
+ projectPath: "/test/project",
282
+ onConnected: () => {
283
+ carolConnected = true;
284
+ console.log(" Carol connected");
285
+ },
286
+ onMessage: (msg) => {
287
+ carolMessages.push(msg);
288
+ },
289
+ onError: (err) => {
290
+ console.log(` Carol error: ${err.message}`);
291
+ },
292
+ });
293
+
294
+ carolClient.connect();
295
+ carolConnected = await waitForConnection(carolClient);
296
+ await wait(200);
297
+
298
+ // Carol works on payment (different domain)
299
+ carolClient.submitIntent("결제 시스템 구현");
300
+ await wait(500);
301
+
302
+ const carolLockMsg = carolMessages.find((m) => m.type === "hub:lock:acquired");
303
+ const carolApproved = !!carolLockMsg;
304
+
305
+ results.push({ test: "Carol Intent - Approved (Different Domain)", passed: carolApproved });
306
+
307
+ if (carolLockMsg) {
308
+ console.log(` Domain: ${carolLockMsg.payload.domains.join(", ")}`);
309
+ }
310
+ console.log(` ${carolApproved ? "✓" : "✗"} ${carolApproved ? "Passed" : "Failed"}\n`);
311
+
312
+ // ===========================================
313
+ // Test 7: Dashboard - Final Status
314
+ // ===========================================
315
+ console.log("7️⃣ Test: Dashboard Final Status\n");
316
+
317
+ try {
318
+ const res = await fetch(`http://localhost:${DASHBOARD_PORT}/api/status`);
319
+ const data = (await res.json()) as {
320
+ connectedUsers: number;
321
+ orchestrator: { activeIntents: number; activeLocks: number };
322
+ };
323
+
324
+ // Alice, Bob, Carol connected (3 users)
325
+ // Alice and Carol have active intents (2 intents)
326
+ const passed = data.connectedUsers === 3 && data.orchestrator.activeIntents === 2;
327
+
328
+ results.push({ test: "Dashboard - Final Status", passed });
329
+ console.log(` Connected Users: ${data.connectedUsers}`);
330
+ console.log(` Active Intents: ${data.orchestrator.activeIntents}`);
331
+ console.log(` Active Locks: ${data.orchestrator.activeLocks}`);
332
+ console.log(` ${passed ? "✓" : "✗"} ${passed ? "Passed" : "Failed"}\n`);
333
+ } catch (error: any) {
334
+ results.push({ test: "Dashboard - Final Status", passed: false, error: error.message });
335
+ console.log(` ✗ Failed: ${error.message}\n`);
336
+ }
337
+
338
+ // ===========================================
339
+ // Test 8: Dashboard HTML Page
340
+ // ===========================================
341
+ console.log("8️⃣ Test: Dashboard HTML Page\n");
342
+
343
+ try {
344
+ const res = await fetch(`http://localhost:${DASHBOARD_PORT}/`);
345
+ const html = await res.text();
346
+
347
+ const passed =
348
+ res.headers.get("content-type")?.includes("text/html") &&
349
+ html.includes("Intent Hub") &&
350
+ html.includes("Connected Users");
351
+
352
+ results.push({ test: "Dashboard HTML Page", passed: passed ?? false });
353
+ console.log(` Content-Type: ${res.headers.get("content-type")}`);
354
+ console.log(` Contains title: ${html.includes("Intent Hub")}`);
355
+ console.log(` ${passed ? "✓" : "✗"} ${passed ? "Passed" : "Failed"}\n`);
356
+ } catch (error: any) {
357
+ results.push({ test: "Dashboard HTML Page", passed: false, error: error.message });
358
+ console.log(` ✗ Failed: ${error.message}\n`);
359
+ }
360
+
361
+ // ===========================================
362
+ // Cleanup
363
+ // ===========================================
364
+ console.log("🧹 Cleaning up...\n");
365
+
366
+ aliceClient.disconnect();
367
+ bobClient.disconnect();
368
+ carolClient.disconnect();
369
+
370
+ await wait(200);
371
+
372
+ dashboardApi.stop();
373
+ hubServer.stop();
374
+
375
+ // ===========================================
376
+ // Summary
377
+ // ===========================================
378
+ console.log("━".repeat(60));
379
+ console.log("\n📊 Test Results Summary\n");
380
+
381
+ const passed = results.filter((r) => r.passed).length;
382
+ const failed = results.filter((r) => !r.passed).length;
383
+
384
+ for (const result of results) {
385
+ console.log(` ${result.passed ? "✓" : "✗"} ${result.test}`);
386
+ if (result.error) {
387
+ console.log(` Error: ${result.error}`);
388
+ }
389
+ }
390
+
391
+ console.log("\n━".repeat(60));
392
+
393
+ if (failed === 0) {
394
+ console.log(`\n✅ MVP 3 Test PASSED! (${passed}/${results.length} tests)\n`);
395
+ process.exit(0);
396
+ } else {
397
+ console.log(`\n❌ MVP 3 Test FAILED! (${passed}/${results.length} tests passed, ${failed} failed)\n`);
398
+ process.exit(1);
399
+ }
400
+ }
401
+
402
+ runTest().catch((error) => {
403
+ console.error("Test crashed:", error);
404
+ process.exit(1);
405
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true,
15
+ "noUncheckedIndexedAccess": true,
16
+ "noImplicitOverride": true,
17
+ "noPropertyAccessFromIndexSignature": true
18
+ }
19
+ }
package/turbo.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "tasks": {
4
+ "build": {
5
+ "dependsOn": ["^build"],
6
+ "outputs": ["dist/**"]
7
+ },
8
+ "dev": {
9
+ "cache": false,
10
+ "persistent": true
11
+ },
12
+ "lint": {
13
+ "dependsOn": ["^build"]
14
+ },
15
+ "typecheck": {
16
+ "dependsOn": ["^build"]
17
+ },
18
+ "clean": {
19
+ "cache": false
20
+ }
21
+ }
22
+ }