stim 1.16.0 → 1.17.1
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/dist/{activity-BxwdD81S.mjs → activity-IRvJY_ru.mjs} +23 -3
- package/dist/{agent-device-usage-output-Dpih1Tfa.mjs → agent-device-usage-output-BK41vnzN.mjs} +3 -3
- package/dist/{android-Ift4kVvt.mjs → android-B6rDWrTm.mjs} +681 -319
- package/dist/{android-B_NumVyQ.mjs → android-B_YNZy61.mjs} +7 -43
- package/dist/{android-r2rBL8kV.mjs → android-DE4v59Mb.mjs} +12 -3
- package/dist/{android-cas-8U4DPqeR.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
- package/dist/{app-install-CKWdbXIX.mjs → app-install-VPkI5WEg.mjs} +6 -5
- package/dist/{budget-DjrURfQn.mjs → budget-CUDz870h.mjs} +62 -25
- package/dist/{build-plan-DjeSb2Xl.mjs → build-plan-BJSXzsCL.mjs} +345 -86
- package/dist/{idle-DYVymG92.mjs → build-progress-D0WkjCPd.mjs} +170 -233
- package/dist/{build-slots-rUk77xqh.mjs → build-slots-41v_d2x9.mjs} +35 -25
- package/dist/{cli-BkYZ_6hy.mjs → cli-BLQqDGlX.mjs} +17 -17
- package/dist/cli.mjs +1 -1
- package/dist/{client-BTY686R6.mjs → client-CxNotugx.mjs} +313 -44
- package/dist/collector-run.mjs +3 -3
- package/dist/{command-output-DnJMdEY-.mjs → command-output-CDAIFD-8.mjs} +3 -3
- package/dist/{created-devices-D5owjN4C.mjs → created-devices-CpvzBL25.mjs} +1 -1
- package/dist/{dependency-state-B6cMXZab.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
- package/dist/{deps-urbmfXig.mjs → deps-CVxlsRFn.mjs} +1 -1
- package/dist/{dev-client-CroAIjjj.mjs → dev-client-B-XC4uRH.mjs} +2 -2
- package/dist/{device-DZQjF7H5.mjs → device-C8IOoJPv.mjs} +7 -7
- package/dist/device-capacity-ZC4XSZ4R.mjs +580 -0
- package/dist/device-host-worker.mjs +436 -154
- package/dist/{device-ios-BadmeL2V.mjs → device-ios-C2Um-XUR.mjs} +75 -44
- package/dist/{device-lease-D-hLqx1b.mjs → device-lease-DpoS36_u.mjs} +2 -2
- package/dist/{device-lease-run-CqjShqWW.mjs → device-lease-run-B8YltIH_.mjs} +3 -3
- package/dist/{device-pool-CUaEWMMm.mjs → device-pool-3o7s5lo4.mjs} +2 -2
- package/dist/{device-remote-D5WVWqOq.mjs → device-remote-hFSkpfQu.mjs} +12 -12
- package/dist/{doctor-Cimf-gGB.mjs → doctor-BF_435OC.mjs} +40 -58
- package/dist/{error-diagnostics-B9L4Ae0x.mjs → error-diagnostics-C-NMnhrk.mjs} +7 -7
- package/dist/{gc-Bqy4bjEu.mjs → gc-BsWKa_-d.mjs} +313 -30
- package/dist/{gradle-BsO1MdsH.mjs → gradle-bsBRy6i9.mjs} +3 -3
- package/dist/{guide-B_uyKTxW.mjs → guide-DC3n6-NH.mjs} +1776 -655
- package/dist/{guide-status-CjEZMAD4.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
- package/dist/hosted-android-DgU31wY3.mjs +32 -0
- package/dist/{hosted-client-a-WmqE2L.mjs → hosted-client-CdSoH-G6.mjs} +5 -6
- package/dist/hosted-ios-BTaVj4Jb.mjs +15 -0
- package/dist/{hosted-logs-D5g041Q3.mjs → hosted-logs-SxfBvSvc.mjs} +16 -16
- package/dist/{hosted-macos-BSZyIb3y.mjs → hosted-macos-CT9E3meL.mjs} +4 -4
- package/dist/{hosted-ios-CIWelIqf.mjs → hosted-native-CZLOrMrN.mjs} +77 -42
- package/dist/idle-BXG__1BA.mjs +176 -0
- package/dist/{idle-shutdown-CTsDnAde.mjs → idle-shutdown-IGyNV8Cr.mjs} +25 -17
- package/dist/{in-use-DvBw0Kxo.mjs → in-use-CvGOUn-x.mjs} +11 -11
- package/dist/{ios-aq3QoGI3.mjs → ios-C7JuT1bI.mjs} +173 -91
- package/dist/{ios-BaInn3sW.mjs → ios-DSfnPfse.mjs} +4 -4
- package/dist/{ios-device-FfCN_C8p.mjs → ios-device-pAN4t54-.mjs} +1 -1
- package/dist/ios-state-8L3lgum6.mjs +89 -0
- package/dist/{launch-verify-2DBRizjo.mjs → launch-verify-lTnWZikR.mjs} +2 -2
- package/dist/{logs-CHEVK8zD.mjs → logs-DNxKcok9.mjs} +36 -23
- package/dist/{macos-CSYEAFmF.mjs → macos-BEs8cwKx.mjs} +75 -34
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +2 -2
- package/dist/{metro-BeK1ZPz1.mjs → metro-g8NqiJp-.mjs} +1 -1
- package/dist/{metro-gateway-BJ-rxQAB.mjs → metro-gateway-CHqK0p-a.mjs} +22 -3
- package/dist/{named-ports-Bk_YXEmE.mjs → named-ports-C8m8EQs2.mjs} +2 -2
- package/dist/{native-run-NaBrRFtQ.mjs → native-run-D1Q56rAD.mjs} +17 -6
- package/dist/{native-runtime-DBzRnEKS.mjs → native-runtime-YhaSxP4v.mjs} +6 -6
- package/dist/offload-worker.mjs +9 -9
- package/dist/{teardown-CL6vDs2Y.mjs → ownership-BMLqyBgJ.mjs} +603 -26
- package/dist/{ownership-DiA16AsN.mjs → ownership-DyRQru0q.mjs} +2 -2
- package/dist/{ports-R2k4Knz3.mjs → ports-4nYqxPWC.mjs} +2 -2
- package/dist/{prebuild-D2fsca_Z.mjs → prebuild-D7RUMkwN.mjs} +3 -3
- package/dist/{preview-DhVbvPAZ.mjs → preview-C_JjkEy4.mjs} +7 -7
- package/dist/{project-Du91Ilvc.mjs → project-D47Rh0ly.mjs} +7 -2
- package/dist/{recordings-BIXOzVnr.mjs → recordings-BNgsD1Tr.mjs} +1 -1
- package/dist/{reload-rM9jV1fz.mjs → reload-byOjE3P4.mjs} +62 -35
- package/dist/{remote-cache-C8-V13XN.mjs → remote-cache-Ci4DQYYj.mjs} +3 -3
- package/dist/{run-f4vI6EnK.mjs → run-CkE9y0nc.mjs} +1 -1
- package/dist/{server-bare-CpPGmnmO.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
- package/dist/{server-expo-MC0rHlOC.mjs → server-expo-CHTyXD0G.mjs} +2 -2
- package/dist/server-expo-CeakhI8P.mjs +2 -0
- package/dist/{settings-oTSkkNrM.mjs → settings-Cfd-0r2d.mjs} +10 -9
- package/dist/{settings-ZkDzkzvB.mjs → settings-SR9OmW9h.mjs} +3 -3
- package/dist/settings.schema.json +123 -76
- package/dist/{simslim-B8-7AoTI.mjs → simslim-BWNrc3M3.mjs} +3 -3
- package/dist/{slot-launch-B8VrHxn1.mjs → slot-launch-DmjBmpQV.mjs} +8 -8
- package/dist/{start-CX8Ig-U2.mjs → start-BEP-XmEA.mjs} +1 -1
- package/dist/{start-ClDfwXa4.mjs → start-BHIersSm.mjs} +11 -11
- package/dist/{state-DcW6vOd_.mjs → state-BKa8wNN5.mjs} +1 -1
- package/dist/{state-3DwSQIBK.mjs → state-DyaNTgfR.mjs} +1 -1
- package/dist/{state-C1jB7Q8q.mjs → state-PeQiJuIu.mjs} +2 -2
- package/dist/{stats-CEZ_i5je.mjs → stats-Bq4fJOdB.mjs} +7 -4
- package/dist/{status-Cs7VLg9D.mjs → status-CqeWbIWW.mjs} +128 -38
- package/dist/{status-BuvBFeII.mjs → status-CzS4bPO9.mjs} +4 -4
- package/dist/{stop-Bffozsac.mjs → stop-Cj01je8D.mjs} +48 -27
- package/dist/{stop-B0Yxtmiy.mjs → stop-D03prQnW.mjs} +4 -4
- package/dist/{stop-Dt_dM16A.mjs → stop-DOxwkH4j.mjs} +2 -2
- package/dist/{stop-cause-CidxIqup.mjs → stop-cause-rhmGfwvt.mjs} +1 -1
- package/dist/supervisor-run.d.mts +7 -4
- package/dist/supervisor-run.mjs +26 -28
- package/dist/{support-D4aYJniO.mjs → support-BE-tbOP9.mjs} +45 -20
- package/dist/{support-CAP8qDUF.mjs → support-WvD__tSV.mjs} +7 -7
- package/dist/{toolchain-DkUflduf.mjs → toolchain-CdrxgUeA.mjs} +8 -8
- package/dist/{warm-progress-CpGv3Wb6.mjs → warm-progress-DF4JRvYI.mjs} +3 -3
- package/dist/watchman-APYjXSQa.mjs +48 -0
- package/dist/{web-DWUaMp8P.mjs → web-DddUdJzr.mjs} +12 -13
- package/dist/web-run.mjs +4 -4
- package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
- package/dist/{workspace-state-B8-aJ1_5.mjs → workspace-state-DqcCbpE7.mjs} +2 -2
- package/dist/{workspaces-BV4pdHFz.mjs → workspaces-Bcib97-6.mjs} +3 -3
- package/dist/{worktree-K-xj9Db0.mjs → worktree-AK_m-d_m.mjs} +141 -40
- package/dist/{worktree-jnG8Iph5.mjs → worktree-CsAjSmEo.mjs} +1 -1
- package/package.json +5 -5
- package/dist/device-capacity-BHwxNBlu.mjs +0 -136
- package/dist/ios-state-DS5UpYTH.mjs +0 -48
- package/dist/machines-BIBUdhpj.mjs +0 -265
- package/dist/ownership-hCkPzGmr.mjs +0 -571
- package/dist/server-expo-CVqO2c35.mjs +0 -2
|
@@ -3,23 +3,23 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
//#region bin/cli.ts
|
|
5
5
|
const commands = /* @__PURE__ */ new Map([
|
|
6
|
-
["doctor", () => import("./doctor-
|
|
7
|
-
["worktree", () => import("./worktree-
|
|
8
|
-
["start", () => import("./start-
|
|
9
|
-
["ports", () => import("./ports-
|
|
10
|
-
["stop", () => import("./stop-
|
|
11
|
-
["ios", () => import("./ios-
|
|
12
|
-
["android", () => import("./android-
|
|
13
|
-
["web", () => import("./web-
|
|
14
|
-
["macos", () => import("./macos-
|
|
15
|
-
["reload", () => import("./reload-
|
|
16
|
-
["device", () => import("./device-
|
|
17
|
-
["logs", () => import("./logs-
|
|
18
|
-
["settings", () => import("./settings-
|
|
19
|
-
["status", () => import("./status-
|
|
20
|
-
["stats", () => import("./stats-
|
|
21
|
-
["gc", () => import("./gc-
|
|
22
|
-
["guide", () => import("./guide-
|
|
6
|
+
["doctor", () => import("./doctor-BF_435OC.mjs")],
|
|
7
|
+
["worktree", () => import("./worktree-CsAjSmEo.mjs")],
|
|
8
|
+
["start", () => import("./start-BEP-XmEA.mjs")],
|
|
9
|
+
["ports", () => import("./ports-4nYqxPWC.mjs")],
|
|
10
|
+
["stop", () => import("./stop-DOxwkH4j.mjs")],
|
|
11
|
+
["ios", () => import("./ios-C7JuT1bI.mjs")],
|
|
12
|
+
["android", () => import("./android-B6rDWrTm.mjs")],
|
|
13
|
+
["web", () => import("./web-DddUdJzr.mjs")],
|
|
14
|
+
["macos", () => import("./macos-BEs8cwKx.mjs")],
|
|
15
|
+
["reload", () => import("./reload-byOjE3P4.mjs")],
|
|
16
|
+
["device", () => import("./device-C8IOoJPv.mjs")],
|
|
17
|
+
["logs", () => import("./logs-DNxKcok9.mjs")],
|
|
18
|
+
["settings", () => import("./settings-SR9OmW9h.mjs")],
|
|
19
|
+
["status", () => import("./status-CqeWbIWW.mjs")],
|
|
20
|
+
["stats", () => import("./stats-Bq4fJOdB.mjs")],
|
|
21
|
+
["gc", () => import("./gc-BsWKa_-d.mjs")],
|
|
22
|
+
["guide", () => import("./guide-DC3n6-NH.mjs")]
|
|
23
23
|
]);
|
|
24
24
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
25
25
|
const program = new Command();
|
package/dist/cli.mjs
CHANGED
|
@@ -4,6 +4,6 @@ const encode = (version) => version.split(".", 3).reduce((sum, part) => sum * 1e
|
|
|
4
4
|
if (encode(process.versions.node) < encode("22.12.0")) {
|
|
5
5
|
process.stderr.write(`STIM_NODE_UNSUPPORTED: Stim needs Node 22.12.0 or later; this is Node ${process.versions.node} at ${process.execPath}. To run Stim where a project pins an older Node, see https://stim.appandflow.com/docs/requirements#older-node-pins\n`);
|
|
6
6
|
process.exitCode = 1;
|
|
7
|
-
} else import("./cli-
|
|
7
|
+
} else import("./cli-BLQqDGlX.mjs");
|
|
8
8
|
//#endregion
|
|
9
9
|
export {};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
2
|
import { _ as loadConfig$1, d as getConfigDir } from "./config-D0DbpZtM.mjs";
|
|
3
|
-
import { w as withDirLock } from "./workspace-state-
|
|
4
|
-
import { T as CCACHE_UNAVAILABLE, a as toolchainMismatches, l as COMPILATION_CACHE_UNAVAILABLE, s as manifestDigest } from "./toolchain-
|
|
3
|
+
import { w as withDirLock } from "./workspace-state-DqcCbpE7.mjs";
|
|
4
|
+
import { T as CCACHE_UNAVAILABLE, a as toolchainMismatches, l as COMPILATION_CACHE_UNAVAILABLE, s as manifestDigest } from "./toolchain-CdrxgUeA.mjs";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync, writeSync } from "node:fs";
|
|
7
7
|
import { basename, dirname, join, relative } from "node:path";
|
|
8
8
|
import { InvalidArgumentError } from "commander";
|
|
9
|
-
import { OFFLOAD_MODES, buildMachinesFile, buildMachinesLock, endpoint, findPeer as findPeer$1, isJsonObject, parseMachine, parseMachine as parseMachine$1, pinnedEndpoint, readBuildMachines, saturation } from "@stim-cli/core/state";
|
|
9
|
+
import { OFFLOAD_MODES, acceptsShape, buildMachinesFile, buildMachinesLock, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, endpoint, findPeer as findPeer$1, isJsonObject, parseMachine, parseMachine as parseMachine$1, pinnedEndpoint, readBuildMachines, readDeviceHostMachines, saturation, settingDefinition } from "@stim-cli/core/state";
|
|
10
|
+
import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
10
11
|
import { hostname } from "node:os";
|
|
11
12
|
import { WebSocket } from "ws";
|
|
12
13
|
//#region src/offload/access-ticket.ts
|
|
@@ -93,16 +94,280 @@ function pinnedEndpoint$1(credential, status = tailscaleStatus) {
|
|
|
93
94
|
return pinnedEndpoint(credential, parseMachine(credential.machine) ? status() : null);
|
|
94
95
|
}
|
|
95
96
|
//#endregion
|
|
97
|
+
//#region src/device-host/machines.ts
|
|
98
|
+
function note$1(title, detail, fix = null) {
|
|
99
|
+
return {
|
|
100
|
+
code: "device-host-machine",
|
|
101
|
+
level: "note",
|
|
102
|
+
title,
|
|
103
|
+
detail,
|
|
104
|
+
fix
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const approval$1 = (machine, id) => `A person on ${machine} approves it with \`stim-server devices grant ${id} --device-host\`.`;
|
|
108
|
+
function configuredMachines() {
|
|
109
|
+
const remote = loadConfig$1()?.remote;
|
|
110
|
+
if (remote !== void 0 && !isJsonObject(remote)) return null;
|
|
111
|
+
const machines = remote?.machines;
|
|
112
|
+
if (machines === void 0) return [];
|
|
113
|
+
return acceptsShape(settingDefinition("remote.machines"), machines) ? machines : null;
|
|
114
|
+
}
|
|
115
|
+
/** The `remote.machines` entries this Mac asked for device-host access, in setting order; null when the setting is invalid. */
|
|
116
|
+
function hostingMachines() {
|
|
117
|
+
const configured = configuredMachines();
|
|
118
|
+
if (configured === null) return null;
|
|
119
|
+
try {
|
|
120
|
+
const asked = readDeviceHostMachines();
|
|
121
|
+
return configured.filter((machine) => asked.some((each) => each.machine === machine));
|
|
122
|
+
} catch {
|
|
123
|
+
return configured;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function store(machines) {
|
|
127
|
+
withDirLock(deviceHostMachinesLock(), () => {
|
|
128
|
+
const file = deviceHostMachinesFile();
|
|
129
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
130
|
+
try {
|
|
131
|
+
writeFileSync(tmp, `${JSON.stringify({
|
|
132
|
+
version: 1,
|
|
133
|
+
machines
|
|
134
|
+
}, null, 2)}\n`, { mode: 384 });
|
|
135
|
+
renameSync(tmp, file);
|
|
136
|
+
} finally {
|
|
137
|
+
rmSync(tmp, { force: true });
|
|
138
|
+
}
|
|
139
|
+
}, { ensureParent: () => mkdirSync(getConfigDir(), { recursive: true }) });
|
|
140
|
+
}
|
|
141
|
+
async function request(machine, peer, port, deviceName, io) {
|
|
142
|
+
const ticket = readAccessTicket();
|
|
143
|
+
const reply = await io.hello(endpoint(peer, port), {
|
|
144
|
+
request: "device-host",
|
|
145
|
+
deviceName,
|
|
146
|
+
...ticket ? { setupTicket: ticket.ticket } : {}
|
|
147
|
+
});
|
|
148
|
+
if (!("result" in reply) || reply.result?.approval?.state !== "pending" || typeof reply.result.deviceToken !== "string" || !reply.result.deviceToken || typeof reply.result.device?.id !== "string" || !reply.result.device.id || typeof reply.result.approval.expiresAt !== "string" || !reply.result.approval.expiresAt) return {
|
|
149
|
+
report: {
|
|
150
|
+
machine,
|
|
151
|
+
dnsName: peer.dnsName,
|
|
152
|
+
state: "unreachable"
|
|
153
|
+
},
|
|
154
|
+
finding: note$1(`Could not ask ${machine} for hosting access`, "The worker did not return a pending request.")
|
|
155
|
+
};
|
|
156
|
+
const credential = {
|
|
157
|
+
machine,
|
|
158
|
+
nodeId: peer.nodeId,
|
|
159
|
+
dnsName: peer.dnsName,
|
|
160
|
+
deviceId: reply.result.device.id,
|
|
161
|
+
deviceToken: reply.result.deviceToken,
|
|
162
|
+
state: "pending",
|
|
163
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
164
|
+
...ticket ? { ticketHash: ticket.ticketHash } : {}
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
report: {
|
|
168
|
+
machine,
|
|
169
|
+
dnsName: peer.dnsName,
|
|
170
|
+
state: "pending",
|
|
171
|
+
deviceId: credential.deviceId,
|
|
172
|
+
requestedAt: credential.requestedAt
|
|
173
|
+
},
|
|
174
|
+
finding: note$1(`Asked ${machine} for hosting access`, `The request lapses at ${reply.result.approval.expiresAt}.`, approval$1(machine, credential.deviceId)),
|
|
175
|
+
credential
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** Reports the device-host approval of each remote Mac, separate from its build approval. Only --fix asks or forgets credentials; every token stays pinned. */
|
|
179
|
+
async function inspectDeviceHostMachines({ fix }, io = realIo, entries = configuredMachines()) {
|
|
180
|
+
if (entries === null) return {
|
|
181
|
+
findings: [note$1("Invalid remote.machines setting", "Use a remote object with machines as an array of tailnet names. Existing hosting credentials and pinned nodes are preserved.", "Run `stim guide settings` and correct the setting before running doctor again.")],
|
|
182
|
+
machines: []
|
|
183
|
+
};
|
|
184
|
+
const unavailable = (state, finding) => ({
|
|
185
|
+
findings: [finding],
|
|
186
|
+
machines: entries.map((machine) => ({
|
|
187
|
+
machine,
|
|
188
|
+
state
|
|
189
|
+
}))
|
|
190
|
+
});
|
|
191
|
+
const unreadable = () => unavailable("credentials-unavailable", note$1("Hosting credentials are unreadable", `Stim preserves ${deviceHostMachinesFile()} and its pinned nodes.`, "Restore the existing file from a trusted backup or restore read access before running doctor again."));
|
|
192
|
+
if (!entries.length) {
|
|
193
|
+
if (!fix) return {
|
|
194
|
+
findings: [],
|
|
195
|
+
machines: []
|
|
196
|
+
};
|
|
197
|
+
try {
|
|
198
|
+
if (!readDeviceHostMachines().length) return {
|
|
199
|
+
findings: [],
|
|
200
|
+
machines: []
|
|
201
|
+
};
|
|
202
|
+
} catch {
|
|
203
|
+
return unreadable();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const claim = tryAcquireClaim({
|
|
207
|
+
root: deviceHostMachinesClaims(),
|
|
208
|
+
mode: "exclusive",
|
|
209
|
+
label: "device-host approval"
|
|
210
|
+
});
|
|
211
|
+
if (!claim.acquired) {
|
|
212
|
+
releaseClaim(claim.pending);
|
|
213
|
+
return unavailable("busy", note$1("Device-host approval is in use", "Another doctor run holds the hosting credential claim. Run doctor again after it finishes."));
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
let credentials;
|
|
217
|
+
try {
|
|
218
|
+
credentials = readDeviceHostMachines();
|
|
219
|
+
} catch {
|
|
220
|
+
return unreadable();
|
|
221
|
+
}
|
|
222
|
+
if (fix) {
|
|
223
|
+
const kept = credentials.filter((each) => entries.includes(each.machine));
|
|
224
|
+
if (kept.length !== credentials.length) {
|
|
225
|
+
store(kept);
|
|
226
|
+
credentials = kept;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (!entries.length) return {
|
|
230
|
+
findings: [],
|
|
231
|
+
machines: []
|
|
232
|
+
};
|
|
233
|
+
const status = io.status();
|
|
234
|
+
if (!isJsonObject(status)) return unavailable("tailscale-off", note$1("Remote Macs are unreachable", "remote.machines names remote Macs, but Tailscale is not running."));
|
|
235
|
+
const self = isJsonObject(status.Self) ? status.Self : {};
|
|
236
|
+
const deviceName = (typeof self.HostName === "string" && self.HostName ? self.HostName : hostname()).replace(/[\p{Cc}\p{Cf}]/gu, "").trim().slice(0, 64) || "Mac";
|
|
237
|
+
const inspected = {
|
|
238
|
+
findings: [],
|
|
239
|
+
machines: []
|
|
240
|
+
};
|
|
241
|
+
const namedNodes = /* @__PURE__ */ new Set();
|
|
242
|
+
for (const machine of new Set(entries)) {
|
|
243
|
+
const parsed = parseMachine$1(machine);
|
|
244
|
+
if (!parsed) {
|
|
245
|
+
inspected.machines.push({
|
|
246
|
+
machine,
|
|
247
|
+
state: "invalid"
|
|
248
|
+
});
|
|
249
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} is not a tailnet name`, "Expected `name` or `name:port`."));
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const current = io.status();
|
|
253
|
+
if (!isJsonObject(current)) {
|
|
254
|
+
inspected.machines.push({
|
|
255
|
+
machine,
|
|
256
|
+
state: "tailscale-off"
|
|
257
|
+
});
|
|
258
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} is unreachable`, "Tailscale stopped before this connection."));
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const peer = findPeer$1(current, parsed.name);
|
|
262
|
+
if (peer === "missing" || peer === "ambiguous") {
|
|
263
|
+
inspected.machines.push({
|
|
264
|
+
machine,
|
|
265
|
+
state: "not-on-tailnet"
|
|
266
|
+
});
|
|
267
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} is not on this tailnet`, peer === "missing" ? "No peer has that name." : "Several peers match that name."));
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const nodeRoute = `${peer.nodeId}:${parsed.port}`;
|
|
271
|
+
if (namedNodes.has(nodeRoute)) {
|
|
272
|
+
inspected.machines.push({
|
|
273
|
+
machine,
|
|
274
|
+
dnsName: peer.dnsName,
|
|
275
|
+
state: "invalid"
|
|
276
|
+
});
|
|
277
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} repeats a named node`, "Name each tailnet node and serve port only once in remote.machines."));
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
namedNodes.add(nodeRoute);
|
|
281
|
+
const credential = credentials.find((each) => each.machine === machine);
|
|
282
|
+
const known = {
|
|
283
|
+
machine,
|
|
284
|
+
dnsName: peer.dnsName,
|
|
285
|
+
...credential ? {
|
|
286
|
+
deviceId: credential.deviceId,
|
|
287
|
+
requestedAt: credential.requestedAt
|
|
288
|
+
} : {}
|
|
289
|
+
};
|
|
290
|
+
if (credential && credential.nodeId !== peer.nodeId) {
|
|
291
|
+
inspected.machines.push({
|
|
292
|
+
...known,
|
|
293
|
+
state: "node-changed"
|
|
294
|
+
});
|
|
295
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} is a different tailnet node`, "Stim refuses to connect or send the saved token.", `If that Mac was replaced, remove ${machine} from remote.machines, run \`stim doctor --fix\`, then add it back and run \`stim doctor --fix\` again to request approval on the new node.`));
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
let ask = !credential && fix;
|
|
299
|
+
if (credential) {
|
|
300
|
+
const reply = await io.hello(endpoint(peer, parsed.port), { deviceToken: credential.deviceToken });
|
|
301
|
+
if ("result" in reply && reply.result?.device?.id === credential.deviceId && Array.isArray(reply.result.capabilities) && reply.result.capabilities.includes("device-host")) {
|
|
302
|
+
if (credential.state !== "approved") {
|
|
303
|
+
credentials = credentials.map((each) => each.machine === machine ? {
|
|
304
|
+
...each,
|
|
305
|
+
state: "approved"
|
|
306
|
+
} : each);
|
|
307
|
+
store(credentials);
|
|
308
|
+
}
|
|
309
|
+
const host = readHostPermissions(reply.result.host);
|
|
310
|
+
if (host && (host.screenRecording === false || host.accessibility === false)) {
|
|
311
|
+
const panes = [...host.screenRecording === false ? ["Screen & System Audio Recording (Screen Recording on macOS 14)"] : [], ...host.accessibility === false ? ["Device Control and Data Access (Accessibility on macOS 26 and earlier)"] : []];
|
|
312
|
+
const detail = [...host.screenRecording === false ? ["Viewing hosted macOS apps needs Screen Recording."] : [], ...host.accessibility === false ? ["Controlling them needs the control permission."] : []];
|
|
313
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} needs ${panes.join(" and ")} for ${host.name}`, detail.join(" "), `On ${machine}, approve ${host.name} in System Settings > Privacy & Security, or run \`stim-server service install\` there again to show the requests.`));
|
|
314
|
+
}
|
|
315
|
+
inspected.machines.push({
|
|
316
|
+
...known,
|
|
317
|
+
state: "approved",
|
|
318
|
+
...host ? { host } : {}
|
|
319
|
+
});
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const pending = "error" in reply && reply.error?.code === "approval-pending";
|
|
323
|
+
const revoked = "error" in reply && reply.error?.code === "unauthorized";
|
|
324
|
+
const ticket = fix && pending && credential.state !== "approved" ? readAccessTicket() : void 0;
|
|
325
|
+
ask = fix && (revoked || !!ticket && credential.ticketHash !== ticket.ticketHash);
|
|
326
|
+
if (pending && !ask) {
|
|
327
|
+
inspected.machines.push({
|
|
328
|
+
...known,
|
|
329
|
+
state: "pending"
|
|
330
|
+
});
|
|
331
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} has not approved this Mac for device hosting yet`, `Requested at ${credential.requestedAt}.`, approval$1(machine, credential.deviceId)));
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (!ask) {
|
|
335
|
+
inspected.machines.push({
|
|
336
|
+
...known,
|
|
337
|
+
state: revoked ? "revoked" : "unreachable"
|
|
338
|
+
});
|
|
339
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} ${revoked ? "no longer accepts this Mac for device hosting" : "did not confirm hosting access"}`, "The saved token and pinned node are preserved.", revoked ? "Run `stim doctor --fix` to ask again." : `Check stim-server and its tailnet serve route on ${machine}, then run doctor again.`));
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (ask) {
|
|
344
|
+
const result = await request(machine, peer, parsed.port, deviceName, io);
|
|
345
|
+
if (result.credential) {
|
|
346
|
+
credentials = [...credentials.filter((each) => each.machine !== machine), result.credential];
|
|
347
|
+
store(credentials);
|
|
348
|
+
}
|
|
349
|
+
inspected.machines.push(result.report);
|
|
350
|
+
inspected.findings.push(result.finding);
|
|
351
|
+
} else {
|
|
352
|
+
inspected.machines.push({
|
|
353
|
+
...known,
|
|
354
|
+
state: "not-asked"
|
|
355
|
+
});
|
|
356
|
+
inspected.findings.push(note$1(`Remote Mac ${machine} has not approved this Mac for device hosting`, "This Mac has not asked for hosting access.", "Run `stim doctor --fix` to ask."));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return inspected;
|
|
360
|
+
} finally {
|
|
361
|
+
releaseClaim(claim.acquired);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
//#endregion
|
|
96
365
|
//#region src/offload/build-machines.ts
|
|
97
|
-
/** The
|
|
98
|
-
function pairedMachines(entries = configuredMachines()) {
|
|
366
|
+
/** The `remote.machines` entries that this Mac asked for build access, in that order. */
|
|
367
|
+
function pairedMachines(entries = configuredMachines() ?? []) {
|
|
99
368
|
const credentials = readBuildMachines();
|
|
100
369
|
return entries.flatMap((entry) => credentials.filter((each) => each.machine === entry));
|
|
101
370
|
}
|
|
102
|
-
function configuredMachines() {
|
|
103
|
-
const machines = loadConfig$1()?.offload?.machines;
|
|
104
|
-
return Array.isArray(machines) ? machines.filter((entry) => typeof entry === "string") : [];
|
|
105
|
-
}
|
|
106
371
|
function updateCredentials(change) {
|
|
107
372
|
const dir = getConfigDir();
|
|
108
373
|
withDirLock(buildMachinesLock(), () => {
|
|
@@ -154,7 +419,7 @@ function problemFix(code, entry) {
|
|
|
154
419
|
case "unreachable": return `Check that stim-server runs on ${entry} and that its tailscale serve route answers, then run \`stim doctor\` again. To keep it running there, run \`stim-server service install --serve\` on ${entry}.`;
|
|
155
420
|
case "checkout": return "Offload syncs the files git lists; run Stim from a git checkout of the app.";
|
|
156
421
|
case "stim-build": return `Update stim-server on ${entry} to the same Stim build as this Mac: there, run \`stim-server service update --release <version>\` for this Mac's release, or \`--from <dir>\` with the packed packages of this Mac's checkout.`;
|
|
157
|
-
case "arch": return "Use a
|
|
422
|
+
case "arch": return "Use a remote Mac with the same CPU architecture as this Mac.";
|
|
158
423
|
case "xcode":
|
|
159
424
|
case "simulator-sdk":
|
|
160
425
|
case "macos-sdk": return `Install and select the same Xcode on ${entry} and this Mac (\`xcode-select -p\` on each).`;
|
|
@@ -166,8 +431,8 @@ function problemFix(code, entry) {
|
|
|
166
431
|
case "ndk":
|
|
167
432
|
case "build-tools":
|
|
168
433
|
case "compile-sdk": return `Install the missing package with sdkmanager in the Android SDK stim-server on ${entry} uses (its ANDROID_HOME, else ~/Library/Android/sdk).`;
|
|
169
|
-
case "disk": return `Free space on ${entry}'s worker root (
|
|
170
|
-
case "busy": return `Builds stay on this Mac until ${entry} has capacity. On ${entry},
|
|
434
|
+
case "disk": return `Free space on ${entry}'s worker root (server.workerRoot there).`;
|
|
435
|
+
case "busy": return `Builds stay on this Mac until ${entry} has capacity. On ${entry}, server.maxLoadPerCore sets the load it accepts and concurrency.maxBuilds how many of its own builds it runs; it takes one offloaded build at a time.`;
|
|
171
436
|
}
|
|
172
437
|
}
|
|
173
438
|
const TRANSIENT = /* @__PURE__ */ new Set(["unreachable", "busy"]);
|
|
@@ -175,7 +440,7 @@ function offloadFindings(entry, problems) {
|
|
|
175
440
|
return problems.map((problem) => ({
|
|
176
441
|
code: `build-machine-${problem.code}`,
|
|
177
442
|
level: TRANSIENT.has(problem.code) ? "note" : "cost",
|
|
178
|
-
title: `
|
|
443
|
+
title: `Remote Mac ${entry} ${PROBLEM_TITLES[problem.code]}`,
|
|
179
444
|
detail: `Builds fall back to this Mac: ${problem.reason}.`,
|
|
180
445
|
fix: problemFix(problem.code, entry)
|
|
181
446
|
}));
|
|
@@ -227,7 +492,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
227
492
|
machine: entry,
|
|
228
493
|
state: "invalid"
|
|
229
494
|
},
|
|
230
|
-
finding: note(`
|
|
495
|
+
finding: note(`Remote Mac ${entry} is not a tailnet name`, "Expected `name` or `name:port`.")
|
|
231
496
|
};
|
|
232
497
|
const peer = findPeer$1(status, parsed.name);
|
|
233
498
|
if (peer === "missing" || peer === "ambiguous") {
|
|
@@ -237,7 +502,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
237
502
|
machine: entry,
|
|
238
503
|
state: "not-on-tailnet"
|
|
239
504
|
},
|
|
240
|
-
finding: note(`
|
|
505
|
+
finding: note(`Remote Mac ${entry} is not on this tailnet`, detail)
|
|
241
506
|
};
|
|
242
507
|
}
|
|
243
508
|
const credential = readBuildMachines().find((each) => each.machine === entry);
|
|
@@ -252,7 +517,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
252
517
|
deviceId: credential.deviceId,
|
|
253
518
|
requestedAt: credential.requestedAt
|
|
254
519
|
},
|
|
255
|
-
finding: note(`
|
|
520
|
+
finding: note(`Remote Mac ${entry} is a different tailnet node`, `This Mac paired with node ${credential.nodeId}, but ${peer.dnsName} is now node ${peer.nodeId}. Stim does not connect to it.`, `If that Mac was replaced, remove ${entry} from remote.machines, run \`stim doctor --fix\` to forget the old pairing, then add it back and run \`stim doctor --fix\` again.`)
|
|
256
521
|
};
|
|
257
522
|
if (!credential) {
|
|
258
523
|
if (fix) return requestAccess(entry, peer, parsed.port, deviceName, io);
|
|
@@ -261,7 +526,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
261
526
|
...known,
|
|
262
527
|
state: "not-asked"
|
|
263
528
|
},
|
|
264
|
-
finding: note(`
|
|
529
|
+
finding: note(`Remote Mac ${entry} has not approved this Mac for builds`, "This Mac has not asked it for build access.", "Run `stim doctor --fix` to ask.")
|
|
265
530
|
};
|
|
266
531
|
}
|
|
267
532
|
const paired = {
|
|
@@ -311,7 +576,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
311
576
|
...paired,
|
|
312
577
|
state: "pending"
|
|
313
578
|
},
|
|
314
|
-
finding: note(`
|
|
579
|
+
finding: note(`Remote Mac ${entry} has not approved this Mac for builds yet`, `Requested at ${credential.requestedAt}.`, approval(entry, credential.deviceId))
|
|
315
580
|
};
|
|
316
581
|
}
|
|
317
582
|
if ("error" in reply && reply.error.code === "unauthorized") {
|
|
@@ -321,7 +586,7 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
321
586
|
...paired,
|
|
322
587
|
state: "revoked"
|
|
323
588
|
},
|
|
324
|
-
finding: note(`
|
|
589
|
+
finding: note(`Remote Mac ${entry} no longer accepts this Mac for builds`, `${reply.error.message} It was revoked, or the request lapsed before approval.`, "Run `stim doctor --fix` to ask again.")
|
|
325
590
|
};
|
|
326
591
|
}
|
|
327
592
|
const reason = "failed" in reply ? reply.failed : "error" in reply ? reply.error.message : "unexpected reply";
|
|
@@ -330,17 +595,21 @@ async function inspectMachine(entry, status, deviceName, fix, io, check) {
|
|
|
330
595
|
...paired,
|
|
331
596
|
state: "unreachable"
|
|
332
597
|
},
|
|
333
|
-
finding: note(`Could not reach
|
|
598
|
+
finding: note(`Could not reach remote Mac ${entry}`, reason, `Check that stim-server runs on ${entry}. To keep it running there, run \`stim-server service install --serve\` on ${entry}.`)
|
|
334
599
|
};
|
|
335
600
|
}
|
|
336
601
|
/**
|
|
337
|
-
* Doctor findings and a report for each `
|
|
602
|
+
* Doctor findings and a report for each `remote.machines` entry. The worker's node is pinned when access is
|
|
338
603
|
* requested; a later connection goes only to the current MagicDNS name of that same node, checked before the token
|
|
339
604
|
* is sent. With `fix`, requests access from a named machine this Mac holds no pairing for, requests again when the
|
|
340
605
|
* pinned node forgot this Mac or, with `STIM_ACCESS_TICKET` set, when a pending request carries another ticket, and forgets pairings of machines no longer named. With `check`, each approved
|
|
341
606
|
* machine is asked for one build offer and reports every reason it would not take this project's build.
|
|
342
607
|
*/
|
|
343
608
|
async function inspectBuildMachines({ fix, check = null }, io = realIo, entries = configuredMachines()) {
|
|
609
|
+
if (entries === null) return {
|
|
610
|
+
findings: [note("Invalid remote.machines setting", "Use a remote object with machines as an array of tailnet names. Existing credentials and pinned nodes are preserved.", "Run `stim guide settings` and correct the setting before running doctor again.")],
|
|
611
|
+
machines: []
|
|
612
|
+
};
|
|
344
613
|
const unnamed = (each) => !entries.includes(each.machine);
|
|
345
614
|
if (fix && readBuildMachines().some(unnamed)) updateCredentials((credentials) => credentials.filter((each) => !unnamed(each)));
|
|
346
615
|
if (entries.length === 0) return {
|
|
@@ -349,7 +618,7 @@ async function inspectBuildMachines({ fix, check = null }, io = realIo, entries
|
|
|
349
618
|
};
|
|
350
619
|
const status = io.status();
|
|
351
620
|
if (!isJsonObject(status)) return {
|
|
352
|
-
findings: [note("
|
|
621
|
+
findings: [note("Remote Macs are unreachable", "remote.machines names remote Macs, but Tailscale is not running.")],
|
|
353
622
|
machines: entries.map((machine) => ({
|
|
354
623
|
machine,
|
|
355
624
|
state: "tailscale-off"
|
|
@@ -373,14 +642,14 @@ async function inspectBuildMachines({ fix, check = null }, io = realIo, entries
|
|
|
373
642
|
//#region src/offload/selection.ts
|
|
374
643
|
var OffloadRefusal = class extends Error {
|
|
375
644
|
code = "STIM_OFFLOAD_REFUSED";
|
|
376
|
-
remedy = "Run stim doctor --fix to ask for build access if not paired. On the worker, a person finds the id with stim-server devices and approves it with stim-server devices grant <id> --build. Check stim settings get
|
|
645
|
+
remedy = "Run stim doctor --fix to ask for build access if not paired. On the worker, a person finds the id with stim-server devices and approves it with stim-server devices grant <id> --build. Check stim settings get remote.machines, or rerun with --remote-build auto or --remote-build local.";
|
|
377
646
|
constructor(machine, reason) {
|
|
378
647
|
super(reason.startsWith(`${machine}: `) ? reason : `${machine}: ${reason}`);
|
|
379
648
|
}
|
|
380
649
|
};
|
|
381
650
|
function resolveBuildMachine(flag, env, setting) {
|
|
382
651
|
const selected = flag ?? (env?.trim() || void 0) ?? setting ?? "auto";
|
|
383
|
-
if (typeof selected !== "string" || !selected.trim() || !parseMachine(selected)) throw Object.assign(/* @__PURE__ */ new Error("--build
|
|
652
|
+
if (typeof selected !== "string" || !selected.trim() || !parseMachine(selected)) throw Object.assign(/* @__PURE__ */ new Error("--remote-build / remote.build must be auto, local, or a tailnet machine name."), { code: "STIM_BAD_ARG" });
|
|
384
653
|
const trimmed = selected.trim();
|
|
385
654
|
const reserved = trimmed.toLowerCase();
|
|
386
655
|
return reserved === "auto" || reserved === "local" ? reserved : trimmed;
|
|
@@ -403,16 +672,16 @@ function requireConfiguredMachine(selected, machines) {
|
|
|
403
672
|
const candidate = parseMachine(entry);
|
|
404
673
|
return candidate?.name === parsed.name && candidate.port === parsed.port;
|
|
405
674
|
});
|
|
406
|
-
if (!match) throw new OffloadRefusal(selected, `not listed in
|
|
675
|
+
if (!match) throw new OffloadRefusal(selected, `not listed in remote.machines (configured: ${entries.join(", ") || "none"})`);
|
|
407
676
|
return match;
|
|
408
677
|
}
|
|
409
678
|
function resolveBuildPlacement(flag) {
|
|
410
|
-
const
|
|
679
|
+
const remote = loadConfig$1()?.remote;
|
|
411
680
|
let selected = "auto";
|
|
412
681
|
try {
|
|
413
|
-
selected = resolveBuildMachine(flag, process.env.
|
|
414
|
-
selected = requireConfiguredMachine(selected,
|
|
415
|
-
if (namedBuildMachine(selected) && pairedMachines([selected]).length === 0) throw new OffloadRefusal(selected, "no
|
|
682
|
+
selected = resolveBuildMachine(flag, process.env.STIM_REMOTE_BUILD, remote?.build);
|
|
683
|
+
selected = requireConfiguredMachine(selected, remote?.machines);
|
|
684
|
+
if (namedBuildMachine(selected) && pairedMachines([selected]).length === 0) throw new OffloadRefusal(selected, "no remote Mac is paired");
|
|
416
685
|
return { selected };
|
|
417
686
|
} catch (error) {
|
|
418
687
|
return {
|
|
@@ -420,7 +689,7 @@ function resolveBuildPlacement(flag) {
|
|
|
420
689
|
failure: {
|
|
421
690
|
code: error.code,
|
|
422
691
|
message: error.message,
|
|
423
|
-
remedy: error instanceof OffloadRefusal ? error.remedy : "Pass --build
|
|
692
|
+
remedy: error instanceof OffloadRefusal ? error.remedy : "Pass --remote-build auto, local, or an entry from stim settings get remote.machines."
|
|
424
693
|
}
|
|
425
694
|
};
|
|
426
695
|
}
|
|
@@ -449,7 +718,7 @@ const CHUNK_BYTES = 61440;
|
|
|
449
718
|
const MAX_BUFFERED = 8388608;
|
|
450
719
|
const DIGEST_BYTES = 32;
|
|
451
720
|
function offloadMode(env = process.env) {
|
|
452
|
-
const raw = env.
|
|
721
|
+
const raw = env.STIM_REMOTE_BUILD_MODE || loadConfig$1()?.remote?.buildMode;
|
|
453
722
|
return OFFLOAD_MODES.includes(raw) ? raw : "auto";
|
|
454
723
|
}
|
|
455
724
|
function buildPlacementCandidates(selected) {
|
|
@@ -477,30 +746,30 @@ function placementLoad(choice) {
|
|
|
477
746
|
})} there`;
|
|
478
747
|
}
|
|
479
748
|
/**
|
|
480
|
-
* Whether a build may go to a
|
|
481
|
-
* this Mac has a free `concurrency.maxBuilds` slot and its load per core is under `
|
|
749
|
+
* Whether a build may go to a remote Mac at all, before any machine is asked. `auto` keeps the build here while
|
|
750
|
+
* this Mac has a free `concurrency.maxBuilds` slot and its load per core is under `server.maxLoadPerCore`.
|
|
482
751
|
* A named selection ignores local capacity and mode, and refuses an unsupported build or missing pairing.
|
|
483
752
|
*/
|
|
484
753
|
function offloadPlacement({ mode, machines, here, unsupported, selected = "auto" }) {
|
|
485
754
|
if (namedBuildMachine(selected)) {
|
|
486
|
-
if (unsupported) throw new OffloadRefusal(selected, `${unsupported}, so a named
|
|
487
|
-
if (machines === 0) throw new OffloadRefusal(selected, "no
|
|
755
|
+
if (unsupported) throw new OffloadRefusal(selected, `${unsupported}, so a named remote Mac cannot take it`);
|
|
756
|
+
if (machines === 0) throw new OffloadRefusal(selected, "no remote Mac is paired");
|
|
488
757
|
return {
|
|
489
758
|
offload: true,
|
|
490
|
-
reason: `selected with --build
|
|
759
|
+
reason: `selected with --remote-build ${selected}`
|
|
491
760
|
};
|
|
492
761
|
}
|
|
493
762
|
if (selected === "local") return {
|
|
494
763
|
offload: false,
|
|
495
|
-
reason: "--build
|
|
764
|
+
reason: "--remote-build local"
|
|
496
765
|
};
|
|
497
766
|
if (mode === "off") return {
|
|
498
767
|
offload: false,
|
|
499
|
-
reason: "
|
|
768
|
+
reason: "remote.buildMode is off"
|
|
500
769
|
};
|
|
501
770
|
if (machines === 0) return {
|
|
502
771
|
offload: false,
|
|
503
|
-
reason: "no
|
|
772
|
+
reason: "no remote Mac is paired"
|
|
504
773
|
};
|
|
505
774
|
if (unsupported) return {
|
|
506
775
|
offload: false,
|
|
@@ -508,7 +777,7 @@ function offloadPlacement({ mode, machines, here, unsupported, selected = "auto"
|
|
|
508
777
|
};
|
|
509
778
|
if (mode === "force") return {
|
|
510
779
|
offload: true,
|
|
511
|
-
reason: "
|
|
780
|
+
reason: "remote.buildMode is force"
|
|
512
781
|
};
|
|
513
782
|
const busy = saturation(here);
|
|
514
783
|
return busy ? {
|
|
@@ -796,7 +1065,7 @@ var BuildConnection = class BuildConnection {
|
|
|
796
1065
|
function replyError(reply) {
|
|
797
1066
|
return "error" in reply ? `${reply.error.code}: ${reply.error.message}` : null;
|
|
798
1067
|
}
|
|
799
|
-
/** The repository on the
|
|
1068
|
+
/** The repository on the remote Mac: one area per git common dir, shared by all its worktrees. */
|
|
800
1069
|
function repoIdentity(projectRoot) {
|
|
801
1070
|
const run = getExecutor().runFile;
|
|
802
1071
|
const repoRoot = realpathSync(run("git", [
|
|
@@ -936,7 +1205,7 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
|
|
|
936
1205
|
asked.forEach((each, at) => {
|
|
937
1206
|
if (!order.includes(at) && "connection" in each) each.connection.close();
|
|
938
1207
|
});
|
|
939
|
-
if (order.length === 0) return reasons.length ? reasons.join("; ") : "no
|
|
1208
|
+
if (order.length === 0) return reasons.length ? reasons.join("; ") : "no remote Mac is paired";
|
|
940
1209
|
for (const reason of reasons) note(reason);
|
|
941
1210
|
const [first, ...rest] = order.map((at) => {
|
|
942
1211
|
const pick = asked[at];
|
|
@@ -1240,7 +1509,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
|
|
|
1240
1509
|
ok: true,
|
|
1241
1510
|
machine,
|
|
1242
1511
|
artifactPath,
|
|
1243
|
-
...
|
|
1512
|
+
...typeof declared.handoff === "string" && /^[0-9a-f]{64}$/.test(declared.handoff) ? { handoff: {
|
|
1244
1513
|
nodeId: choice.credential.nodeId,
|
|
1245
1514
|
token: declared.handoff,
|
|
1246
1515
|
sha256: digest
|
|
@@ -1365,4 +1634,4 @@ function offloadCheck(projectRoot, targets) {
|
|
|
1365
1634
|
};
|
|
1366
1635
|
}
|
|
1367
1636
|
//#endregion
|
|
1368
|
-
export {
|
|
1637
|
+
export { realIo as S, configuredMachines as _, offloadBuild as a, parseMachine$1 as b, placementLoad as c, OffloadRefusal as d, namedBuildMachine as f, inspectBuildMachines as g, resolveBuildPlacement as h, closeOffload as i, remotePhaseText as l, resolveBuildMachine as m, buildPlacementCandidates as n, offloadCheck as o, parseBuildMachineOption as p, chooseBuildMachine as r, offloadPlacement as s, BuildConnection as t, simulatorRuntime as u, hostingMachines as v, pinnedEndpoint$1 as x, inspectDeviceHostMachines as y };
|
package/dist/collector-run.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { R as deviceSlotKey, W as validateDeviceSlot } from "./config-D0DbpZtM.mjs";
|
|
2
2
|
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
3
|
import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
4
|
-
import { x as workspaceLogsDir } from "./workspace-state-
|
|
4
|
+
import { x as workspaceLogsDir } from "./workspace-state-DqcCbpE7.mjs";
|
|
5
5
|
import { r as createNdjsonWriter } from "./ndjson-PclOIwVY.mjs";
|
|
6
6
|
import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-Ee7sDXfp.mjs";
|
|
7
7
|
import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-Cr1h5gnO.mjs";
|
|
8
|
-
import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-
|
|
9
|
-
import { a as
|
|
8
|
+
import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-DyRQru0q.mjs";
|
|
9
|
+
import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-DE4v59Mb.mjs";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import { isAbsolute, join, resolve } from "node:path";
|
|
12
12
|
import { LOG_ROTATE_BYTES } from "@stim-cli/core";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
2
|
-
import { t as NO_PROJECT_REFUSAL } from "./project-
|
|
3
|
-
import { quotedPath } from "@stim-cli/core";
|
|
2
|
+
import { t as NO_PROJECT_REFUSAL } from "./project-D47Rh0ly.mjs";
|
|
3
|
+
import { quotedPath as quotedPath$1 } from "@stim-cli/core";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
//#region src/diagnostics/launch-error-preview.ts
|
|
6
6
|
function framePriority(frame, root) {
|
|
@@ -292,4 +292,4 @@ function stepTimer(now = Date.now) {
|
|
|
292
292
|
return () => `(${formatDuration(elapsed())})`;
|
|
293
293
|
}
|
|
294
294
|
//#endregion
|
|
295
|
-
export { stepTimer as _, formatElapsed as a, launchErrorReport as c, quotedPath as d, refuseNoProject as f, stepClock as g, shortUdid as h, formatDuration as i, phaseLine as l, shortHash as m, appReadinessMessage as n, formatLongDuration as o, releasedLeaseFact as p, clockTime as r, isAppLaunchError as s, SLOW_STEP_MS as t, plural as u, launchErrorPreview as v };
|
|
295
|
+
export { stepTimer as _, formatElapsed as a, launchErrorReport as c, quotedPath$1 as d, refuseNoProject as f, stepClock as g, shortUdid as h, formatDuration as i, phaseLine as l, shortHash as m, appReadinessMessage as n, formatLongDuration as o, releasedLeaseFact as p, clockTime as r, isAppLaunchError as s, SLOW_STEP_MS as t, plural as u, launchErrorPreview as v };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as getConfigDir } from "./config-D0DbpZtM.mjs";
|
|
2
|
-
import { w as withDirLock } from "./workspace-state-
|
|
2
|
+
import { w as withDirLock } from "./workspace-state-DqcCbpE7.mjs";
|
|
3
3
|
import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { createdDevicesFile, createdDevicesLock, readCreatedDevices, readCreatedDevices as readCreatedDevices$1 } from "@stim-cli/core/state";
|
|
5
5
|
//#region src/devices/created-devices.ts
|