stim 1.13.0 → 1.15.0
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 +2 -0
- package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
- package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
- package/dist/android-cas-PnKfAdB2.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
- package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
- package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
- package/dist/cli-0cX5s4NM.mjs +45 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-C2IS36Qf.mjs +1333 -0
- package/dist/collector-run.mjs +8 -7
- package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
- package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CjzLoNs0.mjs +80 -0
- package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
- package/dist/device-capacity-DMuKC7nx.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +769 -0
- package/dist/device-ios-DMQBUPus.mjs +381 -0
- package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
- package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
- package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
- package/dist/hosted-macos-DwowNU7W.mjs +447 -0
- package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
- package/dist/in-use-CndPMilN.mjs +110 -0
- package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
- package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
- package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
- package/dist/machine-usage-D_YYMzfR.mjs +283 -0
- package/dist/machines-CYtOCqcj.mjs +259 -0
- package/dist/macos-BwtbUtTN.mjs +468 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
- package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-GEXp4iBT.mjs +37 -0
- package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
- package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/slot-launch-BY0BrOLh.mjs +65 -0
- package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-DncpJvWL.mjs +16 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CPO4wRg7.mjs +2 -0
- package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
- package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +44 -12
- package/dist/supervisor-run.mjs +276 -33
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
- package/dist/web-run.mjs +326 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-CL2V2Ons.mjs +371 -0
- package/dist/worktree-BT_uULFx.mjs +2 -0
- package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
- package/package.json +10 -5
- package/shim/bundle-response.cjs +55 -10
- package/shim/bundle-response.d.cts +1 -0
- package/shim/expo-metro-config.cjs +10 -2
- package/dist/build-progress-l7d-X-ZP.mjs +0 -247
- package/dist/in-use-wYEaKQM9.mjs +0 -249
- package/dist/ownership-PUP4Dwai.mjs +0 -1138
- package/dist/server-expo-BeYwP_Xy.mjs +0 -2
- package/dist/slot-launch-BIWEW-wI.mjs +0 -19
- package/dist/start-Rw2GD3nV.mjs +0 -2
- package/dist/stats-CaSwmsSZ.mjs +0 -62
- package/dist/stats-D8rUTPHd.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/worktree-3cBa-bQt.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stim",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Stim: fast, isolated React Native environments for coding agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -39,13 +39,18 @@
|
|
|
39
39
|
"types": "./dist/cache-manifest.d.mts",
|
|
40
40
|
"module-sync": "./dist/cache-manifest.mjs",
|
|
41
41
|
"default": "./dist/cache-manifest.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./pull-requests": {
|
|
44
|
+
"types": "./dist/pull-requests.d.mts",
|
|
45
|
+
"module-sync": "./dist/pull-requests.mjs",
|
|
46
|
+
"default": "./dist/pull-requests.mjs"
|
|
42
47
|
}
|
|
43
48
|
},
|
|
44
49
|
"dependencies": {
|
|
45
50
|
"@expo/fingerprint": "^0.20.10",
|
|
46
|
-
"@stim-cli/cache": "^1.
|
|
47
|
-
"@stim-cli/core": "^1.
|
|
48
|
-
"@stim-cli/metro": "^1.
|
|
51
|
+
"@stim-cli/cache": "^1.15.0",
|
|
52
|
+
"@stim-cli/core": "^1.15.0",
|
|
53
|
+
"@stim-cli/metro": "^1.15.0",
|
|
49
54
|
"chalk": "^6.0.0",
|
|
50
55
|
"commander": "^15.0.0",
|
|
51
56
|
"cross-spawn": "^7.0.6",
|
|
@@ -53,7 +58,7 @@
|
|
|
53
58
|
"ws": "^8.21.3"
|
|
54
59
|
},
|
|
55
60
|
"devDependencies": {
|
|
56
|
-
"@stim-cli/expo-build-cache": "1.
|
|
61
|
+
"@stim-cli/expo-build-cache": "1.15.0",
|
|
57
62
|
"@types/cross-spawn": "^6.0.6",
|
|
58
63
|
"@types/which": "^3.0.4",
|
|
59
64
|
"@types/ws": "^8.18.1",
|
package/shim/bundle-response.cjs
CHANGED
|
@@ -2,13 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
const { randomUUID } = require('node:crypto');
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const LOOPBACK = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1']);
|
|
6
|
+
// Metro writes each progress update of a multipart bundle response as its own JSON part:
|
|
7
|
+
// https://github.com/facebook/metro/blob/main/packages/metro/src/Server.js (`writeChunk` with done, total, percent).
|
|
8
|
+
const PROGRESS_PART = /^\{"done":(\d+),"total":(\d+),"percent":(\d+)\}$/;
|
|
9
|
+
const PROGRESS_INTERVAL_MS = 1000;
|
|
10
|
+
|
|
11
|
+
function clientPidFromLsof(output, clientPort, serverPort) {
|
|
12
|
+
const connection = new RegExp(`:${clientPort}->\\S*:${serverPort}$`);
|
|
13
|
+
let pid = null;
|
|
14
|
+
for (const line of String(output).split('\n')) {
|
|
15
|
+
if (line.startsWith('p')) pid = Number(line.slice(1));
|
|
16
|
+
else if (line.startsWith('n') && connection.test(line) && Number.isInteger(pid) && pid > 0) return pid;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// An iOS simulator app is a host process, so the peer of its loopback connection names the device's app.
|
|
22
|
+
function lookupClientPid(req, runLsof) {
|
|
23
|
+
const { remoteAddress, remotePort, localPort } = req.socket;
|
|
24
|
+
if (!runLsof || !LOOPBACK.has(remoteAddress)) return null;
|
|
25
|
+
return Promise.resolve()
|
|
26
|
+
.then(() => runLsof(['-nP', `-iTCP:${remotePort}`, '-Fpn']))
|
|
27
|
+
.then((output) => clientPidFromLsof(output, remotePort, localPort))
|
|
28
|
+
.catch(() => null);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function bundleResponseMiddleware(write, { runLsof } = {}) {
|
|
6
32
|
return (req, res, next) => {
|
|
7
33
|
if (req.method === 'GET' && req.url === '/_stim/metro-warmup') {
|
|
8
34
|
res.end('ready');
|
|
9
35
|
return;
|
|
10
36
|
}
|
|
11
|
-
|
|
37
|
+
const prefetch = req.headers['x-stim-metro-warmup'] === '1';
|
|
12
38
|
let url;
|
|
13
39
|
try {
|
|
14
40
|
url = new URL(req.url, 'http://localhost');
|
|
@@ -20,27 +46,46 @@ function bundleResponseMiddleware(write) {
|
|
|
20
46
|
return next();
|
|
21
47
|
}
|
|
22
48
|
const requestId = randomUUID();
|
|
23
|
-
const
|
|
49
|
+
const kind = prefetch ? 'prefetch' : 'response';
|
|
50
|
+
const clientPid = platform === 'ios' && !prefetch ? lookupClientPid(req, runLsof) : null;
|
|
51
|
+
const send = (ts, stage, statusCode, pid, progress) => {
|
|
24
52
|
try {
|
|
25
53
|
write({
|
|
26
|
-
ts
|
|
54
|
+
ts,
|
|
27
55
|
src: 'metro',
|
|
28
|
-
level:
|
|
29
|
-
event
|
|
56
|
+
level: stage === 'failed' && !prefetch ? 'error' : 'debug',
|
|
57
|
+
event: `bundle_${kind}_${stage}`,
|
|
30
58
|
platform,
|
|
31
59
|
requestId,
|
|
32
|
-
statusCode,
|
|
33
|
-
msg: `${platform} bundle
|
|
60
|
+
...(progress ?? { statusCode }),
|
|
61
|
+
msg: progress ? `${platform} bundle ${progress.percent}%` : `${platform} bundle ${kind} ${stage}`,
|
|
62
|
+
...(pid ? { clientPid: pid } : {}),
|
|
34
63
|
});
|
|
35
64
|
} catch {}
|
|
36
65
|
};
|
|
37
|
-
emit(
|
|
66
|
+
const emit = (stage, statusCode, progress) => {
|
|
67
|
+
const ts = Date.now();
|
|
68
|
+
if (clientPid) clientPid.then((pid) => send(ts, stage, statusCode, pid, progress));
|
|
69
|
+
else send(ts, stage, statusCode, null, progress);
|
|
70
|
+
};
|
|
71
|
+
emit('started');
|
|
72
|
+
const writeChunk = res.write;
|
|
73
|
+
let progressAt = 0;
|
|
74
|
+
res.write = function (chunk, ...rest) {
|
|
75
|
+
const part = typeof chunk === 'string' && chunk.length < 100 ? PROGRESS_PART.exec(chunk) : null;
|
|
76
|
+
const now = part ? Date.now() : 0;
|
|
77
|
+
if (part && now - progressAt >= PROGRESS_INTERVAL_MS) {
|
|
78
|
+
progressAt = now;
|
|
79
|
+
emit('progress', undefined, { done: Number(part[1]), total: Number(part[2]), percent: Number(part[3]) });
|
|
80
|
+
}
|
|
81
|
+
return writeChunk.call(this, chunk, ...rest);
|
|
82
|
+
};
|
|
38
83
|
let ended = false;
|
|
39
84
|
const finish = (complete) => {
|
|
40
85
|
if (ended) return;
|
|
41
86
|
ended = true;
|
|
42
87
|
const success = complete && (res.statusCode === 200 || res.statusCode === 304);
|
|
43
|
-
emit(success ? '
|
|
88
|
+
emit(success ? 'finished' : 'failed', res.statusCode);
|
|
44
89
|
};
|
|
45
90
|
res.once('finish', () => finish(true));
|
|
46
91
|
res.once('close', () => finish(false));
|
|
@@ -2,4 +2,5 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
|
2
2
|
|
|
3
3
|
export function bundleResponseMiddleware(
|
|
4
4
|
write: (record: Record<string, unknown>) => unknown,
|
|
5
|
+
options?: { runLsof?: (args: string[]) => Promise<string> },
|
|
5
6
|
): (req: IncomingMessage, res: ServerResponse, next: () => unknown) => unknown;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const os = require('node:os');
|
|
5
5
|
const path = require('node:path');
|
|
6
|
+
const { execFile } = require('node:child_process');
|
|
6
7
|
const { createRequire } = require('node:module');
|
|
7
8
|
const { pathToFileURL } = require('node:url');
|
|
8
9
|
const { bundleResponseMiddleware } = require('./bundle-response.cjs');
|
|
@@ -118,6 +119,12 @@ function storeAtRoot(store) {
|
|
|
118
119
|
return store[STORE_ROOT_TAG] === storeRoot || store['_root'] === storeRoot;
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
function runLsof(args) {
|
|
123
|
+
return new Promise((resolve, reject) =>
|
|
124
|
+
execFile('lsof', args, { timeout: 2000 }, (error, stdout) => (error ? reject(error) : resolve(stdout))),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
121
128
|
function appendStore(config, defaultConfig) {
|
|
122
129
|
const output = config && typeof config === 'object' ? config : {};
|
|
123
130
|
const configuredStores = output.cacheStores != null ? output.cacheStores : defaultConfig.cacheStores;
|
|
@@ -130,8 +137,9 @@ function appendStore(config, defaultConfig) {
|
|
|
130
137
|
...server,
|
|
131
138
|
enhanceMiddleware(middleware, metroServer) {
|
|
132
139
|
const enhanced = enhanceMiddleware ? enhanceMiddleware(middleware, metroServer) : middleware;
|
|
133
|
-
const observe = bundleResponseMiddleware(
|
|
134
|
-
process.stderr.write(`stim-bundle-response: ${JSON.stringify(record)}\n`),
|
|
140
|
+
const observe = bundleResponseMiddleware(
|
|
141
|
+
(record) => process.stderr.write(`stim-bundle-response: ${JSON.stringify(record)}\n`),
|
|
142
|
+
{ runLsof: process.platform === 'darwin' ? runLsof : undefined },
|
|
135
143
|
);
|
|
136
144
|
return (req, res, next) => observe(req, res, () => enhanced(req, res, next));
|
|
137
145
|
},
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import { A as ownership_claim_exports } from "./config-0jCcMM0E.mjs";
|
|
2
|
-
import { _ as updateWorkspaceState, p as clearWorkspaceStateKey } from "./metro-BPeY1YMh.mjs";
|
|
3
|
-
import { a as formatElapsed, u as plural } from "./command-output-BIL7rlX7.mjs";
|
|
4
|
-
import { BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, LAST_BUILD_KEYS } from "@stim-cli/core/state";
|
|
5
|
-
//#region src/engine/build-progress.ts
|
|
6
|
-
const ACTIVE_BUILD_KEY = "activeBuild";
|
|
7
|
-
const NO_BUILD_PROGRESS = {
|
|
8
|
-
step: () => {},
|
|
9
|
-
durations: () => ({}),
|
|
10
|
-
clear: () => {}
|
|
11
|
-
};
|
|
12
|
-
const COLD_PHASES = [
|
|
13
|
-
"prebuild",
|
|
14
|
-
"pods",
|
|
15
|
-
"compile"
|
|
16
|
-
];
|
|
17
|
-
const DEVICE_PHASES = ["install", "launch"];
|
|
18
|
-
function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
|
|
19
|
-
const startedAt = new Date(now()).toISOString();
|
|
20
|
-
const record = {
|
|
21
|
-
platform,
|
|
22
|
-
slot,
|
|
23
|
-
startedAt,
|
|
24
|
-
phase: "prepare",
|
|
25
|
-
phaseStartedAt: startedAt,
|
|
26
|
-
phases: [{
|
|
27
|
-
phase: "prepare",
|
|
28
|
-
startedAt
|
|
29
|
-
}],
|
|
30
|
-
claim: {
|
|
31
|
-
root: claim.root,
|
|
32
|
-
path: claim.path,
|
|
33
|
-
claimId: claim.claimId,
|
|
34
|
-
pid: claim.owner.pid
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
let warned = false;
|
|
38
|
-
const guard = (fn) => {
|
|
39
|
-
try {
|
|
40
|
-
fn();
|
|
41
|
-
} catch (error) {
|
|
42
|
-
if (warned) return;
|
|
43
|
-
warned = true;
|
|
44
|
-
note(`Build progress could not be recorded in the workspace state: ${error?.message || error}`);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
const write = (before = (state) => state) => guard(() => updateWorkspaceState(root, (state) => ({
|
|
48
|
-
...before(state),
|
|
49
|
-
[ACTIVE_BUILD_KEY]: record
|
|
50
|
-
})));
|
|
51
|
-
write(withInterruptedBuild);
|
|
52
|
-
return {
|
|
53
|
-
step(phase) {
|
|
54
|
-
if (phase === record.phase) return;
|
|
55
|
-
const at = new Date(now()).toISOString();
|
|
56
|
-
record.phase = phase;
|
|
57
|
-
record.phaseStartedAt = at;
|
|
58
|
-
record.phases.push({
|
|
59
|
-
phase,
|
|
60
|
-
startedAt: at
|
|
61
|
-
});
|
|
62
|
-
write();
|
|
63
|
-
},
|
|
64
|
-
durations() {
|
|
65
|
-
return phaseDurations(record.phases, now());
|
|
66
|
-
},
|
|
67
|
-
clear() {
|
|
68
|
-
guard(() => {
|
|
69
|
-
clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function phaseDurations(phases, now) {
|
|
75
|
-
const out = {};
|
|
76
|
-
phases.forEach(({ phase, startedAt }, index) => {
|
|
77
|
-
const start = Date.parse(startedAt);
|
|
78
|
-
const next = phases[index + 1];
|
|
79
|
-
const end = next ? Date.parse(next.startedAt) : now;
|
|
80
|
-
if (!Number.isFinite(start) || !Number.isFinite(end)) return;
|
|
81
|
-
out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
|
|
82
|
-
});
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
85
|
-
const HISTORY_FIELDS = [
|
|
86
|
-
"platform",
|
|
87
|
-
"status",
|
|
88
|
-
"configuration",
|
|
89
|
-
"fingerprint",
|
|
90
|
-
"cacheKey",
|
|
91
|
-
"cacheHit",
|
|
92
|
-
"cacheSkipped",
|
|
93
|
-
"durationMs",
|
|
94
|
-
"startedAt",
|
|
95
|
-
"errorCode",
|
|
96
|
-
"missReason",
|
|
97
|
-
"diagnostics"
|
|
98
|
-
];
|
|
99
|
-
function withHistoryEntry(state, platform, entry) {
|
|
100
|
-
const saved = state[BUILD_HISTORY_KEY];
|
|
101
|
-
const history = saved && typeof saved === "object" && !Array.isArray(saved) ? saved : {};
|
|
102
|
-
const list = Array.isArray(history[platform]) ? history[platform] : [];
|
|
103
|
-
return {
|
|
104
|
-
...state,
|
|
105
|
-
[BUILD_HISTORY_KEY]: {
|
|
106
|
-
...history,
|
|
107
|
-
[platform]: [entry, ...list].slice(0, BUILD_HISTORY_LIMIT)
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function finishedResult(record) {
|
|
112
|
-
if (record.status === "ok") return "succeeded";
|
|
113
|
-
return record.errorCode === "STIM_CANCELLED" ? "cancelled" : "failed";
|
|
114
|
-
}
|
|
115
|
-
function recordFinishedBuild(root, record, { update = updateWorkspaceState, now = Date.now } = {}) {
|
|
116
|
-
const platform = record.platform;
|
|
117
|
-
update(root, (state) => {
|
|
118
|
-
const active = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
119
|
-
const own = active?.platform === platform ? active : null;
|
|
120
|
-
const entry = {
|
|
121
|
-
...Object.fromEntries(HISTORY_FIELDS.filter((key) => key in record).map((key) => [key, record[key]])),
|
|
122
|
-
result: finishedResult(record),
|
|
123
|
-
slot: own?.slot ?? "default",
|
|
124
|
-
phases: own ? phaseDurations(own.phases, now()) : {}
|
|
125
|
-
};
|
|
126
|
-
return withHistoryEntry({
|
|
127
|
-
...state,
|
|
128
|
-
lastBuild: record,
|
|
129
|
-
[LAST_BUILD_KEYS[platform]]: record
|
|
130
|
-
}, platform, entry);
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
function withInterruptedBuild(state) {
|
|
134
|
-
const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
135
|
-
if (!left) return state;
|
|
136
|
-
const last = state[LAST_BUILD_KEYS[left.platform]];
|
|
137
|
-
if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
|
|
138
|
-
return withHistoryEntry(state, left.platform, {
|
|
139
|
-
platform: left.platform,
|
|
140
|
-
status: "failed",
|
|
141
|
-
result: "interrupted",
|
|
142
|
-
slot: left.slot,
|
|
143
|
-
configuration: null,
|
|
144
|
-
fingerprint: null,
|
|
145
|
-
cacheKey: null,
|
|
146
|
-
cacheHit: false,
|
|
147
|
-
cacheSkipped: false,
|
|
148
|
-
durationMs: null,
|
|
149
|
-
startedAt: left.startedAt,
|
|
150
|
-
phases: phaseDurations(left.phases, Date.parse(left.phaseStartedAt))
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function parseActiveBuild(value) {
|
|
154
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
155
|
-
const record = value;
|
|
156
|
-
const claim = record.claim;
|
|
157
|
-
if (record.platform !== "ios" && record.platform !== "android") return null;
|
|
158
|
-
if (!isPhase(record.phase)) return null;
|
|
159
|
-
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
160
|
-
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
161
|
-
const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
|
|
162
|
-
return {
|
|
163
|
-
platform: record.platform,
|
|
164
|
-
slot: typeof record.slot === "string" ? record.slot : "default",
|
|
165
|
-
startedAt: record.startedAt,
|
|
166
|
-
phase: record.phase,
|
|
167
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
168
|
-
phases,
|
|
169
|
-
claim: {
|
|
170
|
-
root: claim.root,
|
|
171
|
-
path: typeof claim.path === "string" ? claim.path : "",
|
|
172
|
-
claimId: claim.claimId,
|
|
173
|
-
pid: typeof claim.pid === "number" ? claim.pid : 0
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function isPhase(value) {
|
|
178
|
-
return BUILD_PHASES.includes(value);
|
|
179
|
-
}
|
|
180
|
-
function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
|
|
181
|
-
if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
|
|
182
|
-
if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
|
|
183
|
-
return survey.unresolved.length ? "unknown" : "stale";
|
|
184
|
-
}
|
|
185
|
-
function liveOutcome(record) {
|
|
186
|
-
const seen = new Set(record.phases.map((entry) => entry.phase));
|
|
187
|
-
if (COLD_PHASES.some((phase) => seen.has(phase))) return "cold";
|
|
188
|
-
if (DEVICE_PHASES.some((phase) => seen.has(phase))) return "hit";
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
function median(values) {
|
|
192
|
-
if (!values.length) return null;
|
|
193
|
-
const sorted = values.toSorted((a, b) => a - b);
|
|
194
|
-
const mid = Math.floor(sorted.length / 2);
|
|
195
|
-
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
196
|
-
}
|
|
197
|
-
function estimateBuild(history, platform, known, phase) {
|
|
198
|
-
const lists = history?.[platform];
|
|
199
|
-
const outcome = known ?? latestOutcome(lists);
|
|
200
|
-
const samples = outcome && lists?.[outcome] || [];
|
|
201
|
-
const phaseSamples = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
|
|
202
|
-
return {
|
|
203
|
-
outcome,
|
|
204
|
-
expectedMs: median(samples.map((sample) => sample.durationMs)),
|
|
205
|
-
expectedPhaseMs: median(phaseSamples),
|
|
206
|
-
basis: samples.length
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function latestOutcome(lists) {
|
|
210
|
-
let latest = null;
|
|
211
|
-
for (const outcome of ["hit", "cold"]) {
|
|
212
|
-
const last = lists?.[outcome]?.at(-1);
|
|
213
|
-
const at = last ? Date.parse(last.at) : NaN;
|
|
214
|
-
if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
|
|
215
|
-
outcome,
|
|
216
|
-
at
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return latest?.outcome ?? null;
|
|
220
|
-
}
|
|
221
|
-
function buildReport(record, { state, history }) {
|
|
222
|
-
return {
|
|
223
|
-
platform: record.platform,
|
|
224
|
-
slot: record.slot,
|
|
225
|
-
state,
|
|
226
|
-
phase: record.phase,
|
|
227
|
-
startedAt: record.startedAt,
|
|
228
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
229
|
-
...estimateBuild(history, record.platform, liveOutcome(record), record.phase)
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
function remainingText(remainingMs) {
|
|
233
|
-
return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
|
|
234
|
-
}
|
|
235
|
-
function buildStatusLine(report, now) {
|
|
236
|
-
const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
|
|
237
|
-
if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
|
|
238
|
-
const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
|
|
239
|
-
const head = `build: ${report.platform}${slot} ${report.phase}, ${formatElapsed(elapsedMs)} elapsed`;
|
|
240
|
-
if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
|
|
241
|
-
if (report.expectedMs === null) return head;
|
|
242
|
-
const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
|
|
243
|
-
const remainingMs = report.expectedMs - elapsedMs;
|
|
244
|
-
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
245
|
-
}
|
|
246
|
-
//#endregion
|
|
247
|
-
export { buildStatusLine as a, recordFinishedBuild as c, buildReport as i, startBuildProgress as l, NO_BUILD_PROGRESS as n, estimateBuild as o, activeBuildState as r, parseActiveBuild as s, ACTIVE_BUILD_KEY as t };
|
package/dist/in-use-wYEaKQM9.mjs
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import { A as ownership_claim_exports, d as getConfigDir, p as getProject } from "./config-0jCcMM0E.mjs";
|
|
2
|
-
import { h as readWorkspaceState, k as workspaceDir } from "./metro-BPeY1YMh.mjs";
|
|
3
|
-
import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-PT8aQpCa.mjs";
|
|
4
|
-
import { a as withWorkspaceProcessLock, o as workspaceProcessLockError, s as workspaceProcessLockPath } from "./named-ports-n7tnJsI8.mjs";
|
|
5
|
-
import { a as formatElapsed } from "./command-output-BIL7rlX7.mjs";
|
|
6
|
-
import { h as listBuildLocks } from "./device-lease-CL9dZf73.mjs";
|
|
7
|
-
import { n as managedLockHolders, t as resolveSupervisorTarget } from "./ownership-PUP4Dwai.mjs";
|
|
8
|
-
import { a as readWebRecord, l as webFacts } from "./state-l1pYwOre.mjs";
|
|
9
|
-
import { lstatSync, readdirSync, rmSync, rmdirSync, statSync, unlinkSync } from "node:fs";
|
|
10
|
-
import { realpathSync as realpathSync$1 } from "fs";
|
|
11
|
-
import { resolve } from "path";
|
|
12
|
-
import { join as join$1 } from "node:path";
|
|
13
|
-
//#region src/engine/build-slots.ts
|
|
14
|
-
const SLOT_PREFIX = "slot-";
|
|
15
|
-
const SLOT_LABEL = "build slot";
|
|
16
|
-
const SLOT_POLL_MS = 1e3;
|
|
17
|
-
const SLOT_PROGRESS_MS = 3e4;
|
|
18
|
-
const SLOT_CEILING_MS = 54e5;
|
|
19
|
-
function sleepAsync(ms) {
|
|
20
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
-
}
|
|
22
|
-
function buildSlotsDir() {
|
|
23
|
-
return join$1(getConfigDir(), "build-slots");
|
|
24
|
-
}
|
|
25
|
-
function buildSlotPath(index) {
|
|
26
|
-
return join$1(buildSlotsDir(), `${SLOT_PREFIX}${index}`);
|
|
27
|
-
}
|
|
28
|
-
function toRecord(holder) {
|
|
29
|
-
const details = holder.details;
|
|
30
|
-
return {
|
|
31
|
-
pid: holder.owner.pid,
|
|
32
|
-
index: typeof details.index === "number" ? details.index : null,
|
|
33
|
-
projectRoot: typeof details.projectRoot === "string" ? details.projectRoot : null,
|
|
34
|
-
startedAt: holder.startedAt || null,
|
|
35
|
-
logFile: typeof details.logFile === "string" ? details.logFile : null
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function tryAcquireBuildSlot({ max, root = null, logFile = null }) {
|
|
39
|
-
if (!max || max <= 0) return {
|
|
40
|
-
acquired: true,
|
|
41
|
-
unlimited: true
|
|
42
|
-
};
|
|
43
|
-
let refusal = null;
|
|
44
|
-
let busy = false;
|
|
45
|
-
for (let index = 0; index < max; index++) {
|
|
46
|
-
const path = buildSlotPath(index);
|
|
47
|
-
let attempt;
|
|
48
|
-
try {
|
|
49
|
-
attempt = (0, ownership_claim_exports.tryAcquireClaim)({
|
|
50
|
-
root: path,
|
|
51
|
-
mode: "exclusive",
|
|
52
|
-
label: SLOT_LABEL,
|
|
53
|
-
details: {
|
|
54
|
-
index,
|
|
55
|
-
projectRoot: root,
|
|
56
|
-
logFile
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
} catch (err) {
|
|
60
|
-
if (!(0, ownership_claim_exports.isClaimRefusal)(err)) throw err;
|
|
61
|
-
refusal ??= err;
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
65
|
-
if (!attempt.acquired) {
|
|
66
|
-
busy = true;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
declareSpawnsOn(attempt.acquired);
|
|
70
|
-
return {
|
|
71
|
-
acquired: true,
|
|
72
|
-
path,
|
|
73
|
-
index,
|
|
74
|
-
slot: {
|
|
75
|
-
pid: attempt.acquired.owner.pid,
|
|
76
|
-
index,
|
|
77
|
-
projectRoot: root,
|
|
78
|
-
startedAt: attempt.acquired.startedAt,
|
|
79
|
-
logFile
|
|
80
|
-
},
|
|
81
|
-
claim: attempt.acquired
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
if (refusal && !busy) throw refusal;
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
function slotWaitingLine({ max, elapsedMs }) {
|
|
88
|
-
return `${"build".padEnd(11)} waiting for a build slot (all ${max} in use, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle concurrency`;
|
|
89
|
-
}
|
|
90
|
-
async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, sleep = sleepAsync, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS }) {
|
|
91
|
-
if (!max || max <= 0) return {
|
|
92
|
-
acquired: true,
|
|
93
|
-
unlimited: true
|
|
94
|
-
};
|
|
95
|
-
const started = now();
|
|
96
|
-
let lastProgress = started;
|
|
97
|
-
for (;;) {
|
|
98
|
-
const got = tryAcquireBuildSlot({
|
|
99
|
-
max,
|
|
100
|
-
root,
|
|
101
|
-
logFile
|
|
102
|
-
});
|
|
103
|
-
if (got) return got;
|
|
104
|
-
const elapsed = now() - started;
|
|
105
|
-
if (elapsed >= ceilingMs) {
|
|
106
|
-
const err = /* @__PURE__ */ new Error(`Waited ${formatElapsed(elapsed)} for one of ${max} build slots, and every slot is held by a process that is still running, or by a holder Stim cannot identify. Slots live under ` + buildSlotsDir() + "; remove a slot directory whose builder is not really building, or raise concurrency.maxBuilds.");
|
|
107
|
-
err.code = "STIM_BUILD_SLOT_TIMEOUT";
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
110
|
-
if (now() - lastProgress >= progressMs) {
|
|
111
|
-
lastProgress = now();
|
|
112
|
-
out(slotWaitingLine({
|
|
113
|
-
max,
|
|
114
|
-
elapsedMs: elapsed
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
|
-
await sleep(intervalMs);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function releaseBuildSlot(handle) {
|
|
121
|
-
if (!handle || handle.unlimited) return false;
|
|
122
|
-
stopDeclaringSpawnsOn(handle.claim);
|
|
123
|
-
return (0, ownership_claim_exports.releaseClaim)(handle.claim);
|
|
124
|
-
}
|
|
125
|
-
function listBuildSlots() {
|
|
126
|
-
const dir = buildSlotsDir();
|
|
127
|
-
let names;
|
|
128
|
-
try {
|
|
129
|
-
names = readdirSync(dir);
|
|
130
|
-
} catch {
|
|
131
|
-
return [];
|
|
132
|
-
}
|
|
133
|
-
const slots = [];
|
|
134
|
-
for (const name of names) {
|
|
135
|
-
if (!name.startsWith(SLOT_PREFIX)) continue;
|
|
136
|
-
const path = join$1(dir, name);
|
|
137
|
-
try {
|
|
138
|
-
if (!statSync(path).isDirectory()) continue;
|
|
139
|
-
} catch {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const survey = (0, ownership_claim_exports.readClaimSet)(path);
|
|
143
|
-
const holder = survey.live[0] ?? survey.dead[0];
|
|
144
|
-
const info = holder ? toRecord(holder) : null;
|
|
145
|
-
const index = Number(name.slice(5));
|
|
146
|
-
slots.push({
|
|
147
|
-
path,
|
|
148
|
-
name,
|
|
149
|
-
index: Number.isFinite(index) ? index : null,
|
|
150
|
-
pid: info?.pid ?? null,
|
|
151
|
-
projectRoot: info?.projectRoot ?? null,
|
|
152
|
-
startedAt: info?.startedAt ?? null,
|
|
153
|
-
logFile: info?.logFile ?? null,
|
|
154
|
-
alive: survey.live.length > 0,
|
|
155
|
-
unresolved: survey.unresolved.length > 0
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
return slots;
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
|
-
//#region src/commands/gc/paths.ts
|
|
162
|
-
function canonicalPath(p) {
|
|
163
|
-
try {
|
|
164
|
-
return realpathSync$1(p);
|
|
165
|
-
} catch {
|
|
166
|
-
return resolve(p);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region src/workspace/in-use.ts
|
|
171
|
-
const NATIVE_RUN = "native-run";
|
|
172
|
-
const NATIVE_RUN_HELD = "a stim ios, android or stop run holds its native-run.lock";
|
|
173
|
-
function workspaceInUse(root, { supervisor = true, managedLocks = true, nativeRun = true } = {}) {
|
|
174
|
-
const reasons = [];
|
|
175
|
-
if (supervisor) {
|
|
176
|
-
const project = getProject(root);
|
|
177
|
-
const target = resolveSupervisorTarget({
|
|
178
|
-
state: readWorkspaceState(root)?.supervisor,
|
|
179
|
-
record: project?.supervisor,
|
|
180
|
-
reservedPort: project?.metroPort
|
|
181
|
-
});
|
|
182
|
-
if (target.status === "ours") reasons.push(`its dev server supervisor (pid ${target.pid}) is running`);
|
|
183
|
-
else if (target.status === "unverified") reasons.push(`its dev server supervisor cannot be verified: ${target.reason ?? "unknown identity"}`);
|
|
184
|
-
const browser = webFacts(readWebRecord(root));
|
|
185
|
-
if (browser?.status === "running" || browser?.status === "orphaned") reasons.push(`its owned Chrome (pid ${browser.record.chromeProcess?.pid}) is running`);
|
|
186
|
-
else if (browser?.status === "unverified") reasons.push("its owned Chrome cannot be verified");
|
|
187
|
-
}
|
|
188
|
-
if (nativeRun) {
|
|
189
|
-
const claims = (0, ownership_claim_exports.readClaimSet)(workspaceProcessLockPath(workspaceDir(root), NATIVE_RUN, true));
|
|
190
|
-
if (claims.live.length) reasons.push(NATIVE_RUN_HELD);
|
|
191
|
-
else if (claims.unresolved[0]) reasons.push(`its native-run.lock cannot be resolved: ${claims.unresolved[0].reason}`);
|
|
192
|
-
}
|
|
193
|
-
const self = canonicalPath(root);
|
|
194
|
-
for (const [kind, entries] of [["build lock", listBuildLocks()], ["build slot", listBuildSlots()]]) for (const entry of entries) {
|
|
195
|
-
if (!entry.alive && !entry.unresolved) continue;
|
|
196
|
-
if (entry.projectRoot !== null && canonicalPath(entry.projectRoot) === self) reasons.push(`a ${entry.alive ? "live" : "unresolvable"} ${kind} at ${entry.path} names it`);
|
|
197
|
-
}
|
|
198
|
-
if (managedLocks) reasons.push(...managedLockHolders(root));
|
|
199
|
-
return reasons;
|
|
200
|
-
}
|
|
201
|
-
function emptyWorkspaceDir(dir) {
|
|
202
|
-
if (lstatSync(dir).isSymbolicLink()) {
|
|
203
|
-
unlinkSync(dir);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
for (const name of readdirSync(dir)) if (name !== `${NATIVE_RUN}.lock`) rmSync(join$1(dir, name), {
|
|
207
|
-
recursive: true,
|
|
208
|
-
force: true
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
async function withIdleWorkspace(root, fn, { purpose, ...checks }) {
|
|
212
|
-
try {
|
|
213
|
-
return await withWorkspaceProcessLock(workspaceDir(root), NATIVE_RUN, async () => {
|
|
214
|
-
const reasons = workspaceInUse(root, {
|
|
215
|
-
...checks,
|
|
216
|
-
nativeRun: false
|
|
217
|
-
});
|
|
218
|
-
if (reasons.length) return {
|
|
219
|
-
ran: false,
|
|
220
|
-
reasons
|
|
221
|
-
};
|
|
222
|
-
return {
|
|
223
|
-
ran: true,
|
|
224
|
-
value: await fn()
|
|
225
|
-
};
|
|
226
|
-
}, {
|
|
227
|
-
external: true,
|
|
228
|
-
waitMs: 0,
|
|
229
|
-
ownerPurpose: purpose
|
|
230
|
-
});
|
|
231
|
-
} catch (error) {
|
|
232
|
-
if (workspaceProcessLockError(error)) return {
|
|
233
|
-
ran: false,
|
|
234
|
-
reasons: [NATIVE_RUN_HELD]
|
|
235
|
-
};
|
|
236
|
-
if ((0, ownership_claim_exports.isClaimRefusal)(error) || (0, ownership_claim_exports.isClaimUnavailable)(error)) return {
|
|
237
|
-
ran: false,
|
|
238
|
-
reasons: [`its native-run.lock cannot be taken: ${error.reason}`]
|
|
239
|
-
};
|
|
240
|
-
throw error;
|
|
241
|
-
} finally {
|
|
242
|
-
try {
|
|
243
|
-
const dir = workspaceDir(root);
|
|
244
|
-
if (!lstatSync(dir).isSymbolicLink()) rmdirSync(dir);
|
|
245
|
-
} catch {}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
//#endregion
|
|
249
|
-
export { acquireBuildSlot as a, canonicalPath as i, withIdleWorkspace as n, listBuildSlots as o, workspaceInUse as r, releaseBuildSlot as s, emptyWorkspaceDir as t };
|