agent-browser 0.3.1 → 0.3.3

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/src/daemon.ts DELETED
@@ -1,187 +0,0 @@
1
- import * as net from 'net';
2
- import * as fs from 'fs';
3
- import * as path from 'path';
4
- import * as os from 'os';
5
- import { BrowserManager } from './browser.js';
6
- import { parseCommand, serializeResponse, errorResponse } from './protocol.js';
7
- import { executeCommand } from './actions.js';
8
-
9
- // Session support - each session gets its own socket/pid
10
- let currentSession = process.env.AGENT_BROWSER_SESSION || 'default';
11
-
12
- /**
13
- * Set the current session
14
- */
15
- export function setSession(session: string): void {
16
- currentSession = session;
17
- }
18
-
19
- /**
20
- * Get the current session
21
- */
22
- export function getSession(): string {
23
- return currentSession;
24
- }
25
-
26
- /**
27
- * Get the socket path for the current session
28
- */
29
- export function getSocketPath(session?: string): string {
30
- const sess = session ?? currentSession;
31
- return path.join(os.tmpdir(), `agent-browser-${sess}.sock`);
32
- }
33
-
34
- /**
35
- * Get the PID file path for the current session
36
- */
37
- export function getPidFile(session?: string): string {
38
- const sess = session ?? currentSession;
39
- return path.join(os.tmpdir(), `agent-browser-${sess}.pid`);
40
- }
41
-
42
- /**
43
- * Check if daemon is running for the current session
44
- */
45
- export function isDaemonRunning(session?: string): boolean {
46
- const pidFile = getPidFile(session);
47
- if (!fs.existsSync(pidFile)) return false;
48
-
49
- try {
50
- const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10);
51
- // Check if process exists
52
- process.kill(pid, 0);
53
- return true;
54
- } catch {
55
- // Process doesn't exist, clean up stale files
56
- cleanupSocket(session);
57
- return false;
58
- }
59
- }
60
-
61
- /**
62
- * Clean up socket and PID file for the current session
63
- */
64
- export function cleanupSocket(session?: string): void {
65
- const socketPath = getSocketPath(session);
66
- const pidFile = getPidFile(session);
67
- try {
68
- if (fs.existsSync(socketPath)) fs.unlinkSync(socketPath);
69
- if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile);
70
- } catch {
71
- // Ignore cleanup errors
72
- }
73
- }
74
-
75
- /**
76
- * Start the daemon server
77
- */
78
- export async function startDaemon(): Promise<void> {
79
- // Clean up any stale socket
80
- cleanupSocket();
81
-
82
- const browser = new BrowserManager();
83
- let shuttingDown = false;
84
-
85
- const server = net.createServer((socket) => {
86
- let buffer = '';
87
-
88
- socket.on('data', async (data) => {
89
- buffer += data.toString();
90
-
91
- // Process complete lines
92
- while (buffer.includes('\n')) {
93
- const newlineIdx = buffer.indexOf('\n');
94
- const line = buffer.substring(0, newlineIdx);
95
- buffer = buffer.substring(newlineIdx + 1);
96
-
97
- if (!line.trim()) continue;
98
-
99
- try {
100
- const parseResult = parseCommand(line);
101
-
102
- if (!parseResult.success) {
103
- const resp = errorResponse(parseResult.id ?? 'unknown', parseResult.error);
104
- socket.write(serializeResponse(resp) + '\n');
105
- continue;
106
- }
107
-
108
- // Auto-launch browser if not already launched and this isn't a launch command
109
- if (
110
- !browser.isLaunched() &&
111
- parseResult.command.action !== 'launch' &&
112
- parseResult.command.action !== 'close'
113
- ) {
114
- await browser.launch({ id: 'auto', action: 'launch', headless: true });
115
- }
116
-
117
- // Handle close command specially
118
- if (parseResult.command.action === 'close') {
119
- const response = await executeCommand(parseResult.command, browser);
120
- socket.write(serializeResponse(response) + '\n');
121
-
122
- if (!shuttingDown) {
123
- shuttingDown = true;
124
- setTimeout(() => {
125
- server.close();
126
- cleanupSocket();
127
- process.exit(0);
128
- }, 100);
129
- }
130
- return;
131
- }
132
-
133
- const response = await executeCommand(parseResult.command, browser);
134
- socket.write(serializeResponse(response) + '\n');
135
- } catch (err) {
136
- const message = err instanceof Error ? err.message : String(err);
137
- socket.write(serializeResponse(errorResponse('error', message)) + '\n');
138
- }
139
- }
140
- });
141
-
142
- socket.on('error', () => {
143
- // Client disconnected, ignore
144
- });
145
- });
146
-
147
- const socketPath = getSocketPath();
148
- const pidFile = getPidFile();
149
-
150
- // Write PID file before listening
151
- fs.writeFileSync(pidFile, process.pid.toString());
152
-
153
- server.listen(socketPath, () => {
154
- // Daemon is ready
155
- });
156
-
157
- server.on('error', (err) => {
158
- console.error('Server error:', err);
159
- cleanupSocket();
160
- process.exit(1);
161
- });
162
-
163
- // Handle shutdown signals
164
- const shutdown = async () => {
165
- if (shuttingDown) return;
166
- shuttingDown = true;
167
- await browser.close();
168
- server.close();
169
- cleanupSocket();
170
- process.exit(0);
171
- };
172
-
173
- process.on('SIGINT', shutdown);
174
- process.on('SIGTERM', shutdown);
175
-
176
- // Keep process alive
177
- process.stdin.resume();
178
- }
179
-
180
- // Run daemon if this is the entry point
181
- if (process.argv[1]?.endsWith('daemon.js') || process.env.AGENT_BROWSER_DAEMON === '1') {
182
- startDaemon().catch((err) => {
183
- console.error('Daemon error:', err);
184
- cleanupSocket();
185
- process.exit(1);
186
- });
187
- }