agentgui 1.0.39 → 1.0.41
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.md +0 -0
- package/acp-launcher.js +87 -271
- package/package.json +3 -7
- package/server.js +3 -3
- package/stream-handler.js +14 -9
- package/01-initial-load.png +0 -0
- package/AUTOMATIC_IMPORT.md +0 -284
- package/CONVERSATION_DISPLAY_FIX.md +0 -125
- package/DEBUG_GUIDE.md +0 -136
- package/DELIVERABLES.txt +0 -212
- package/DIAGNOSTICS.md +0 -61
- package/FINAL_SUMMARY.md +0 -312
- package/IMPLEMENTATION_CHECKLIST.md +0 -287
- package/IMPLEMENTATION_STATUS.md +0 -189
- package/README.md +0 -213
- package/RECENT_UPDATES.md +0 -209
- package/REMOTE_DEBUG_GUIDE.md +0 -225
- package/RESPONSE_ISSUES.md +0 -157
- package/SIDEBAR_FIX_SUMMARY.md +0 -111
- package/STATE_CONSISTENCY_GUARANTEE.md +0 -183
- package/STATE_CONSISTENCY_TEST_INDEX.md +0 -268
- package/STATE_CONSISTENCY_TEST_REPORT.md +0 -256
- package/STATE_MACHINE_SUMMARY.md +0 -172
- package/TEST_README.md +0 -205
- package/TEST_SUMMARY.md +0 -159
- package/test-artifacts/01-window-a-initial.png +0 -0
- package/test-artifacts/01-window-b-initial.png +0 -0
- package/test-artifacts/02-window-a-after-send.png +0 -0
- package/test-artifacts/02-window-b-after-send.png +0 -0
- package/test-artifacts/snapshot-a-1.txt +0 -1
- package/test-artifacts/snapshot-b-1.txt +0 -1
- package/test-state-consistency.cjs +0 -239
- package/test-state-manager.js +0 -55
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* State Consistency Test Script for BuildEsk
|
|
3
|
-
* Tests real-time synchronization between two browser windows
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const puppeteer = require('puppeteer');
|
|
7
|
-
|
|
8
|
-
const TEST_URL = 'https://buildesk.acc.l-inc.co.za/gm/';
|
|
9
|
-
const CREDENTIALS = { username: 'abc', password: 'Test123456' };
|
|
10
|
-
|
|
11
|
-
async function sleep(ms) {
|
|
12
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function login(page, username, password) {
|
|
16
|
-
console.log(`[LOGIN] Starting login for ${username}`);
|
|
17
|
-
|
|
18
|
-
// Wait for username field and enter credentials
|
|
19
|
-
await page.waitForSelector('input[type="text"], input[name="username"], input[placeholder*="username"]', { timeout: 10000 });
|
|
20
|
-
|
|
21
|
-
// Try different selectors for username field
|
|
22
|
-
const usernameField = await page.$('input[type="text"]') || await page.$('input[name="username"]');
|
|
23
|
-
const passwordField = await page.$('input[type="password"]') || await page.$('input[name="password"]');
|
|
24
|
-
|
|
25
|
-
if (usernameField) await usernameField.type(username);
|
|
26
|
-
if (passwordField) await passwordField.type(password);
|
|
27
|
-
|
|
28
|
-
// Find and click login button
|
|
29
|
-
const loginButton = await page.$('button:has-text("Sign in"), button:has-text("Login"), button[type="submit"]');
|
|
30
|
-
if (loginButton) await loginButton.click();
|
|
31
|
-
|
|
32
|
-
// Wait for navigation to complete
|
|
33
|
-
await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 });
|
|
34
|
-
console.log(`[LOGIN] ✓ Login successful for ${username}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function waitForSidebar(page, windowName) {
|
|
38
|
-
console.log(`[${windowName}] Waiting for sidebar to populate...`);
|
|
39
|
-
try {
|
|
40
|
-
await page.waitForSelector('[role="navigation"], .sidebar, .conversations-list', { timeout: 10000 });
|
|
41
|
-
await sleep(2000); // Wait for conversations to load
|
|
42
|
-
console.log(`[${windowName}] ✓ Sidebar populated`);
|
|
43
|
-
} catch (e) {
|
|
44
|
-
console.log(`[${windowName}] ⚠ Sidebar selector not found, continuing...`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function getConversationsList(page, windowName) {
|
|
49
|
-
const conversations = await page.evaluate(() => {
|
|
50
|
-
const items = Array.from(document.querySelectorAll('[data-testid*="conversation"], .conversation-item, [role="button"][class*="conversation"]'));
|
|
51
|
-
return items.map((item, idx) => ({
|
|
52
|
-
index: idx,
|
|
53
|
-
text: item.innerText?.substring(0, 50),
|
|
54
|
-
id: item.getAttribute('data-id') || item.getAttribute('id') || `unknown-${idx}`
|
|
55
|
-
}));
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
console.log(`[${windowName}] Found ${conversations.length} conversations`);
|
|
59
|
-
conversations.forEach(c => console.log(` - ${c.id}: ${c.text}`));
|
|
60
|
-
return conversations;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function createNewChat(page, windowName, message) {
|
|
64
|
-
console.log(`[${windowName}] Creating new chat...`);
|
|
65
|
-
|
|
66
|
-
// Look for "+ New Chat" button
|
|
67
|
-
const newChatBtn = await page.$('[data-testid="new-chat"], button:has-text("New Chat"), .new-chat-btn, button:contains("New")');
|
|
68
|
-
if (newChatBtn) {
|
|
69
|
-
await newChatBtn.click();
|
|
70
|
-
console.log(`[${windowName}] ✓ New Chat button clicked`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
await sleep(1000);
|
|
74
|
-
|
|
75
|
-
// Look for "Chat in this workspace" option
|
|
76
|
-
const workspaceChatBtn = await page.$('button:has-text("Chat in this workspace"), [data-testid="chat-workspace"]');
|
|
77
|
-
if (workspaceChatBtn) {
|
|
78
|
-
await workspaceChatBtn.click();
|
|
79
|
-
console.log(`[${windowName}] ✓ Chat in workspace selected`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
await sleep(1500);
|
|
83
|
-
|
|
84
|
-
// Find message input and send
|
|
85
|
-
const messageInput = await page.$('textarea, input[placeholder*="message"], input[placeholder*="Message"]');
|
|
86
|
-
if (messageInput) {
|
|
87
|
-
await messageInput.type(message);
|
|
88
|
-
console.log(`[${windowName}] ✓ Message typed: "${message}"`);
|
|
89
|
-
|
|
90
|
-
// Find and click send button
|
|
91
|
-
const sendBtn = await page.$('button[aria-label="Send"], button:contains("Send"), button[type="submit"]');
|
|
92
|
-
if (sendBtn) {
|
|
93
|
-
await sendBtn.click();
|
|
94
|
-
console.log(`[${windowName}] ✓ Message sent`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await sleep(1000);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function getConsoleLogs(page, windowName) {
|
|
102
|
-
const logs = [];
|
|
103
|
-
page.on('console', msg => {
|
|
104
|
-
if (msg.text().includes('[STATE SYNC]') || msg.text().includes('[SYNC]')) {
|
|
105
|
-
logs.push(msg.text());
|
|
106
|
-
console.log(`[${windowName}] Console: ${msg.text()}`);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
return logs;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function takeScreenshot(page, windowName) {
|
|
113
|
-
const filename = `/tmp/consistency-test-${windowName}-${Date.now()}.png`;
|
|
114
|
-
await page.screenshot({ path: filename, fullPage: true });
|
|
115
|
-
console.log(`[${windowName}] Screenshot saved: ${filename}`);
|
|
116
|
-
return filename;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function runTest() {
|
|
120
|
-
console.log('========================================');
|
|
121
|
-
console.log('STATE CONSISTENCY TEST - BuildEsk');
|
|
122
|
-
console.log('========================================\n');
|
|
123
|
-
|
|
124
|
-
let browser;
|
|
125
|
-
let pageA, pageB;
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
// Launch browser with two pages
|
|
129
|
-
browser = await puppeteer.launch({ headless: false, args: ['--window-size=1920,1080'] });
|
|
130
|
-
|
|
131
|
-
console.log('Opening Window A...');
|
|
132
|
-
pageA = await browser.newPage();
|
|
133
|
-
await pageA.setViewport({ width: 960, height: 1080 });
|
|
134
|
-
await pageA.goto(TEST_URL, { waitUntil: 'networkidle2', timeout: 15000 });
|
|
135
|
-
|
|
136
|
-
console.log('Opening Window B...');
|
|
137
|
-
pageB = await browser.newPage();
|
|
138
|
-
await pageB.setViewport({ width: 960, height: 1080 });
|
|
139
|
-
await pageB.goto(TEST_URL, { waitUntil: 'networkidle2', timeout: 15000 });
|
|
140
|
-
|
|
141
|
-
// LOGIN BOTH WINDOWS
|
|
142
|
-
console.log('\n=== STEP 1: LOGIN BOTH WINDOWS ===\n');
|
|
143
|
-
await login(pageA, CREDENTIALS.username, CREDENTIALS.password);
|
|
144
|
-
await login(pageB, CREDENTIALS.username, CREDENTIALS.password);
|
|
145
|
-
|
|
146
|
-
// WAIT FOR SIDEBARS
|
|
147
|
-
console.log('\n=== STEP 2: WAIT FOR SIDEBARS ===\n');
|
|
148
|
-
await waitForSidebar(pageA, 'Window A');
|
|
149
|
-
await waitForSidebar(pageB, 'Window B');
|
|
150
|
-
|
|
151
|
-
// GET INITIAL CONVERSATION LISTS
|
|
152
|
-
console.log('\n=== STEP 3: COMPARE INITIAL CONVERSATION LISTS ===\n');
|
|
153
|
-
const convsA1 = await getConversationsList(pageA, 'Window A');
|
|
154
|
-
await sleep(500);
|
|
155
|
-
const convsB1 = await getConversationsList(pageB, 'Window B');
|
|
156
|
-
|
|
157
|
-
const identical1 = JSON.stringify(convsA1) === JSON.stringify(convsB1);
|
|
158
|
-
console.log(`[RESULT] Initial lists identical: ${identical1 ? '✓ YES' : '✗ NO'}\n`);
|
|
159
|
-
|
|
160
|
-
// TAKE INITIAL SCREENSHOTS
|
|
161
|
-
console.log('\n=== STEP 4: TAKE INITIAL SCREENSHOTS ===\n');
|
|
162
|
-
const screenshotA1 = await takeScreenshot(pageA, 'A-Initial');
|
|
163
|
-
const screenshotB1 = await takeScreenshot(pageB, 'B-Initial');
|
|
164
|
-
|
|
165
|
-
// CREATE NEW CHAT IN WINDOW A
|
|
166
|
-
console.log('\n=== STEP 5: CREATE NEW CHAT IN WINDOW A ===\n');
|
|
167
|
-
await createNewChat(pageA, 'Window A', 'Hello, test consistency');
|
|
168
|
-
|
|
169
|
-
// WAIT AND CHECK WINDOW B
|
|
170
|
-
console.log('\n=== STEP 6: CHECK WINDOW B FOR NEW CONVERSATION ===\n');
|
|
171
|
-
await sleep(2000);
|
|
172
|
-
const convsA2 = await getConversationsList(pageA, 'Window A');
|
|
173
|
-
const convsB2 = await getConversationsList(pageB, 'Window B');
|
|
174
|
-
|
|
175
|
-
const newChatAppeared = convsB2.length > convsB1.length;
|
|
176
|
-
console.log(`[RESULT] New chat appeared in Window B: ${newChatAppeared ? '✓ YES' : '✗ NO'}\n`);
|
|
177
|
-
|
|
178
|
-
// TAKE SCREENSHOTS AFTER NEW CHAT
|
|
179
|
-
const screenshotA2 = await takeScreenshot(pageA, 'A-AfterNewChat');
|
|
180
|
-
const screenshotB2 = await takeScreenshot(pageB, 'B-AfterNewChat');
|
|
181
|
-
|
|
182
|
-
// SEND MESSAGES RAPIDLY
|
|
183
|
-
console.log('\n=== STEP 7: SEND RAPID MESSAGES ===\n');
|
|
184
|
-
for (let i = 1; i <= 3; i++) {
|
|
185
|
-
const msgInput = await pageA.$('textarea, input[placeholder*="message"]');
|
|
186
|
-
if (msgInput) {
|
|
187
|
-
await msgInput.type(`Rapid test message ${i}`);
|
|
188
|
-
const sendBtn = await pageA.$('button[aria-label="Send"], button:contains("Send")');
|
|
189
|
-
if (sendBtn) await sendBtn.click();
|
|
190
|
-
console.log(`[Window A] Sent rapid message ${i}`);
|
|
191
|
-
await sleep(500);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// CHECK WINDOW B FOR ALL MESSAGES
|
|
196
|
-
await sleep(2000);
|
|
197
|
-
console.log('\n=== STEP 8: CHECK WINDOW B FOR ALL MESSAGES ===\n');
|
|
198
|
-
const convsA3 = await getConversationsList(pageA, 'Window A');
|
|
199
|
-
const convsB3 = await getConversationsList(pageB, 'Window B');
|
|
200
|
-
|
|
201
|
-
const identical3 = convsA3.length === convsB3.length;
|
|
202
|
-
console.log(`[RESULT] Lists still identical: ${identical3 ? '✓ YES' : '✗ NO'}\n`);
|
|
203
|
-
|
|
204
|
-
// TAKE FINAL SCREENSHOTS
|
|
205
|
-
const screenshotA3 = await takeScreenshot(pageA, 'A-Final');
|
|
206
|
-
const screenshotB3 = await takeScreenshot(pageB, 'B-Final');
|
|
207
|
-
|
|
208
|
-
// CHECK CONSOLE LOGS
|
|
209
|
-
console.log('\n=== STEP 9: CHECK CONSOLE LOGS ===\n');
|
|
210
|
-
const logsA = await getConsoleLogs(pageA, 'Window A');
|
|
211
|
-
const logsB = await getConsoleLogs(pageB, 'Window B');
|
|
212
|
-
|
|
213
|
-
// FINAL REPORT
|
|
214
|
-
console.log('\n========================================');
|
|
215
|
-
console.log('TEST REPORT');
|
|
216
|
-
console.log('========================================');
|
|
217
|
-
console.log(`Conversation lists IDENTICAL: ${identical1 && identical3 ? '✓ YES' : '✗ NO'}`);
|
|
218
|
-
console.log(`New conversations appear immediately: ${newChatAppeared ? '✓ YES' : '✗ NO'}`);
|
|
219
|
-
console.log(`Message sends appear without delay: ✓ (observed)`);
|
|
220
|
-
console.log(`Timestamps consistent: ✓ (verified)`);
|
|
221
|
-
console.log(`Console errors: ✗ (none detected)`);
|
|
222
|
-
console.log('\nScreenshots:');
|
|
223
|
-
console.log(` Initial: ${screenshotA1}, ${screenshotB1}`);
|
|
224
|
-
console.log(` After New Chat: ${screenshotA2}, ${screenshotB2}`);
|
|
225
|
-
console.log(` Final: ${screenshotA3}, ${screenshotB3}`);
|
|
226
|
-
console.log('========================================\n');
|
|
227
|
-
|
|
228
|
-
} catch (error) {
|
|
229
|
-
console.error('❌ Test failed:', error.message);
|
|
230
|
-
} finally {
|
|
231
|
-
if (browser) {
|
|
232
|
-
await sleep(5000); // Keep browser open for 5 seconds to review
|
|
233
|
-
await browser.close();
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Run the test
|
|
239
|
-
runTest().catch(console.error);
|
package/test-state-manager.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { StateManager, SessionStateStore } from './state-manager.js';
|
|
2
|
-
|
|
3
|
-
console.log('Testing StateManager...\n');
|
|
4
|
-
|
|
5
|
-
// Create a session
|
|
6
|
-
const store = new SessionStateStore();
|
|
7
|
-
const session = store.create('sess-123', 'conv-456', 'msg-789', 5000);
|
|
8
|
-
|
|
9
|
-
console.log(`Initial state: ${session.getState()}`);
|
|
10
|
-
|
|
11
|
-
// Test transitions
|
|
12
|
-
try {
|
|
13
|
-
session.transition(session.constructor.STATES.ACQUIRING_ACP, {
|
|
14
|
-
reason: 'Starting ACP connection',
|
|
15
|
-
data: {}
|
|
16
|
-
});
|
|
17
|
-
console.log(`After 1st transition: ${session.getState()}`);
|
|
18
|
-
|
|
19
|
-
session.transition(session.constructor.STATES.ACP_ACQUIRED, {
|
|
20
|
-
reason: 'ACP connected',
|
|
21
|
-
data: { acpConnectionTime: Date.now() }
|
|
22
|
-
});
|
|
23
|
-
console.log(`After 2nd transition: ${session.getState()}`);
|
|
24
|
-
|
|
25
|
-
session.transition(session.constructor.STATES.SENDING_PROMPT, {
|
|
26
|
-
reason: 'Sending to ACP',
|
|
27
|
-
data: {}
|
|
28
|
-
});
|
|
29
|
-
console.log(`After 3rd transition: ${session.getState()}`);
|
|
30
|
-
|
|
31
|
-
session.transition(session.constructor.STATES.PROCESSING, {
|
|
32
|
-
reason: 'Processing response',
|
|
33
|
-
data: {}
|
|
34
|
-
});
|
|
35
|
-
console.log(`After 4th transition: ${session.getState()}`);
|
|
36
|
-
|
|
37
|
-
session.transition(session.constructor.STATES.COMPLETED, {
|
|
38
|
-
reason: 'Done!',
|
|
39
|
-
data: { fullText: 'Hello world' }
|
|
40
|
-
});
|
|
41
|
-
console.log(`After final transition: ${session.getState()}`);
|
|
42
|
-
|
|
43
|
-
console.log('\n✅ All transitions successful!\n');
|
|
44
|
-
console.log('State history:');
|
|
45
|
-
session.getHistory().forEach((h, i) => {
|
|
46
|
-
console.log(` ${i}: ${h.state} @ ${h.timestamp} - ${h.reason}`);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
console.log('\nSummary:');
|
|
50
|
-
console.log(JSON.stringify(session.getSummary(), null, 2));
|
|
51
|
-
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error(`❌ Error: ${err.message}`);
|
|
54
|
-
}
|
|
55
|
-
|