codelocal 1.5.71 → 1.5.73
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 +1 -1
- package/bin/codelocal.js +381 -41
- package/bin/helpers/computer-darwin-amd64 +0 -0
- package/bin/helpers/computer-darwin-arm64 +0 -0
- package/bin/helpers/computer-linux-amd64 +0 -0
- package/bin/helpers/computer-linux-arm64 +0 -0
- package/bin/helpers/computer-native-darwin-amd64 +0 -0
- package/bin/helpers/computer-native-darwin-arm64 +0 -0
- package/bin/helpers/computer-windows-amd64.exe +0 -0
- package/bin/helpers/computer-windows-arm64.exe +0 -0
- package/bin/native/codelocal-darwin-arm64 +0 -0
- package/bin/native/codelocal-darwin-x64 +0 -0
- package/bin/native/codelocal-linux-arm64 +0 -0
- package/bin/native/codelocal-linux-x64 +0 -0
- package/bin/native/codelocal-win32-arm64.exe +0 -0
- package/bin/native/codelocal-win32-x64.exe +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ codelocal
|
|
|
27
27
|
|
|
28
28
|
On first start, CodeLocal asks which local capabilities connected MCP clients may use. Browser Automation lets a compatible AI client inspect and interact with websites in an isolated session; if enabled, CodeLocal downloads one managed Chromium browser and shows the install progress before starting. Coding works without this optional download. Computer Use remains a separate opt-in capability and includes both the native desktop helper and a managed Mobile MCP backend inside the CodeLocal package. Mobile automation becomes active only when a simulator, emulator or authorized real device is available; Android targets require platform tools/adb and iOS targets require the relevant Xcode/device tooling. Penpot MCP is also packaged as a managed CodeLocal backend: the user does not install a separate MCP server, and CodeLocal starts the local Penpot bridge lazily when its tools are first used.
|
|
29
29
|
|
|
30
|
-
The Go runtime then pairs this machine if needed, syncs authorized workspaces, and waits for authenticated MCP clients. One machine runs one runtime; multiple workspaces activate lazily inside it.
|
|
30
|
+
The npm launcher checks the selected release channel before normal startup. When a newer CodeLocal package is available it updates itself before launching the native runtime, verifies the installed version, and restarts automatically. Update failures never block CodeLocal: the current runtime continues and shows a manual update command. Set `CODELOCAL_AUTO_UPDATE=0` to disable automatic installation while keeping the normal update notice, or `CODELOCAL_UPDATE_CHECK=0` to disable update checks entirely.\n\nThe Go runtime then pairs this machine if needed, syncs authorized workspaces, and waits for authenticated MCP clients. One machine runs one runtime; multiple workspaces activate lazily inside it.
|
|
31
31
|
|
|
32
32
|
Use `codelocal status` to inspect it and `codelocal stop` to stop it.
|
|
33
33
|
|
package/bin/codelocal.js
CHANGED
|
@@ -1,45 +1,385 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const os = require('node:os');
|
|
3
4
|
const path = require('node:path');
|
|
4
|
-
const
|
|
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
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
5
|
+
const { spawnSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
|
|
8
|
+
const UPDATE_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
9
|
+
const UPDATE_TIMEOUT_MS = 1800;
|
|
10
|
+
const FALSE_VALUES = new Set(['0', 'false', 'off', 'no']);
|
|
11
|
+
const CHANNEL_RE = /^[A-Za-z][A-Za-z0-9._-]{0,31}$/;
|
|
12
|
+
const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
13
|
+
|
|
14
|
+
function normalizeVersion(value) {
|
|
15
|
+
const text = String(value || '').trim();
|
|
16
|
+
if (/^[vV]\d/.test(text)) return text.slice(1);
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseVersion(value) {
|
|
21
|
+
const match = SEMVER_RE.exec(normalizeVersion(value));
|
|
22
|
+
if (!match) return null;
|
|
23
|
+
return {
|
|
24
|
+
major: Number(match[1]),
|
|
25
|
+
minor: Number(match[2]),
|
|
26
|
+
patch: Number(match[3]),
|
|
27
|
+
prerelease: match[4] ? match[4].split('.') : [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function comparePrerelease(left, right) {
|
|
32
|
+
if (left.length === 0 && right.length === 0) return 0;
|
|
33
|
+
if (left.length === 0) return 1;
|
|
34
|
+
if (right.length === 0) return -1;
|
|
35
|
+
const limit = Math.max(left.length, right.length);
|
|
36
|
+
for (let index = 0; index < limit; index += 1) {
|
|
37
|
+
if (index >= left.length) return -1;
|
|
38
|
+
if (index >= right.length) return 1;
|
|
39
|
+
if (left[index] === right[index]) continue;
|
|
40
|
+
const leftNumeric = /^\d+$/.test(left[index]);
|
|
41
|
+
const rightNumeric = /^\d+$/.test(right[index]);
|
|
42
|
+
if (leftNumeric && rightNumeric) {
|
|
43
|
+
const a = BigInt(left[index]);
|
|
44
|
+
const b = BigInt(right[index]);
|
|
45
|
+
return a < b ? -1 : 1;
|
|
46
|
+
}
|
|
47
|
+
if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
|
|
48
|
+
return left[index] < right[index] ? -1 : 1;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function compareVersions(left, right) {
|
|
54
|
+
const a = parseVersion(left);
|
|
55
|
+
const b = parseVersion(right);
|
|
56
|
+
if (!a || !b) return null;
|
|
57
|
+
for (const field of ['major', 'minor', 'patch']) {
|
|
58
|
+
if (a[field] !== b[field]) return a[field] < b[field] ? -1 : 1;
|
|
59
|
+
}
|
|
60
|
+
return comparePrerelease(a.prerelease, b.prerelease);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function falseLike(value) {
|
|
64
|
+
return FALSE_VALUES.has(String(value || '').trim().toLowerCase());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function releaseChannel(installedVersion, env = process.env) {
|
|
68
|
+
const configured = String(env.CODELOCAL_RELEASE_CHANNEL || '').trim();
|
|
69
|
+
if (CHANNEL_RE.test(configured)) return configured;
|
|
70
|
+
const parsed = parseVersion(installedVersion);
|
|
71
|
+
return parsed && parsed.prerelease.length > 0 ? 'beta' : 'latest';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function updateCheckEnabled(env = process.env) {
|
|
75
|
+
return !falseLike(env.CODELOCAL_UPDATE_CHECK);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function autoUpdateEnabled(env = process.env) {
|
|
79
|
+
return !falseLike(env.CODELOCAL_AUTO_UPDATE);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function shouldAutoUpdate(args) {
|
|
83
|
+
return Array.isArray(args) && args.length === 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function stateDir(env = process.env) {
|
|
87
|
+
const configured = String(env.CODELOCAL_STATE_DIR || '').trim();
|
|
88
|
+
return configured || path.join(os.homedir(), '.codelocal');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function cachePath(env = process.env) {
|
|
92
|
+
return path.join(stateDir(env), 'update-check.json');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readCache(env = process.env) {
|
|
96
|
+
try {
|
|
97
|
+
const parsed = JSON.parse(fs.readFileSync(cachePath(env), 'utf8'));
|
|
98
|
+
if (!parseVersion(parsed.latestVersion) || !Number.isFinite(parsed.checkedAt)) return null;
|
|
99
|
+
return parsed;
|
|
100
|
+
} catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function writeCache(channel, latestVersion, env = process.env, now = Date.now()) {
|
|
106
|
+
try {
|
|
107
|
+
const dir = stateDir(env);
|
|
108
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
109
|
+
if (process.platform !== 'win32') fs.chmodSync(dir, 0o700);
|
|
110
|
+
const destination = cachePath(env);
|
|
111
|
+
const temporary = `${destination}.${process.pid}.tmp`;
|
|
112
|
+
fs.writeFileSync(temporary, `${JSON.stringify({ checkedAt: now, channel, latestVersion }, null, 2)}\n`, { mode: 0o600 });
|
|
113
|
+
fs.renameSync(temporary, destination);
|
|
114
|
+
if (process.platform !== 'win32') fs.chmodSync(destination, 0o600);
|
|
115
|
+
} catch {
|
|
116
|
+
// Update caching is an optimization and must never block CodeLocal startup.
|
|
117
|
+
}
|
|
41
118
|
}
|
|
42
|
-
|
|
43
|
-
|
|
119
|
+
|
|
120
|
+
function registryURL(env = process.env) {
|
|
121
|
+
const configured = String(env.CODELOCAL_UPDATE_REGISTRY || env.npm_config_registry || DEFAULT_REGISTRY).trim();
|
|
122
|
+
try {
|
|
123
|
+
const url = new URL(configured);
|
|
124
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') return DEFAULT_REGISTRY;
|
|
125
|
+
return url.toString().replace(/\/$/, '');
|
|
126
|
+
} catch {
|
|
127
|
+
return DEFAULT_REGISTRY;
|
|
128
|
+
}
|
|
44
129
|
}
|
|
45
|
-
|
|
130
|
+
|
|
131
|
+
async function fetchLatest(channel, env = process.env, fetchImpl = globalThis.fetch) {
|
|
132
|
+
if (typeof fetchImpl !== 'function') throw new Error('fetch is unavailable');
|
|
133
|
+
const base = new URL(registryURL(env));
|
|
134
|
+
base.pathname = `${base.pathname.replace(/\/$/, '')}/-/package/codelocal/dist-tags`;
|
|
135
|
+
base.search = '';
|
|
136
|
+
base.hash = '';
|
|
137
|
+
const controller = new AbortController();
|
|
138
|
+
const timer = setTimeout(() => controller.abort(), UPDATE_TIMEOUT_MS);
|
|
139
|
+
try {
|
|
140
|
+
const response = await fetchImpl(base, {
|
|
141
|
+
headers: { Accept: 'application/json', 'User-Agent': 'codelocal-auto-update/1' },
|
|
142
|
+
signal: controller.signal,
|
|
143
|
+
});
|
|
144
|
+
if (!response.ok) throw new Error(`registry returned ${response.status}`);
|
|
145
|
+
const tags = await response.json();
|
|
146
|
+
const latest = normalizeVersion(tags[channel]);
|
|
147
|
+
if (!parseVersion(latest)) throw new Error('registry returned an invalid version');
|
|
148
|
+
return latest;
|
|
149
|
+
} finally {
|
|
150
|
+
clearTimeout(timer);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function resolveLatest(installedVersion, channel, env = process.env, options = {}) {
|
|
155
|
+
const now = options.now ? options.now() : Date.now();
|
|
156
|
+
const cached = (options.readCache || readCache)(env);
|
|
157
|
+
if (cached && cached.channel === channel && now >= cached.checkedAt && now - cached.checkedAt < UPDATE_CACHE_TTL_MS) {
|
|
158
|
+
return cached.latestVersion;
|
|
159
|
+
}
|
|
160
|
+
const latest = await fetchLatest(channel, env, options.fetchImpl || globalThis.fetch);
|
|
161
|
+
(options.writeCache || writeCache)(channel, latest, env, now);
|
|
162
|
+
return latest;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function readInstalledVersion(packageRoot) {
|
|
166
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
167
|
+
const version = normalizeVersion(manifest.version);
|
|
168
|
+
if (!parseVersion(version)) throw new Error('installed package has an invalid version');
|
|
169
|
+
return version;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function npmCommand() {
|
|
173
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function npmInvocation(version, env = process.env) {
|
|
177
|
+
const args = ['install', '-g', `codelocal@${version}`, '--no-audit', '--no-fund', '--registry', registryURL(env)];
|
|
178
|
+
return { command: npmCommand(), args };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function comparablePath(value) {
|
|
182
|
+
try {
|
|
183
|
+
return fs.realpathSync(value);
|
|
184
|
+
} catch {
|
|
185
|
+
return path.resolve(value);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function isGlobalInstall(packageRoot, env = process.env, run = spawnSync) {
|
|
190
|
+
const result = run(npmCommand(), ['root', '-g', '--silent'], { encoding: 'utf8', env });
|
|
191
|
+
if (result.error || result.status !== 0 || !String(result.stdout || '').trim()) return false;
|
|
192
|
+
const expected = path.join(String(result.stdout).trim(), 'codelocal');
|
|
193
|
+
return comparablePath(expected) === comparablePath(packageRoot);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function runtimePID(env = process.env) {
|
|
197
|
+
try {
|
|
198
|
+
const payload = JSON.parse(fs.readFileSync(path.join(stateDir(env), 'runtime.lock'), 'utf8'));
|
|
199
|
+
return Number.isInteger(payload.pid) && payload.pid > 0 ? payload.pid : 0;
|
|
200
|
+
} catch {
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function processAlive(pid) {
|
|
206
|
+
if (!pid) return false;
|
|
207
|
+
try {
|
|
208
|
+
process.kill(pid, 0);
|
|
209
|
+
return true;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
return error && error.code === 'EPERM';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function delay(ms) {
|
|
216
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function stopRuntimeBeforeUpdate(packageRoot, env = process.env, run = spawnSync, options = {}) {
|
|
220
|
+
const pid = (options.runtimePID || runtimePID)(env);
|
|
221
|
+
if (!pid) return true;
|
|
222
|
+
const rc = runNative(packageRoot, ['stop'], env, { spawnSync: run, stdio: 'ignore' });
|
|
223
|
+
if (rc !== 0) return false;
|
|
224
|
+
const alive = options.processAlive || processAlive;
|
|
225
|
+
const sleep = options.delay || delay;
|
|
226
|
+
for (let attempt = 0; attempt < 50; attempt += 1) {
|
|
227
|
+
if (!alive(pid)) return true;
|
|
228
|
+
await sleep(100);
|
|
229
|
+
}
|
|
230
|
+
return !alive(pid);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function maybeAutoUpdate(packageRoot, args, env = process.env, options = {}) {
|
|
234
|
+
if (!updateCheckEnabled(env) || !autoUpdateEnabled(env) || env.CODELOCAL_AUTO_UPDATE_RESTART === '1' || !shouldAutoUpdate(args)) {
|
|
235
|
+
return { restarted: false };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let installedVersion;
|
|
239
|
+
let channel;
|
|
240
|
+
let latestVersion;
|
|
241
|
+
try {
|
|
242
|
+
installedVersion = (options.readInstalledVersion || readInstalledVersion)(packageRoot);
|
|
243
|
+
channel = releaseChannel(installedVersion, env);
|
|
244
|
+
latestVersion = await resolveLatest(installedVersion, channel, env, options);
|
|
245
|
+
} catch {
|
|
246
|
+
return { restarted: false };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const comparison = compareVersions(installedVersion, latestVersion);
|
|
250
|
+
if (comparison === null || comparison >= 0) return { restarted: false };
|
|
251
|
+
|
|
252
|
+
const run = options.spawnSync || spawnSync;
|
|
253
|
+
const globalInstall = options.isGlobalInstall
|
|
254
|
+
? options.isGlobalInstall(packageRoot, env, run)
|
|
255
|
+
: isGlobalInstall(packageRoot, env, run);
|
|
256
|
+
if (!globalInstall) return { restarted: false };
|
|
257
|
+
|
|
258
|
+
const log = options.log || ((message) => console.error(message));
|
|
259
|
+
const runtimeStopped = options.stopRuntimeBeforeUpdate
|
|
260
|
+
? await options.stopRuntimeBeforeUpdate(packageRoot, env, run)
|
|
261
|
+
: await stopRuntimeBeforeUpdate(packageRoot, env, run, options);
|
|
262
|
+
if (!runtimeStopped) {
|
|
263
|
+
log('CodeLocal found a newer package, but the current runtime did not stop cleanly. Update deferred to keep the active runtime safe.');
|
|
264
|
+
return { restarted: false, failed: true };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
log(`CodeLocal ${installedVersion} → ${latestVersion}. Updating automatically...`);
|
|
268
|
+
const invocation = npmInvocation(latestVersion, env);
|
|
269
|
+
const install = run(invocation.command, invocation.args, { stdio: 'inherit', env });
|
|
270
|
+
if (install.error || install.status !== 0) {
|
|
271
|
+
const reason = install.error ? install.error.message : `npm exited with status ${install.status}`;
|
|
272
|
+
log(`CodeLocal auto-update failed (${reason}). Continuing with ${installedVersion}.`);
|
|
273
|
+
log(`Manual update: npm install -g codelocal@${channel}`);
|
|
274
|
+
return { restarted: false, failed: true };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let updatedVersion;
|
|
278
|
+
try {
|
|
279
|
+
updatedVersion = (options.readInstalledVersion || readInstalledVersion)(packageRoot);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
log(`CodeLocal auto-update could not verify the installed version (${error.message}). Continuing with ${installedVersion}.`);
|
|
282
|
+
return { restarted: false, failed: true };
|
|
283
|
+
}
|
|
284
|
+
if (compareVersions(updatedVersion, latestVersion) !== 0) {
|
|
285
|
+
log(`CodeLocal auto-update expected ${latestVersion} but found ${updatedVersion}. Continuing without restart.`);
|
|
286
|
+
return { restarted: false, failed: true };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
log(`CodeLocal updated to ${updatedVersion}. Restarting...`);
|
|
290
|
+
const script = options.scriptPath || __filename;
|
|
291
|
+
const restart = run(process.execPath, [script, ...args], {
|
|
292
|
+
stdio: 'inherit',
|
|
293
|
+
env: { ...env, CODELOCAL_AUTO_UPDATE_RESTART: '1' },
|
|
294
|
+
});
|
|
295
|
+
if (restart.error) {
|
|
296
|
+
log(`CodeLocal updated, but automatic restart failed: ${restart.error.message}`);
|
|
297
|
+
return { restarted: false, failed: true };
|
|
298
|
+
}
|
|
299
|
+
return { restarted: true, status: restart.status, signal: restart.signal };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function platformFiles() {
|
|
303
|
+
return {
|
|
304
|
+
files: {
|
|
305
|
+
'darwin-arm64': 'codelocal-darwin-arm64',
|
|
306
|
+
'darwin-x64': 'codelocal-darwin-x64',
|
|
307
|
+
'linux-arm64': 'codelocal-linux-arm64',
|
|
308
|
+
'linux-x64': 'codelocal-linux-x64',
|
|
309
|
+
'win32-x64': 'codelocal-win32-x64.exe',
|
|
310
|
+
'win32-arm64': 'codelocal-win32-arm64.exe',
|
|
311
|
+
},
|
|
312
|
+
helperFiles: {
|
|
313
|
+
'darwin-arm64': 'computer-darwin-arm64',
|
|
314
|
+
'darwin-x64': 'computer-darwin-amd64',
|
|
315
|
+
'linux-arm64': 'computer-linux-arm64',
|
|
316
|
+
'linux-x64': 'computer-linux-amd64',
|
|
317
|
+
'win32-x64': 'computer-windows-amd64.exe',
|
|
318
|
+
'win32-arm64': 'computer-windows-arm64.exe',
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function runNative(packageRoot, args, env = process.env, options = {}) {
|
|
324
|
+
const key = `${process.platform}-${process.arch}`;
|
|
325
|
+
const { files, helperFiles } = platformFiles();
|
|
326
|
+
const file = files[key];
|
|
327
|
+
const helperFile = helperFiles[key];
|
|
328
|
+
if (!file || !helperFile) {
|
|
329
|
+
console.error(`CodeLocal does not have native binaries for ${key}.`);
|
|
330
|
+
return 1;
|
|
331
|
+
}
|
|
332
|
+
const playwrightCli = path.join(packageRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'playwright-cli.cmd' : 'playwright-cli');
|
|
333
|
+
const binary = path.join(__dirname, 'native', file);
|
|
334
|
+
const computerHelper = path.join(__dirname, 'helpers', helperFile);
|
|
335
|
+
const childEnv = {
|
|
336
|
+
...env,
|
|
337
|
+
CODELOCAL_PACKAGE_ROOT: packageRoot,
|
|
338
|
+
CODELOCAL_PLAYWRIGHT_CLI: env.CODELOCAL_PLAYWRIGHT_CLI || playwrightCli,
|
|
339
|
+
CODELOCAL_COMPUTER_HELPER: env.CODELOCAL_COMPUTER_HELPER || computerHelper,
|
|
340
|
+
};
|
|
341
|
+
const result = (options.spawnSync || spawnSync)(binary, args, { stdio: options.stdio || 'inherit', env: childEnv });
|
|
342
|
+
if (result.error) {
|
|
343
|
+
console.error(result.error.message);
|
|
344
|
+
return 1;
|
|
345
|
+
}
|
|
346
|
+
if (result.signal) {
|
|
347
|
+
process.kill(process.pid, result.signal);
|
|
348
|
+
return 1;
|
|
349
|
+
}
|
|
350
|
+
return result.status ?? 1;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function main() {
|
|
354
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
355
|
+
const args = process.argv.slice(2);
|
|
356
|
+
const update = await maybeAutoUpdate(packageRoot, args, process.env);
|
|
357
|
+
if (update.restarted) {
|
|
358
|
+
if (update.signal) process.kill(process.pid, update.signal);
|
|
359
|
+
process.exit(update.status ?? 1);
|
|
360
|
+
}
|
|
361
|
+
process.exit(runNative(packageRoot, args, process.env));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (require.main === module) {
|
|
365
|
+
main().catch((error) => {
|
|
366
|
+
console.error(error && error.message ? error.message : String(error));
|
|
367
|
+
process.exit(1);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
module.exports = {
|
|
372
|
+
autoUpdateEnabled,
|
|
373
|
+
compareVersions,
|
|
374
|
+
fetchLatest,
|
|
375
|
+
maybeAutoUpdate,
|
|
376
|
+
normalizeVersion,
|
|
377
|
+
npmInvocation,
|
|
378
|
+
readCache,
|
|
379
|
+
releaseChannel,
|
|
380
|
+
resolveLatest,
|
|
381
|
+
shouldAutoUpdate,
|
|
382
|
+
stopRuntimeBeforeUpdate,
|
|
383
|
+
updateCheckEnabled,
|
|
384
|
+
writeCache,
|
|
385
|
+
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED