agentgui 1.0.40 → 1.0.42

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/acp-launcher.js CHANGED
@@ -1,36 +1,31 @@
1
- import { spawn } from 'child_process';
1
+ import { createClient } from 'claude-code-acp';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import os from 'os';
5
5
 
6
- // Common paths where claude-code-acp might be installed
7
- const CLAUDE_CODE_ACP_PATHS = [
8
- '/config/.gmweb/npm-global/bin/claude-code-acp',
9
- '/usr/local/bin/claude-code-acp',
10
- '/usr/bin/claude-code-acp',
11
- path.join(os.homedir(), '.local/bin/claude-code-acp'),
12
- path.join(os.homedir(), '.gmweb/npm-global/bin/claude-code-acp'),
13
- 'claude-code-acp', // fallback to PATH
14
- ];
15
-
16
- // Common paths where opencode might be installed
17
- const OPENCODE_PATHS = [
18
- '/usr/local/bin/opencode',
19
- '/usr/bin/opencode',
20
- path.join(os.homedir(), '.local/bin/opencode'),
21
- 'opencode', // fallback to PATH
22
- ];
23
-
24
- function findBinary(paths) {
25
- for (const p of paths) {
6
+ /**
7
+ * Load CLI configuration to ensure identical behavior
8
+ */
9
+ function loadCLIConfig() {
10
+ const configPaths = [
11
+ path.join(os.homedir(), '.claude', 'config.json'),
12
+ path.join(os.homedir(), '.claude-code', 'config.json'),
13
+ path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'claude', 'config.json')
14
+ ];
15
+
16
+ for (const configPath of configPaths) {
26
17
  try {
27
- fs.accessSync(p, fs.constants.X_OK);
28
- return p;
29
- } catch (_) {
30
- continue;
18
+ if (fs.existsSync(configPath)) {
19
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
20
+ console.log(`[ACP] Loaded CLI config from ${configPath}`);
21
+ return config;
22
+ }
23
+ } catch (e) {
24
+ // Config file doesn't exist or is invalid, continue
31
25
  }
32
26
  }
33
- return null;
27
+
28
+ return {};
34
29
  }
35
30
 
36
31
  const RIPPLEUI_SYSTEM_PROMPT = `CRITICAL INSTRUCTION: You are responding in a web-based HTML interface. EVERY response must be formatted as beautiful, styled HTML using RippleUI and Tailwind CSS. This is NOT a text-based interface - users see raw HTML rendered in their browser.
@@ -94,221 +89,108 @@ MANDATORY RULES:
94
89
  ✓ Use color classes: text-gray-700, bg-blue-50, border-blue-500
95
90
  ✓ Make visual hierarchy clear: use different font sizes, colors, cards
96
91
 
97
- EXAMPLES OF COMPLETE RESPONSES:
98
-
99
- Example 1 - Answer:
100
- <div class="space-y-4 p-6"><h2 class="text-2xl font-bold">Explanation</h2><p class="text-gray-700">Here is the detailed explanation...</p></div>
101
-
102
- Example 2 - Code:
103
- <div class="space-y-4 p-6"><h3 class="text-xl font-bold">JavaScript Function</h3><pre class="bg-gray-900 text-white p-4 rounded overflow-x-auto"><code>const greet = () => console.log('Hello');</code></pre></div>
104
-
105
- Example 3 - Multiple sections:
106
- <div class="space-y-4 p-6"><h2 class="text-2xl font-bold">Topic</h2><div class="card bg-white shadow p-4"><h3 class="font-bold">Section 1</h3><p>Content here</p></div><div class="card bg-white shadow p-4"><h3 class="font-bold">Section 2</h3><p>More content</p></div></div>
107
-
108
92
  YOU MUST ALWAYS OUTPUT VALID, COMPLETE HTML.
109
93
  The user's interface shows YOUR HTML directly - make it beautiful, well-organized, and professional.`;
110
94
 
111
95
  export default class ACPConnection {
112
96
  constructor() {
113
- this.child = null;
114
- this.buffer = '';
115
- this.nextRequestId = 1;
116
- this.pendingRequests = new Map();
97
+ this.client = null;
117
98
  this.sessionId = null;
118
99
  this.onUpdate = null;
119
- this.cwd = '/config';
120
100
  }
121
101
 
102
+ /**
103
+ * Connect to ACP bridge and create session
104
+ * Uses identical configuration to CLI version
105
+ */
122
106
  async connect(agentType, cwd) {
123
- this.cwd = cwd;
124
-
125
- const acpSetup = async () => {
126
- await this._spawnACP(agentType, cwd);
127
- await this.sendRequest('initialize', {
128
- protocolVersion: 1,
129
- clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } },
130
- }, 10000);
131
- const result = await this.sendRequest('session/new', { cwd, mcpServers: [] }, 30000);
132
- this.sessionId = result.sessionId;
133
- await this.sendRequest('session/set_mode', { sessionId: this.sessionId, modeId: 'bypassPermissions' }, 10000);
134
- };
135
-
136
- const deadline = new Promise((_, reject) => setTimeout(() => reject(new Error('ACP handshake timeout (60s)')), 60000));
137
-
138
107
  try {
139
- await Promise.race([acpSetup(), deadline]);
140
- console.log(`[ACP] Connected via ACP bridge (${agentType})`);
141
- } catch (acpErr) {
142
- console.error(`[ACP] FATAL: Bridge failed: ${acpErr.message}`);
143
- console.error(`[ACP] The ACP bridge is REQUIRED. Please install the bridge for ${agentType}.`);
144
- if (this.child) {
145
- try { this.child.kill('SIGTERM'); } catch (_) {}
146
- this.child = null;
147
- }
148
- throw acpErr;
149
- }
150
- }
151
-
152
- _spawnACP(agentType, cwd) {
153
- return new Promise((resolve, reject) => {
154
- const env = { ...process.env };
155
- delete env.NODE_OPTIONS;
156
- delete env.NODE_INSPECT;
157
- delete env.NODE_DEBUG;
158
-
159
- // Ensure npm global bin directories are in PATH
160
- const npmGlobalBins = [
161
- '/config/.gmweb/npm-global/bin',
162
- path.join(os.homedir(), '.gmweb/npm-global/bin'),
163
- path.join(os.homedir(), '.local/bin'),
164
- '/usr/local/bin',
165
- ];
166
- const currentPath = env.PATH || '';
167
- const newPathEntries = npmGlobalBins.filter(p => !currentPath.includes(p));
168
- if (newPathEntries.length > 0) {
169
- env.PATH = [...newPathEntries, currentPath].join(':');
170
- }
171
-
172
- try {
173
- let cmd;
174
- let args;
175
- if (agentType === 'opencode') {
176
- cmd = findBinary(OPENCODE_PATHS);
177
- args = ['acp'];
178
- } else {
179
- cmd = findBinary(CLAUDE_CODE_ACP_PATHS);
180
- args = [];
181
- }
182
-
183
- if (!cmd) {
184
- reject(new Error(`Could not find ${agentType} ACP binary. Please ensure ${agentType === 'opencode' ? 'opencode' : 'claude-code-acp'} is installed and in your PATH.`));
185
- return;
186
- }
187
-
188
- this.child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'], env, shell: false });
189
- } catch (err) {
190
- reject(new Error(`Failed to spawn ACP: ${err.message}`));
191
- return;
192
- }
193
-
194
- this.child.stderr.on('data', d => console.error(`[ACP:stderr]`, d.toString().trim()));
195
- this.child.on('error', err => reject(new Error(`ACP spawn error: ${err.message}`)));
196
- this.child.on('exit', () => {
197
- this.child = null;
198
- for (const [id, req] of this.pendingRequests) {
199
- req.reject(new Error('ACP process exited'));
200
- clearTimeout(req.timeoutId);
201
- }
202
- this.pendingRequests.clear();
203
- });
204
-
205
- this.child.stdout.setEncoding('utf8');
206
- this.child.stdout.on('data', data => {
207
- this.buffer += data;
208
- const lines = this.buffer.split('\n');
209
- this.buffer = lines.pop() || '';
210
- for (const line of lines) {
211
- if (!line.trim()) continue;
212
- try { this.handleMessage(JSON.parse(line)); }
213
- catch (e) { console.error('[ACP:parse]', line.substring(0, 200), e.message); }
214
- }
108
+ console.log(`[ACP] Connecting to ${agentType}...`);
109
+
110
+ // Load CLI configuration for identical behavior
111
+ const cliConfig = loadCLIConfig();
112
+
113
+ // Create client with CLI-identical configuration
114
+ // Pass through all environment for OAuth and plugin support
115
+ const clientConfig = {
116
+ agent: agentType === 'opencode' ? 'opencode' : 'claude-code',
117
+ cwd,
118
+ // Use same environment as CLI (HOME, PATH, etc.)
119
+ env: process.env,
120
+ // Load plugins just like CLI does
121
+ plugins: true,
122
+ // Use OAuth for authentication (same as CLI)
123
+ oauth: true,
124
+ // Use model preferences from CLI config
125
+ modelPreferences: cliConfig.modelPreferences || undefined,
126
+ // Enable all capabilities that CLI enables
127
+ capabilities: {
128
+ fs: true,
129
+ mcp: true,
130
+ web: true,
131
+ terminal: true
132
+ },
133
+ // Pass through any other CLI settings
134
+ ...cliConfig
135
+ };
136
+
137
+ // Remove potential conflicting fields
138
+ delete clientConfig.agent; // Re-add below
139
+ delete clientConfig.cwd; // Re-add below
140
+
141
+ this.client = await createClient({
142
+ agent: clientConfig.agent || (agentType === 'opencode' ? 'opencode' : 'claude-code'),
143
+ cwd,
144
+ ...clientConfig
215
145
  });
216
146
 
217
- setTimeout(resolve, 300);
218
- });
219
- }
220
-
221
- handleMessage(msg) {
222
- if (msg.method) { this.handleIncoming(msg); return; }
223
- if (msg.id !== undefined && this.pendingRequests.has(msg.id)) {
224
- const req = this.pendingRequests.get(msg.id);
225
- this.pendingRequests.delete(msg.id);
226
- clearTimeout(req.timeoutId);
227
- if (msg.error) req.reject(new Error(msg.error.message || JSON.stringify(msg.error)));
228
- else req.resolve(msg.result);
229
- }
230
- }
231
-
232
- handleIncoming(msg) {
233
- if (msg.method === 'session/update' && msg.params) {
234
- if (this.onUpdate) this.onUpdate(msg.params);
235
- this.resetPromptTimeout();
236
- return;
237
- }
238
- if (msg.method === 'session/request_permission' && msg.id !== undefined) {
239
- this.sendResponse(msg.id, { outcome: { outcome: 'selected', optionId: 'allow' } });
240
- this.resetPromptTimeout();
241
- return;
242
- }
243
- if (msg.method === 'fs/read_text_file' && msg.id !== undefined) {
244
- try { this.sendResponse(msg.id, { content: fs.readFileSync(msg.params?.path, 'utf-8') }); }
245
- catch (e) { this.sendError(msg.id, -32000, e.message); }
246
- return;
247
- }
248
- if (msg.method === 'fs/write_text_file' && msg.id !== undefined) {
249
- try { fs.writeFileSync(msg.params?.path, msg.params?.content, 'utf-8'); this.sendResponse(msg.id, null); }
250
- catch (e) { this.sendError(msg.id, -32000, e.message); }
251
- return;
252
- }
253
- }
254
-
255
- resetPromptTimeout() {
256
- for (const [id, req] of this.pendingRequests) {
257
- if (req.method === 'session/prompt') {
258
- clearTimeout(req.timeoutId);
259
- req.timeoutId = setTimeout(() => {
260
- this.pendingRequests.delete(id);
261
- req.reject(new Error('session/prompt timeout'));
262
- }, 300000);
263
- }
147
+ console.log(`[ACP] ✅ Connected to ${agentType} (CLI-identical mode)`);
148
+ } catch (err) {
149
+ console.error(`[ACP] ❌ FATAL: Connection failed: ${err.message}`);
150
+ throw new Error(`ACP connection failed for ${agentType}: ${err.message}`);
264
151
  }
265
152
  }
266
153
 
267
- sendRequest(method, params, timeoutMs = 60000) {
268
- return new Promise((resolve, reject) => {
269
- if (!this.child) { reject(new Error('ACP not connected')); return; }
270
- const id = this.nextRequestId++;
271
- const timeoutId = setTimeout(() => {
272
- this.pendingRequests.delete(id);
273
- reject(new Error(`${method} timeout (${timeoutMs}ms)`));
274
- }, timeoutMs);
275
- this.pendingRequests.set(id, { resolve, reject, timeoutId, method });
276
- this.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, ...(params && { params }) }) + '\n');
277
- });
278
- }
279
-
280
- sendResponse(id, result) {
281
- if (!this.child) return;
282
- this.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, result }) + '\n');
283
- }
284
-
285
- sendError(id, code, message) {
286
- if (!this.child) return;
287
- this.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } }) + '\n');
288
- }
289
-
154
+ /**
155
+ * Initialize ACP session
156
+ */
290
157
  async initialize() {
291
- return this.sendRequest('initialize', {
158
+ if (!this.client) throw new Error('ACP not connected');
159
+ return this.client.request('initialize', {
292
160
  protocolVersion: 1,
293
- clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } },
161
+ clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } }
294
162
  });
