stim 1.18.0 → 1.20.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 +21 -4
- package/dist/{activity-BxnkDZDi.mjs → activity-BrGh9EAI.mjs} +3 -3
- package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
- package/dist/android-0vv-OruW.mjs +6 -0
- package/dist/android-Brx6EKvJ.mjs +1258 -0
- package/dist/{android-DC3ZLuw0.mjs → android-BsYNR81W.mjs} +103 -45
- package/dist/{android-CBwCNicO.mjs → android-CK3fpEyZ.mjs} +2 -2
- package/dist/{android-cas-BBFyr9CA.mjs → android-cas-DCAuXryb.mjs} +9 -5
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api-run.mjs +159 -8
- package/dist/{api-D0VtFhqk.mjs → api-zuX3ynYN.mjs} +9 -7
- package/dist/api.d.mts +104 -4
- package/dist/api.mjs +1 -1
- package/dist/{app-install-D-PUENug.mjs → app-install-0LgaQRT7.mjs} +39 -18
- package/dist/artifact-CnC0mfov.mjs +807 -0
- package/dist/artifact-DClXJNWx.mjs +772 -0
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
- package/dist/{web-DTU0uiWj.mjs → browser-web-CzBmhmgs.mjs} +136 -174
- package/dist/{budget-DIhL2BKx.mjs → budget-BONq9vXY.mjs} +3096 -3244
- package/dist/build-BixRI6sB.mjs +462 -0
- package/dist/build-plan-CP0tckNU.mjs +553 -0
- package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/ccache-CjHQ5F8g.mjs +142 -0
- package/dist/{chrome-DJnmnS5q.mjs → chrome-Dp2lMLBe.mjs} +1 -1
- package/dist/{cli-DNJMwADx.mjs → cli-B2R8wH1F.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-DzhapoMB.mjs → client-BLy1Pw2V.mjs} +172 -165
- package/dist/collector-run.d.mts +10 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-CBtzyIgF.mjs → command-output-BjPN99ZB.mjs} +2 -2
- package/dist/{config-CgYMahz7.mjs → config-D0LhTY3S.mjs} +13 -13
- package/dist/{created-devices-DKbeWsiK.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
- package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
- package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
- package/dist/{dev-client-CLnIH02x.mjs → dev-client-ClATaJoH.mjs} +2 -2
- package/dist/{device-D7oCHGWi.mjs → device-B7lsC0K1.mjs} +8 -8
- package/dist/device-DVCwAFlX.mjs +727 -0
- package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-Ca_ke1LE.mjs} +25 -15
- package/dist/device-host-worker.mjs +38 -18
- package/dist/{device-ios-6MewKKnc.mjs → device-ios-CRUqPxKw.mjs} +12 -11
- package/dist/{device-lease-Co-EwifR.mjs → device-lease-DHOBXGgS.mjs} +135 -22
- package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
- package/dist/{device-pool-F5WvRPtD.mjs → device-pool-L2-5GxMy.mjs} +3 -3
- package/dist/{device-remote-tHbd1fKy.mjs → device-remote-Bmg42063.mjs} +17 -69
- package/dist/doctor-C2MSuMMg.mjs +515 -0
- package/dist/{doctor-B9ckYUoU.mjs → doctor-DPAqhVCK.mjs} +334 -721
- package/dist/doctor-watchman-CB4NnVZm.mjs +260 -0
- package/dist/{simslim-EHBQ2R4G.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
- package/dist/{stim-installations-aR_WsNOA.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
- package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
- package/dist/errors-DzkMYh8Q.mjs +205 -0
- package/dist/{exec-DWhCZDGm.mjs → exec-B81Qodjn.mjs} +69 -15
- package/dist/{gc-Dh6mXOKC.mjs → gc-PWp34zGb.mjs} +23 -22
- package/dist/{gradle-C6GKnunQ.mjs → gradle-C2OEKCCI.mjs} +50 -125
- package/dist/{guide-tm6igAaa.mjs → guide-Dai9lphv.mjs} +862 -538
- package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
- package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-Io01s5By.mjs} +9 -3
- package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
- package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
- package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
- package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-BdAQi21M.mjs} +23 -16
- package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
- package/dist/ios-BZ9dg2Fr.mjs +9 -0
- package/dist/{ios-B3SbOWdw.mjs → ios-CXLIUxXJ.mjs} +180 -24
- package/dist/ios-CZuv6gRv.mjs +1112 -0
- package/dist/{ios-Bvbf0SGY.mjs → ios-VGvNdsv2.mjs} +1 -1
- package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-B1B14xND.mjs} +1 -1
- package/dist/{ios-device-vOaByMhw.mjs → ios-device-BreZOpM0.mjs} +3 -3
- package/dist/ios-project-B9drt_aY.mjs +197 -0
- package/dist/{ios-state-B2pES6Vs.mjs → ios-state-CjrL2qv-.mjs} +1 -1
- package/dist/js-swap-C8icNYIY.mjs +432 -0
- package/dist/launch-DxH0THLP.mjs +745 -0
- package/dist/launch-YrbqaIFj.mjs +1530 -0
- package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
- package/dist/{logs-1Ylc1Ri6.mjs → logs-DHaRNfg7.mjs} +11 -11
- package/dist/macos-C0iljhsN.mjs +2 -0
- package/dist/{macos-DF6C7wUU.mjs → macos-V_3Ui7g4.mjs} +125 -155
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +13 -10
- package/dist/{metro-Dh8T4Ytd.mjs → metro-D_j9sN-B.mjs} +209 -43
- package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
- package/dist/miss-reason-BPAzZS0r.mjs +238 -0
- package/dist/{named-ports-BFIz1Shz.mjs → named-ports-C2lvoPsb.mjs} +12 -5
- package/dist/native-android-lHzaew7r.mjs +226 -0
- package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
- package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
- package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
- package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
- package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
- package/dist/offload-worker.d.mts +12 -6
- package/dist/offload-worker.mjs +409 -73
- package/dist/{ownership-D6Se7gg_.mjs → ownership-DXzMMSx6.mjs} +2 -2
- package/dist/{placement-log-BcPhRwR4.mjs → placement-log-reFbjqEr.mjs} +7 -3
- package/dist/plan-BDk2AeY_.mjs +260 -0
- package/dist/plan-placement-D_YYlE6N.mjs +73 -0
- package/dist/{ports-BLTtfBq-.mjs → ports-jzvAJXXL.mjs} +3 -3
- package/dist/{prebuild-juCyreaR.mjs → prebuild-Bw44QxVh.mjs} +4 -4
- package/dist/{preview-D5V07Nrl.mjs → preview-BaBJ72Al.mjs} +51 -34
- package/dist/project-B8_duAzW.mjs +1067 -0
- package/dist/project-plan-BPwbLwQu.mjs +10 -0
- package/dist/{pull-request-u4vp7zmK.mjs → pull-request-vOhLNmIb.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/react-native-android-chm1DMlA.mjs +921 -0
- package/dist/react-native-build-oAw6gQeW.mjs +239 -0
- package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
- package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
- package/dist/{recordings-BAWltsVt.mjs → recordings-Bk-VivUV.mjs} +1 -1
- package/dist/{reload-DvyWzVjJ.mjs → reload-D34GkY78.mjs} +17 -14
- package/dist/remote-BU9UyhCJ.mjs +192 -0
- package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
- package/dist/result-BDoRk1k3.mjs +186 -0
- package/dist/{run-vhtDgpHO.mjs → run-qvff78hv.mjs} +3 -3
- package/dist/{server-bare-B9E7S1aR.mjs → server-bare-dWjAarki.mjs} +6 -6
- package/dist/server-command-7XIKlWtO.mjs +69 -0
- package/dist/{server-expo-DoBHhuzK.mjs → server-expo-CsYu2aKL.mjs} +107 -82
- package/dist/server-expo-DV43vep4.mjs +2 -0
- package/dist/settings-Bbztm4oV.mjs +1503 -0
- package/dist/{settings-Byp2AQ_E.mjs → settings-CT3E71-i.mjs} +6 -7
- package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
- package/dist/settings.schema.json +156 -6
- package/dist/simslim-ChMfe8rg.mjs +149 -0
- package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-B9hn96wd.mjs} +6 -6
- package/dist/{stage-g_WqWeaE.mjs → stage-BNKKdDNc.mjs} +6 -3
- package/dist/start-CbQCSnXQ.mjs +2 -0
- package/dist/{start-D-IeOyoK.mjs → start-CdvcTaXr.mjs} +113 -77
- package/dist/{state-xnqpx3AD.mjs → state-Boo0IMJq.mjs} +4 -2
- package/dist/{state-BG-aAk4k.mjs → state-DI84A-uu.mjs} +29 -10
- package/dist/{stats-DY6ekz8F.mjs → stats-BIIDrjA8.mjs} +6 -6
- package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
- package/dist/{status-DCjZeE-K.mjs → status-DARMkc9q.mjs} +80 -294
- package/dist/status-watch-DvmI3SmN.mjs +296 -0
- package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
- package/dist/{stop-DIJtD2GL.mjs → stop-CCZS-C9m.mjs} +2 -2
- package/dist/stop-WQPQHLuy.mjs +72 -0
- package/dist/{stop-BTjs3xbc.mjs → stop-iNemHsJC.mjs} +81 -33
- package/dist/supervisor-run.d.mts +7 -2
- package/dist/supervisor-run.mjs +32 -20
- package/dist/{support-Bwvbrq5-.mjs → support-CnE_SIjt.mjs} +17 -7
- package/dist/{support-BaayeYCf.mjs → support-DCco5fut.mjs} +61 -8
- package/dist/swiftpm-macos-afeNUExW.mjs +119 -0
- package/dist/{native-run-B06FkmZx.mjs → tailnet-CoJUb2tB.mjs} +113 -6
- package/dist/toolchain-BIupIro1.mjs +2 -0
- package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-DqyDXs30.mjs} +225 -315
- package/dist/{trigger-CJMhwXe8.mjs → trigger-C0MWBi8O.mjs} +3 -3
- package/dist/trigger-SHLOWJ4O.mjs +2 -0
- package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-C3ASD6z5.mjs} +134 -37
- package/dist/{status-Dcr0Qexd.mjs → watchman-CQl51YZu.mjs} +75 -7
- package/dist/web-B3eldHFH.mjs +123 -0
- package/dist/web-BLXpOe6b.mjs +2 -0
- package/dist/web-run.mjs +10 -10
- package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
- package/dist/{workspaces-xXItD8Dj.mjs → workspaces-D2xSHBDY.mjs} +1297 -1211
- package/dist/{worktree-BSYlofkq.mjs → worktree-BxDqaTev.mjs} +102 -63
- package/dist/worktree-q7_OZNY0.mjs +2 -0
- package/package.json +8 -6
- package/shim/bundle-response.cjs +2 -1
- package/shim/bundle-response.d.cts +1 -1
- package/shim/expo-metro-config.cjs +1 -1
- package/shim/native-android.gradle +101 -0
- package/dist/android-BKA16DTf.mjs +0 -4
- package/dist/android-BvwuMUJ9.mjs +0 -3572
- package/dist/guide-status-Bhf9SJXc.mjs +0 -125
- package/dist/ios-CPdkoKaa.mjs +0 -3953
- package/dist/ios-DNpdygiv.mjs +0 -7
- package/dist/macos-Ck7OBMNY.mjs +0 -2
- package/dist/metro-store-BAHFcJm6.mjs +0 -106
- package/dist/plan-placement-CtxkCO54.mjs +0 -1859
- package/dist/project-C3ChRLZy.mjs +0 -212
- package/dist/projects-DD7dBTCj.mjs +0 -92
- package/dist/server-expo-Db9HBUoa.mjs +0 -2
- package/dist/settings-CQyMElEP.mjs +0 -701
- package/dist/start-NTc1Ifqs.mjs +0 -2
- package/dist/stop-BGhKMOuH.mjs +0 -48
- package/dist/trigger-DWAq9hkw.mjs +0 -2
- package/dist/web-B6_bFDn7.mjs +0 -2
- package/dist/worktree-BJfnU6r5.mjs +0 -2
- package/dist/worktree-CsKYexJM.mjs +0 -753
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { n as debugLog, t as getExecutor } from "./exec-
|
|
2
|
-
import { _ as loadConfig$1, d as getConfigDir } from "./config-
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
1
|
+
import { n as debugLog, t as getExecutor } from "./exec-B81Qodjn.mjs";
|
|
2
|
+
import { _ as loadConfig$1, d as getConfigDir } from "./config-D0LhTY3S.mjs";
|
|
3
|
+
import { D as withDirLock } from "./workspace-state-CSIFuuDa.mjs";
|
|
4
|
+
import { a as markApproved, c as pinnedEndpoint$1, i as lapsedLine, l as realIo, n as findPeer$1, o as parseMachine$1, r as isLapsed, s as pendingReport, t as endpoint, u as requestedLine, x as runCancellationSignal } from "./tailnet-CoJUb2tB.mjs";
|
|
5
|
+
import { n as CCACHE_UNAVAILABLE } from "./ccache-CjHQ5F8g.mjs";
|
|
6
|
+
import { l as toolchainMismatches, m as readRubyVersion, v as COMPILATION_CACHE_UNAVAILABLE } from "./toolchain-DqyDXs30.mjs";
|
|
7
|
+
import { c as gitVisiblePaths, i as nativeGradleTransfer, l as nativeTransferManifest, m as manifestDigest, s as checkNativeTransferMembership, u as sourceManifest } from "./native-gradle-inputs-BQnIdAlL.mjs";
|
|
5
8
|
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync, writeSync } from "node:fs";
|
|
6
|
-
import { basename, dirname, join, relative } from "node:path";
|
|
7
|
-
import { OFFLOAD_MODES, acceptsShape, buildMachinesFile, buildMachinesLock, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock,
|
|
8
|
-
import { hostname } from "node:os";
|
|
9
|
+
import { basename, dirname, isAbsolute, join, relative, sep } from "node:path";
|
|
10
|
+
import { OFFLOAD_MODES, acceptsShape, automaticMachineEnabled, buildMachinesFile, buildMachinesLock, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, isJsonObject, parseMachine, readBuildMachines, readDeviceHostMachines, requireAutomaticMachine, runId, saturation, settingDefinition } from "@stim-cli/core/state";
|
|
9
11
|
import { InvalidArgumentError } from "commander";
|
|
10
12
|
import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
11
13
|
import { createHash } from "node:crypto";
|
|
14
|
+
import { hostname } from "node:os";
|
|
15
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
12
16
|
import { WebSocket } from "ws";
|
|
13
17
|
//#region src/offload/access-ticket.ts
|
|
14
18
|
function readAccessTicket() {
|
|
@@ -27,95 +31,6 @@ function readHostPermissions(value) {
|
|
|
27
31
|
} : void 0;
|
|
28
32
|
}
|
|
29
33
|
//#endregion
|
|
30
|
-
//#region src/offload/tailnet.ts
|
|
31
|
-
const MAC_APP_TAILSCALE = "/Applications/Tailscale.app/Contents/MacOS/Tailscale";
|
|
32
|
-
const HELLO_TIMEOUT_MS = 1e4;
|
|
33
|
-
function isLapsed(credential) {
|
|
34
|
-
return credential.state === "pending" && !!credential.expiresAt && Date.parse(credential.expiresAt) <= Date.now();
|
|
35
|
-
}
|
|
36
|
-
function markApproved(credential) {
|
|
37
|
-
const { expiresAt: _expiresAt, ...rest } = credential;
|
|
38
|
-
return {
|
|
39
|
-
...rest,
|
|
40
|
-
state: "approved"
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function pendingReport(credential) {
|
|
44
|
-
return {
|
|
45
|
-
state: "pending",
|
|
46
|
-
...credential.expiresAt ? { expiresAt: credential.expiresAt } : {}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function lapsedLine(machine, credential) {
|
|
50
|
-
return `${machine} did not approve this Mac before the request lapsed at ${credential.expiresAt}.`;
|
|
51
|
-
}
|
|
52
|
-
function requestedLine(credential) {
|
|
53
|
-
return `Requested at ${credential.requestedAt}${credential.expiresAt ? `; the request lapses at ${credential.expiresAt}` : ""}.`;
|
|
54
|
-
}
|
|
55
|
-
function tailscaleStatus() {
|
|
56
|
-
for (const binary of ["tailscale", MAC_APP_TAILSCALE]) {
|
|
57
|
-
const output = getExecutor().runFileQuiet(binary, ["status", "--json"], { timeoutMs: 5e3 });
|
|
58
|
-
if (output === null) continue;
|
|
59
|
-
try {
|
|
60
|
-
const status = JSON.parse(output);
|
|
61
|
-
return isJsonObject(status) && status.BackendState === "Running" ? status : null;
|
|
62
|
-
} catch {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
function hello({ url, servername, host }, auth) {
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
const socket = new WebSocket(url, {
|
|
71
|
-
handshakeTimeout: HELLO_TIMEOUT_MS,
|
|
72
|
-
servername,
|
|
73
|
-
headers: { Host: host }
|
|
74
|
-
});
|
|
75
|
-
const done = (reply) => {
|
|
76
|
-
clearTimeout(timer);
|
|
77
|
-
socket.removeAllListeners();
|
|
78
|
-
socket.on("error", () => {});
|
|
79
|
-
socket.close();
|
|
80
|
-
resolve(reply);
|
|
81
|
-
};
|
|
82
|
-
const timer = setTimeout(() => done({ failed: "no reply in time" }), HELLO_TIMEOUT_MS);
|
|
83
|
-
socket.on("open", () => {
|
|
84
|
-
socket.send(JSON.stringify({
|
|
85
|
-
id: 1,
|
|
86
|
-
method: "hello",
|
|
87
|
-
params: {
|
|
88
|
-
protocol: 1,
|
|
89
|
-
client: {
|
|
90
|
-
name: "stim",
|
|
91
|
-
version: "1"
|
|
92
|
-
},
|
|
93
|
-
auth
|
|
94
|
-
}
|
|
95
|
-
}));
|
|
96
|
-
});
|
|
97
|
-
socket.on("message", (data) => {
|
|
98
|
-
let message;
|
|
99
|
-
try {
|
|
100
|
-
message = JSON.parse(String(data));
|
|
101
|
-
} catch {
|
|
102
|
-
message = null;
|
|
103
|
-
}
|
|
104
|
-
if (isJsonObject(message) && ("result" in message || "error" in message)) return done(message);
|
|
105
|
-
done({ failed: "the reply was not a hello result" });
|
|
106
|
-
});
|
|
107
|
-
socket.on("error", (error) => done({ failed: error.message }));
|
|
108
|
-
socket.on("close", () => done({ failed: "the connection closed before a reply" }));
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
const realIo = {
|
|
112
|
-
status: tailscaleStatus,
|
|
113
|
-
hello
|
|
114
|
-
};
|
|
115
|
-
function pinnedEndpoint$1(credential, status = tailscaleStatus) {
|
|
116
|
-
return pinnedEndpoint(credential, parseMachine(credential.machine) ? status() : null);
|
|
117
|
-
}
|
|
118
|
-
//#endregion
|
|
119
34
|
//#region src/device-host/machines.ts
|
|
120
35
|
function note$1(title, detail, fix = null) {
|
|
121
36
|
return {
|
|
@@ -689,6 +604,9 @@ function parseBuildMachineOption(value) {
|
|
|
689
604
|
throw new InvalidArgumentError(error.message);
|
|
690
605
|
}
|
|
691
606
|
}
|
|
607
|
+
function requireLocalBuild(selected) {
|
|
608
|
+
if (selected === "auto" && !automaticMachineEnabled("build", "local")) throw new OffloadRefusal("auto", "local is disabled in remote.buildPoolDisabled; enable it or select a machine explicitly");
|
|
609
|
+
}
|
|
692
610
|
function namedBuildMachine(selected) {
|
|
693
611
|
return selected !== "auto" && selected !== "local";
|
|
694
612
|
}
|
|
@@ -785,9 +703,11 @@ function offloadMode(env = process.env) {
|
|
|
785
703
|
return OFFLOAD_MODES.includes(raw) ? raw : "auto";
|
|
786
704
|
}
|
|
787
705
|
function buildPlacementCandidates(selected) {
|
|
706
|
+
const config = loadConfig$1();
|
|
788
707
|
return {
|
|
708
|
+
localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local", config),
|
|
789
709
|
mode: selected === "local" ? "off" : offloadMode(),
|
|
790
|
-
machines: selected === "local" ? [] : namedBuildMachine(selected) ? pairedMachines([selected]).slice(0, 1) : pairedMachines()
|
|
710
|
+
machines: selected === "local" ? [] : namedBuildMachine(selected) ? pairedMachines([selected]).slice(0, 1) : pairedMachines().filter((entry) => automaticMachineEnabled("build", entry.machine, config))
|
|
791
711
|
};
|
|
792
712
|
}
|
|
793
713
|
function remotePhaseText(name, msg, machine) {
|
|
@@ -813,7 +733,7 @@ function placementLoad(choice) {
|
|
|
813
733
|
* this Mac has a free `concurrency.maxBuilds` slot and its load per core is under `server.maxLoadPerCore`.
|
|
814
734
|
* A named selection ignores local capacity and mode, and refuses an unsupported build or missing pairing.
|
|
815
735
|
*/
|
|
816
|
-
function offloadPlacement({ mode, machines, here, unsupported, selected = "auto" }) {
|
|
736
|
+
function offloadPlacement({ mode, machines, here, unsupported, localEnabled = true, selected = "auto" }) {
|
|
817
737
|
if (namedBuildMachine(selected)) {
|
|
818
738
|
if (unsupported) throw new OffloadRefusal(selected, `${unsupported}, so a named remote Mac cannot take it`);
|
|
819
739
|
if (machines === 0) throw new OffloadRefusal(selected, "no remote Mac is paired");
|
|
@@ -828,6 +748,15 @@ function offloadPlacement({ mode, machines, here, unsupported, selected = "auto"
|
|
|
828
748
|
code: "local-selected",
|
|
829
749
|
reason: "--remote-build local"
|
|
830
750
|
};
|
|
751
|
+
if (!localEnabled) {
|
|
752
|
+
const reason = mode === "off" ? "remote.buildMode is off" : unsupported ?? (machines === 0 ? "no enabled remote Mac is paired" : null);
|
|
753
|
+
if (reason) throw new OffloadRefusal("auto", `${reason}; local is disabled in remote.buildPoolDisabled`);
|
|
754
|
+
return {
|
|
755
|
+
offload: true,
|
|
756
|
+
code: "local-disabled",
|
|
757
|
+
reason: "local is disabled in remote.buildPoolDisabled"
|
|
758
|
+
};
|
|
759
|
+
}
|
|
831
760
|
if (mode === "off") return {
|
|
832
761
|
offload: false,
|
|
833
762
|
code: "mode-off",
|
|
@@ -891,7 +820,7 @@ function offerProblems(offer, target) {
|
|
|
891
820
|
* A machine that reports no load (a stim-server older than capacity) takes an `auto` build only while
|
|
892
821
|
* every local slot is busy. The rest rank warmest first, then least loaded.
|
|
893
822
|
*/
|
|
894
|
-
function pickOffer({ mode, here, offers, target, selected = "auto" }) {
|
|
823
|
+
function pickOffer({ mode, here, offers, target, localEnabled = true, selected = "auto" }) {
|
|
895
824
|
const slotsFull = here.maxBuilds > 0 && here.builds >= here.maxBuilds;
|
|
896
825
|
const reasons = [];
|
|
897
826
|
const candidates = [];
|
|
@@ -911,7 +840,7 @@ function pickOffer({ mode, here, offers, target, selected = "auto" }) {
|
|
|
911
840
|
const problems = offerProblems(offer, target);
|
|
912
841
|
if (problems.length) return skip(machine, problemCode(problems[0]), problems.map((problem) => problem.reason).join("; "), problems.map((problem) => problem.code));
|
|
913
842
|
const load = offer.capacity.loadPerCore;
|
|
914
|
-
if (selected === "auto" && mode === "auto" && !slotsFull) {
|
|
843
|
+
if (selected === "auto" && localEnabled && mode === "auto" && !slotsFull) {
|
|
915
844
|
if (typeof load !== "number") return skip(machine, "load", "capacity unknown (older stim-server) while this Mac has a free slot");
|
|
916
845
|
if (load >= here.loadPerCore) return skip(machine, "load", `no less loaded (load ${load}/core there, ${here.loadPerCore}/core here)`);
|
|
917
846
|
}
|
|
@@ -1146,6 +1075,7 @@ var BuildConnection = class BuildConnection {
|
|
|
1146
1075
|
});
|
|
1147
1076
|
}
|
|
1148
1077
|
async sendBinary(frame) {
|
|
1078
|
+
if (this.closed) return;
|
|
1149
1079
|
this.socket.send(frame, { binary: true });
|
|
1150
1080
|
while (this.socket.bufferedAmount > MAX_BUFFERED && !this.closed) await new Promise((resolve) => setTimeout(resolve, 5));
|
|
1151
1081
|
}
|
|
@@ -1183,6 +1113,14 @@ var BuildConnection = class BuildConnection {
|
|
|
1183
1113
|
}
|
|
1184
1114
|
forget() {
|
|
1185
1115
|
this.ended = true;
|
|
1116
|
+
this.closed ??= "the connection was closed by this client";
|
|
1117
|
+
for (const resolve of this.pending.values()) resolve({ error: {
|
|
1118
|
+
code: "closed",
|
|
1119
|
+
message: this.closed
|
|
1120
|
+
} });
|
|
1121
|
+
this.pending.clear();
|
|
1122
|
+
this.progress = null;
|
|
1123
|
+
this.binary = null;
|
|
1186
1124
|
clearInterval(this.keepalive);
|
|
1187
1125
|
this.socket.removeAllListeners("close");
|
|
1188
1126
|
openSockets.delete(this.socket);
|
|
@@ -1221,61 +1159,37 @@ function repoIdentity(projectRoot) {
|
|
|
1221
1159
|
lockfile: lock ? createHash("sha256").update(readFileSync(join(repoRoot, lock))).digest("hex") : null
|
|
1222
1160
|
};
|
|
1223
1161
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
repoRoot
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
"
|
|
1232
|
-
"--exclude-standard"
|
|
1233
|
-
], {
|
|
1234
|
-
untrimmed: true,
|
|
1235
|
-
timeoutMs: 12e4
|
|
1236
|
-
});
|
|
1237
|
-
const files = [];
|
|
1238
|
-
for (const path of new Set(listed.split("\0").filter(Boolean))) {
|
|
1239
|
-
const absolute = join(repoRoot, path);
|
|
1240
|
-
let stat;
|
|
1241
|
-
try {
|
|
1242
|
-
stat = lstatSync(absolute);
|
|
1243
|
-
} catch {
|
|
1244
|
-
continue;
|
|
1245
|
-
}
|
|
1246
|
-
if (stat.isSymbolicLink()) {
|
|
1247
|
-
const target = Buffer.from(readlinkSync(absolute));
|
|
1248
|
-
files.push({
|
|
1249
|
-
path,
|
|
1250
|
-
kind: "link",
|
|
1251
|
-
size: target.length,
|
|
1252
|
-
sha256: sha256(target)
|
|
1253
|
-
});
|
|
1254
|
-
} else if (stat.isFile()) {
|
|
1255
|
-
const content = readFileSync(absolute);
|
|
1256
|
-
files.push({
|
|
1257
|
-
path,
|
|
1258
|
-
kind: stat.mode & 73 ? "exec" : "file",
|
|
1259
|
-
size: content.length,
|
|
1260
|
-
sha256: sha256(content)
|
|
1261
|
-
});
|
|
1262
|
-
}
|
|
1162
|
+
const sha256 = (content) => createHash("sha256").update(content).digest("hex");
|
|
1163
|
+
/** Why the native inputs cannot be sent to a remote Mac, such as an ignored file among them, or null when they can. */
|
|
1164
|
+
function nativeTransferRefusal(repoRoot, snapshot) {
|
|
1165
|
+
try {
|
|
1166
|
+
checkNativeTransferMembership(snapshot, gitVisiblePaths(repoRoot));
|
|
1167
|
+
return null;
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
return error.message.split("\n")[0];
|
|
1263
1170
|
}
|
|
1264
|
-
return files;
|
|
1265
1171
|
}
|
|
1266
|
-
const sha256 = (content) => createHash("sha256").update(content).digest("hex");
|
|
1267
1172
|
function blobContent(repoRoot, file) {
|
|
1268
1173
|
const absolute = join(repoRoot, file.path);
|
|
1269
|
-
return file.kind === "link" ? Buffer.from(readlinkSync(absolute)) : readFileSync(absolute);
|
|
1174
|
+
return file.kind === "directory" ? Buffer.alloc(0) : file.kind === "link" ? Buffer.from(readlinkSync(absolute)) : readFileSync(absolute);
|
|
1270
1175
|
}
|
|
1271
1176
|
/** Closes every connection the choice still holds. */
|
|
1272
1177
|
function closeOffload(choice) {
|
|
1273
1178
|
choice.connection.close();
|
|
1274
1179
|
for (const each of choice.runnersUp.splice(0)) each.connection.close();
|
|
1275
1180
|
}
|
|
1181
|
+
const NATIVE_BUILD_FEATURE = {
|
|
1182
|
+
xcode: "native-xcode-build",
|
|
1183
|
+
gradle: "native-gradle-build"
|
|
1184
|
+
};
|
|
1185
|
+
const unsupportedNative = (provider) => `This worker does not support native ${provider === "xcode" ? "Xcode" : "Gradle"} builds.`;
|
|
1186
|
+
const ANDROID_PACKAGE = /^[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+$/;
|
|
1187
|
+
function nativeTransferInput(native) {
|
|
1188
|
+
return native?.provider === "xcode" ? native.snapshot : native?.transfer;
|
|
1189
|
+
}
|
|
1276
1190
|
/** Connects to one paired machine and asks it for an offer; the caller closes the connection it returns. */
|
|
1277
1191
|
async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_MS, offerMs = OFFER_TIMEOUT_MS } = {}) {
|
|
1278
|
-
const target = pinnedEndpoint$1(credential);
|
|
1192
|
+
const target = await pinnedEndpoint$1(credential);
|
|
1279
1193
|
if (typeof target === "string") return {
|
|
1280
1194
|
credential,
|
|
1281
1195
|
failure: target
|
|
@@ -1285,10 +1199,18 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
|
|
|
1285
1199
|
credential,
|
|
1286
1200
|
failure: connection.failure
|
|
1287
1201
|
};
|
|
1202
|
+
if (identity.native && !connection.supports(NATIVE_BUILD_FEATURE[identity.native])) {
|
|
1203
|
+
connection.close();
|
|
1204
|
+
return {
|
|
1205
|
+
credential,
|
|
1206
|
+
failure: unsupportedNative(identity.native)
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
const native = identity.native === "gradle" || identity.native && connection.supports("native-xcode-toolchain") ? identity.native : void 0;
|
|
1288
1210
|
const reply = await connection.request("build.offer", {
|
|
1289
1211
|
repo: identity.repo,
|
|
1290
1212
|
...identity.lockfile ? { lockfile: identity.lockfile } : {},
|
|
1291
|
-
...identity.rubyVersion ? { rubyVersion: identity.rubyVersion } : {}
|
|
1213
|
+
...native ? { native } : identity.rubyVersion ? { rubyVersion: identity.rubyVersion } : {}
|
|
1292
1214
|
}, offerMs);
|
|
1293
1215
|
const failure = replyError(reply);
|
|
1294
1216
|
if (failure || !("result" in reply)) {
|
|
@@ -1317,12 +1239,15 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
|
|
|
1317
1239
|
return `this app is not in a git checkout (${error.message.split("\n")[0]})`;
|
|
1318
1240
|
}
|
|
1319
1241
|
if (namedBuildMachine(selected)) machines = machines.filter((each) => each.machine === selected).slice(0, 1);
|
|
1242
|
+
else machines = machines.filter((each) => automaticMachineEnabled("build", each.machine));
|
|
1320
1243
|
const rubyVersion = readRubyVersion(projectRoot) ?? void 0;
|
|
1321
1244
|
const asked = await Promise.all(machines.map((credential) => probeMachine(credential, {
|
|
1322
1245
|
...identity,
|
|
1323
|
-
rubyVersion
|
|
1246
|
+
rubyVersion,
|
|
1247
|
+
...target.platform !== "macos" ? { native: target.native } : {}
|
|
1324
1248
|
})));
|
|
1325
1249
|
const { order, reasons, candidates } = pickOffer({
|
|
1250
|
+
localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local"),
|
|
1326
1251
|
selected,
|
|
1327
1252
|
mode,
|
|
1328
1253
|
here,
|
|
@@ -1353,9 +1278,14 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
|
|
|
1353
1278
|
target,
|
|
1354
1279
|
offerMs: Date.now() - started,
|
|
1355
1280
|
identity,
|
|
1356
|
-
runnersUp: rest
|
|
1281
|
+
runnersUp: rest,
|
|
1282
|
+
automatic: selected === "auto"
|
|
1357
1283
|
};
|
|
1358
1284
|
}
|
|
1285
|
+
function validArtifactIdentity(request, fingerprint) {
|
|
1286
|
+
if (request.platform === "macos") return true;
|
|
1287
|
+
return request.native?.provider === "gradle" ? fingerprint === null : typeof fingerprint === "string" && fingerprint.length > 0;
|
|
1288
|
+
}
|
|
1359
1289
|
const ARTIFACT_NAME = {
|
|
1360
1290
|
ios: /^[^/]+\.app$/,
|
|
1361
1291
|
android: /^[^/]+\.apk$/,
|
|
@@ -1366,12 +1296,12 @@ const ARTIFACT_NAME = {
|
|
|
1366
1296
|
* `RESUME_WINDOW_MS`, shorter than the machine's grace for a dropped connection, has passed. Returns why it
|
|
1367
1297
|
* could not.
|
|
1368
1298
|
*/
|
|
1369
|
-
async function resumeJob(credential, job, abandoned) {
|
|
1299
|
+
async function resumeJob(credential, job, abandoned, signal, native) {
|
|
1370
1300
|
const deadline = Date.now() + RESUME_WINDOW_MS;
|
|
1371
1301
|
let delay = RESUME_DELAY_MS;
|
|
1372
1302
|
let last = "no attempt";
|
|
1373
1303
|
while (!abandoned()) {
|
|
1374
|
-
const target = pinnedEndpoint$1(credential);
|
|
1304
|
+
const target = await pinnedEndpoint$1(credential);
|
|
1375
1305
|
const connection = typeof target === "string" ? {
|
|
1376
1306
|
failure: target,
|
|
1377
1307
|
refused: false
|
|
@@ -1380,9 +1310,24 @@ async function resumeJob(credential, job, abandoned) {
|
|
|
1380
1310
|
if (connection.refused) return `the machine turned this Mac away (${connection.failure})`;
|
|
1381
1311
|
last = connection.failure;
|
|
1382
1312
|
} else {
|
|
1313
|
+
if (abandoned()) {
|
|
1314
|
+
connection.close();
|
|
1315
|
+
break;
|
|
1316
|
+
}
|
|
1317
|
+
if (native && !connection.supports(NATIVE_BUILD_FEATURE[native])) {
|
|
1318
|
+
connection.close();
|
|
1319
|
+
return unsupportedNative(native);
|
|
1320
|
+
}
|
|
1383
1321
|
const early = [];
|
|
1384
1322
|
connection.onProgress((event) => early.push(event));
|
|
1323
|
+
const cancel = () => connection.close();
|
|
1324
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
1385
1325
|
const reply = await connection.request("build.attach", { job }, OFFER_TIMEOUT_MS);
|
|
1326
|
+
signal?.removeEventListener("abort", cancel);
|
|
1327
|
+
if (abandoned()) {
|
|
1328
|
+
connection.close();
|
|
1329
|
+
break;
|
|
1330
|
+
}
|
|
1386
1331
|
if ("result" in reply) {
|
|
1387
1332
|
const outcome = isJsonObject(reply.result) ? reply.result.outcome : null;
|
|
1388
1333
|
return {
|
|
@@ -1398,17 +1343,18 @@ async function resumeJob(credential, job, abandoned) {
|
|
|
1398
1343
|
}
|
|
1399
1344
|
connection.drop();
|
|
1400
1345
|
}
|
|
1401
|
-
if (Date.now() + delay > deadline) break;
|
|
1402
|
-
await
|
|
1346
|
+
if (abandoned() || Date.now() + delay > deadline) break;
|
|
1347
|
+
await setTimeout$1(delay, void 0, { signal }).catch(() => {});
|
|
1403
1348
|
delay = Math.min(delay * 2, RESUME_MAX_DELAY_MS);
|
|
1404
1349
|
}
|
|
1405
1350
|
return `no connection to it within ${RESUME_WINDOW_MS / 6e4} min (${last})`;
|
|
1406
1351
|
}
|
|
1407
1352
|
/** Mirrors the checkout on the machine: the manifest in pages, then every blob it lacks. */
|
|
1408
|
-
async function syncSource(connection, identity, onEnter) {
|
|
1353
|
+
async function syncSource(connection, identity, onEnter, native) {
|
|
1409
1354
|
onEnter("sync");
|
|
1410
1355
|
const syncStarted = Date.now();
|
|
1411
|
-
const manifest = sourceManifest(identity.repoRoot);
|
|
1356
|
+
const manifest = native && "declaration" in native ? nativeGradleTransfer(join(identity.repoRoot, identity.project), native.declaration).files : native ? nativeTransferManifest(identity.repoRoot, native, sourceManifest(identity.repoRoot)) : sourceManifest(identity.repoRoot);
|
|
1357
|
+
if (native && "declaration" in native && manifestDigest(manifest) !== native.digest) return { failure: "The native Gradle source changed before upload." };
|
|
1412
1358
|
const bySha = new Map(manifest.map((file) => [file.sha256, file]));
|
|
1413
1359
|
const missing = [];
|
|
1414
1360
|
for (let index = 0; index < manifest.length || index === 0;) {
|
|
@@ -1452,12 +1398,20 @@ async function syncSource(connection, identity, onEnter) {
|
|
|
1452
1398
|
digest: manifestDigest(manifest)
|
|
1453
1399
|
};
|
|
1454
1400
|
}
|
|
1401
|
+
function stagedArtifactEscapes(stagingDir, artifactPath, hasContents) {
|
|
1402
|
+
if ((hasContents ? [artifactPath, join(artifactPath, "Contents")] : [artifactPath]).some((path) => lstatSync(path, { throwIfNoEntry: false })?.isSymbolicLink())) return true;
|
|
1403
|
+
if (!existsSync(artifactPath)) return false;
|
|
1404
|
+
const inside = relative(realpathSync(stagingDir), realpathSync(artifactPath));
|
|
1405
|
+
return inside === ".." || inside.startsWith(`..${sep}`) || isAbsolute(inside);
|
|
1406
|
+
}
|
|
1455
1407
|
/**
|
|
1456
1408
|
* Builds on the chosen machine and brings the `.app` or `.apk` back into `stagingDir`, verified against the
|
|
1457
1409
|
* sha256 the machine reports. The caller re-fingerprints and stores it.
|
|
1458
1410
|
*/
|
|
1459
1411
|
async function offloadBuild({ choice, expectedFingerprint, request, stagingDir, onPhase, onEnter, onRecord, note }) {
|
|
1460
1412
|
const { identity } = choice;
|
|
1413
|
+
const native = request.platform !== "macos" ? request.native : void 0;
|
|
1414
|
+
let sourceDigest = null;
|
|
1461
1415
|
const started = Date.now();
|
|
1462
1416
|
const fail = (reason) => {
|
|
1463
1417
|
closeOffload(choice);
|
|
@@ -1467,23 +1421,38 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1467
1421
|
reason: reason.split("\n")[0].slice(0, 300)
|
|
1468
1422
|
};
|
|
1469
1423
|
};
|
|
1424
|
+
const signal = runCancellationSignal();
|
|
1425
|
+
const throwIfCancelled = () => {
|
|
1426
|
+
if (signal?.aborted) throw Object.assign(/* @__PURE__ */ new Error("The offloaded build was cancelled."), { code: "STIM_CANCELLED" });
|
|
1427
|
+
};
|
|
1428
|
+
let settle;
|
|
1429
|
+
let settled = false;
|
|
1430
|
+
const outcome = new Promise((resolve) => {
|
|
1431
|
+
settle = (value) => {
|
|
1432
|
+
settled = true;
|
|
1433
|
+
resolve(value);
|
|
1434
|
+
};
|
|
1435
|
+
});
|
|
1436
|
+
const cancel = () => {
|
|
1437
|
+
settle({
|
|
1438
|
+
ok: false,
|
|
1439
|
+
code: "cancelled"
|
|
1440
|
+
});
|
|
1441
|
+
closeOffload(choice);
|
|
1442
|
+
};
|
|
1443
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
1470
1444
|
try {
|
|
1445
|
+
throwIfCancelled();
|
|
1446
|
+
if (!validArtifactIdentity(request, expectedFingerprint)) return fail("The build request has an invalid reusable artifact identity.");
|
|
1447
|
+
if (native?.provider === "xcode" && native.snapshot.hash !== expectedFingerprint) return fail("The native source snapshot does not match the requested artifact identity.");
|
|
1471
1448
|
let job = null;
|
|
1472
1449
|
let early = [];
|
|
1473
|
-
let settle;
|
|
1474
|
-
let settled = false;
|
|
1475
|
-
const outcome = new Promise((resolve) => {
|
|
1476
|
-
settle = (value) => {
|
|
1477
|
-
settled = true;
|
|
1478
|
-
resolve(value);
|
|
1479
|
-
};
|
|
1480
|
-
});
|
|
1481
1450
|
let resuming = false;
|
|
1482
1451
|
const reattach = async (why) => {
|
|
1483
1452
|
if (resuming || settled) return;
|
|
1484
1453
|
resuming = true;
|
|
1485
1454
|
note(`offload: the connection to ${choice.machine} dropped (${why}); reattaching to the build there`);
|
|
1486
|
-
const resumed = await resumeJob(choice.credential, job, () => settled);
|
|
1455
|
+
const resumed = await resumeJob(choice.credential, job, () => settled, signal, native?.provider);
|
|
1487
1456
|
resuming = false;
|
|
1488
1457
|
if (settled) {
|
|
1489
1458
|
if (typeof resumed !== "string") resumed.connection.close();
|
|
@@ -1526,21 +1495,44 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1526
1495
|
return true;
|
|
1527
1496
|
};
|
|
1528
1497
|
for (;;) {
|
|
1529
|
-
|
|
1498
|
+
if (choice.automatic && !automaticMachineEnabled("build", choice.machine)) {
|
|
1499
|
+
const reason = `${choice.machine} is disabled in remote.buildPoolDisabled`;
|
|
1500
|
+
if (moveOn(reason)) continue;
|
|
1501
|
+
return fail(reason);
|
|
1502
|
+
}
|
|
1503
|
+
if (native && !choice.connection.supports(NATIVE_BUILD_FEATURE[native.provider])) {
|
|
1504
|
+
const reason = unsupportedNative(native.provider);
|
|
1505
|
+
if (moveOn(reason)) continue;
|
|
1506
|
+
return fail(reason);
|
|
1507
|
+
}
|
|
1508
|
+
const synced = await syncSource(choice.connection, identity, onEnter, nativeTransferInput(native));
|
|
1509
|
+
throwIfCancelled();
|
|
1530
1510
|
if ("failure" in synced) {
|
|
1531
1511
|
if (moveOn(synced.failure)) continue;
|
|
1532
1512
|
return fail(synced.failure);
|
|
1533
1513
|
}
|
|
1534
1514
|
({syncMs, uploadedBytes} = synced);
|
|
1515
|
+
sourceDigest = synced.digest;
|
|
1535
1516
|
onPhase("sync", `${synced.files} files, uploaded ${synced.uploaded} (${mb(uploadedBytes)}) in ${seconds(syncMs)}`);
|
|
1536
1517
|
workerStarted = Date.now();
|
|
1537
1518
|
early = [];
|
|
1538
1519
|
choice.connection.onProgress((event) => job === null ? early.push(event) : handle(event));
|
|
1520
|
+
if (choice.automatic) requireAutomaticMachine("build", choice.machine);
|
|
1521
|
+
throwIfCancelled();
|
|
1539
1522
|
const reply = await choice.connection.request("build.start", {
|
|
1540
1523
|
repo: identity.repo,
|
|
1541
1524
|
project: identity.project,
|
|
1542
1525
|
platform: request.platform,
|
|
1543
1526
|
fingerprint: request.platform === "macos" ? synced.digest : expectedFingerprint,
|
|
1527
|
+
...native ? { native: {
|
|
1528
|
+
provider: native.provider,
|
|
1529
|
+
sourceDigest: synced.digest,
|
|
1530
|
+
...native.provider === "xcode" ? {
|
|
1531
|
+
cacheKey: native.cacheKey,
|
|
1532
|
+
arch: native.arch,
|
|
1533
|
+
parameters: native.snapshot.parameters
|
|
1534
|
+
} : { inputs: native.transfer.declaration }
|
|
1535
|
+
} } : {},
|
|
1544
1536
|
...request.platform === "macos" ? { macos: {
|
|
1545
1537
|
product: request.product,
|
|
1546
1538
|
infoPlist: request.infoPlist,
|
|
@@ -1550,6 +1542,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1550
1542
|
} } : {
|
|
1551
1543
|
configuration: request.platform === "ios" ? request.configuration : null,
|
|
1552
1544
|
scheme: request.platform === "ios" ? request.scheme : null,
|
|
1545
|
+
iosProjectPath: request.platform === "ios" ? request.iosProjectPath ?? null : null,
|
|
1553
1546
|
runtime: request.platform === "ios" ? request.runtime : null,
|
|
1554
1547
|
packageName: packageName(join(identity.repoRoot, identity.project)),
|
|
1555
1548
|
isExpo: request.isExpo,
|
|
@@ -1558,6 +1551,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1558
1551
|
},
|
|
1559
1552
|
stimBuild: choice.target.local.stimBuild
|
|
1560
1553
|
});
|
|
1554
|
+
throwIfCancelled();
|
|
1561
1555
|
if ("result" in reply) {
|
|
1562
1556
|
job = reply.result.job;
|
|
1563
1557
|
break;
|
|
@@ -1575,14 +1569,18 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1575
1569
|
}), JOB_TIMEOUT_MS);
|
|
1576
1570
|
const result = await outcome;
|
|
1577
1571
|
clearTimeout(timer);
|
|
1572
|
+
throwIfCancelled();
|
|
1578
1573
|
const { connection, machine } = choice;
|
|
1579
1574
|
connection.onProgress(null);
|
|
1580
1575
|
const workerMs = Date.now() - workerStarted;
|
|
1581
1576
|
if (result.ok !== true) return fail(`${String(result.code ?? "failed")}: ${String(result.message ?? "")}`);
|
|
1577
|
+
if (native && (result.sourceDigest !== sourceDigest || result.fingerprint !== expectedFingerprint)) return fail("The worker returned a different native source or artifact identity.");
|
|
1578
|
+
if (native?.provider === "gradle" && !ANDROID_PACKAGE.test(String(result.androidPackage ?? ""))) return fail("The worker returned no verified native APK package.");
|
|
1582
1579
|
const artifact = result.artifact;
|
|
1583
1580
|
const name = typeof artifact?.name === "string" ? artifact.name : "";
|
|
1584
1581
|
if (!ARTIFACT_NAME[request.platform].test(name) || typeof artifact.sha256 !== "string") return fail(`the machine reported no .${request.platform === "android" ? "apk" : "app"} artifact`);
|
|
1585
1582
|
onEnter("fetch");
|
|
1583
|
+
throwIfCancelled();
|
|
1586
1584
|
const fetchStarted = Date.now();
|
|
1587
1585
|
rmSync(stagingDir, {
|
|
1588
1586
|
recursive: true,
|
|
@@ -1612,6 +1610,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1612
1610
|
const fetched = await connection.request("build.artifact", { job }, 9e5);
|
|
1613
1611
|
connection.onBinary(null);
|
|
1614
1612
|
closeSync(fd);
|
|
1613
|
+
throwIfCancelled();
|
|
1615
1614
|
const fetchFailure = replyError(fetched);
|
|
1616
1615
|
if (fetchFailure || !("result" in fetched)) return fail(`fetch: ${fetchFailure ?? "no reply"}`);
|
|
1617
1616
|
const digest = hash.digest("hex");
|
|
@@ -1624,8 +1623,10 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1624
1623
|
"-C",
|
|
1625
1624
|
stagingDir
|
|
1626
1625
|
], { timeoutMs: 6e5 });
|
|
1626
|
+
throwIfCancelled();
|
|
1627
1627
|
rmSync(archive, { force: true });
|
|
1628
1628
|
const artifactPath = join(stagingDir, name);
|
|
1629
|
+
if (stagedArtifactEscapes(stagingDir, artifactPath, request.platform === "macos")) return fail(`fetch: ${machine} returned ${name} as or through a symbolic link or outside the staging directory`);
|
|
1629
1630
|
if (request.platform === "ios" && !existsSync(join(artifactPath, "Info.plist"))) return fail(`fetch: ${name} has no Info.plist`);
|
|
1630
1631
|
if (request.platform === "android" && !(lstatSync(artifactPath, { throwIfNoEntry: false })?.isFile() ?? false)) return fail(`fetch: ${name} is not a file`);
|
|
1631
1632
|
if (request.platform === "macos") {
|
|
@@ -1647,6 +1648,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1647
1648
|
sha256: digest
|
|
1648
1649
|
} } : {},
|
|
1649
1650
|
compilationCache: request.platform === "ios" ? compilationActivity(result.compilationCache) : COMPILATION_CACHE_UNAVAILABLE,
|
|
1651
|
+
...native?.provider === "gradle" ? { androidPackage: result.androidPackage } : {},
|
|
1650
1652
|
ccache: request.platform === "android" ? ccacheActivity(result.compilationCache) : CCACHE_UNAVAILABLE,
|
|
1651
1653
|
timings: {
|
|
1652
1654
|
offerMs: choice.offerMs,
|
|
@@ -1660,7 +1662,11 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1660
1662
|
}
|
|
1661
1663
|
};
|
|
1662
1664
|
} catch (error) {
|
|
1665
|
+
closeOffload(choice);
|
|
1666
|
+
throwIfCancelled();
|
|
1663
1667
|
return fail(error.message.split("\n")[0] ?? String(error));
|
|
1668
|
+
} finally {
|
|
1669
|
+
signal?.removeEventListener("abort", cancel);
|
|
1664
1670
|
}
|
|
1665
1671
|
}
|
|
1666
1672
|
function packageName(projectRoot) {
|
|
@@ -1754,9 +1760,10 @@ function offloadCheck(projectRoot, targets) {
|
|
|
1754
1760
|
};
|
|
1755
1761
|
probe.connection.close();
|
|
1756
1762
|
resolved ??= targets();
|
|
1763
|
+
const resolvedTargets = await resolved;
|
|
1757
1764
|
const problems = [];
|
|
1758
|
-
for (const target of
|
|
1759
|
-
const labeled =
|
|
1765
|
+
for (const target of resolvedTargets) for (const problem of offerProblems(probe.offer, target)) {
|
|
1766
|
+
const labeled = resolvedTargets.length > 1 && !SHARED_PROBLEMS.has(problem.code) ? {
|
|
1760
1767
|
...problem,
|
|
1761
1768
|
reason: `${PLATFORM_LABEL[target.platform]}: ${problem.reason}`
|
|
1762
1769
|
} : problem;
|
|
@@ -1769,4 +1776,4 @@ function offloadCheck(projectRoot, targets) {
|
|
|
1769
1776
|
};
|
|
1770
1777
|
}
|
|
1771
1778
|
//#endregion
|
|
1772
|
-
export {
|
|
1779
|
+
export { inspectDeviceHostMachines as C, hostingMachines as S, requireLocalBuild as _, nativeTransferRefusal as a, inspectBuildMachines as b, offloadPlacement as c, simulatorRuntime as d, setRemoteLogSink as f, parseBuildMachineOption as g, namedBuildMachine as h, closeOffload as i, placementLoad as l, buildPlacementSettings as m, buildPlacementCandidates as n, offloadBuild as o, OffloadRefusal as p, chooseBuildMachine as r, offloadCheck as s, BuildConnection as t, remotePhaseText as u, resolveBuildMachine as v, configuredMachines as x, resolveBuildPlacement as y };
|
package/dist/collector-run.d.mts
CHANGED
|
@@ -10,8 +10,18 @@ interface ExecOptions {
|
|
|
10
10
|
omitEnv?: readonly string[];
|
|
11
11
|
/** Text written to the child's stdin; `runFile` only. */
|
|
12
12
|
input?: string;
|
|
13
|
+
/** `runFileAsync` only: called with the child right after it starts; a throw kills the child and rejects the call. */
|
|
14
|
+
onSpawn?: (child: ChildProcess) => void;
|
|
13
15
|
/** `runFile` only: return stdout as written, without trimming surrounding whitespace. */
|
|
14
16
|
untrimmed?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* `runFile` and `runFileAsync`: reject nonempty stderr even when the command exits successfully.
|
|
19
|
+
*/
|
|
20
|
+
rejectStderr?: boolean;
|
|
21
|
+
/** `runFile` and `runFileAsync`: run in its own session with all stdio ignored and return ''; the child reports through a file, so a background process it leaves behind cannot hold a pipe open. */
|
|
22
|
+
detachedSilent?: boolean;
|
|
23
|
+
/** `runFile` and `runFileAsync`: exact values replaced with `***` in every string field of a thrown error, including message, stack, stdout, stderr and output. */
|
|
24
|
+
redact?: readonly string[];
|
|
15
25
|
}
|
|
16
26
|
interface Executor {
|
|
17
27
|
run(cmd: string, opts?: ExecOptions): string;
|
package/dist/collector-run.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
+
import { R as deviceSlotKey, W as validateDeviceSlot } from "./config-D0LhTY3S.mjs";
|
|
3
|
+
import { w as workspaceLogsDir } from "./workspace-state-CSIFuuDa.mjs";
|
|
2
4
|
import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { r as
|
|
6
|
-
import { a as
|
|
7
|
-
import {
|
|
8
|
-
import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-CBwCNicO.mjs";
|
|
9
|
-
import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-Bvbf0SGY.mjs";
|
|
5
|
+
import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
|
|
6
|
+
import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-B1B14xND.mjs";
|
|
7
|
+
import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-DXzMMSx6.mjs";
|
|
8
|
+
import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-CK3fpEyZ.mjs";
|
|
9
|
+
import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-VGvNdsv2.mjs";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import { isAbsolute, join, resolve } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
2
|
-
import { t as NO_PROJECT_REFUSAL } from "./project-
|
|
3
|
-
import chalk from "chalk";
|
|
2
|
+
import { t as NO_PROJECT_REFUSAL } from "./project-B8_duAzW.mjs";
|
|
4
3
|
import { quotedPath as quotedPath$1 } from "@stim-cli/core";
|
|
4
|
+
import chalk from "chalk";
|
|
5
5
|
//#region src/diagnostics/launch-error-preview.ts
|
|
6
6
|
function framePriority(frame, root) {
|
|
7
7
|
const normalized = frame.replaceAll("\\", "/");
|