stim 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/activity-BxwdD81S.mjs +609 -0
- package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
- package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
- package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
- package/dist/android-cas-8U4DPqeR.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
- package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
- package/dist/attempt-Bk2ouQVL.mjs +39 -0
- package/dist/budget-DjrURfQn.mjs +2700 -0
- package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
- package/dist/build-slots-rUk77xqh.mjs +132 -0
- package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
- package/dist/cli-BkYZ_6hy.mjs +51 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-BTY686R6.mjs +1368 -0
- package/dist/collector-run.mjs +9 -195
- package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
- package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
- package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
- package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
- package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CroAIjjj.mjs +43 -0
- package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
- package/dist/device-capacity-BHwxNBlu.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +964 -0
- package/dist/device-ios-BadmeL2V.mjs +381 -0
- package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
- package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
- package/dist/device-pool-CUaEWMMm.mjs +125 -0
- package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
- package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
- package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
- package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
- package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
- package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
- package/dist/hosted-client-a-WmqE2L.mjs +197 -0
- package/dist/hosted-ios-CIWelIqf.mjs +220 -0
- package/dist/hosted-logs-D5g041Q3.mjs +187 -0
- package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
- package/dist/idle-DYVymG92.mjs +1099 -0
- package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
- package/dist/in-use-DvBw0Kxo.mjs +130 -0
- package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
- package/dist/ios-Cr1h5gnO.mjs +189 -0
- package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
- package/dist/ios-state-DS5UpYTH.mjs +48 -0
- package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
- package/dist/logs-CHEVK8zD.mjs +371 -0
- package/dist/machines-BIBUdhpj.mjs +265 -0
- package/dist/macos-CSYEAFmF.mjs +473 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/maintenance-run.d.mts +4 -0
- package/dist/maintenance-run.mjs +254 -0
- package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
- package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
- package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
- package/dist/native-run-NaBrRFtQ.mjs +147 -0
- package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
- package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
- package/dist/offload-worker.d.mts +122 -0
- package/dist/offload-worker.mjs +606 -0
- package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
- package/dist/ownership-hCkPzGmr.mjs +571 -0
- package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
- package/dist/prebuild-D2fsca_Z.mjs +213 -0
- package/dist/preview-DhVbvPAZ.mjs +318 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-BIXOzVnr.mjs +37 -0
- package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
- package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
- package/dist/run-f4vI6EnK.mjs +119 -0
- package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
- package/dist/server-expo-CVqO2c35.mjs +2 -0
- package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
- package/dist/settings-BBpMcDbD.mjs +25 -0
- package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
- package/dist/settings-oTSkkNrM.mjs +1439 -0
- package/dist/settings.schema.json +845 -97
- package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
- package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
- package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CX8Ig-U2.mjs +2 -0
- package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
- package/dist/state-3DwSQIBK.mjs +41 -0
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
- package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
- package/dist/stats-CEZ_i5je.mjs +77 -0
- package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
- package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
- package/dist/status-DlKvVJBE.mjs +49 -0
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/stop-B0Yxtmiy.mjs +48 -0
- package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
- package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
- package/dist/stop-cause-CidxIqup.mjs +97 -0
- package/dist/supervisor-run.d.mts +43 -11
- package/dist/supervisor-run.mjs +363 -24
- package/dist/support-CAP8qDUF.mjs +316 -0
- package/dist/support-D4aYJniO.mjs +201 -0
- package/dist/teardown-CL6vDs2Y.mjs +727 -0
- package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
- package/dist/trigger-Bemu8ytw.mjs +65 -0
- package/dist/trigger-CXts6qt1.mjs +2 -0
- package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
- package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
- package/dist/web-run.mjs +310 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
- package/dist/workspaces-BV4pdHFz.mjs +306 -0
- package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
- package/dist/worktree-jnG8Iph5.mjs +2 -0
- package/package.json +10 -5
- package/shim/bundle-response.cjs +28 -12
- package/dist/activity-CYVDcrt3.mjs +0 -356
- package/dist/budget-CGDkhvv_.mjs +0 -1745
- package/dist/build-progress-DxKpwnaS.mjs +0 -247
- package/dist/idle-DXtx3RbX.mjs +0 -191
- package/dist/in-use-DlqBDKqY.mjs +0 -249
- package/dist/logs-Civ4gbBH.mjs +0 -486
- package/dist/merge-state-ytFQCeh4.mjs +0 -262
- package/dist/server-expo-DIHDhvGg.mjs +0 -2
- package/dist/settings-D61iNOsB.mjs +0 -629
- package/dist/start-Cetfvy8l.mjs +0 -2
- package/dist/stats-CFpFGlJV.mjs +0 -62
- package/dist/stats-CX1Z8Tca.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
- package/dist/worktree-BVrHsYZG.mjs +0 -752
- package/dist/worktree-CHWWvm5v.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { _ as loadConfig$1, d as getConfigDir } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { w as withDirLock } from "./workspace-state-B8-aJ1_5.mjs";
|
|
3
|
+
import { S as readHostPermissions, _ as findPeer$1, b as realIo, g as endpoint, v as parseMachine$1, x as readAccessTicket } from "./client-BTY686R6.mjs";
|
|
4
|
+
import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { acceptsShape, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, isJsonObject, readDeviceHostMachines, settingDefinition } from "@stim-cli/core/state";
|
|
6
|
+
import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
7
|
+
import { hostname } from "node:os";
|
|
8
|
+
//#region src/device-host/machines.ts
|
|
9
|
+
function note(title, detail, fix = null) {
|
|
10
|
+
return {
|
|
11
|
+
code: "device-host-machine",
|
|
12
|
+
level: "note",
|
|
13
|
+
title,
|
|
14
|
+
detail,
|
|
15
|
+
fix
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const approval = (machine, id) => `A person on ${machine} approves it with \`stim-server devices grant ${id} --device-host\`.`;
|
|
19
|
+
function configuredMachines() {
|
|
20
|
+
const hosting = loadConfig$1()?.hosting;
|
|
21
|
+
if (hosting !== void 0 && !isJsonObject(hosting)) return null;
|
|
22
|
+
const machines = hosting?.machines;
|
|
23
|
+
if (machines === void 0) return [];
|
|
24
|
+
return acceptsShape(settingDefinition("hosting.machines"), machines) ? machines : null;
|
|
25
|
+
}
|
|
26
|
+
function store(machines) {
|
|
27
|
+
withDirLock(deviceHostMachinesLock(), () => {
|
|
28
|
+
const file = deviceHostMachinesFile();
|
|
29
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
30
|
+
try {
|
|
31
|
+
writeFileSync(tmp, `${JSON.stringify({
|
|
32
|
+
version: 1,
|
|
33
|
+
machines
|
|
34
|
+
}, null, 2)}\n`, { mode: 384 });
|
|
35
|
+
renameSync(tmp, file);
|
|
36
|
+
} finally {
|
|
37
|
+
rmSync(tmp, { force: true });
|
|
38
|
+
}
|
|
39
|
+
}, { ensureParent: () => mkdirSync(getConfigDir(), { recursive: true }) });
|
|
40
|
+
}
|
|
41
|
+
async function request(machine, peer, port, deviceName, io) {
|
|
42
|
+
const ticket = readAccessTicket();
|
|
43
|
+
const reply = await io.hello(endpoint(peer, port), {
|
|
44
|
+
request: "device-host",
|
|
45
|
+
deviceName,
|
|
46
|
+
...ticket ? { setupTicket: ticket.ticket } : {}
|
|
47
|
+
});
|
|
48
|
+
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 {
|
|
49
|
+
report: {
|
|
50
|
+
machine,
|
|
51
|
+
dnsName: peer.dnsName,
|
|
52
|
+
state: "unreachable"
|
|
53
|
+
},
|
|
54
|
+
finding: note(`Could not ask ${machine} for hosting access`, "The worker did not return a pending request.")
|
|
55
|
+
};
|
|
56
|
+
const credential = {
|
|
57
|
+
machine,
|
|
58
|
+
nodeId: peer.nodeId,
|
|
59
|
+
dnsName: peer.dnsName,
|
|
60
|
+
deviceId: reply.result.device.id,
|
|
61
|
+
deviceToken: reply.result.deviceToken,
|
|
62
|
+
state: "pending",
|
|
63
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64
|
+
...ticket ? { ticketHash: ticket.ticketHash } : {}
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
report: {
|
|
68
|
+
machine,
|
|
69
|
+
dnsName: peer.dnsName,
|
|
70
|
+
state: "pending",
|
|
71
|
+
deviceId: credential.deviceId,
|
|
72
|
+
requestedAt: credential.requestedAt
|
|
73
|
+
},
|
|
74
|
+
finding: note(`Asked ${machine} for hosting access`, `The request lapses at ${reply.result.approval.expiresAt}.`, approval(machine, credential.deviceId)),
|
|
75
|
+
credential
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Reports separately approved hosting machines. Only --fix asks or forgets credentials; every token stays pinned. */
|
|
79
|
+
async function inspectDeviceHostMachines({ fix }, io = realIo, entries = configuredMachines()) {
|
|
80
|
+
if (entries === null) return {
|
|
81
|
+
findings: [note("Invalid hosting.machines setting", "Use a hosting 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.")],
|
|
82
|
+
machines: []
|
|
83
|
+
};
|
|
84
|
+
const unavailable = (state, finding) => ({
|
|
85
|
+
findings: [finding],
|
|
86
|
+
machines: entries.map((machine) => ({
|
|
87
|
+
machine,
|
|
88
|
+
state
|
|
89
|
+
}))
|
|
90
|
+
});
|
|
91
|
+
const unreadable = () => unavailable("credentials-unavailable", note("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."));
|
|
92
|
+
if (!entries.length) {
|
|
93
|
+
if (!fix) return {
|
|
94
|
+
findings: [],
|
|
95
|
+
machines: []
|
|
96
|
+
};
|
|
97
|
+
try {
|
|
98
|
+
if (!readDeviceHostMachines().length) return {
|
|
99
|
+
findings: [],
|
|
100
|
+
machines: []
|
|
101
|
+
};
|
|
102
|
+
} catch {
|
|
103
|
+
return unreadable();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const claim = tryAcquireClaim({
|
|
107
|
+
root: deviceHostMachinesClaims(),
|
|
108
|
+
mode: "exclusive",
|
|
109
|
+
label: "hosting machine approval"
|
|
110
|
+
});
|
|
111
|
+
if (!claim.acquired) {
|
|
112
|
+
releaseClaim(claim.pending);
|
|
113
|
+
return unavailable("busy", note("Hosting machine approval is in use", "Another doctor run holds the hosting credential claim. Run doctor again after it finishes."));
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
let credentials;
|
|
117
|
+
try {
|
|
118
|
+
credentials = readDeviceHostMachines();
|
|
119
|
+
} catch {
|
|
120
|
+
return unreadable();
|
|
121
|
+
}
|
|
122
|
+
if (fix) {
|
|
123
|
+
const kept = credentials.filter((each) => entries.includes(each.machine));
|
|
124
|
+
if (kept.length !== credentials.length) {
|
|
125
|
+
store(kept);
|
|
126
|
+
credentials = kept;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!entries.length) return {
|
|
130
|
+
findings: [],
|
|
131
|
+
machines: []
|
|
132
|
+
};
|
|
133
|
+
const status = io.status();
|
|
134
|
+
if (!isJsonObject(status)) return unavailable("tailscale-off", note("Hosting machines are unreachable", "hosting.machines names hosting machines, but Tailscale is not running."));
|
|
135
|
+
const self = isJsonObject(status.Self) ? status.Self : {};
|
|
136
|
+
const deviceName = (typeof self.HostName === "string" && self.HostName ? self.HostName : hostname()).replace(/[\p{Cc}\p{Cf}]/gu, "").trim().slice(0, 64) || "Mac";
|
|
137
|
+
const inspected = {
|
|
138
|
+
findings: [],
|
|
139
|
+
machines: []
|
|
140
|
+
};
|
|
141
|
+
const namedNodes = /* @__PURE__ */ new Set();
|
|
142
|
+
for (const machine of new Set(entries)) {
|
|
143
|
+
const parsed = parseMachine$1(machine);
|
|
144
|
+
if (!parsed) {
|
|
145
|
+
inspected.machines.push({
|
|
146
|
+
machine,
|
|
147
|
+
state: "invalid"
|
|
148
|
+
});
|
|
149
|
+
inspected.findings.push(note(`Hosting machine ${machine} is not a tailnet name`, "Expected `name` or `name:port`."));
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const current = io.status();
|
|
153
|
+
if (!isJsonObject(current)) {
|
|
154
|
+
inspected.machines.push({
|
|
155
|
+
machine,
|
|
156
|
+
state: "tailscale-off"
|
|
157
|
+
});
|
|
158
|
+
inspected.findings.push(note(`Hosting machine ${machine} is unreachable`, "Tailscale stopped before this connection."));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const peer = findPeer$1(current, parsed.name);
|
|
162
|
+
if (peer === "missing" || peer === "ambiguous") {
|
|
163
|
+
inspected.machines.push({
|
|
164
|
+
machine,
|
|
165
|
+
state: "not-on-tailnet"
|
|
166
|
+
});
|
|
167
|
+
inspected.findings.push(note(`Hosting machine ${machine} is not on this tailnet`, peer === "missing" ? "No peer has that name." : "Several peers match that name."));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const nodeRoute = `${peer.nodeId}:${parsed.port}`;
|
|
171
|
+
if (namedNodes.has(nodeRoute)) {
|
|
172
|
+
inspected.machines.push({
|
|
173
|
+
machine,
|
|
174
|
+
dnsName: peer.dnsName,
|
|
175
|
+
state: "invalid"
|
|
176
|
+
});
|
|
177
|
+
inspected.findings.push(note(`Hosting machine ${machine} repeats a named node`, "Name each tailnet node and serve port only once in hosting.machines."));
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
namedNodes.add(nodeRoute);
|
|
181
|
+
const credential = credentials.find((each) => each.machine === machine);
|
|
182
|
+
const known = {
|
|
183
|
+
machine,
|
|
184
|
+
dnsName: peer.dnsName,
|
|
185
|
+
...credential ? {
|
|
186
|
+
deviceId: credential.deviceId,
|
|
187
|
+
requestedAt: credential.requestedAt
|
|
188
|
+
} : {}
|
|
189
|
+
};
|
|
190
|
+
if (credential && credential.nodeId !== peer.nodeId) {
|
|
191
|
+
inspected.machines.push({
|
|
192
|
+
...known,
|
|
193
|
+
state: "node-changed"
|
|
194
|
+
});
|
|
195
|
+
inspected.findings.push(note(`Hosting machine ${machine} is a different tailnet node`, "Stim refuses to connect or send the saved token.", `If that Mac was replaced, remove ${machine} from hosting.machines, run \`stim doctor --fix\`, then add it back and run \`stim doctor --fix\` again to request approval on the new node.`));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
let ask = !credential && fix;
|
|
199
|
+
if (credential) {
|
|
200
|
+
const reply = await io.hello(endpoint(peer, parsed.port), { deviceToken: credential.deviceToken });
|
|
201
|
+
if ("result" in reply && reply.result?.device?.id === credential.deviceId && Array.isArray(reply.result.capabilities) && reply.result.capabilities.includes("device-host")) {
|
|
202
|
+
if (credential.state !== "approved") {
|
|
203
|
+
credentials = credentials.map((each) => each.machine === machine ? {
|
|
204
|
+
...each,
|
|
205
|
+
state: "approved"
|
|
206
|
+
} : each);
|
|
207
|
+
store(credentials);
|
|
208
|
+
}
|
|
209
|
+
const host = readHostPermissions(reply.result.host);
|
|
210
|
+
if (host && (host.screenRecording === false || host.accessibility === false)) {
|
|
211
|
+
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)"] : []];
|
|
212
|
+
const detail = [...host.screenRecording === false ? ["Viewing hosted macOS apps needs Screen Recording."] : [], ...host.accessibility === false ? ["Controlling them needs the control permission."] : []];
|
|
213
|
+
inspected.findings.push(note(`Hosting machine ${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.`));
|
|
214
|
+
}
|
|
215
|
+
inspected.machines.push({
|
|
216
|
+
...known,
|
|
217
|
+
state: "approved",
|
|
218
|
+
...host ? { host } : {}
|
|
219
|
+
});
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const pending = "error" in reply && reply.error?.code === "approval-pending";
|
|
223
|
+
const revoked = "error" in reply && reply.error?.code === "unauthorized";
|
|
224
|
+
const ticket = fix && pending && credential.state !== "approved" ? readAccessTicket() : void 0;
|
|
225
|
+
ask = fix && (revoked || !!ticket && credential.ticketHash !== ticket.ticketHash);
|
|
226
|
+
if (pending && !ask) {
|
|
227
|
+
inspected.machines.push({
|
|
228
|
+
...known,
|
|
229
|
+
state: "pending"
|
|
230
|
+
});
|
|
231
|
+
inspected.findings.push(note(`Hosting machine ${machine} has not approved this Mac yet`, `Requested at ${credential.requestedAt}.`, approval(machine, credential.deviceId)));
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (!ask) {
|
|
235
|
+
inspected.machines.push({
|
|
236
|
+
...known,
|
|
237
|
+
state: revoked ? "revoked" : "unreachable"
|
|
238
|
+
});
|
|
239
|
+
inspected.findings.push(note(`Hosting machine ${machine} ${revoked ? "no longer accepts this Mac" : "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.`));
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (ask) {
|
|
244
|
+
const result = await request(machine, peer, parsed.port, deviceName, io);
|
|
245
|
+
if (result.credential) {
|
|
246
|
+
credentials = [...credentials.filter((each) => each.machine !== machine), result.credential];
|
|
247
|
+
store(credentials);
|
|
248
|
+
}
|
|
249
|
+
inspected.machines.push(result.report);
|
|
250
|
+
inspected.findings.push(result.finding);
|
|
251
|
+
} else {
|
|
252
|
+
inspected.machines.push({
|
|
253
|
+
...known,
|
|
254
|
+
state: "not-asked"
|
|
255
|
+
});
|
|
256
|
+
inspected.findings.push(note(`Hosting machine ${machine} has not approved this Mac`, "This Mac has not asked for hosting access.", "Run `stim doctor --fix` to ask."));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return inspected;
|
|
260
|
+
} finally {
|
|
261
|
+
releaseClaim(claim.acquired);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//#endregion
|
|
265
|
+
export { inspectDeviceHostMachines as n, configuredMachines as t };
|