295
163
  }
296
164
 
165
+ /**
166
+ * Create new session
167
+ */
297
168
  async newSession(cwd) {
298
- const result = await this.sendRequest('session/new', { cwd, mcpServers: [] }, 120000);
169
+ if (!this.client) throw new Error('ACP not connected');
170
+ const result = await this.client.request('session/new', { cwd, mcpServers: [] });
299
171
  this.sessionId = result.sessionId;
300
172
  return result;
301
173
  }
302
174
 
175
+ /**
176
+ * Set session mode
177
+ */
303
178
  async setSessionMode(modeId) {
304
- return this.sendRequest('session/set_mode', { sessionId: this.sessionId, modeId });
179
+ if (!this.client) throw new Error('ACP not connected');
180
+ return this.client.request('session/set_mode', { sessionId: this.sessionId, modeId });
305
181
  }
306
182
 
183
+ /**
184
+ * Inject skills and system prompt
185
+ */
307
186
  async injectSkills(additionalContext = '') {
308
- // Combine the system prompt with any additional context
309
- const systemPrompt = additionalContext ? `${RIPPLEUI_SYSTEM_PROMPT}\n\n---\n\n${additionalContext}` : RIPPLEUI_SYSTEM_PROMPT;
187
+ if (!this.client) throw new Error('ACP not connected');
188
+
189
+ const systemPrompt = additionalContext
190
+ ? `${RIPPLEUI_SYSTEM_PROMPT}\n\n---\n\n${additionalContext}`
191
+ : RIPPLEUI_SYSTEM_PROMPT;
310
192
 
311
- return this.sendRequest('session/skill_inject', {
193
+ return this.client.request('session/skill_inject', {
312
194
  sessionId: this.sessionId,
313
195
  skills: [],
314
196
  notification: [{ type: 'text', text: systemPrompt }]
@@ -316,30 +198,61 @@ export default class ACPConnection {
316
198
  }
317
199
 
318
200
  /**
319
- * Inject system prompt as initial context
201
+ * Inject system context
320
202
  */
321
203
  async injectSystemContext() {
322
- return this.sendRequest('session/context', {
204
+ if (!this.client) throw new Error('ACP not connected');
205
+
206
+ return this.client.request('session/context', {
323
207
  sessionId: this.sessionId,
324
208
  context: RIPPLEUI_SYSTEM_PROMPT,
325
209
  role: 'system'
326
210
  });
327
211
  }
328
212
 
213
+ /**
214
+ * Send prompt and stream updates
215
+ */
329
216
  async sendPrompt(prompt) {
217
+ if (!this.client) throw new Error('ACP not connected');
218
+
330
219
  const promptContent = Array.isArray(prompt) ? prompt : [{ type: 'text', text: prompt }];
331
- return this.sendRequest('session/prompt', { sessionId: this.sessionId, prompt: promptContent }, 300000);
220
+
221
+ // Setup update handler before sending
222
+ if (this.onUpdate) {
223
+ this.client.on('update', (update) => {
224
+ // Forward updates immediately with no delay
225
+ this.onUpdate({ update });
226
+ });
227
+ }
228
+
229
+ // Send prompt and get result
230
+ return this.client.request('session/prompt', {
231
+ sessionId: this.sessionId,
232
+ prompt: promptContent
233
+ }, 300000);
332
234
  }
333
235
 
236
+ /**
237
+ * Check if connection is running
238
+ */
334
239
  isRunning() {
335
- return this.child && !this.child.killed;
240
+ return this.client !== null;
336
241
  }
337
242
 
243
+ /**
244
+ * Terminate connection
245
+ */
338
246
  async terminate() {
339
- if (!this.child) return;
340
- this.child.stdin.end();
341
- this.child.kill('SIGTERM');
342
- await new Promise(r => { this.child?.on('exit', r); setTimeout(r, 5000); });
343
- this.child = null;
247
+ if (!this.client) return;
248
+
249
+ try {
250
+ await this.client.close();
251
+ } catch (err) {
252
+ console.error(`[ACP] Error during terminate: ${err.message}`);
253
+ } finally {
254
+ this.client = null;
255
+ this.sessionId = null;
256
+ }
344
257
  }
345
258
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -18,15 +18,11 @@
18
18
  "homepage": "https://github.com/AnEntrypoint/agentgui#readme",
19
19
  "scripts": {
20
20
  "start": "node server.js",
21
- "start:bun": "bun run server-bun.js",
22
- "dev": "node server.js --watch",
23
- "dev:bun": "bun run server-bun.js --watch",
24
- "test": "node run-browser-tests.js",
25
- "test:integration": "./test-integration.sh",
26
- "test:all": "npm run test:integration && npm run test"
21
+ "dev": "node server.js --watch"
27
22
  },
28
23
  "dependencies": {
29
24
  "better-sqlite3": "^12.6.2",
25
+ "claude-code-acp": "^1.0.0",
30
26
  "ws": "^8.14.2"
31
27
  }
32
28
  }
package/server.js CHANGED
@@ -551,10 +551,10 @@ async function processMessage(conversationId, messageId, sessionId, content, age
551
551
  console.error(`[processMessage] State history: ${JSON.stringify(summary, null, 2)}`);
552
552
 
553
553
  } finally {
554
- // Cleanup: remove from state store after completion
555
- setTimeout(() => {
554
+ // Cleanup: remove from state store immediately (async to not block)
555
+ setImmediate(() => {
556
556
  sessionStateStore.remove(sessionId);
557
- }, 5000);
557
+ });
558
558
 
559
559
  // Log final state
560
560
  console.log(`[processMessage] Final state: ${stateManager.getState()}`);
package/stream-handler.js CHANGED
@@ -62,15 +62,9 @@ export class StreamHandler {
62
62
  this.sequence = persistedUpdate.sequence;
63
63
  this.updateCount++;
64
64
 
65
- // Validate consistency after write
66
- const validation = StateValidator.validateSession(this.sessionId);
67
- if (!validation.valid) {
68
- console.error(`[StreamHandler] State validation failed after update:`, validation);
69
- // Log but continue - database is still source of truth
70
- }
71
-
72
65
  // CRITICAL: Broadcast happens AFTER database write confirms
73
66
  // This ensures clients see data that's already persisted
67
+ // Broadcast immediately with zero delay
74
68
  this.broadcastFn({
75
69
  type: 'stream_update',
76
70
  sessionId: this.sessionId,
@@ -79,8 +73,19 @@ export class StreamHandler {
79
73
  update: persistedUpdate.content,
80
74
  sequence: this.sequence,
81
75
  persisted: true,
82
- timestamp: persistedUpdate.created_at,
83
- validation: validation.valid ? undefined : { error: validation.error }
76
+ timestamp: persistedUpdate.created_at
77
+ });
78
+
79
+ // Validate consistency asynchronously (don't block broadcast)
80
+ setImmediate(() => {
81
+ try {
82
+ const validation = StateValidator.validateSession(this.sessionId);
83
+ if (!validation.valid) {
84
+ console.error(`[StreamHandler] State validation failed: ${validation.error}`);
85
+ }
86
+ } catch (validationErr) {
87
+ console.error(`[StreamHandler] Validation error: ${validationErr.message}`);
88
+ }
84
89
  });
85
90
  } catch (err) {
86
91
  console.error(`[StreamHandler] Error persisting update: ${err.message}`);
package/DELIVERABLES.txt DELETED
@@ -1,212 +0,0 @@
1
- ================================================================================
2
- STATE CONSISTENCY TEST DELIVERABLES
3
- ================================================================================
4
-
5
- TEST COMPLETED: February 3, 2026
6
- SYSTEM TESTED: BuildEsk LIVE (https://buildesk.acc.l-inc.co.za/gm/)
7
- CREDENTIALS: abc / Test123456
8
-
9
- ================================================================================
10
- DOCUMENTED FINDINGS
11
- ================================================================================
12
-
13
- ✓ VERIFIED - Conversation lists are IDENTICAL between windows
14
- ✓ VERIFIED - No console errors detected
15
- ✓ VERIFIED - Multi-session support working
16
- ✓ VERIFIED - Authentication system functional
17
-
18
- ⚠ PENDING - Real-time message synchronization (manual test needed)
19
- ⚠ PENDING - Timestamp consistency (manual test needed)
20
- ⚠ PENDING - Rapid message handling (manual test needed)
21
-
22
- ================================================================================
23
- DOCUMENTATION FILES
24
- ================================================================================
25
-
26
- MAIN DOCUMENTS:
27
- → TEST_README.md
28
- Entry point - Quick overview and navigation
29
-
30
- → TEST_SUMMARY.md
31
- Executive summary - Key findings and recommendations
32
-
33
- → STATE_CONSISTENCY_TEST_REPORT.md
34
- Comprehensive report - Detailed procedures and technical details
35
-
36
- → STATE_CONSISTENCY_TEST_INDEX.md
37
- Complete index - Navigation guide and quick reference
38
-
39
- REFERENCE:
40
- → STATE_CONSISTENCY_GUARANTEE.md
41
- Implementation details
42
-
43
- → DELIVERABLES.txt
44
- This file
45
-
46
- ================================================================================
47
- TEST ARTIFACTS
48
- ================================================================================
49
-
50
- LOCATION: test-artifacts/
51
-
52
- SCREENSHOTS (1280x720 PNG):
53
- ├── 01-window-a-initial.png
54
- ├── 01-window-b-initial.png
55
- ├── 02-window-a-after-send.png
56
- └── 02-window-b-after-send.png
57
-
58
- PAGE SNAPSHOTS:
59
- ├── snapshot-a-1.txt
60
- └── snapshot-b-1.txt
61
-
62
- CONSOLE LOGS:
63
- ├── console-a.log
64
- └── console-b.log
65
-
66
- VERIFICATION: diff snapshot-a-1.txt snapshot-b-1.txt → No differences ✓
67
-
68
- ================================================================================
69
- QUICK START GUIDE
70
- ================================================================================
71
-
72
- 1. FOR QUICK OVERVIEW:
73
- Read: TEST_README.md (2 min)
74
-
75
- 2. FOR MANUAL TESTING:
76
- Read: STATE_CONSISTENCY_TEST_REPORT.md
77
- Sections: "Manual Test Procedures" and "Commands for Manual Testing"
78
-
79
- 3. TO VERIFY FINDINGS:
80
- Check: test-artifacts/ screenshots and snapshots
81
-
82
- 4. FOR TECHNICAL DETAILS:
83
- Read: STATE_CONSISTENCY_TEST_REPORT.md
84
- Section: "Appendix: Technical Details"
85
-
86
- ================================================================================
87
- COMMAND REFERENCE
88
- ================================================================================
89
-
90
- LAUNCH DUAL SESSIONS:
91
- # Terminal 1
92
- agent-browser --headed --session window-a \
93
- --credentials abc Test123456 \
94
- open https://buildesk.acc.l-inc.co.za/gm/
95
-
96
- # Terminal 2
97
- agent-browser --headed --session window-b \
98
- --credentials abc Test123456 \
99
- open https://buildesk.acc.l-inc.co.za/gm/
100
-
101
- TAKE SCREENSHOTS:
102
- agent-browser --session window-a screenshot --full manual-a.png
103
- agent-browser --session window-b screenshot --full manual-b.png
104
-
105
- CHECK CONSOLE:
106
- agent-browser --session window-a console
107
- agent-browser --session window-b console
108
-
109
- GET PAGE SNAPSHOT:
110
- agent-browser --session window-a snapshot -i -c
111
-
112
- ================================================================================
113
- TEST RESULTS SUMMARY
114
- ================================================================================
115
-
116
- AUTOMATED TEST RESULTS:
117
- ✓ Server Connectivity ..................... PASSED
118
- ✓ Session A Initialization ............... PASSED
119
- ✓ Session B Initialization ............... PASSED
120
- ✓ Authentication (both sessions) ......... PASSED
121
- ✓ Initial Conversation Lists Match ....... PASSED (IDENTICAL)
122
- ✓ Console Error Detection ................ PASSED (No errors)
123
- ✓ Page Snapshot Comparison ............... PASSED (Identical)
124
-
125
- TOTAL: 7/7 PASSED ✓
126
-
127
- MANUAL TEST STATUS:
128
- ⚠ New Conversation Sync ................. PENDING
129
- ⚠ Message Send Synchronization .......... PENDING
130
- ⚠ Timestamp Consistency ................. PENDING
131
- ⚠ Rapid Message Handling ................ PENDING
132
-
133
- ================================================================================
134
- FINAL RECOMMENDATIONS
135
- ================================================================================
136
-
137
- NEXT STEPS:
138
- 1. Review test artifacts in test-artifacts/
139
- 2. Execute manual test procedures from STATE_CONSISTENCY_TEST_REPORT.md
140
- 3. Document real-time sync behavior and latencies
141
- 4. Analyze console logs for state sync patterns
142
- 5. Validate timestamp consistency across windows
143
- 6. Test rapid message scenarios for race conditions
144
- 7. Create final consolidated test report
145
-
146
- EXPECTED OUTCOMES:
147
- - Measure message send latency (target: < 100ms)
148
- - Verify timestamp updates propagate to both windows
149
- - Confirm no lost messages under rapid sending
150
- - Document WebSocket/polling implementation
151
- - Validate connection resilience
152
-
153
- ================================================================================
154
- FILE LOCATIONS
155
- ================================================================================
156
-
157
- All files are located in: /config/workspace/agentgui/
158
-
159
- Documentation:
160
- - TEST_README.md
161
- - TEST_SUMMARY.md
162
- - STATE_CONSISTENCY_TEST_REPORT.md
163
- - STATE_CONSISTENCY_TEST_INDEX.md
164
- - STATE_CONSISTENCY_GUARANTEE.md
165
- - DELIVERABLES.txt (this file)
166
-
167
- Test Artifacts:
168
- - test-artifacts/ (directory)
169
- ├── 4 PNG screenshots
170
- ├── 2 TXT snapshots
171
- └── 2 console logs
172
-
173
- ================================================================================
174
- VERIFICATION CHECKLIST
175
- ================================================================================
176
-
177
- ✓ Server is reachable and responding with HTTP 200
178
- ✓ Authentication credentials work correctly
179
- ✓ Both sessions connect without conflicts
180
- ✓ Conversation lists load and are identical
181
- ✓ Console logs collected (no errors)
182
- ✓ Screenshots captured for both windows
183
- ✓ Page snapshots created and compared
184
- ✓ Diff analysis shows identical content
185
- ✓ Test documentation complete
186
- ✓ Manual test procedures documented
187
- ✓ Test artifacts organized and available
188
-
189
- ================================================================================
190
- SUPPORT & QUESTIONS
191
- ================================================================================
192
-
193
- For detailed information, see:
194
- - TEST_README.md for quick overview
195
- - STATE_CONSISTENCY_TEST_REPORT.md for procedures
196
- - STATE_CONSISTENCY_TEST_INDEX.md for navigation
197
-
198
- To run manual tests:
199
- - Follow commands in STATE_CONSISTENCY_TEST_REPORT.md section:
200
- "Commands for Manual Testing"
201
-
202
- To review evidence:
203
- - Check screenshots in test-artifacts/
204
- - Compare snapshots: test-artifacts/snapshot-*.txt
205
-
206
- ================================================================================
207
- TEST EXECUTION: AUTOMATED ✓ COMPLETE
208
- MANUAL PHASE: READY TO BEGIN ⚠
209
- ================================================================================
210
-
211
- Report Generated: February 3, 2026
212
- Status: All automated tests passed, manual phase ready for execution