doer-agent 0.1.6 → 0.1.7

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 CHANGED
@@ -11,7 +11,6 @@
11
11
  주요 엔트리 포인트:
12
12
 
13
13
  - `doer-agent`: 에이전트 본체 CLI
14
- - `playwright-mcp-call`: Playwright MCP 호출용 CLI
15
14
  - `codex`: Codex 래퍼 CLI
16
15
 
17
16
  ## 요구 사항
package/dist/agent.js CHANGED
@@ -1,14 +1,10 @@
1
1
  import { spawn, spawnSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
- import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
4
- import net from "node:net";
5
- import { arch, homedir } from "node:os";
3
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { homedir } from "node:os";
6
5
  import path from "node:path";
7
6
  import { fileURLToPath } from "node:url";
8
7
  import { AckPolicy, connect, DeliverPolicy, JSONCodec, RetentionPolicy, StorageType } from "nats";
9
- const PLAYWRIGHT_SKIP_BROWSER_GC = "1";
10
- const PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS_DEFAULT = 10800;
11
- const PLAYWRIGHT_MCP_DAEMON_SIGNATURE_VERSION = "2026-03-15";
12
8
  const DEFAULT_SERVER_BASE_URL = "https://doer.cranix.net";
13
9
  const AGENT_MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
14
10
  const AGENT_PROJECT_DIR = path.join(AGENT_MODULE_DIR, "..");
@@ -144,18 +140,6 @@ function resolveCodexHomePath() {
144
140
  function parseEnvBoolean(value) {
145
141
  return value?.trim().toLowerCase() === "true";
146
142
  }
147
- function parseEnvStringArray(value) {
148
- if (!value?.trim()) {
149
- return [];
150
- }
151
- try {
152
- const parsed = JSON.parse(value);
153
- return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : [];
154
- }
155
- catch {
156
- return [];
157
- }
158
- }
159
143
  function parseEnvInteger(value, fallback) {
160
144
  const normalized = value?.trim();
161
145
  if (!normalized) {
@@ -164,211 +148,6 @@ function parseEnvInteger(value, fallback) {
164
148
  const parsed = Number.parseInt(normalized, 10);
165
149
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
166
150
  }
167
- function resolvePlaywrightMcpProxyPath() {
168
- const candidates = [
169
- path.join(AGENT_PROJECT_DIR, "runtime/bin/doer-mcp-proxy"),
170
- path.join(process.cwd(), "agent/runtime/bin/doer-mcp-proxy"),
171
- path.join(process.cwd(), "runtime/bin/doer-mcp-proxy"),
172
- ];
173
- for (const candidate of candidates) {
174
- if (existsSync(candidate)) {
175
- return candidate;
176
- }
177
- }
178
- return "";
179
- }
180
- const PLAYWRIGHT_MCP_PROXY_LAUNCHER_PATH = path.join(AGENT_PROJECT_DIR, "runtime/bin/playwright-mcp-proxy-launcher.sh");
181
- function resolvePlaywrightMcpDaemonStatePaths() {
182
- const daemonDir = path.join(resolveAgentStateDir(), "playwright-mcp-daemon");
183
- return {
184
- daemonDir,
185
- socketPath: path.join(daemonDir, "playwright-mcp.sock"),
186
- pidPath: path.join(daemonDir, "daemon.pid"),
187
- metaPath: path.join(daemonDir, "daemon-meta.json"),
188
- };
189
- }
190
- function parseEnvAssignmentArgs(values) {
191
- const envPatch = {};
192
- for (const value of values) {
193
- const separatorIndex = value.indexOf("=");
194
- if (separatorIndex <= 0) {
195
- continue;
196
- }
197
- const key = value.slice(0, separatorIndex).trim();
198
- const envValue = value.slice(separatorIndex + 1);
199
- if (!key) {
200
- continue;
201
- }
202
- envPatch[key] = envValue;
203
- }
204
- return envPatch;
205
- }
206
- function escapeShellArg(value) {
207
- return `'${value.replace(/'/g, `'\"'\"'`)}'`;
208
- }
209
- async function readPidFile(pidPath) {
210
- const raw = await readFile(pidPath, "utf8").catch(() => "");
211
- const parsed = Number.parseInt(raw.trim(), 10);
212
- return Number.isInteger(parsed) && parsed > 1 ? parsed : null;
213
- }
214
- function isProcessAlive(pid) {
215
- try {
216
- process.kill(pid, 0);
217
- return true;
218
- }
219
- catch {
220
- return false;
221
- }
222
- }
223
- async function waitForPlaywrightMcpSocketReady(socketPath, timeoutMs) {
224
- const startedAt = Date.now();
225
- while (Date.now() - startedAt <= timeoutMs) {
226
- const isReady = await new Promise((resolve) => {
227
- const socket = net.createConnection({ path: socketPath });
228
- let settled = false;
229
- const finish = (value) => {
230
- if (settled) {
231
- return;
232
- }
233
- settled = true;
234
- resolve(value);
235
- };
236
- socket.once("connect", () => {
237
- socket.end();
238
- finish(true);
239
- });
240
- socket.once("error", () => {
241
- finish(false);
242
- });
243
- setTimeout(() => {
244
- socket.destroy();
245
- finish(false);
246
- }, 250).unref?.();
247
- });
248
- if (isReady) {
249
- return true;
250
- }
251
- await sleep(120);
252
- }
253
- return false;
254
- }
255
- async function stopPlaywrightMcpDaemon(paths) {
256
- const pid = await readPidFile(paths.pidPath);
257
- if (pid && isProcessAlive(pid)) {
258
- try {
259
- process.kill(pid, "SIGTERM");
260
- }
261
- catch {
262
- // ignore
263
- }
264
- const waitStartedAt = Date.now();
265
- while (Date.now() - waitStartedAt < 1800 && isProcessAlive(pid)) {
266
- await sleep(120);
267
- }
268
- if (isProcessAlive(pid)) {
269
- try {
270
- process.kill(pid, "SIGKILL");
271
- }
272
- catch {
273
- // ignore
274
- }
275
- }
276
- }
277
- await Promise.all([
278
- rename(paths.socketPath, `${paths.socketPath}.stale.${Date.now()}`).catch(() => undefined),
279
- rename(paths.pidPath, `${paths.pidPath}.stale.${Date.now()}`).catch(() => undefined),
280
- rename(paths.metaPath, `${paths.metaPath}.stale.${Date.now()}`).catch(() => undefined),
281
- ]);
282
- }
283
- async function ensureManagedPlaywrightMcpDaemon(args) {
284
- const paths = resolvePlaywrightMcpDaemonStatePaths();
285
- await mkdir(paths.daemonDir, { recursive: true });
286
- const daemonCommand = args.command;
287
- const targetEnvPatch = parseEnvAssignmentArgs(args.browserEnvArgs);
288
- const daemonCommandArgs = args.daemonArgs;
289
- const signature = JSON.stringify({
290
- version: PLAYWRIGHT_MCP_DAEMON_SIGNATURE_VERSION,
291
- daemonCommand,
292
- daemonCommandArgs,
293
- targetEnvPatch,
294
- idleTtlSeconds: parseEnvInteger(process.env.DOER_PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS, PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS_DEFAULT),
295
- });
296
- const existingMetaRaw = await readFile(paths.metaPath, "utf8").catch(() => "");
297
- let existingMeta = null;
298
- if (existingMetaRaw) {
299
- try {
300
- existingMeta = JSON.parse(existingMetaRaw);
301
- }
302
- catch {
303
- existingMeta = null;
304
- }
305
- }
306
- const existingPid = await readPidFile(paths.pidPath);
307
- if (existingMeta?.signature === signature
308
- && existingPid
309
- && isProcessAlive(existingPid)
310
- && await waitForPlaywrightMcpSocketReady(paths.socketPath, 350)) {
311
- return paths.socketPath;
312
- }
313
- await stopPlaywrightMcpDaemon(paths);
314
- const daemonScriptPath = path.join(AGENT_MODULE_DIR, "playwright-mcp-daemon.ts");
315
- const idleTtlSeconds = String(parseEnvInteger(process.env.DOER_PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS, PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS_DEFAULT));
316
- const child = spawn(process.execPath, ["--import", "tsx", daemonScriptPath], {
317
- cwd: AGENT_PROJECT_DIR,
318
- detached: true,
319
- stdio: "ignore",
320
- env: {
321
- ...process.env,
322
- DOER_PLAYWRIGHT_MCP_DAEMON_SOCKET: paths.socketPath,
323
- DOER_PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS: idleTtlSeconds,
324
- DOER_PLAYWRIGHT_MCP_TARGET_COMMAND: daemonCommand,
325
- DOER_PLAYWRIGHT_MCP_TARGET_ARGS_JSON: JSON.stringify(daemonCommandArgs),
326
- DOER_PLAYWRIGHT_MCP_TARGET_ENV_JSON: JSON.stringify(targetEnvPatch),
327
- },
328
- });
329
- child.unref();
330
- if (!child.pid) {
331
- throw new Error("failed to start playwright mcp daemon: missing pid");
332
- }
333
- await writeFile(paths.pidPath, `${child.pid}\n`, "utf8");
334
- await writeFile(paths.metaPath, `${JSON.stringify({ signature, pid: child.pid, socketPath: paths.socketPath, updatedAt: new Date().toISOString() }, null, 2)}\n`, "utf8");
335
- const ready = await waitForPlaywrightMcpSocketReady(paths.socketPath, 6000);
336
- if (!ready) {
337
- throw new Error(`playwright mcp daemon socket not ready: ${paths.socketPath}`);
338
- }
339
- return paths.socketPath;
340
- }
341
- async function ensureCodexPlaywrightMcpLauncher() {
342
- const browserEnvArgs = [
343
- `PLAYWRIGHT_SKIP_BROWSER_GC=${PLAYWRIGHT_SKIP_BROWSER_GC}`,
344
- ];
345
- const daemonArgsFromEnv = parseEnvStringArray(process.env.DOER_PLAYWRIGHT_MCP_DAEMON_ARGS_JSON);
346
- const [daemonCommandFromArgs, ...daemonArgsRest] = daemonArgsFromEnv;
347
- const daemonCommand = daemonCommandFromArgs || "npx";
348
- let daemonArgs = daemonCommandFromArgs && daemonArgsFromEnv.length > 0
349
- ? daemonArgsRest
350
- : ["-y", "@playwright/mcp"];
351
- const hasBrowserOption = daemonArgs.some((arg) => arg === "--browser" || arg.startsWith("--browser="));
352
- if (arch() === "arm64" && !hasBrowserOption) {
353
- daemonArgs = [...daemonArgs, "--browser", "chromium"];
354
- }
355
- const hasNoSandboxOption = daemonArgs.some((arg) => arg === "--no-sandbox");
356
- if (typeof process.getuid === "function" && process.getuid() === 0 && !hasNoSandboxOption) {
357
- daemonArgs = [...daemonArgs, "--no-sandbox"];
358
- }
359
- const socketPath = await ensureManagedPlaywrightMcpDaemon({
360
- command: daemonCommand,
361
- daemonArgs,
362
- browserEnvArgs,
363
- });
364
- if (!existsSync(PLAYWRIGHT_MCP_PROXY_LAUNCHER_PATH)) {
365
- throw new Error(`playwright mcp proxy launcher script not found: ${PLAYWRIGHT_MCP_PROXY_LAUNCHER_PATH}`);
366
- }
367
- return PLAYWRIGHT_MCP_PROXY_LAUNCHER_PATH;
368
- }
369
- function resolveAgentStateDir() {
370
- return process.env.DOER_AGENT_STATE_DIR?.trim() || path.join(homedir(), ".doer-agent");
371
- }
372
151
  function resolveContainerReachableServerBaseUrl(serverBaseUrl) {
373
152
  return serverBaseUrl;
374
153
  }
@@ -957,10 +736,6 @@ async function runTask(args) {
957
736
  cwd: taskWorkspace,
958
737
  baseEnvPatch: baseTaskEnvPatch,
959
738
  });
960
- await ensureCodexPlaywrightMcpLauncher();
961
- const codexMcpEnvPatch = {
962
- PLAYWRIGHT_SKIP_BROWSER_GC: PLAYWRIGHT_SKIP_BROWSER_GC,
963
- };
964
739
  await recordAgentEvent({ jetstream: args.jetstream,
965
740
  serverBaseUrl: args.serverBaseUrl,
966
741
  taskId: args.taskId,
@@ -995,7 +770,6 @@ async function runTask(args) {
995
770
  ...process.env,
996
771
  ...baseTaskEnvPatch,
997
772
  ...taskGitEnv.envPatch,
998
- ...codexMcpEnvPatch,
999
773
  PATH: taskPath,
1000
774
  DOER_AGENT_TOKEN: args.agentToken,
1001
775
  },
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "doer-agent",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Reverse-polling agent runtime for doer",
5
5
  "type": "module",
6
6
  "main": "dist/agent.js",
7
7
  "bin": {
8
8
  "doer-agent": "dist/cli.js",
9
- "playwright-mcp-call": "dist/playwright-mcp-call-cli.js",
10
9
  "codex": "dist/codex-cli.js"
11
10
  },
12
11
  "files": [
@@ -18,17 +17,15 @@
18
17
  "access": "public"
19
18
  },
20
19
  "scripts": {
21
- "build": "tsc -p tsconfig.build.json && chmod +x dist/cli.js dist/playwright-mcp-call-cli.js dist/codex-cli.js",
20
+ "build": "tsc -p tsconfig.build.json && chmod +x dist/cli.js dist/codex-cli.js",
22
21
  "start": "node --import tsx src/agent.ts",
23
22
  "start:dist": "node dist/agent.js",
24
23
  "codex": "codex",
25
- "playwright-mcp-call": "node --import tsx src/playwright-mcp-call.ts",
26
24
  "prepublishOnly": "npm run build"
27
25
  },
28
26
  "dependencies": {
29
27
  "@modelcontextprotocol/sdk": "^1.27.1",
30
28
  "@openai/codex-sdk": "^0.115.0",
31
- "@playwright/mcp": "0.0.68",
32
29
  "nats": "^2.29.3"
33
30
  },
34
31
  "devDependencies": {
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./playwright-mcp-call.js";
@@ -1,103 +0,0 @@
1
- import { Buffer } from "node:buffer";
2
- import { existsSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import path from "node:path";
5
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
7
- function parseArgs(argv) {
8
- const parsed = { tool: "", argsBase64: "" };
9
- for (let i = 0; i < argv.length; i += 1) {
10
- const token = argv[i];
11
- if (token === "--tool") {
12
- parsed.tool = (argv[i + 1] || "").trim();
13
- i += 1;
14
- continue;
15
- }
16
- if (token === "--args-base64") {
17
- parsed.argsBase64 = (argv[i + 1] || "").trim();
18
- i += 1;
19
- }
20
- }
21
- return parsed;
22
- }
23
- function resolveProxyPath() {
24
- const candidates = [
25
- path.join(process.cwd(), "agent/runtime/bin/doer-mcp-proxy"),
26
- path.join(process.cwd(), "runtime/bin/doer-mcp-proxy"),
27
- ];
28
- for (const candidate of candidates) {
29
- if (existsSync(candidate)) {
30
- return candidate;
31
- }
32
- }
33
- return "";
34
- }
35
- function resolveSocketPath() {
36
- const explicit = (process.env.DOER_MCP_SOCKET || "").trim();
37
- if (explicit) {
38
- return explicit;
39
- }
40
- const stateDir = (process.env.DOER_AGENT_STATE_DIR || "").trim() || path.join(homedir(), ".doer-agent");
41
- return path.join(stateDir, "playwright-mcp-daemon", "playwright-mcp.sock");
42
- }
43
- function decodeToolArgs(argsBase64) {
44
- if (!argsBase64) {
45
- return {};
46
- }
47
- const raw = Buffer.from(argsBase64, "base64").toString("utf8");
48
- const parsed = JSON.parse(raw);
49
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
50
- throw new Error("decoded tool arguments must be a JSON object");
51
- }
52
- return parsed;
53
- }
54
- async function main() {
55
- const { tool, argsBase64 } = parseArgs(process.argv.slice(2));
56
- if (!tool) {
57
- throw new Error("--tool is required");
58
- }
59
- const proxyPath = resolveProxyPath();
60
- if (!proxyPath) {
61
- throw new Error("doer-mcp-proxy binary not found");
62
- }
63
- const socketPath = resolveSocketPath();
64
- const toolArgs = decodeToolArgs(argsBase64);
65
- const transport = new StdioClientTransport({
66
- command: proxyPath,
67
- args: [],
68
- env: {
69
- ...process.env,
70
- DOER_MCP_SOCKET: socketPath,
71
- },
72
- stderr: "pipe",
73
- });
74
- const client = new Client({
75
- name: "doer-agent-playwright-mcp-runner",
76
- version: "0.1.0",
77
- }, {
78
- capabilities: {},
79
- });
80
- try {
81
- await client.connect(transport);
82
- const result = await client.callTool({
83
- name: tool,
84
- arguments: toolArgs,
85
- });
86
- process.stdout.write(`${JSON.stringify({
87
- ok: true,
88
- tool,
89
- content: result.content ?? null,
90
- isError: result.isError === true,
91
- structuredContent: result.structuredContent ?? null,
92
- result,
93
- })}\n`);
94
- }
95
- finally {
96
- await client.close().catch(() => undefined);
97
- }
98
- }
99
- main().catch((error) => {
100
- const message = error instanceof Error ? error.message : String(error);
101
- process.stderr.write(`${JSON.stringify({ ok: false, error: message })}\n`);
102
- process.exit(1);
103
- });
@@ -1,175 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { mkdir, rm } from "node:fs/promises";
4
- import net from "node:net";
5
- import path from "node:path";
6
- function parseInteger(value, fallback) {
7
- const normalized = value?.trim();
8
- if (!normalized) {
9
- return fallback;
10
- }
11
- const parsed = Number.parseInt(normalized, 10);
12
- return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
13
- }
14
- const socketPath = process.env.DOER_PLAYWRIGHT_MCP_DAEMON_SOCKET?.trim() || "";
15
- const targetCommand = process.env.DOER_PLAYWRIGHT_MCP_TARGET_COMMAND?.trim() || "";
16
- const idleTtlSeconds = parseInteger(process.env.DOER_PLAYWRIGHT_MCP_DAEMON_IDLE_TTL_SECONDS, 10800);
17
- let targetArgs = [];
18
- try {
19
- const parsed = JSON.parse(process.env.DOER_PLAYWRIGHT_MCP_TARGET_ARGS_JSON || "[]");
20
- if (Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
21
- targetArgs = parsed;
22
- }
23
- }
24
- catch {
25
- targetArgs = [];
26
- }
27
- let targetEnvPatch = {};
28
- try {
29
- const parsed = JSON.parse(process.env.DOER_PLAYWRIGHT_MCP_TARGET_ENV_JSON || "{}");
30
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
31
- targetEnvPatch = Object.fromEntries(Object.entries(parsed).flatMap(([key, value]) => (typeof value === "string" ? [[key, value]] : [])));
32
- }
33
- }
34
- catch {
35
- targetEnvPatch = {};
36
- }
37
- if (!socketPath) {
38
- process.stderr.write("playwright-mcp-daemon error: DOER_PLAYWRIGHT_MCP_DAEMON_SOCKET is required\n");
39
- process.exit(1);
40
- }
41
- if (!targetCommand) {
42
- process.stderr.write("playwright-mcp-daemon error: DOER_PLAYWRIGHT_MCP_TARGET_COMMAND is required\n");
43
- process.exit(1);
44
- }
45
- let child = null;
46
- let activeClient = null;
47
- let shuttingDown = false;
48
- let lastActivityAt = Date.now();
49
- const idleTtlMs = idleTtlSeconds * 1000;
50
- function markActivity() {
51
- lastActivityAt = Date.now();
52
- }
53
- function spawnTargetIfNeeded() {
54
- if (child) {
55
- return;
56
- }
57
- child = spawn(targetCommand, targetArgs, {
58
- stdio: ["pipe", "pipe", "pipe"],
59
- env: { ...process.env, ...targetEnvPatch },
60
- });
61
- child.stdout.on("data", (chunk) => {
62
- markActivity();
63
- if (activeClient && !activeClient.destroyed) {
64
- activeClient.write(chunk);
65
- }
66
- });
67
- child.stderr.on("data", (chunk) => {
68
- process.stderr.write(chunk);
69
- });
70
- child.on("exit", () => {
71
- child = null;
72
- if (activeClient && !activeClient.destroyed) {
73
- activeClient.end();
74
- activeClient = null;
75
- }
76
- markActivity();
77
- });
78
- }
79
- async function shutdown(server) {
80
- if (shuttingDown) {
81
- return;
82
- }
83
- shuttingDown = true;
84
- if (activeClient && !activeClient.destroyed) {
85
- activeClient.destroy();
86
- activeClient = null;
87
- }
88
- if (child) {
89
- child.kill("SIGTERM");
90
- await new Promise((resolve) => {
91
- const timeout = setTimeout(() => {
92
- if (child) {
93
- child.kill("SIGKILL");
94
- }
95
- resolve();
96
- }, 2000);
97
- timeout.unref?.();
98
- child?.once("exit", () => {
99
- clearTimeout(timeout);
100
- resolve();
101
- });
102
- });
103
- child = null;
104
- }
105
- await new Promise((resolve) => server.close(() => resolve()));
106
- if (existsSync(socketPath)) {
107
- await rm(socketPath, { force: true });
108
- }
109
- process.exit(0);
110
- }
111
- async function main() {
112
- await mkdir(path.dirname(socketPath), { recursive: true });
113
- if (existsSync(socketPath)) {
114
- await rm(socketPath, { force: true });
115
- }
116
- const server = net.createServer((socket) => {
117
- if (activeClient && !activeClient.destroyed) {
118
- socket.end();
119
- return;
120
- }
121
- activeClient = socket;
122
- markActivity();
123
- spawnTargetIfNeeded();
124
- socket.on("data", (chunk) => {
125
- markActivity();
126
- spawnTargetIfNeeded();
127
- if (child && !child.killed) {
128
- child.stdin.write(chunk);
129
- }
130
- });
131
- socket.on("close", () => {
132
- if (activeClient === socket) {
133
- activeClient = null;
134
- }
135
- markActivity();
136
- });
137
- socket.on("error", () => {
138
- if (activeClient === socket) {
139
- activeClient = null;
140
- }
141
- markActivity();
142
- });
143
- });
144
- server.on("error", (error) => {
145
- process.stderr.write(`playwright-mcp-daemon error: ${error instanceof Error ? error.message : String(error)}\n`);
146
- process.exit(1);
147
- });
148
- await new Promise((resolve, reject) => {
149
- server.once("error", reject);
150
- server.listen(socketPath, () => {
151
- server.off("error", reject);
152
- resolve();
153
- });
154
- });
155
- const interval = setInterval(() => {
156
- if (shuttingDown) {
157
- return;
158
- }
159
- if (activeClient && !activeClient.destroyed) {
160
- return;
161
- }
162
- if (Date.now() - lastActivityAt < idleTtlMs) {
163
- return;
164
- }
165
- void shutdown(server);
166
- }, 30000);
167
- interval.unref?.();
168
- process.on("SIGTERM", () => {
169
- void shutdown(server);
170
- });
171
- process.on("SIGINT", () => {
172
- void shutdown(server);
173
- });
174
- }
175
- void main();
@@ -1,15 +0,0 @@
1
- #!/bin/sh
2
- set -eu
3
- SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
4
- if [ -z "${DOER_MCP_SOCKET:-}" ]; then
5
- if [ -n "${DOER_AGENT_STATE_DIR:-}" ]; then
6
- DOER_MCP_SOCKET="$DOER_AGENT_STATE_DIR/playwright-mcp-daemon/playwright-mcp.sock"
7
- elif [ -n "${HOME:-}" ]; then
8
- DOER_MCP_SOCKET="$HOME/.doer-agent/playwright-mcp-daemon/playwright-mcp.sock"
9
- else
10
- echo "playwright-mcp-proxy-launcher.sh: DOER_MCP_SOCKET is not set and neither DOER_AGENT_STATE_DIR nor HOME is available" >&2
11
- exit 1
12
- fi
13
- fi
14
- export DOER_MCP_SOCKET
15
- exec "$SCRIPT_DIR/doer-mcp-proxy" "$@"