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.
- package/.claude/settings.local.json +7 -0
- package/.turbo/cache/019f5ae385027cb1-meta.json +1 -0
- package/.turbo/cache/019f5ae385027cb1.tar.zst +0 -0
- package/.turbo/cache/040af6112a552a64-meta.json +1 -0
- package/.turbo/cache/040af6112a552a64.tar.zst +0 -0
- package/.turbo/cache/11195eac3ca5c6ce-meta.json +1 -0
- package/.turbo/cache/11195eac3ca5c6ce.tar.zst +0 -0
- package/.turbo/cache/13d11166efdf11cf-meta.json +1 -0
- package/.turbo/cache/13d11166efdf11cf.tar.zst +0 -0
- package/.turbo/cache/19af1af3b136706c-meta.json +1 -0
- package/.turbo/cache/19af1af3b136706c.tar.zst +0 -0
- package/.turbo/cache/1d33efac91c05b50-meta.json +1 -0
- package/.turbo/cache/1d33efac91c05b50.tar.zst +0 -0
- package/.turbo/cache/200b85a612af2d13-meta.json +1 -0
- package/.turbo/cache/200b85a612af2d13.tar.zst +0 -0
- package/.turbo/cache/210308c9ea929858-meta.json +1 -0
- package/.turbo/cache/210308c9ea929858.tar.zst +0 -0
- package/.turbo/cache/38df8e44c617835e-meta.json +1 -0
- package/.turbo/cache/38df8e44c617835e.tar.zst +0 -0
- package/.turbo/cache/3e449de5ef60a7a0-meta.json +1 -0
- package/.turbo/cache/3e449de5ef60a7a0.tar.zst +0 -0
- package/.turbo/cache/51ff024a97c2b4f5-meta.json +1 -0
- package/.turbo/cache/51ff024a97c2b4f5.tar.zst +0 -0
- package/.turbo/cache/54bc756eeebb377a-meta.json +1 -0
- package/.turbo/cache/54bc756eeebb377a.tar.zst +0 -0
- package/.turbo/cache/5ed6a840acafc873-meta.json +1 -0
- package/.turbo/cache/5ed6a840acafc873.tar.zst +0 -0
- package/.turbo/cache/6702dc24e5ca3c2e-meta.json +1 -0
- package/.turbo/cache/6702dc24e5ca3c2e.tar.zst +0 -0
- package/.turbo/cache/725c72cf71ea854f-meta.json +1 -0
- package/.turbo/cache/725c72cf71ea854f.tar.zst +0 -0
- package/.turbo/cache/7344ca28d348037a-meta.json +1 -0
- package/.turbo/cache/7344ca28d348037a.tar.zst +0 -0
- package/.turbo/cache/748fb444cdc0b78c-meta.json +1 -0
- package/.turbo/cache/748fb444cdc0b78c.tar.zst +0 -0
- package/.turbo/cache/789677c36fe7fb98-meta.json +1 -0
- package/.turbo/cache/789677c36fe7fb98.tar.zst +0 -0
- package/.turbo/cache/89ff6c6f38dd4a18-meta.json +1 -0
- package/.turbo/cache/89ff6c6f38dd4a18.tar.zst +0 -0
- package/.turbo/cache/8dbc92d00de0c92e-meta.json +1 -0
- package/.turbo/cache/8dbc92d00de0c92e.tar.zst +0 -0
- package/.turbo/cache/8eb03f40082b9441-meta.json +1 -0
- package/.turbo/cache/8eb03f40082b9441.tar.zst +0 -0
- package/.turbo/cache/9157134d4b916017-meta.json +1 -0
- package/.turbo/cache/9157134d4b916017.tar.zst +0 -0
- package/.turbo/cache/94219ffd32b48e93-meta.json +1 -0
- package/.turbo/cache/94219ffd32b48e93.tar.zst +0 -0
- package/.turbo/cache/95c1d160b4fa84eb-meta.json +1 -0
- package/.turbo/cache/95c1d160b4fa84eb.tar.zst +0 -0
- package/.turbo/cache/998833ea02dfb225-meta.json +1 -0
- package/.turbo/cache/998833ea02dfb225.tar.zst +0 -0
- package/.turbo/cache/a5974ef6ade3eb90-meta.json +1 -0
- package/.turbo/cache/a5974ef6ade3eb90.tar.zst +0 -0
- package/.turbo/cache/aab811809257decb-meta.json +1 -0
- package/.turbo/cache/aab811809257decb.tar.zst +0 -0
- package/.turbo/cache/ab2f82a54da854fd-meta.json +1 -0
- package/.turbo/cache/ab2f82a54da854fd.tar.zst +0 -0
- package/.turbo/cache/abbf4d95d62a7303-meta.json +1 -0
- package/.turbo/cache/abbf4d95d62a7303.tar.zst +0 -0
- package/.turbo/cache/af4441f519f9ce50-meta.json +1 -0
- package/.turbo/cache/af4441f519f9ce50.tar.zst +0 -0
- package/.turbo/cache/b9b85aaaf03d00a6-meta.json +1 -0
- package/.turbo/cache/b9b85aaaf03d00a6.tar.zst +0 -0
- package/.turbo/cache/cd58ee8721bbfed7-meta.json +1 -0
- package/.turbo/cache/cd58ee8721bbfed7.tar.zst +0 -0
- package/.turbo/cache/d285e48b8afa30b5-meta.json +1 -0
- package/.turbo/cache/d285e48b8afa30b5.tar.zst +0 -0
- package/.turbo/cache/d33e90229142acce-meta.json +1 -0
- package/.turbo/cache/d33e90229142acce.tar.zst +0 -0
- package/.turbo/cache/d57839a0d3b04540-meta.json +1 -0
- package/.turbo/cache/d57839a0d3b04540.tar.zst +0 -0
- package/.turbo/cache/d8554ef2c8b6e5eb-meta.json +1 -0
- package/.turbo/cache/d8554ef2c8b6e5eb.tar.zst +0 -0
- package/.turbo/cache/dc7375b51290e102-meta.json +1 -0
- package/.turbo/cache/dc7375b51290e102.tar.zst +0 -0
- package/.turbo/cache/e5310fe547fdbf0a-meta.json +1 -0
- package/.turbo/cache/e5310fe547fdbf0a.tar.zst +0 -0
- package/.turbo/cache/f12bb5f2f188758d-meta.json +1 -0
- package/.turbo/cache/f12bb5f2f188758d.tar.zst +0 -0
- package/.turbo/cache/f2db5af0c0b4d23f-meta.json +1 -0
- package/.turbo/cache/f2db5af0c0b4d23f.tar.zst +0 -0
- package/.turbo/cache/f8935ade01a88cd7-meta.json +1 -0
- package/.turbo/cache/f8935ade01a88cd7.tar.zst +0 -0
- package/.turbo/cache/f982b8dd966f823a-meta.json +1 -0
- package/.turbo/cache/f982b8dd966f823a.tar.zst +0 -0
- package/.turbo/cache/f9d4036dd350ba1a-meta.json +1 -0
- package/.turbo/cache/f9d4036dd350ba1a.tar.zst +0 -0
- package/README.md +661 -0
- package/README_ko.md +577 -0
- package/bun.lock +135 -0
- package/package.json +26 -0
- package/packages/agent/.turbo/turbo-build.log +5 -0
- package/packages/agent/.turbo/turbo-typecheck.log +1 -0
- package/packages/agent/dist/connection/hub-client.d.ts +33 -0
- package/packages/agent/dist/connection/hub-client.d.ts.map +1 -0
- package/packages/agent/dist/connection/index.d.ts +2 -0
- package/packages/agent/dist/connection/index.d.ts.map +1 -0
- package/packages/agent/dist/hooks/index.d.ts +3 -0
- package/packages/agent/dist/hooks/index.d.ts.map +1 -0
- package/packages/agent/dist/hooks/intent-hub-hooks.d.ts +47 -0
- package/packages/agent/dist/hooks/intent-hub-hooks.d.ts.map +1 -0
- package/packages/agent/dist/index.d.ts +6 -0
- package/packages/agent/dist/index.d.ts.map +1 -0
- package/packages/agent/dist/index.js +3315 -0
- package/packages/agent/dist/plugin/index.d.ts +3 -0
- package/packages/agent/dist/plugin/index.d.ts.map +1 -0
- package/packages/agent/dist/plugin/intent-hub-plugin.d.ts +54 -0
- package/packages/agent/dist/plugin/intent-hub-plugin.d.ts.map +1 -0
- package/packages/agent/package.json +32 -0
- package/packages/agent/src/connection/hub-client.ts +152 -0
- package/packages/agent/src/connection/index.ts +1 -0
- package/packages/agent/src/hooks/index.ts +2 -0
- package/packages/agent/src/hooks/intent-hub-hooks.ts +245 -0
- package/packages/agent/src/index.ts +5 -0
- package/packages/agent/src/plugin/index.ts +2 -0
- package/packages/agent/src/plugin/intent-hub-plugin.ts +153 -0
- package/packages/agent/tsconfig.json +9 -0
- package/packages/hub/.turbo/turbo-build.log +6 -0
- package/packages/hub/.turbo/turbo-typecheck.log +1 -0
- package/packages/hub/dist/api/dashboard.d.ts +17 -0
- package/packages/hub/dist/api/dashboard.d.ts.map +1 -0
- package/packages/hub/dist/cli.d.ts +3 -0
- package/packages/hub/dist/cli.d.ts.map +1 -0
- package/packages/hub/dist/cli.js +7719 -0
- package/packages/hub/dist/core/conflict-detector.d.ts +36 -0
- package/packages/hub/dist/core/conflict-detector.d.ts.map +1 -0
- package/packages/hub/dist/core/index.d.ts +7 -0
- package/packages/hub/dist/core/index.d.ts.map +1 -0
- package/packages/hub/dist/core/intent-analyzer.d.ts +8 -0
- package/packages/hub/dist/core/intent-analyzer.d.ts.map +1 -0
- package/packages/hub/dist/core/lock-manager.d.ts +13 -0
- package/packages/hub/dist/core/lock-manager.d.ts.map +1 -0
- package/packages/hub/dist/core/orchestrator.d.ts +46 -0
- package/packages/hub/dist/core/orchestrator.d.ts.map +1 -0
- package/packages/hub/dist/index.d.ts +9 -0
- package/packages/hub/dist/index.d.ts.map +1 -0
- package/packages/hub/dist/index.js +4686 -0
- package/packages/hub/dist/llm/index.d.ts +7 -0
- package/packages/hub/dist/llm/index.d.ts.map +1 -0
- package/packages/hub/dist/llm/negotiation-engine.d.ts +40 -0
- package/packages/hub/dist/llm/negotiation-engine.d.ts.map +1 -0
- package/packages/hub/dist/llm/provider.d.ts +46 -0
- package/packages/hub/dist/llm/provider.d.ts.map +1 -0
- package/packages/hub/dist/llm/smart-analyzer.d.ts +20 -0
- package/packages/hub/dist/llm/smart-analyzer.d.ts.map +1 -0
- package/packages/hub/dist/server/hub-server.d.ts +35 -0
- package/packages/hub/dist/server/hub-server.d.ts.map +1 -0
- package/packages/hub/dist/server/index.d.ts +5 -0
- package/packages/hub/dist/server/index.d.ts.map +1 -0
- package/packages/hub/dist/server/message-handler.d.ts +18 -0
- package/packages/hub/dist/server/message-handler.d.ts.map +1 -0
- package/packages/hub/dist/server/smart-hub-server.d.ts +43 -0
- package/packages/hub/dist/server/smart-hub-server.d.ts.map +1 -0
- package/packages/hub/dist/state/index.d.ts +2 -0
- package/packages/hub/dist/state/index.d.ts.map +1 -0
- package/packages/hub/dist/state/session-manager.d.ts +19 -0
- package/packages/hub/dist/state/session-manager.d.ts.map +1 -0
- package/packages/hub/dist/tunnel/index.d.ts +14 -0
- package/packages/hub/dist/tunnel/index.d.ts.map +1 -0
- package/packages/hub/package.json +54 -0
- package/packages/hub/src/api/dashboard.ts +261 -0
- package/packages/hub/src/cli.ts +193 -0
- package/packages/hub/src/core/conflict-detector.ts +138 -0
- package/packages/hub/src/core/index.ts +6 -0
- package/packages/hub/src/core/intent-analyzer.ts +112 -0
- package/packages/hub/src/core/lock-manager.ts +95 -0
- package/packages/hub/src/core/orchestrator.ts +255 -0
- package/packages/hub/src/index.ts +8 -0
- package/packages/hub/src/llm/index.ts +17 -0
- package/packages/hub/src/llm/negotiation-engine.ts +297 -0
- package/packages/hub/src/llm/provider.ts +175 -0
- package/packages/hub/src/llm/smart-analyzer.ts +169 -0
- package/packages/hub/src/server/hub-server.ts +219 -0
- package/packages/hub/src/server/index.ts +4 -0
- package/packages/hub/src/server/message-handler.ts +111 -0
- package/packages/hub/src/server/smart-hub-server.ts +374 -0
- package/packages/hub/src/state/index.ts +1 -0
- package/packages/hub/src/state/session-manager.ts +59 -0
- package/packages/hub/src/tunnel/index.ts +153 -0
- package/packages/hub/tsconfig.json +9 -0
- package/packages/shared/.turbo/turbo-build.log +5 -0
- package/packages/shared/.turbo/turbo-typecheck.log +1 -0
- package/packages/shared/dist/index.d.ts +3 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +50 -0
- package/packages/shared/dist/types/domain.d.ts +50 -0
- package/packages/shared/dist/types/domain.d.ts.map +1 -0
- package/packages/shared/dist/types/index.d.ts +4 -0
- package/packages/shared/dist/types/index.d.ts.map +1 -0
- package/packages/shared/dist/types/intent.d.ts +24 -0
- package/packages/shared/dist/types/intent.d.ts.map +1 -0
- package/packages/shared/dist/types/message.d.ts +151 -0
- package/packages/shared/dist/types/message.d.ts.map +1 -0
- package/packages/shared/dist/utils/id.d.ts +6 -0
- package/packages/shared/dist/utils/id.d.ts.map +1 -0
- package/packages/shared/dist/utils/index.d.ts +3 -0
- package/packages/shared/dist/utils/index.d.ts.map +1 -0
- package/packages/shared/dist/utils/message.d.ts +5 -0
- package/packages/shared/dist/utils/message.d.ts.map +1 -0
- package/packages/shared/package.json +33 -0
- package/packages/shared/src/index.ts +2 -0
- package/packages/shared/src/types/domain.ts +57 -0
- package/packages/shared/src/types/index.ts +3 -0
- package/packages/shared/src/types/intent.ts +34 -0
- package/packages/shared/src/types/message.ts +188 -0
- package/packages/shared/src/utils/id.ts +21 -0
- package/packages/shared/src/utils/index.ts +2 -0
- package/packages/shared/src/utils/message.ts +30 -0
- package/packages/shared/tsconfig.json +9 -0
- package/scripts/test-e2e.ts +194 -0
- package/scripts/test-mvp2.ts +167 -0
- package/scripts/test-mvp3.ts +405 -0
- package/tsconfig.json +19 -0
- 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
|
+
}
|