agent-state-machine 1.4.2 → 2.0.1
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/README.md +2 -6
- package/bin/cli.js +4 -19
- package/package.json +4 -2
- package/vercel-server/api/events/[token].js +119 -0
- package/vercel-server/api/history/[token].js +51 -0
- package/vercel-server/api/session/[token].js +49 -0
- package/vercel-server/api/submit/[token].js +94 -0
- package/vercel-server/api/ws/cli.js +186 -0
- package/vercel-server/local-server.js +30 -329
- package/vercel-server/public/index.html +17 -5
- package/{lib → vercel-server}/ui/index.html +339 -114
- package/lib/ui/server.js +0 -150
package/lib/ui/server.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File: /lib/ui/server.js
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import http from 'http';
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = path.dirname(__filename);
|
|
12
|
-
|
|
13
|
-
export function startServer(workflowDir, initialPort = 3000) {
|
|
14
|
-
const clients = new Set();
|
|
15
|
-
const stateDir = path.join(workflowDir, 'state');
|
|
16
|
-
|
|
17
|
-
// Watch for changes in the state directory
|
|
18
|
-
// We debounce slightly to avoid sending multiple events for a single write burst
|
|
19
|
-
let debounceTimer;
|
|
20
|
-
const broadcastUpdate = () => {
|
|
21
|
-
if (debounceTimer) clearTimeout(debounceTimer);
|
|
22
|
-
debounceTimer = setTimeout(() => {
|
|
23
|
-
const msg = 'data: update\n\n';
|
|
24
|
-
for (const client of clients) {
|
|
25
|
-
try {
|
|
26
|
-
client.write(msg);
|
|
27
|
-
} catch (e) {
|
|
28
|
-
clients.delete(client);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}, 100);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
if (fs.existsSync(stateDir)) {
|
|
36
|
-
fs.watch(stateDir, (eventType, filename) => {
|
|
37
|
-
if (filename && (filename === 'history.jsonl' || filename.startsWith('history'))) {
|
|
38
|
-
broadcastUpdate();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
} else {
|
|
42
|
-
console.warn('Warning: State directory does not exist yet. Live updates might not work until it is created.');
|
|
43
|
-
}
|
|
44
|
-
} catch (err) {
|
|
45
|
-
console.warn('Warning: Failed to setup file watcher:', err.message);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Request Handler
|
|
49
|
-
const requestHandler = (req, res) => {
|
|
50
|
-
// Serve the main HTML page
|
|
51
|
-
if (req.url === '/' || req.url === '/index.html') {
|
|
52
|
-
const htmlPath = path.join(__dirname, 'index.html');
|
|
53
|
-
fs.readFile(htmlPath, (err, content) => {
|
|
54
|
-
if (err) {
|
|
55
|
-
res.writeHead(500);
|
|
56
|
-
res.end('Error loading UI');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
60
|
-
res.end(content);
|
|
61
|
-
});
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Server-Sent Events endpoint
|
|
66
|
-
if (req.url === '/api/events') {
|
|
67
|
-
res.writeHead(200, {
|
|
68
|
-
'Content-Type': 'text/event-stream',
|
|
69
|
-
'Cache-Control': 'no-cache',
|
|
70
|
-
'Connection': 'keep-alive',
|
|
71
|
-
});
|
|
72
|
-
res.write('retry: 10000\n\n');
|
|
73
|
-
|
|
74
|
-
clients.add(res);
|
|
75
|
-
|
|
76
|
-
req.on('close', () => {
|
|
77
|
-
clients.delete(res);
|
|
78
|
-
});
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Serve API
|
|
83
|
-
if (req.url === '/api/history') {
|
|
84
|
-
const historyFile = path.join(stateDir, 'history.jsonl');
|
|
85
|
-
|
|
86
|
-
if (!fs.existsSync(historyFile)) {
|
|
87
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
88
|
-
res.end(JSON.stringify({
|
|
89
|
-
workflowName: path.basename(workflowDir),
|
|
90
|
-
entries: []
|
|
91
|
-
}));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const fileContent = fs.readFileSync(historyFile, 'utf-8');
|
|
97
|
-
const lines = fileContent.trim().split('\n');
|
|
98
|
-
const entries = lines
|
|
99
|
-
.map(line => {
|
|
100
|
-
try { return JSON.parse(line); } catch { return null; }
|
|
101
|
-
})
|
|
102
|
-
.filter(Boolean);
|
|
103
|
-
|
|
104
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
105
|
-
res.end(JSON.stringify({
|
|
106
|
-
workflowName: path.basename(workflowDir),
|
|
107
|
-
entries
|
|
108
|
-
}));
|
|
109
|
-
} catch (err) {
|
|
110
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
111
|
-
res.end(JSON.stringify({ error: err.message }));
|
|
112
|
-
}
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 404
|
|
117
|
-
res.writeHead(404);
|
|
118
|
-
res.end('Not found');
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// Port hunting logic
|
|
122
|
-
let port = initialPort;
|
|
123
|
-
const maxPort = initialPort + 100; // Try up to 100 ports
|
|
124
|
-
|
|
125
|
-
const attemptServer = () => {
|
|
126
|
-
const server = http.createServer(requestHandler);
|
|
127
|
-
|
|
128
|
-
server.on('error', (e) => {
|
|
129
|
-
if (e.code === 'EADDRINUSE') {
|
|
130
|
-
if (port < maxPort) {
|
|
131
|
-
console.log(`Port ${port} is in use, trying ${port + 1}...`);
|
|
132
|
-
port++;
|
|
133
|
-
attemptServer();
|
|
134
|
-
} else {
|
|
135
|
-
console.error(`Error: Could not find an open port between ${initialPort} and ${maxPort}.`);
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
console.error('Server error:', e);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
server.listen(port, () => {
|
|
143
|
-
console.log(`\n> Follow UI running at http://localhost:${port}`);
|
|
144
|
-
console.log(`> Viewing history for: ${workflowDir}`);
|
|
145
|
-
console.log(`> Press Ctrl+C to stop`);
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
attemptServer();
|
|
150
|
-
}
|