stim 1.8.0 → 1.10.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.
Files changed (91) hide show
  1. package/README.md +23 -155
  2. package/dist/{android-DWssqHQ8.mjs → android-787HhP5w.mjs} +168 -39
  3. package/dist/{android-BRgBYzU0.mjs → android-DBkeHwpm.mjs} +250 -200
  4. package/dist/{android-DeYdjjBP.mjs → android-DPov-fv2.mjs} +2 -2
  5. package/dist/{android-cas-SWIjzeuL.mjs → android-cas-CITmIeWY.mjs} +22 -14
  6. package/dist/android-cas-compiler.mjs +2 -2
  7. package/dist/app-install-CrJ6t_bv.mjs +819 -0
  8. package/dist/budget-BP4jZZL4.mjs +620 -0
  9. package/dist/build-progress-BXx-ZBe4.mjs +512 -0
  10. package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Pubfp8wV.mjs} +4 -4
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +22 -19
  13. package/dist/collector-run.d.mts +7 -1
  14. package/dist/collector-run.mjs +10 -9
  15. package/dist/{command-output-B3ycpsYv.mjs → command-output-D5z2_bcF.mjs} +11 -2
  16. package/dist/{config-B7iyKWkL.mjs → config-BEq0Qw_a.mjs} +134 -121
  17. package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-r9UesA9a.mjs} +2 -2
  18. package/dist/{deps-oCXVNEqQ.mjs → deps-DP4eWqea.mjs} +8 -5
  19. package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-DJHoca49.mjs} +1 -1
  20. package/dist/{device-BUoZyMoR.mjs → dev-client-92U593KT.mjs} +1090 -660
  21. package/dist/{device-RdujjHLB.mjs → device-DhTZe7L4.mjs} +13 -20
  22. package/dist/{build-lock-CgtsB6TV.mjs → device-lease-CbEaIk7b.mjs} +481 -27
  23. package/dist/{device-pool-BxRwdufO.mjs → device-pool-Di8Q-9Ro.mjs} +7 -7
  24. package/dist/{device-remote-ByN8P6CB.mjs → device-remote-Dy1jGj3U.mjs} +645 -119
  25. package/dist/{doctor-BMt156qe.mjs → doctor-B-inAJmt.mjs} +137 -113
  26. package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-xxWKNO3-.mjs} +22 -17
  27. package/dist/exec-DK8KaVHK.mjs +133 -0
  28. package/dist/{gc-v2YcoJvm.mjs → gc-ChPFZMRC.mjs} +836 -813
  29. package/dist/{guide-BTAlD1_y.mjs → guide-DwmaD_Wa.mjs} +953 -209
  30. package/dist/guide-status-CWvti2Lg.mjs +125 -0
  31. package/dist/idle-DpRLp5lj.mjs +157 -0
  32. package/dist/{build-slots-C-oAHRT1.mjs → in-use-CjUluqIX.mjs} +102 -8
  33. package/dist/{ios-BcCiI4TS.mjs → ios-B2Fpqvlb.mjs} +60 -71
  34. package/dist/{ios-BP04pY5f.mjs → ios-Dd-hYJBh.mjs} +241 -234
  35. package/dist/{ios-device-CFXA46ez.mjs → ios-device-BiOsSVzd.mjs} +3 -2
  36. package/dist/{ios-device-CauFJiYx.mjs → ios-device-CtRdEVjx.mjs} +149 -52
  37. package/dist/launch-verify-CQS_Kg-C.mjs +365 -0
  38. package/dist/{logs-CakdBTtm.mjs → logs-MARIy6m9.mjs} +20 -15
  39. package/dist/metro-BWLOJ_Wr.mjs +409 -0
  40. package/dist/{named-ports-DzMOlmaX.mjs → named-ports-DiTfSz6p.mjs} +4 -4
  41. package/dist/{ndjson-BZwI1NBv.mjs → ndjson-CDY9IkVC.mjs} +23 -43
  42. package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
  43. package/dist/{ownership-Cp52QAK1.mjs → ownership-D2xbLVoz.mjs} +2 -3
  44. package/dist/{teardown-BJqEzPo_.mjs → ownership-DZjdx8Gq.mjs} +664 -612
  45. package/dist/{ports-BIbJaKNW.mjs → ports-CLSSFOuz.mjs} +3 -3
  46. package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
  47. package/dist/{project-DDZWf_16.mjs → project-BXZzOABt.mjs} +8 -3
  48. package/dist/{reload-BdypPbjM.mjs → reload-DoETJ3rl.mjs} +11 -13
  49. package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DVbb7kXH.mjs} +2 -2
  50. package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-BvOCeakp.mjs} +8 -7
  51. package/dist/server-expo-DBVTdult.mjs +2 -0
  52. package/dist/{settings-BXXorVM2.mjs → settings-DOugPlPz.mjs} +59 -159
  53. package/dist/settings-EWYNwe72.mjs +378 -0
  54. package/dist/settings.schema.json +1064 -0
  55. package/dist/simslim-Ca3487H6.mjs +436 -0
  56. package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
  57. package/dist/spawn-claims-CUleC2cM.mjs +49 -0
  58. package/dist/{start-CmxtOKjU.mjs → start-F9gv5dcC.mjs} +159 -114
  59. package/dist/start-VoFsPSes.mjs +2 -0
  60. package/dist/{state-DZobzxLW.mjs → state-WGdIbi_d.mjs} +5 -3
  61. package/dist/{stats-BYcZ6n1h.mjs → stats-BAgJaLA4.mjs} +66 -5
  62. package/dist/{stats-CLg5RuDS.mjs → stats-DBYJ5bxL.mjs} +4 -4
  63. package/dist/status-DLCD-o3s.mjs +764 -0
  64. package/dist/status-Dr4fRkym.mjs +216 -0
  65. package/dist/{guide-status-Craq9z0t.mjs → stim-installations-CINXy_su.mjs} +3 -122
  66. package/dist/{stop-C8JW6kKp.mjs → stop-Dj4pfmyv.mjs} +111 -31
  67. package/dist/{stop-B1kOpYei.mjs → stop-ZvOeTmKb.mjs} +2 -2
  68. package/dist/supervisor-run.d.mts +11 -2
  69. package/dist/supervisor-run.mjs +228 -42
  70. package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-BXA96myD.mjs} +14 -9
  71. package/dist/workspaces-BTUyFfkv.mjs +1003 -0
  72. package/dist/worktree-4aZg2NnI.mjs +2 -0
  73. package/dist/{worktree-CFLA-6MX.mjs → worktree-BMS7GeqB.mjs} +523 -61
  74. package/dist/{worktree-FG_ZKKdb.mjs → worktree-BlizKDpZ.mjs} +200 -54
  75. package/dist/{xcode-B6YaWeg0.mjs → xcode-B2tBkf0m.mjs} +66 -57
  76. package/package.json +6 -6
  77. package/skill/SKILL.md +2 -0
  78. package/dist/app-install-BDbsSgCl.mjs +0 -1175
  79. package/dist/dev-client-BmT-ioFI.mjs +0 -797
  80. package/dist/device-lease-Ffz_M5t0.mjs +0 -359
  81. package/dist/exec-B29XNuhP.mjs +0 -77
  82. package/dist/logs-query-BGL-Pl12.mjs +0 -290
  83. package/dist/metro-C7bcJ0uo.mjs +0 -233
  84. package/dist/ownership-wolE-0Do.mjs +0 -470
  85. package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
  86. package/dist/reclaim-KJ-0uWEF.mjs +0 -361
  87. package/dist/server-expo-YDDG3eP7.mjs +0 -2
  88. package/dist/spawn-entry-nCE6m770.mjs +0 -14
  89. package/dist/status-DdkLki47.mjs +0 -426
  90. package/dist/workspace-state-BT5E3SA2.mjs +0 -146
  91. package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
