-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathutils.ts
More file actions
136 lines (118 loc) · 3.75 KB
/
utils.ts
File metadata and controls
136 lines (118 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import process from 'node:process';
import {logger} from '../logger.js';
import type {YargsOptions} from '../third_party/index.js';
export const DAEMON_SCRIPT_PATH = path.join(import.meta.dirname, 'daemon.js');
export const INDEX_SCRIPT_PATH = path.join(
import.meta.dirname,
'..',
'bin',
'chrome-devtools-mcp.js',
);
const APP_NAME = 'chrome-devtools-mcp';
export const DAEMON_CLIENT_NAME = 'chrome-devtools-cli-daemon';
// Using these paths due to strict limits on the POSIX socket path length.
export function getSocketPath(sessionId: string): string {
const uid = os.userInfo().uid;
const suffix = sessionId ? `-${sessionId}` : '';
const appName = APP_NAME + suffix;
if (IS_WINDOWS) {
// Windows uses Named Pipes, not file paths.
// This format is required for server.listen()
return path.join('\\\\.\\pipe', appName, 'server.sock');
}
// 1. Try XDG_RUNTIME_DIR (Linux standard, sometimes macOS)
if (process.env.XDG_RUNTIME_DIR) {
return path.join(process.env.XDG_RUNTIME_DIR, appName, 'server.sock');
}
// 2. macOS/Unix Fallback: Use /tmp/
// We use /tmp/ because it is much shorter than ~/Library/Application Support/
// and keeps us well under the 104-character limit.
return path.join('/tmp', `${appName}-${uid}.sock`);
}
export function getRuntimeHome(sessionId: string): string {
const platform = os.platform();
const uid = os.userInfo().uid;
const suffix = sessionId ? `-${sessionId}` : '';
const appName = APP_NAME + suffix;
// 1. Check for the modern Unix standard
if (process.env.XDG_RUNTIME_DIR) {
return path.join(process.env.XDG_RUNTIME_DIR, appName);
}
// 2. Fallback for macOS and older Linux
if (platform === 'darwin' || platform === 'linux') {
// /tmp is cleared on boot, making it perfect for PIDs
return path.join('/tmp', `${appName}-${uid}`);
}
// 3. Windows Fallback
return path.join(os.tmpdir(), appName);
}
export const IS_WINDOWS = os.platform() === 'win32';
export function getPidFilePath(sessionId: string) {
const runtimeDir = getRuntimeHome(sessionId);
return path.join(runtimeDir, 'daemon.pid');
}
export function getDaemonPid(sessionId: string) {
try {
const pidFile = getPidFilePath(sessionId);
logger(`Daemon pid file ${pidFile} sessionId=${sessionId}`);
if (!fs.existsSync(pidFile)) {
return null;
}
const pidContent = fs.readFileSync(pidFile, 'utf-8');
const pid = parseInt(pidContent.trim(), 10);
logger(`Daemon pid: ${pid}`);
if (isNaN(pid)) {
return null;
}
return pid;
} catch {
return null;
}
}
export function isDaemonRunning(sessionId: string): boolean {
const pid = getDaemonPid(sessionId);
if (pid) {
try {
process.kill(pid, 0); // Throws if process doesn't exist
return true;
} catch {
// Process is dead, stale PID file. Proceed with startup.
}
}
return false;
}
export function serializeArgs(
options: Record<string, YargsOptions>,
argv: Record<string, unknown>,
): string[] {
const args: string[] = [];
for (const key of Object.keys(options)) {
if (argv[key] === undefined || argv[key] === null) {
continue;
}
const value = argv[key];
const kebabKey = key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
if (typeof value === 'boolean') {
if (value) {
args.push(`--${kebabKey}`);
} else {
args.push(`--no-${kebabKey}`);
}
} else if (Array.isArray(value)) {
for (const item of value) {
args.push(`--${kebabKey}`, String(item));
}
} else {
args.push(`--${kebabKey}`, String(value));
}
}
return args;
}