-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathutils.ts
More file actions
129 lines (111 loc) · 3.36 KB
/
utils.ts
File metadata and controls
129 lines (111 loc) · 3.36 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
/**
* @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,
'..',
'index.js',
);
const APP_NAME = 'chrome-devtools-mcp';
// Using these paths due to strict limits on the POSIX socket path length.
export function getSocketPath(): string {
const uid = os.userInfo().uid;
if (IS_WINDOWS) {
// Windows uses Named Pipes, not file paths.
// This format is required for server.listen()
return path.join('\\\\.\\pipe', APP_NAME, '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, APP_NAME, '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', `${APP_NAME}-${uid}.sock`);
}
export function getRuntimeHome(): string {
const platform = os.platform();
const uid = os.userInfo().uid;
// 1. Check for the modern Unix standard
if (process.env.XDG_RUNTIME_DIR) {
return path.join(process.env.XDG_RUNTIME_DIR, APP_NAME);
}
// 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', `${APP_NAME}-${uid}`);
}
// 3. Windows Fallback
return path.join(os.tmpdir(), APP_NAME);
}
export const IS_WINDOWS = os.platform() === 'win32';
export function getPidFilePath() {
const runtimeDir = getRuntimeHome();
return path.join(runtimeDir, 'daemon.pid');
}
export function getDaemonPid() {
try {
const pidFile = getPidFilePath();
logger(`Daemon pid file ${pidFile}`);
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(pid = getDaemonPid()): pid is number {
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;
}