@@ -1,470 +0,0 @@
1
- import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
- import { u as getConfigDir, w as process_identity_exports } from "./config-B7iyKWkL.mjs";
3
- import { t as createLineReader } from "./process-output-Dl5uKE03.mjs";
4
- import { i as pidExists, o as signalProcessTree } from "./metro-C7bcJ0uo.mjs";
5
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
6
- import { t as probePublicHttp } from "./public-http-probe-CyMDrQ3c.mjs";
7
- import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync } from "node:fs";
8
- import { createHash, randomUUID } from "node:crypto";
9
- import { basename, join, resolve, sep } from "node:path";
10
- //#region src/engine/tunnel.ts
11
- function tunnelArgv(provider, port, ngrokUrl, logFile) {
12
- if (provider === "cloudflared") return {
13
- bin: "cloudflared",
14
- args: [
15
- "tunnel",
16
- "--url",
17
- `http://127.0.0.1:${port}`,
18
- ...logFile ? ["--logfile", logFile] : []
19
- ]
20
- };
21
- return {
22
- bin: "ngrok",
23
- args: [
24
- "http",
25
- String(port),
26
- `--log=${logFile || "stdout"}`,
27
- "--log-format=json",
28
- ...ngrokUrl ? ["--url", ngrokUrl] : []
29
- ]
30
- };
31
- }
32
- const CLOUDFLARED_URL_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
33
- function parseCloudflaredLine(line) {
34
- const match = line.match(CLOUDFLARED_URL_RE);
35
- return match ? match[0] : null;
36
- }
37
- function parseNgrokLine(line) {
38
- let data;
39
- try {
40
- data = JSON.parse(line);
41
- } catch {
42
- return null;
43
- }
44
- if (typeof data !== "object" || data === null) return null;
45
- const url = data.url;
46
- return typeof url === "string" && /^https?:\/\//i.test(url) ? url : null;
47
- }
48
- function parserFor(provider) {
49
- return provider === "cloudflared" ? parseCloudflaredLine : parseNgrokLine;
50
- }
51
- const URL_TIMEOUT_MS = 15e3;
52
- const REACHABLE_TIMEOUT_MS = 24e4;
53
- const REACHABLE_POLL_MS = 2e3;
54
- const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
55
- async function withManagedTunnelLock(root, fn, options = {}) {
56
- return withWorkspaceProcessLock(managedTunnelLockRoot(root), "metro-tunnel", fn, {
57
- ...options,
58
- rejectOwnerPurposes: ["workspace removal"]
59
- });
60
- }
61
- async function withManagedTunnelRemovalLock(root, fn, options = {}) {
62
- return withWorkspaceProcessLock(managedTunnelLockRoot(root), "metro-tunnel", fn, {
63
- ...options,
64
- ownerPurpose: "workspace removal"
65
- });
66
- }
67
- async function withManagedRemoteWorktreeLock(worktreeRoot, fn, options = {}) {
68
- return withWorkspaceProcessLock(managedRemoteWorktreeLockRoot(worktreeRoot), "managed-remote", fn, {
69
- ...options,
70
- external: true,
71
- rejectOwnerPurposes: ["worktree removal"]
72
- });
73
- }
74
- async function withManagedRemoteWorktreeRemovalLock(worktreeRoot, fn, options = {}) {
75
- return withWorkspaceProcessLock(managedRemoteWorktreeLockRoot(worktreeRoot), "managed-remote", fn, {
76
- ...options,
77
- external: true,
78
- ownerPurpose: "worktree removal"
79
- });
80
- }
81
- function managedTunnelLockRoot(root) {
82
- const key = createHash("sha256").update(resolve(root)).digest("hex");
83
- return join(getConfigDir(), "process-locks", key);
84
- }
85
- function managedRemoteWorktreeLockRoot(worktreeRoot) {
86
- const key = createHash("sha256").update(resolve(worktreeRoot)).digest("hex");
87
- return join(getConfigDir(), "process-locks", "worktrees", key);
88
- }
89
- async function defaultProbeReachable(url, signal) {
90
- const status = await probePublicHttp(url, signal);
91
- return status !== null && status > 0;
92
- }
93
- function waitForUrl(child, parseLine, timeoutMs) {
94
- return new Promise((resolve) => {
95
- let settled = false;
96
- let timer;
97
- let onOut;
98
- let onErr;
99
- let onError;
100
- let onExit;
101
- const finish = (url, exited = false) => {
102
- if (settled) return;
103
- settled = true;
104
- clearTimeout(timer);
105
- child.stdout?.removeListener("data", onOut);
106
- child.stderr?.removeListener("data", onErr);
107
- child.removeListener("error", onError);
108
- child.removeListener("exit", onExit);
109
- resolve({
110
- url,
111
- exited
112
- });
113
- };
114
- const onLine = (line) => {
115
- if (settled) return;
116
- const url = parseLine(line);
117
- if (url) finish(url);
118
- };
119
- const outReader = createLineReader(onLine);
120
- const errReader = createLineReader(onLine);
121
- onOut = (chunk) => outReader.push(chunk);
122
- onErr = (chunk) => errReader.push(chunk);
123
- onError = () => finish(null);
124
- onExit = () => finish(null, true);
125
- child.stdout?.setEncoding?.("utf-8");
126
- child.stderr?.setEncoding?.("utf-8");
127
- child.stdout?.on("data", onOut);
128
- child.stderr?.on("data", onErr);
129
- child.on("error", onError);
130
- child.on("exit", onExit);
131
- timer = setTimeout(() => finish(null), timeoutMs);
132
- });
133
- }
134
- function waitForFileUrl(child, logFile, parseLine, timeoutMs) {
135
- return new Promise((resolve) => {
136
- let settled = false;
137
- const finish = (url, exited = false) => {
138
- if (settled) return;
139
- settled = true;
140
- clearInterval(interval);
141
- clearTimeout(timer);
142
- child.removeListener("error", onError);
143
- child.removeListener("exit", onExit);
144
- resolve({
145
- url,
146
- exited
147
- });
148
- };
149
- const probe = () => {
150
- try {
151
- for (const line of readFileSync(logFile, "utf-8").split(/\r?\n/)) {
152
- const url = parseLine(line);
153
- if (url) return finish(url);
154
- }
155
- } catch {}
156
- };
157
- const onError = () => finish(null);
158
- const onExit = () => finish(null, true);
159
- child.on("error", onError);
160
- child.on("exit", onExit);
161
- const interval = setInterval(probe, 25);
162
- const timer = setTimeout(() => finish(null), timeoutMs);
163
- probe();
164
- });
165
- }
166
- function createTunnelLogFile(provider) {
167
- const dir = join(getConfigDir(), "tunnel-logs");
168
- mkdirSync(dir, { recursive: true });
169
- const path = join(dir, `${provider}-${randomUUID()}.log`);
170
- closeSync(openSync(path, "wx", 384));
171
- return path;
172
- }
173
- function removeTunnelLogFile(path) {
174
- if (!path) return;
175
- try {
176
- unlinkSync(path);
177
- } catch {}
178
- }
179
- function removeRecordedTunnelLogFile(path) {
180
- if (!path) return;
181
- const dir = resolve(join(getConfigDir(), "tunnel-logs"));
182
- const resolved = resolve(path);
183
- if (!resolved.startsWith(`${dir}${sep}`) || resolve(join(dir, basename(resolved))) !== resolved) return;
184
- removeTunnelLogFile(resolved);
185
- }
186
- async function waitUntilReachable({ url, now, sleep, probe, timeoutMs }) {
187
- const deadline = now() + timeoutMs;
188
- for (;;) {
189
- if (await probe(url, new AbortController().signal).catch(() => false)) return true;
190
- if (now() >= deadline) return false;
191
- await sleep(REACHABLE_POLL_MS);
192
- }
193
- }
194
- const CLEANUP_TIMEOUT_MS = 1e3;
195
- const CLEANUP_POLL_MS = 25;
196
- async function startTunnel({ provider, port, spawnFn = null, urlTimeoutMs = URL_TIMEOUT_MS, reachableTimeoutMs = REACHABLE_TIMEOUT_MS, probeReachable = defaultProbeReachable, now = Date.now, sleep = defaultSleep, ngrokUrl = null, requireReachable = true, cleanupTimeoutMs = CLEANUP_TIMEOUT_MS, isChildAlive = pidExists, readProcessToken = process_identity_exports.captureProcessToken, logFile = null }) {
197
- const spawn = spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts));
198
- const outputFile = logFile || (spawnFn ? null : createTunnelLogFile(provider));
199
- const { bin, args } = tunnelArgv(provider, port, ngrokUrl, outputFile);
200
- let child;
201
- try {
202
- child = spawn(bin, args, {
203
- stdio: outputFile ? [
204
- "ignore",
205
- "ignore",
206
- "ignore"
207
- ] : [
208
- "ignore",
209
- "pipe",
210
- "pipe"
211
- ],
212
- detached: true
213
- });
214
- } catch (err) {
215
- removeTunnelLogFile(outputFile);
216
- return {
217
- failed: true,
218
- reason: `Could not start ${provider}: ${describe(err)}`
219
- };
220
- }
221
- let childExited = false;
222
- child.once("exit", () => {
223
- childExited = true;
224
- });
225
- const cleanup = async (alreadyExited = childExited) => {
226
- const stopped = await terminateChild(child, {
227
- alreadyExited,
228
- timeoutMs: cleanupTimeoutMs,
229
- now,
230
- sleep,
231
- isAlive: isChildAlive
232
- });
233
- if (stopped) removeTunnelLogFile(outputFile);
234
- return stopped ? { status: "stopped" } : {
235
- status: "failed",
236
- reason: `Sent SIGKILL but could not confirm that pid ${child.pid ?? "unknown"} exited.`
237
- };
238
- };
239
- const failAfterCleanup = async (reason, alreadyExited = childExited) => {
240
- const stopped = await cleanup(alreadyExited);
241
- return stopped.status === "stopped" ? {
242
- failed: true,
243
- reason
244
- } : {
245
- failed: true,
246
- reason: `${reason} ${stopped.reason}`,
247
- cleanupFailed: true
248
- };
249
- };
250
- const pid = child.pid;
251
- if (!pid) return failAfterCleanup(`${provider} started but reported no pid.`);
252
- const captureChildIdentity = () => {
253
- try {
254
- return readProcessToken(pid);
255
- } catch {
256
- return null;
257
- }
258
- };
259
- const initialProcessToken = captureChildIdentity();
260
- if (!initialProcessToken) return failAfterCleanup(`${provider} started but its process identity token could not be read.`);
261
- const { url, exited } = outputFile ? await waitForFileUrl(child, outputFile, parserFor(provider), urlTimeoutMs) : await waitForUrl(child, parserFor(provider), urlTimeoutMs);
262
- if (!url) return failAfterCleanup(exited ? `${provider} exited before printing a tunnel URL.` : `${provider} did not print a tunnel URL within ${urlTimeoutMs}ms.`, exited || childExited);
263
- if (!outputFile) resumeChildPipes(child);
264
- if (requireReachable) {
265
- if (!await waitUntilReachable({
266
- url,
267
- now,
268
- sleep,
269
- probe: probeReachable,
270
- timeoutMs: reachableTimeoutMs
271
- })) return failAfterCleanup(`${url} did not become reachable within ${reachableTimeoutMs}ms; ${provider} may still be registering, or the network path is blocked.`);
272
- }
273
- const finalProcessToken = captureChildIdentity();
274
- if (!finalProcessToken || finalProcessToken !== initialProcessToken) return failAfterCleanup(`${provider} process identity changed before its tunnel could be recorded.`);
275
- if (!outputFile) unrefChildPipes(child);
276
- child.unref?.();
277
- if (childExited) return failAfterCleanup(`${provider} exited before its tunnel could be recorded.`, true);
278
- return {
279
- url,
280
- pid,
281
- processToken: initialProcessToken,
282
- logFile: outputFile,
283
- cleanup: () => cleanup()
284
- };
285
- }
286
- async function startTunnelSequence({ providers, port, ngrokUrl = null, requireReachable = true, start = startTunnel }) {
287
- const failures = [];
288
- for (const provider of providers) {
289
- const result = await start({
290
- provider,
291
- port,
292
- ngrokUrl: provider === "ngrok" ? ngrokUrl : null,
293
- requireReachable
294
- });
295
- if (!("failed" in result)) return {
296
- provider,
297
- ...result
298
- };
299
- failures.push(`${provider}: ${result.reason}`);
300
- if (result.cleanupFailed) return {
301
- failed: true,
302
- reason: failures.join(" ")
303
- };
304
- }
305
- return {
306
- failed: true,
307
- reason: failures.join(" ") || "No managed tunnel provider was selected."
308
- };
309
- }
310
- function closeChildPipes(child) {
311
- child.stdout?.destroy?.();
312
- child.stderr?.destroy?.();
313
- }
314
- function unrefChildPipes(child) {
315
- resumeChildPipes(child);
316
- for (const stream of [child.stdout, child.stderr]) stream?.unref?.();
317
- }
318
- function resumeChildPipes(child) {
319
- child.stdout?.resume?.();
320
- child.stderr?.resume?.();
321
- }
322
- async function signalAndWaitForExit(child, signal, { timeoutMs, now, sleep, isAlive, platform }) {
323
- let exited = false;
324
- const onExit = () => {
325
- exited = true;
326
- };
327
- child.once("exit", onExit);
328
- try {
329
- if (platform === "win32" && child.pid) signalProcessTree(child.pid, signal, { platform });
330
- child.kill(signal);
331
- } catch (err) {
332
- child.removeListener("exit", onExit);
333
- return isEsrch(err);
334
- }
335
- const hasExited = () => exited;
336
- const deadline = now() + timeoutMs;
337
- while (!hasExited() && now() < deadline) await sleep(CLEANUP_POLL_MS);
338
- if (!hasExited() && child.pid && !isAlive(child.pid)) exited = true;
339
- child.removeListener("exit", onExit);
340
- return hasExited();
341
- }
342
- async function terminateChild(child, { alreadyExited, timeoutMs, now, sleep, isAlive, platform = process.platform }) {
343
- if (alreadyExited) {
344
- closeChildPipes(child);
345
- return true;
346
- }
347
- if (await signalAndWaitForExit(child, "SIGTERM", {
348
- timeoutMs,
349
- now,
350
- sleep,
351
- isAlive,
352
- platform
353
- })) {
354
- closeChildPipes(child);
355
- return true;
356
- }
357
- const killed = await signalAndWaitForExit(child, "SIGKILL", {
358
- timeoutMs,
359
- now,
360
- sleep,
361
- isAlive,
362
- platform
363
- });
364
- closeChildPipes(child);
365
- return killed;
366
- }
367
- function describe(err) {
368
- return err?.message || String(err);
369
- }
370
- const STOP_TIMEOUT_MS = 5e3;
371
- const STOP_POLL_MS = 100;
372
- function isEsrch(err) {
373
- return err?.code === "ESRCH";
374
- }
375
- async function stopTunnel(record, { isAlive = pidExists, inspectIdentity = process_identity_exports.inspectProcessIdentity, platform = process.platform, kill = (pid) => signalProcessTree(pid, "SIGTERM", { platform }), now = Date.now, sleep = defaultSleep, timeoutMs = STOP_TIMEOUT_MS } = {}) {
376
- const missing = () => {
377
- removeRecordedTunnelLogFile(record?.logFile);
378
- return { status: "missing" };
379
- };
380
- const pid = record?.pid;
381
- if (!pid || !isAlive(pid)) return missing();
382
- if (!record.processToken) return {
383
- status: "failed",
384
- reason: `tunnel pid ${pid} has no process identity token, so Stim cannot verify ownership. Keep the record. Inspect the process, stop it with the provider tooling, remove the stale metroTunnel state, and retry.`
385
- };
386
- const identity = inspectIdentity(record);
387
- if (identity === "gone" || identity === "different") return missing();
388
- if (identity !== "same") return {
389
- status: "failed",
390
- reason: `could not verify the process identity for tunnel pid ${pid}; refusing to signal it.`
391
- };
392
- try {
393
- kill(pid);
394
- } catch (err) {
395
- return isEsrch(err) ? missing() : {
396
- status: "failed",
397
- reason: describe(err)
398
- };
399
- }
400
- const deadline = now() + timeoutMs;
401
- const exited = () => {
402
- if (!isAlive(pid)) return true;
403
- const current = inspectIdentity(record);
404
- return current === "gone" || current === "different";
405
- };
406
- while (now() < deadline && !exited()) await sleep(STOP_POLL_MS);
407
- if (!exited()) return {
408
- status: "failed",
409
- reason: `pid ${pid} did not exit within ${timeoutMs}ms.`
410
- };
411
- removeRecordedTunnelLogFile(record.logFile);
412
- return { status: "stopped" };
413
- }
414
- //#endregion
415
- //#region src/supervisor/ownership.ts
416
- function resolveSupervisorTarget({ state, record, reservedPort, isAlive = pidExists, inspectIdentity = process_identity_exports.inspectProcessIdentity } = {}) {
417
- const statePid = numberOrNull(state?.pid);
418
- const recordPid = numberOrNull(record?.pid);
419
- const pid = statePid ?? recordPid;
420
- if (!pid) return { status: "none" };
421
- if (statePid && recordPid && statePid !== recordPid) return {
422
- status: "unverified",
423
- pid,
424
- reason: `workspace state.json records supervisor pid ${statePid} but the registry records pid ${recordPid}`
425
- };
426
- if (!isAlive(pid)) return {
427
- status: "stale",
428
- pid
429
- };
430
- const port = numberOrNull(state?.port) ?? numberOrNull(record?.port);
431
- if (reservedPort !== null && reservedPort !== void 0 && port !== null && port !== reservedPort) return {
432
- status: "unverified",
433
- pid,
434
- reason: `supervisor pid ${pid} records port ${port}, but this project reserved port ${reservedPort}`
435
- };
436
- if (reservedPort !== null && reservedPort !== void 0 && port === null) return {
437
- status: "unverified",
438
- pid,
439
- reason: `supervisor pid ${pid} has no recorded port, so it cannot be matched against reserved port ${reservedPort}`
440
- };
441
- const identityRecord = statePid ? state : record;
442
- if (statePid && recordPid && state?.processToken !== record?.processToken) return {
443
- status: "unverified",
444
- pid,
445
- reason: "workspace state and registry process identities disagree"
446
- };
447
- const identity = inspectIdentity(identityRecord);
448
- if (identity === "gone" || identity === "different") return {
449
- status: "stale",
450
- pid
451
- };
452
- if (identity !== "same") return {
453
- status: "unverified",
454
- pid,
455
- reason: "the recorded process identity could not be verified"
456
- };
457
- return {
458
- status: "ours",
459
- processToken: identityRecord.processToken,
460
- pid,
461
- port,
462
- mode: state?.mode ?? record?.mode ?? null,
463
- startedAt: state?.startedAt ?? record?.startedAt ?? null
464
- };
465
- }
466
- function numberOrNull(v) {
467
- return typeof v === "number" && Number.isSafeInteger(v) && v > 0 ? v : null;
468
- }
469
- //#endregion
470
- export { withManagedRemoteWorktreeLock as a, withManagedTunnelRemovalLock as c, terminateChild as i, startTunnelSequence as n, withManagedRemoteWorktreeRemovalLock as o, stopTunnel as r, withManagedTunnelLock as s, resolveSupervisorTarget as t };
@@ -1,61 +0,0 @@
1
- import { resolve4 } from "node:dns/promises";
2
- import { request } from "node:https";
3
- //#region src/engine/public-http-probe.ts
4
- const DNS_TIMEOUT_MS = 5e3;
5
- async function resolveAddresses(hostname, signal) {
6
- if (signal.aborted) throw signal.reason;
7
- let timer;
8
- let onAbort;
9
- const unavailable = new Promise((_resolve, reject) => {
10
- onAbort = () => reject(signal.reason);
11
- signal.addEventListener("abort", onAbort, { once: true });
12
- if (signal.aborted) onAbort();
13
- else timer = setTimeout(() => reject(/* @__PURE__ */ new Error("DNS lookup timed out")), DNS_TIMEOUT_MS);
14
- });
15
- try {
16
- return await Promise.race([resolve4(hostname), unavailable]);
17
- } finally {
18
- clearTimeout(timer);
19
- if (onAbort) signal.removeEventListener("abort", onAbort);
20
- }
21
- }
22
- async function probePublicHttp(url, signal) {
23
- try {
24
- return (await fetch(url, {
25
- signal,
26
- redirect: "follow"
27
- })).status;
28
- } catch (error) {
29
- const cause = error?.cause;
30
- if (cause?.code !== "ENOTFOUND" && cause?.code !== "EAI_AGAIN") return null;
31
- }
32
- const hostname = new URL(url).hostname;
33
- if (!hostname.endsWith(".trycloudflare.com")) return null;
34
- let addresses;
35
- try {
36
- addresses = await resolveAddresses(hostname, signal);
37
- } catch {
38
- return null;
39
- }
40
- const firstAddress = addresses[0];
41
- if (!firstAddress) return null;
42
- return new Promise((resolve) => {
43
- const request$1 = request(url, {
44
- signal,
45
- lookup: (_hostname, options, callback) => {
46
- if (options.all) callback(null, addresses.map((address) => ({
47
- address,
48
- family: 4
49
- })));
50
- else callback(null, firstAddress, 4);
51
- }
52
- }, (response) => {
53
- response.resume();
54
- resolve(response.statusCode ?? null);
55
- });
56
- request$1.on("error", () => resolve(null));
57
- request$1.end();
58
- });
59
- }
60
- //#endregion
61
- export { probePublicHttp as t };