stim 1.18.0 → 1.19.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 (140) hide show
  1. package/README.md +1 -1
  2. package/dist/{activity-BxnkDZDi.mjs → activity-BSw0x84R.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +5 -5
  4. package/dist/{android-BvwuMUJ9.mjs → android-BXc6BmEi.mjs} +507 -347
  5. package/dist/{android-DC3ZLuw0.mjs → android-BdQC6zs1.mjs} +6 -6
  6. package/dist/{android-BKA16DTf.mjs → android-BvV1gGdN.mjs} +3 -3
  7. package/dist/{android-CBwCNicO.mjs → android-DE5g_5gv.mjs} +2 -2
  8. package/dist/{android-cas-BBFyr9CA.mjs → android-cas-C87geAg-.mjs} +3 -3
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/{api-D0VtFhqk.mjs → api-DIf_s86s.mjs} +5 -7
  11. package/dist/api-run.mjs +8 -8
  12. package/dist/api.d.mts +8 -2
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-D-PUENug.mjs → app-install-CFI4ptUL.mjs} +33 -13
  15. package/dist/{web-DTU0uiWj.mjs → browser-web-CDhqQxhv.mjs} +134 -172
  16. package/dist/{budget-DIhL2BKx.mjs → budget-Dz-kyXLv.mjs} +15 -202
  17. package/dist/{build-facts-DcLv2HSd.d.mts → build-facts-B87vo-Im.d.mts} +32 -1
  18. package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-DiwKSyv9.mjs} +1 -1
  19. package/dist/cache-manifest.mjs +1 -1
  20. package/dist/{chrome-DJnmnS5q.mjs → chrome-BTUOo8p2.mjs} +1 -1
  21. package/dist/{cli-DNJMwADx.mjs → cli-C9Zvgbdc.mjs} +20 -20
  22. package/dist/cli.mjs +1 -1
  23. package/dist/{client-DzhapoMB.mjs → client-CuUo8Nvg.mjs} +248 -23
  24. package/dist/collector-run.d.mts +6 -0
  25. package/dist/collector-run.mjs +6 -6
  26. package/dist/{command-output-CBtzyIgF.mjs → command-output-Bt8ygHE7.mjs} +1 -1
  27. package/dist/{config-CgYMahz7.mjs → config-DC5jEtd1.mjs} +6 -2
  28. package/dist/{created-devices-DKbeWsiK.mjs → created-devices-D0s26Hx5.mjs} +2 -2
  29. package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
  30. package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
  31. package/dist/{dev-client-CLnIH02x.mjs → dev-client-CDY_zAmD.mjs} +2 -2
  32. package/dist/{device-D7oCHGWi.mjs → device-BHw0WlHl.mjs} +8 -8
  33. package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-BoN1jQkO.mjs} +23 -12
  34. package/dist/device-host-worker.mjs +14 -14
  35. package/dist/{gradle-C6GKnunQ.mjs → device-ios-B2ruohE-.mjs} +659 -105
  36. package/dist/{device-lease-Co-EwifR.mjs → device-lease-Cu7PtQpZ.mjs} +5 -5
  37. package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
  38. package/dist/{device-pool-F5WvRPtD.mjs → device-pool-CP4rAsHx.mjs} +3 -3
  39. package/dist/{device-remote-tHbd1fKy.mjs → device-remote-B5GiUifk.mjs} +15 -16
  40. package/dist/{doctor-B9ckYUoU.mjs → doctor-PRJH94v6.mjs} +53 -29
  41. package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
  42. package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics--v5HGOU0.mjs} +10 -10
  43. package/dist/{exec-DWhCZDGm.mjs → exec-i8GDPwq9.mjs} +32 -8
  44. package/dist/{gc-Dh6mXOKC.mjs → gc-CyHMcKcn.mjs} +19 -19
  45. package/dist/{guide-tm6igAaa.mjs → guide-dRaQJJk9.mjs} +409 -472
  46. package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
  47. package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-C5G4h_OJ.mjs} +1 -1
  48. package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-Bik035eL.mjs} +1 -1
  49. package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-CI9Az9a4.mjs} +7 -7
  50. package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-DABm3ScO.mjs} +4 -4
  51. package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-DbV2aUVw.mjs} +12 -8
  52. package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DYiMBn34.mjs} +7 -7
  53. package/dist/{ios-B3SbOWdw.mjs → ios-BWbHFZVz.mjs} +5 -5
  54. package/dist/{ios-Bvbf0SGY.mjs → ios-DCrkgXEM.mjs} +1 -1
  55. package/dist/{ios-DNpdygiv.mjs → ios-DYUr9LGc.mjs} +7 -6
  56. package/dist/ios-ITYno9rO.mjs +2241 -0
  57. package/dist/{ios-device-vOaByMhw.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
  58. package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-CrW8aMb5.mjs} +1 -1
  59. package/dist/{ios-state-B2pES6Vs.mjs → ios-state-By0XuLTQ.mjs} +1 -1
  60. package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-DCveSE6d.mjs} +4 -4
  61. package/dist/{logs-1Ylc1Ri6.mjs → logs-Bao1HOMy.mjs} +10 -10
  62. package/dist/{macos-DF6C7wUU.mjs → macos-ciyBdTY5.mjs} +108 -130
  63. package/dist/macos-nIOATJmR.mjs +2 -0
  64. package/dist/macos-run.mjs +1 -1
  65. package/dist/maintenance-run.mjs +7 -7
  66. package/dist/manifest-CX0d1IkZ.mjs +148 -0
  67. package/dist/{metro-Dh8T4Ytd.mjs → metro-DI2AjPF_.mjs} +194 -41
  68. package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BxpJLIwh.mjs} +2 -2
  69. package/dist/{plan-placement-CtxkCO54.mjs → miss-reason-CjQCOKqq.mjs} +180 -296
  70. package/dist/{named-ports-BFIz1Shz.mjs → named-ports-B4iWH4E-.mjs} +12 -5
  71. package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BGxsbfny.mjs} +6 -6
  72. package/dist/offload-worker.d.mts +1 -29
  73. package/dist/offload-worker.mjs +9 -8
  74. package/dist/{ownership-D6Se7gg_.mjs → ownership-EB0ySdGK.mjs} +2 -2
  75. package/dist/{placement-log-BcPhRwR4.mjs → placement-log-Dxe34rJm.mjs} +7 -3
  76. package/dist/plan-placement-BVY59qa8.mjs +290 -0
  77. package/dist/{ports-BLTtfBq-.mjs → ports-ByPc0_97.mjs} +3 -3
  78. package/dist/{prebuild-juCyreaR.mjs → prebuild-BKJ3wJI1.mjs} +4 -4
  79. package/dist/{preview-D5V07Nrl.mjs → preview-BbSottmO.mjs} +16 -17
  80. package/dist/project-B5eQ1USs.mjs +612 -0
  81. package/dist/{pull-request-u4vp7zmK.mjs → pull-request-IHNdMnG8.mjs} +1 -1
  82. package/dist/pull-requests.mjs +1 -1
  83. package/dist/react-native-ios-BMh2i25I.mjs +2 -0
  84. package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
  85. package/dist/{recordings-BAWltsVt.mjs → recordings-Bv8McZN4.mjs} +1 -1
  86. package/dist/{reload-DvyWzVjJ.mjs → reload-rAPdqeRR.mjs} +13 -14
  87. package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-N3hAEaAL.mjs} +4 -4
  88. package/dist/{run-vhtDgpHO.mjs → run-lAkle1-c.mjs} +2 -2
  89. package/dist/{server-bare-B9E7S1aR.mjs → server-bare-CkIjnegq.mjs} +3 -3
  90. package/dist/server-expo-DGsdUGX2.mjs +2 -0
  91. package/dist/{server-expo-DoBHhuzK.mjs → server-expo-n3tUi3Em.mjs} +3 -3
  92. package/dist/{settings-Byp2AQ_E.mjs → settings-2am7TSxp.mjs} +5 -6
  93. package/dist/{settings-CQyMElEP.mjs → settings-CxgngUZk.mjs} +767 -15
  94. package/dist/settings.schema.json +72 -6
  95. package/dist/{simslim-EHBQ2R4G.mjs → simslim-D9LkJxIO.mjs} +5 -5
  96. package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
  97. package/dist/{stage-g_WqWeaE.mjs → stage-BgaZJVZY.mjs} +1 -1
  98. package/dist/{start-NTc1Ifqs.mjs → start-D8NbxNBb.mjs} +1 -1
  99. package/dist/{start-D-IeOyoK.mjs → start-DtxthMfI.mjs} +29 -22
  100. package/dist/{state-BG-aAk4k.mjs → state-D2KtnALG.mjs} +2 -2
  101. package/dist/{state-xnqpx3AD.mjs → state-Tp4uImDS.mjs} +4 -2
  102. package/dist/{stats-DY6ekz8F.mjs → stats-8EJ5ivFT.mjs} +6 -6
  103. package/dist/{status-DCjZeE-K.mjs → status-BOyp0CUl.mjs} +25 -27
  104. package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
  105. package/dist/{stim-installations-aR_WsNOA.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
  106. package/dist/stop-D0UIpZuh.mjs +72 -0
  107. package/dist/{stop-DIJtD2GL.mjs → stop-DRipAg-e.mjs} +2 -2
  108. package/dist/{stop-BTjs3xbc.mjs → stop-zDlknFoz.mjs} +78 -31
  109. package/dist/supervisor-run.mjs +14 -14
  110. package/dist/{support-BaayeYCf.mjs → support-CNqYkV0y.mjs} +7 -7
  111. package/dist/{support-Bwvbrq5-.mjs → support-DsNaFg6D.mjs} +5 -5
  112. package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
  113. package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-C3xSoyUl.mjs} +27 -270
  114. package/dist/{trigger-CJMhwXe8.mjs → trigger-CAhmG-4s.mjs} +3 -3
  115. package/dist/trigger-CoalsMTV.mjs +2 -0
  116. package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-pFLB2e6P.mjs} +133 -36
  117. package/dist/{status-Dcr0Qexd.mjs → watchman-BL1IdOtq.mjs} +75 -7
  118. package/dist/web-DFpFeZu5.mjs +2 -0
  119. package/dist/web-DbbrPUn0.mjs +127 -0
  120. package/dist/web-run.mjs +7 -7
  121. package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CR9X86xJ.mjs} +1 -1
  122. package/dist/{workspaces-xXItD8Dj.mjs → workspaces-Djb2gfi9.mjs} +102 -18
  123. package/dist/{worktree-BSYlofkq.mjs → worktree-BL4M1rhB.mjs} +45 -42
  124. package/dist/{worktree-BJfnU6r5.mjs → worktree-DV-A0LNL.mjs} +1 -1
  125. package/package.json +5 -5
  126. package/shim/bundle-response.cjs +2 -1
  127. package/shim/bundle-response.d.cts +1 -1
  128. package/shim/expo-metro-config.cjs +1 -1
  129. package/dist/device-ios-6MewKKnc.mjs +0 -412
  130. package/dist/guide-status-Bhf9SJXc.mjs +0 -125
  131. package/dist/ios-CPdkoKaa.mjs +0 -3953
  132. package/dist/macos-Ck7OBMNY.mjs +0 -2
  133. package/dist/native-run-B06FkmZx.mjs +0 -158
  134. package/dist/project-C3ChRLZy.mjs +0 -212
  135. package/dist/projects-DD7dBTCj.mjs +0 -92
  136. package/dist/server-expo-Db9HBUoa.mjs +0 -2
  137. package/dist/stop-BGhKMOuH.mjs +0 -48
  138. package/dist/trigger-DWAq9hkw.mjs +0 -2
  139. package/dist/web-B6_bFDn7.mjs +0 -2
  140. package/dist/worktree-CsKYexJM.mjs +0 -753
@@ -1,8 +1,9 @@
1
- import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-CBtzyIgF.mjs";
2
- import { H as projectDeviceSlots, R as deviceSlotKey } from "./config-CgYMahz7.mjs";
3
- import { n as isInsideProject } from "./metro-Dh8T4Ytd.mjs";
4
- import { g as workspaceAgentDeviceDir } from "./workspace-state-C59dqG-Z.mjs";
5
- import { r as cdpEndpoint } from "./state-BG-aAk4k.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-Bt8ygHE7.mjs";
3
+ import { H as projectDeviceSlots, R as deviceSlotKey } from "./config-DC5jEtd1.mjs";
4
+ import { g as workspaceAgentDeviceDir } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { n as isInsideProject } from "./metro-DI2AjPF_.mjs";
6
+ import { r as cdpEndpoint } from "./state-D2KtnALG.mjs";
6
7
  import { basename, sep } from "path";
7
8
  import { ACTIVITY_RECENCY_BASES } from "@stim-cli/core/state";
8
9
  //#region src/status.ts
@@ -153,7 +154,10 @@ function environmentState(project, { simsByUdid = {}, metro = null, worktrees =
153
154
  startedAt: supervisor.startedAt ?? null,
154
155
  healthy: Boolean(supervisor.healthy)
155
156
  } : null,
156
- agentDevice: { stateDir: workspaceAgentDeviceDir(project.__path) },
157
+ agentDevice: {
158
+ stateDir: workspaceAgentDeviceDir(project.__path),
159
+ installed: agentDeviceInstalled()
160
+ },
157
161
  logs: logs ? {
158
162
  dir: logs.dir,
159
163
  errorsSinceMarker: logs.errorsSinceMarker ?? 0
@@ -432,5 +436,69 @@ function deviceLeaseLines(states, now) {
432
436
  }
433
437
  return lines;
434
438
  }
439
+ const AGENT_DEVICE_CACHE_MS = 3e4;
440
+ let agentDeviceCache;
441
+ function agentDeviceInstalled() {
442
+ const now = Date.now();
443
+ const age = agentDeviceCache ? now - agentDeviceCache.at : -1;
444
+ if (agentDeviceCache && age >= 0 && age < AGENT_DEVICE_CACHE_MS) return agentDeviceCache.installed;
445
+ let installed = false;
446
+ try {
447
+ installed = Boolean(getExecutor().findExecutable("agent-device"));
448
+ } catch {
449
+ installed = false;
450
+ }
451
+ agentDeviceCache = {
452
+ at: now,
453
+ installed
454
+ };
455
+ return installed;
456
+ }
457
+ //#endregion
458
+ //#region src/watchman.ts
459
+ /** Runs one watchman command with `--no-spawn`, so Stim never starts a daemon, and parses its JSON answer. */
460
+ const runWatchman = async (args, timeoutMs) => JSON.parse(await getExecutor().runFileAsync("watchman", ["--no-spawn", ...args], { timeoutMs }));
461
+ function parseWatchRoots(payload) {
462
+ const roots = payload?.roots;
463
+ if (!Array.isArray(roots)) return null;
464
+ return roots.filter((root) => typeof root === "string");
465
+ }
466
+ function parseSubscriberNames(payload) {
467
+ if (!payload || typeof payload !== "object" || "error" in payload) return null;
468
+ const subscribers = payload.subscribers;
469
+ if (subscribers === void 0) return [];
470
+ if (!Array.isArray(subscribers)) return null;
471
+ const names = [];
472
+ for (const subscriber of subscribers) {
473
+ const name = subscriber?.info?.name;
474
+ if (typeof name !== "string") return null;
475
+ names.push(name);
476
+ }
477
+ return names;
478
+ }
479
+ function parseTriggerCount(payload) {
480
+ const triggers = payload?.triggers;
481
+ return Array.isArray(triggers) ? triggers.length : null;
482
+ }
483
+ function parseWatchmanPid(payload) {
484
+ const pid = payload?.pid;
485
+ return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : null;
486
+ }
487
+ /** The connected clients in a `debug-status` answer, or null when the answer does not list them. */
488
+ function parseWatchmanClients(payload) {
489
+ if (!payload || typeof payload !== "object" || "error" in payload) return null;
490
+ const clients = payload.clients;
491
+ if (!Array.isArray(clients)) return null;
492
+ const parsed = [];
493
+ for (const client of clients) {
494
+ const peer = client?.peer;
495
+ if (typeof peer?.pid !== "number") return null;
496
+ parsed.push({
497
+ pid: peer.pid,
498
+ name: typeof peer.name === "string" ? peer.name : null
499
+ });
500
+ }
501
+ return parsed;
502
+ }
435
503
  //#endregion
436
- export { statusActivity as _, capacity as a, withWebFacts as b, diskLine as c, gitSummaryText as d, metroReverseTargets as f, remoteDeviceState as g, remoteDeviceLine as h, applyMachineMemory as i, environmentState as l, poolLine as m, activityLabel as n, deviceLeaseLines as o, parseDfFree as p, addReverseMissingIssue as r, deviceLeaseStates as s, RECENT_LAUNCH_MS as t, formatSpace as u, tightVolumes as v, unprovisionedWorktrees as y };
504
+ export { statusActivity as C, withWebFacts as E, remoteDeviceState as S, unprovisionedWorktrees as T, gitSummaryText as _, parseWatchmanPid as a, poolLine as b, activityLabel as c, capacity as d, deviceLeaseLines as f, formatSpace as g, environmentState as h, parseWatchmanClients as i, addReverseMissingIssue as l, diskLine as m, parseTriggerCount as n, runWatchman as o, deviceLeaseStates as p, parseWatchRoots as r, RECENT_LAUNCH_MS as s, parseSubscriberNames as t, applyMachineMemory as u, metroReverseTargets as v, tightVolumes as w, remoteDeviceLine as x, parseDfFree as y };
@@ -0,0 +1,2 @@
1
+ import { n as webCommand, t as runWeb } from "./web-DbbrPUn0.mjs";
2
+ export { webCommand as default, runWeb };
@@ -0,0 +1,127 @@
1
+ import { f as refuseNoProject, l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
2
+ import { E as upsertProject, p as getProject } from "./config-DC5jEtd1.mjs";
3
+ import { i as recordWorkspaceUse, x as workspaceLogsDir } from "./workspace-state-CR9X86xJ.mjs";
4
+ import { d as projectRegistry, n as findCommandWorkspace } from "./project-B5eQ1USs.mjs";
5
+ import { B as settingShapeErrors, I as resolveSettings, i as SETTING_SHAPE_REMEDY, mt as repoRoot, nt as gitCommonDir } from "./settings-CxgngUZk.mjs";
6
+ import { o as readWebRecord, r as cdpEndpoint } from "./state-D2KtnALG.mjs";
7
+ import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-C65jk_q2.mjs";
8
+ import { n as ensureWorkspaceStorageSafely } from "./native-runtime-BGxsbfny.mjs";
9
+ import { t as liveWebRecord } from "./page-Bv9s2KwY.mjs";
10
+ import chalk from "chalk";
11
+ //#region src/commands/web.ts
12
+ const printNote = (line) => console.error(line);
13
+ async function runWeb({ root, headed, note }) {
14
+ const startedAt = Date.now();
15
+ await ensureWorkspaceStorageSafely(root, { note });
16
+ if (!getProject(root)) upsertProject(root, {});
17
+ const settings = resolveSettings({
18
+ projectPath: root,
19
+ gitCommonDir: gitCommonDir(root),
20
+ repoRoot: repoRoot(root)
21
+ });
22
+ const [shapeError] = settingShapeErrors(settings);
23
+ if (shapeError) return {
24
+ ok: false,
25
+ error: {
26
+ code: "STIM_BAD_ARG",
27
+ message: shapeError,
28
+ remedy: SETTING_SHAPE_REMEDY
29
+ }
30
+ };
31
+ const selected = projectRegistry.selectWeb(root);
32
+ if ("problem" in selected) {
33
+ const { message, remedy } = selected.problem;
34
+ return {
35
+ ok: false,
36
+ error: {
37
+ code: "STIM_NO_PROJECT",
38
+ message,
39
+ remedy
40
+ }
41
+ };
42
+ }
43
+ const runtime = (await selected.load()).runtime({
44
+ settings,
45
+ headed,
46
+ note
47
+ });
48
+ const preparation = await runtime.prepare();
49
+ if (!preparation.ok) return {
50
+ ok: false,
51
+ error: {
52
+ ...preparation.error,
53
+ remedy: preparation.error.remedy ?? null
54
+ }
55
+ };
56
+ const { prepared } = preparation;
57
+ const { url } = prepared;
58
+ const launch = await runtime.launch(prepared, {
59
+ root,
60
+ note
61
+ });
62
+ if (!launch.ok) return launch;
63
+ const { verdict, remedy } = await runtime.verify(prepared, { since: launch.since });
64
+ const live = liveWebRecord(readWebRecord(root));
65
+ const record = live ?? launch.record;
66
+ return {
67
+ ok: true,
68
+ remedy,
69
+ facts: {
70
+ platform: "web",
71
+ browser: "chrome",
72
+ version: record.version ?? null,
73
+ running: live !== null,
74
+ pid: live?.chromeProcess?.pid ?? null,
75
+ supervisorPid: live?.pid ?? null,
76
+ url,
77
+ headless: record.headless,
78
+ viewport: record.viewport,
79
+ profile: record.profile,
80
+ cdpEndpoint: live ? cdpEndpoint(live.cdpPort) : null,
81
+ targetId: live?.targetId ?? null,
82
+ reused: launch.reused,
83
+ launched: verdict.launched,
84
+ metroPort: prepared.metroPort,
85
+ logs: { dir: workspaceLogsDir(root) },
86
+ durationMs: Date.now() - startedAt
87
+ }
88
+ };
89
+ }
90
+ function webCommand(program) {
91
+ program.command("web").description("Open this workspace's page in a Stim-owned headless Chrome and capture its console, errors and failed requests in stim logs").option("--headed", "Show the Chrome window instead of running headless").option("--json", "Print the result as one JSON object; progress goes to stderr").action(async (opts) => {
92
+ const json = Boolean(opts.json);
93
+ const root = findCommandWorkspace(process.cwd());
94
+ if (!root) {
95
+ refuseNoProject({ json });
96
+ return;
97
+ }
98
+ recordWorkspaceUse(root);
99
+ const result = await runWeb({
100
+ root,
101
+ headed: Boolean(opts.headed),
102
+ note: printNote
103
+ });
104
+ if (!result.ok) {
105
+ printNote(chalk.red(phaseLine("error", `${result.error.code}: ${result.error.message}`)));
106
+ if (result.error.remedy) printNote(phaseLine("remedy", result.error.remedy));
107
+ if (json) console.log(JSON.stringify(result.error));
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ const { facts, remedy } = result;
112
+ if (remedy) printNote(chalk.yellow(phaseLine("launch", remedy)));
113
+ const links = workspaceLinks(root, { platform: "web" });
114
+ if (json) {
115
+ console.log(JSON.stringify(links ? {
116
+ ...facts,
117
+ links
118
+ } : facts));
119
+ return;
120
+ }
121
+ const launched = facts.launched === true ? chalk.green("loaded") : chalk.yellow(facts.launched === "bundling" ? "bundling" : "unverified");
122
+ console.log(facts.running ? `${facts.url} ${launched} in ${facts.version ?? "Chrome"} (pid ${facts.pid}, ${facts.headless ? "headless" : "headed"}, ${facts.viewport}). DevTools: ${facts.cdpEndpoint}. Logs: stim logs --errors.` : `${facts.url} ${launched}, and the owned Chrome is no longer running. Run stim logs --errors, then stim web again.`);
123
+ if (links) console.error(chalk.dim(workspaceLinkLine(links)));
124
+ });
125
+ }
126
+ //#endregion
127
+ export { webCommand as n, runWeb as t };
package/dist/web-run.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
3
- import { u as signalProcessTree } from "./metro-Dh8T4Ytd.mjs";
4
- import { _ as removeSingletonFiles, c as webClaimRoot, d as webLogFile, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, l as webDir, m as writeWebRecord, n as browserLogFile, s as updateWebRecord } from "./state-BG-aAk4k.mjs";
5
- import { c as probeWebDrivers } from "./activity-BxnkDZDi.mjs";
6
- import { r as recordCreatedDevice } from "./created-devices-DKbeWsiK.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
+ import { d as signalProcessTree } from "./metro-DI2AjPF_.mjs";
4
+ import { _ as removeSingletonFiles, c as webClaimRoot, d as webLogFile, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, l as webDir, m as writeWebRecord, n as browserLogFile, s as updateWebRecord } from "./state-D2KtnALG.mjs";
5
+ import { c as probeWebDrivers } from "./activity-BSw0x84R.mjs";
6
+ import { r as recordCreatedDevice } from "./created-devices-D0s26Hx5.mjs";
7
7
  import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
8
- import { t as relaunchWithLogFile } from "./detached-entry-BLfcgc4O.mjs";
9
- import { i as chromeArgs, n as DESKTOP_PAGE, r as PHONE_SCREEN } from "./chrome-DJnmnS5q.mjs";
8
+ import { t as relaunchWithLogFile } from "./detached-entry-pB_IPfV4.mjs";
10
9
  import { t as connectOwnedBrowser } from "./cdp-Dq_ypAlJ.mjs";
10
+ import { i as chromeArgs, n as DESKTOP_PAGE, r as PHONE_SCREEN } from "./chrome-BTUOo8p2.mjs";
11
11
  import { existsSync, mkdirSync, openSync, realpathSync } from "node:fs";
12
12
  import { isAbsolute, resolve } from "node:path";
13
13
  import { WEB_VIEWPORTS } from "@stim-cli/core/state";
@@ -1,5 +1,5 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname, isAbsolute, join, relative } from "node:path";
5
5
  import { join as join$1, resolve as resolve$1 } from "path";
@@ -1,25 +1,24 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
3
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { a as formatElapsed, l as phaseLine } from "./command-output-CBtzyIgF.mjs";
5
- import { D as withConfigLock$1, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, P as measuredDirectorySize, _ as loadConfig$1, d as getConfigDir, g as isPathPrefix, j as formatBytes, k as acquireAvdClaim, p as getProject, z as deviceSlotPlatforms } from "./config-CgYMahz7.mjs";
6
- import { y as repoRoot } from "./worktree-CsKYexJM.mjs";
7
- import { o as pidExists, u as signalProcessTree } from "./metro-Dh8T4Ytd.mjs";
8
- import { S as workspaceName, g as workspaceAgentDeviceDir, r as readWorkspaceState$1, s as workspaceLastUsed, v as workspaceDir } from "./workspace-state-C59dqG-Z.mjs";
9
- import { _ as removeSingletonFiles, c as webClaimRoot, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, o as readWebRecord, t as CDP_PORT_LABEL, u as webFacts } from "./state-BG-aAk4k.mjs";
10
- import { t as agentDeviceDaemon, u as readAgentDeviceRecords } from "./activity-BxnkDZDi.mjs";
11
- import { h as listBuildLocks } from "./device-lease-Co-EwifR.mjs";
4
+ import { a as formatElapsed, l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
5
+ import { D as withConfigLock$1, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, P as measuredDirectorySize, _ as loadConfig$1, d as getConfigDir, g as isPathPrefix, j as formatBytes, k as acquireAvdClaim, p as getProject, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
6
+ import { S as workspaceName, g as workspaceAgentDeviceDir, r as readWorkspaceState$1, s as workspaceLastUsed, v as workspaceDir } from "./workspace-state-CR9X86xJ.mjs";
7
+ import { Y as resolveTailscaleBinary, mt as repoRoot } from "./settings-CxgngUZk.mjs";
8
+ import { d as signalProcessTree, s as pidExists } from "./metro-DI2AjPF_.mjs";
9
+ import { _ as removeSingletonFiles, c as webClaimRoot, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, o as readWebRecord, t as CDP_PORT_LABEL, u as webFacts } from "./state-D2KtnALG.mjs";
10
+ import { t as agentDeviceDaemon, u as readAgentDeviceRecords } from "./activity-BSw0x84R.mjs";
11
+ import { h as listBuildLocks } from "./device-lease-Cu7PtQpZ.mjs";
12
12
  import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Kqiifsk2.mjs";
13
- import { n as readCreatedDevices$1, r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-DKbeWsiK.mjs";
14
- import { B as ownedAvdSystemImage, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, M as listOrphanedAvdDirectories, O as listAdbDevices, X as shutdownAndroidEmulator, Z as sleepSync, _ as avdStorageRoots, dt as parkSim, et as waitForAndroidEmulatorShutdown, f as assertOwnedAvdStopped, h as avdPathExists, it as isStimOwnedAvd, lt as eraseParkedAfter, mt as removeParkedAfter, nt as wipeAvdUserData, pt as readParked, x as deleteAvd } from "./android-DC3ZLuw0.mjs";
15
- import { D as shutdownIosSim, T as resolveOwnedIosSim, _ as parkedSimName, c as eraseIosSim, o as deleteIosSim, p as listIosDeviceTypes, s as deleteParkedIosSim, v as parseRuntimeVersion, x as renameIosSim } from "./ios-B3SbOWdw.mjs";
16
- import { J as resolveTailscaleBinary } from "./settings-CQyMElEP.mjs";
17
- import { a as withWorkspaceProcessLock, o as workspaceProcessLockError, r as releaseBrowserPort, s as workspaceProcessLockPath } from "./named-ports-BFIz1Shz.mjs";
18
- import { i as macosRuntimeClaim } from "./state-xnqpx3AD.mjs";
13
+ import { n as readCreatedDevices$1, r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-D0s26Hx5.mjs";
14
+ import { B as ownedAvdSystemImage, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, M as listOrphanedAvdDirectories, O as listAdbDevices, X as shutdownAndroidEmulator, Z as sleepSync, _ as avdStorageRoots, dt as parkSim, et as waitForAndroidEmulatorShutdown, f as assertOwnedAvdStopped, h as avdPathExists, it as isStimOwnedAvd, lt as eraseParkedAfter, mt as removeParkedAfter, nt as wipeAvdUserData, pt as readParked, x as deleteAvd } from "./android-BdQC6zs1.mjs";
15
+ import { D as shutdownIosSim, T as resolveOwnedIosSim, _ as parkedSimName, c as eraseIosSim, o as deleteIosSim, p as listIosDeviceTypes, s as deleteParkedIosSim, v as parseRuntimeVersion, x as renameIosSim } from "./ios-BWbHFZVz.mjs";
16
+ import { a as withWorkspaceProcessLock, o as workspaceProcessLockError, r as releaseBrowserPort, s as workspaceProcessLockPath } from "./named-ports-B4iWH4E-.mjs";
17
+ import { a as macosRuntimeClaim, n as macosDir } from "./state-Tp4uImDS.mjs";
19
18
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync } from "node:fs";
20
19
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
21
20
  import { basename as basename$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
22
- import { buildSlotsDir, hostedNativeRecords, isJsonObject, macosAppState, parseHostedNativePlacement, readJsonFile, readMacosRecord, tryAcquireBuildSlotClaim, unreadableHostedNative } from "@stim-cli/core/state";
21
+ import { buildSlotsDir, hostedNativeRecords, isJsonObject, macosAppState, parseHostedNativePlacement, readJsonFile, readMacosRecord, requireAutomaticMachine, tryAcquireBuildSlotClaim, unreadableHostedNative } from "@stim-cli/core/state";
23
22
  import { homedir } from "node:os";
24
23
  import chalk from "chalk";
25
24
  import { isDeepStrictEqual } from "node:util";
@@ -101,7 +100,8 @@ function tryAcquireBuildSlot({ max, root = null, logFile = null }) {
101
100
  function slotWaitingLine({ max, elapsedMs }) {
102
101
  return `${"build".padEnd(11)} waiting for a build slot (all ${max} in use, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle concurrency`;
103
102
  }
104
- async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, waitingFor = () => {}, sleep = sleepAsync$1, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS }) {
103
+ async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, waitingFor = () => {}, sleep = sleepAsync$1, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS, automatic = false }) {
104
+ if (automatic) requireAutomaticMachine("build", "local");
105
105
  if (!max || max <= 0) return {
106
106
  acquired: true,
107
107
  unlimited: true
@@ -111,6 +111,7 @@ async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.n
111
111
  let waited = false;
112
112
  try {
113
113
  for (;;) {
114
+ if (automatic) requireAutomaticMachine("build", "local");
114
115
  const got = tryAcquireBuildSlot({
115
116
  max,
116
117
  root,
@@ -910,6 +911,83 @@ async function teardownBrowserHeld(root, { deleteProfile = false } = {}) {
910
911
  }
911
912
  }
912
913
  //#endregion
914
+ //#region src/macos/instances.ts
915
+ const BUNDLE_EXECUTABLE = /^[^/]+\.app\/Contents\/MacOS\/[^/]+$/;
916
+ function bundleDirs(root) {
917
+ const dir = macosDir(root);
918
+ if (process.platform !== "darwin" || !existsSync(dir)) return [];
919
+ return [.../* @__PURE__ */ new Set([dir, realpathSync(dir)])];
920
+ }
921
+ function isBundleExecutable(path, dirs) {
922
+ return dirs.some((dir) => path.startsWith(`${dir}/`) && BUNDLE_EXECUTABLE.test(path.slice(dir.length + 1)));
923
+ }
924
+ /** Pids from `ps -axww -o pid=,comm=` output whose command names a bundle executable inside `dirs`. */
925
+ function bundleCandidates(psOutput, dirs) {
926
+ const pids = [];
927
+ for (const line of psOutput.split("\n")) {
928
+ const match = /^\s*(\d+)\s+(.+)$/.exec(line);
929
+ if (match && isBundleExecutable(match[2], dirs)) pids.push(Number(match[1]));
930
+ }
931
+ return pids;
932
+ }
933
+ /** Whether `lsof -Fn -d txt` output for one process names a bundle executable inside `dirs`. */
934
+ function lsofNamesBundleExecutable(lsofOutput, dirs) {
935
+ return lsofOutput.split("\n").some((line) => line.startsWith("n") && isBundleExecutable(line.slice(1), dirs));
936
+ }
937
+ function candidatePids(dirs) {
938
+ if (!dirs.length) return [];
939
+ return bundleCandidates(getExecutor().runFile("ps", [
940
+ "-axww",
941
+ "-o",
942
+ "pid=,comm="
943
+ ], { timeoutMs: 1e4 }), dirs).filter((pid) => pid !== process.pid);
944
+ }
945
+ /** Pids that claim to run an app bundle from the workspace's macOS directory. `ps` reports argv[0], so this is a lead. */
946
+ function bundleInstancePids(root) {
947
+ return candidatePids(bundleDirs(root));
948
+ }
949
+ function unverified(pid, why) {
950
+ return Object.assign(/* @__PURE__ */ new Error(`Cannot verify macOS app pid ${pid}: ${why}; no signal was sent.`), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
951
+ }
952
+ /**
953
+ * Every running process whose executable is an app bundle Stim built in the workspace's macOS directory, however it
954
+ * was launched. Each identity is captured before its executable is confirmed with lsof.
955
+ */
956
+ function runningBundleInstances(root) {
957
+ const dirs = bundleDirs(root);
958
+ const instances = [];
959
+ for (const pid of candidatePids(dirs)) {
960
+ const processToken = (0, process_identity_exports.captureProcessToken)(pid);
961
+ const start = (0, process_identity_exports.processStartMicros)(pid);
962
+ if (!processToken || start.status !== "running") {
963
+ if (start.status === "gone") continue;
964
+ throw unverified(pid, "its identity cannot be captured");
965
+ }
966
+ const record = {
967
+ pid,
968
+ processToken,
969
+ startedAtMicros: start.startedAtMicros
970
+ };
971
+ let open;
972
+ try {
973
+ open = getExecutor().runFile("lsof", [
974
+ "-a",
975
+ "-p",
976
+ String(pid),
977
+ "-d",
978
+ "txt",
979
+ "-Fn"
980
+ ], { timeoutMs: 1e4 });
981
+ } catch (error) {
982
+ if (["gone", "different"].includes((0, process_identity_exports.inspectProcessIdentity)(record))) continue;
983
+ open = String(error.stdout ?? "");
984
+ if (!open.trim()) throw unverified(pid, `lsof failed (${error.message.split("\n")[0]})`);
985
+ }
986
+ if (lsofNamesBundleExecutable(open, dirs)) instances.push(record);
987
+ }
988
+ return instances;
989
+ }
990
+ //#endregion
913
991
  //#region src/engine/public-http-probe.ts
914
992
  const DNS_TIMEOUT_MS = 5e3;
915
993
  async function resolveAddresses(hostname, signal) {
@@ -1486,6 +1564,12 @@ function workspaceInUse(root, { supervisor = true, managedLocks = true, hosted =
1486
1564
  if (macos?.host) reasons.push(`its macOS app runs on ${macos.host.machine}`);
1487
1565
  else if (macos?.state === "running" || macos?.state === "orphaned" || macos?.build.state === "running") reasons.push("its macOS app or build is running");
1488
1566
  else if (macos?.state === "unverified" || !macos && readWorkspaceState$1(root)?.macos !== void 0) reasons.push("its macOS process owner cannot be verified");
1567
+ else try {
1568
+ const pids = bundleInstancePids(root);
1569
+ if (pids.length) reasons.push(`its macOS app is running (pid ${pids.join(", ")})`);
1570
+ } catch (error) {
1571
+ reasons.push(`its running macOS apps cannot be listed: ${error.message}`);
1572
+ }
1489
1573
  const runtime = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
1490
1574
  if (runtime.live.length) reasons.push("its macOS runtime claim is held");
1491
1575
  else if (runtime.unresolved[0]) reasons.push(`its macOS runtime cannot be verified: ${runtime.unresolved[0].reason}`);
@@ -1855,4 +1939,4 @@ function sizeText(bytes) {
1855
1939
  return bytes === null ? "size unknown" : formatBytes(bytes);
1856
1940
  }
1857
1941
  //#endregion
1858
- export { teardownParkedIosSim as A, eraseParkedAvd as C, teardownOwnedBrowser as D, teardownOwnedAvd as E, takeGcResults as F, canonicalPath as I, listBuildSlots as M, releaseBuildSlot as N, teardownOwnedIosSim as O, recordGcResult as P, probePublicHttp as S, teardownBrowserHeld as T, terminateChild as _, collectWorkspaceOutputs as a, withManagedTunnelLock as b, listWorkspaceDirs as c, emptyWorkspaceDir as d, withIdleWorkspace as f, stopTunnel as g, startTunnelSequence as h, collectOrphanedWorkspaces as i, acquireBuildSlot as j, teardownParkedAvd as k, rootPresence as l, resolveSupervisorTarget as m, WORKSPACE_OUTPUT_DIRS as n, deleteOrphanedWorkspaces as o, workspaceInUse as p, clearWorkspaceOutputs as r, isInsideWorkspaces as s, REBUILD_COST as t, sizeText as u, withManagedRemoteWorktreeLock as v, eraseParkedIosSim as w, withManagedTunnelRemovalLock as x, withManagedRemoteWorktreeRemovalLock as y };
1942
+ export { teardownParkedAvd as A, runningBundleInstances as C, teardownOwnedAvd as D, teardownBrowserHeld as E, recordGcResult as F, takeGcResults as I, canonicalPath as L, acquireBuildSlot as M, listBuildSlots as N, teardownOwnedBrowser as O, releaseBuildSlot as P, probePublicHttp as S, eraseParkedIosSim as T, terminateChild as _, collectWorkspaceOutputs as a, withManagedTunnelLock as b, listWorkspaceDirs as c, emptyWorkspaceDir as d, withIdleWorkspace as f, stopTunnel as g, startTunnelSequence as h, collectOrphanedWorkspaces as i, teardownParkedIosSim as j, teardownOwnedIosSim as k, rootPresence as l, resolveSupervisorTarget as m, WORKSPACE_OUTPUT_DIRS as n, deleteOrphanedWorkspaces as o, workspaceInUse as p, clearWorkspaceOutputs as r, isInsideWorkspaces as s, REBUILD_COST as t, sizeText as u, withManagedRemoteWorktreeLock as v, eraseParkedAvd as w, withManagedTunnelRemovalLock as x, withManagedRemoteWorktreeRemovalLock as y };
@@ -1,31 +1,31 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
3
- import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CBtzyIgF.mjs";
4
- import { E as upsertProject, H as projectDeviceSlots, S as removeProject, _ as loadConfig$1, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject } from "./config-CgYMahz7.mjs";
5
- import { C as sourceCheckoutOf, S as restoreFile, T as warmWorktreePaths, _ as readWorktreeExclude, b as resolveFullRef, c as gitCommonDirOnDisk, d as hasUncommittedWork, f as isPodInstallChurn, g as podsOutOfSync, h as locallyKnownUpstream, i as depsOutOfSync, l as hasPopulatedSubmodules, m as listWorktrees, n as cloneIgnoredEntries, o as dirtyPaths, r as deleteBranch, s as gitCommonDir, t as branchExists, u as hasRemote, v as removeWorktree, w as unpushedCommits } from "./worktree-CsKYexJM.mjs";
6
- import { n as appProjectProblem, s as findProjectRoot$1 } from "./project-C3ChRLZy.mjs";
7
- import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-Dh8T4Ytd.mjs";
8
- import { g as workspaceAgentDeviceDir, i as recordWorkspaceUse, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-C59dqG-Z.mjs";
9
- import { o as readWebRecord } from "./state-BG-aAk4k.mjs";
10
- import { Gt as readRemoteSessionId, Ht as readMetroTunnel, Rt as clearManagedMetroTunnel, Wt as readRemoteSession, b as withdrawDevServerStopRequest, o as machineNumber, v as requestDevServerStop, zt as clearRemoteSession } from "./budget-DIhL2BKx.mjs";
11
- import { D as teardownOwnedBrowser, E as teardownOwnedAvd, O as teardownOwnedIosSim, d as emptyWorkspaceDir, f as withIdleWorkspace, g as stopTunnel, m as resolveSupervisorTarget, x as withManagedTunnelRemovalLock, y as withManagedRemoteWorktreeRemovalLock } from "./workspaces-xXItD8Dj.mjs";
12
- import { t as agentDeviceDaemon } from "./activity-BxnkDZDi.mjs";
13
- import { u as releaseWorkspaceLeases } from "./device-lease-Co-EwifR.mjs";
14
- import { ft as parkedMaxSetting, ot as POOL_SETTING_REMEDY } from "./android-DC3ZLuw0.mjs";
15
- import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Behws_fi.mjs";
16
- import { F as resolveSettings, U as unknownSettingKeys, i as SETTING_SHAPE_REMEDY, j as readCommittedSettings, z as settingShapeErrors } from "./settings-CQyMElEP.mjs";
17
- import { t as clearNamedPorts } from "./named-ports-BFIz1Shz.mjs";
18
- import { c as DEPS_ERROR, f as runCaptured, g as HEARTBEAT_INTERVAL_MS, k as podInstallCommand, l as podsAreStale, p as runPodInstall, u as readPodState } from "./toolchain-Bnyd_K3A.mjs";
19
- import { i as stopHostedAndroid } from "./hosted-android-Bv285t_t.mjs";
20
- import { f as resolveEasCliBin } from "./remote-cache-BGg7aGIZ.mjs";
21
- import { i as endRecordedSession } from "./device-remote-tHbd1fKy.mjs";
22
- import { n as verifyCollectorOwnership } from "./ownership-D6Se7gg_.mjs";
23
- import { r as stopHostedIos } from "./hosted-ios-D5mNmtj4.mjs";
24
- import { t as stopMacosApp } from "./stop-BGhKMOuH.mjs";
25
- import { a as pullRequestLookup, r as endedPullRequest } from "./pull-request-u4vp7zmK.mjs";
26
- import { a as forgetStatusMeasures, s as mergeState, t as startWarmProgress } from "./warm-progress-CjB-MP6H.mjs";
27
- import { r as workspaceRecordingEnabled } from "./recordings-BAWltsVt.mjs";
28
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-xKoOypBm.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
+ import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-Bt8ygHE7.mjs";
4
+ import { E as upsertProject, H as projectDeviceSlots, S as removeProject, _ as loadConfig$1, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject } from "./config-DC5jEtd1.mjs";
5
+ import { g as workspaceAgentDeviceDir, i as recordWorkspaceUse, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-CR9X86xJ.mjs";
6
+ import { C as clearRemoteSession, E as readMetroTunnel, O as readRemoteSession, S as clearManagedMetroTunnel, a as isMobileProject, k as readRemoteSessionId, r as findProjectRoot } from "./project-B5eQ1USs.mjs";
7
+ import { $ as depsOutOfSync, B as settingShapeErrors, I as resolveSettings, Q as deleteBranch, W as unknownSettingKeys, X as branchExists, Z as cloneIgnoredEntries, _t as restoreFile, at as hasRemote, bt as warmWorktreePaths, dt as podsOutOfSync, ft as readWorktreeExclude, ht as resolveFullRef, i as SETTING_SHAPE_REMEDY, it as hasPopulatedSubmodules, j as readCommittedSettings, lt as listWorktrees, nt as gitCommonDir, ot as hasUncommittedWork, pt as removeWorktree, rt as gitCommonDirOnDisk, st as isPodInstallChurn, tt as dirtyPaths, ut as locallyKnownUpstream, vt as sourceCheckoutOf, yt as unpushedCommits } from "./settings-CxgngUZk.mjs";
8
+ import { d as signalProcessTree, r as killMetroTree, s as pidExists, u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
9
+ import { o as readWebRecord } from "./state-D2KtnALG.mjs";
10
+ import { b as withdrawDevServerStopRequest, o as machineNumber, v as requestDevServerStop } from "./budget-Dz-kyXLv.mjs";
11
+ import { D as teardownOwnedAvd, O as teardownOwnedBrowser, d as emptyWorkspaceDir, f as withIdleWorkspace, g as stopTunnel, k as teardownOwnedIosSim, m as resolveSupervisorTarget, x as withManagedTunnelRemovalLock, y as withManagedRemoteWorktreeRemovalLock } from "./workspaces-Djb2gfi9.mjs";
12
+ import { t as agentDeviceDaemon } from "./activity-BSw0x84R.mjs";
13
+ import { u as releaseWorkspaceLeases } from "./device-lease-Cu7PtQpZ.mjs";
14
+ import { ft as parkedMaxSetting, ot as POOL_SETTING_REMEDY } from "./android-BdQC6zs1.mjs";
15
+ import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-C65jk_q2.mjs";
16
+ import { t as clearNamedPorts } from "./named-ports-B4iWH4E-.mjs";
17
+ import { t as macosAppPresent } from "./state-Tp4uImDS.mjs";
18
+ import { c as podsAreStale, d as runCaptured, f as runPodInstall, h as HEARTBEAT_INTERVAL_MS, j as podInstallCommand, l as readPodState, s as DEPS_ERROR } from "./toolchain-C3xSoyUl.mjs";
19
+ import { i as stopHostedAndroid } from "./hosted-android-Bs7fytj7.mjs";
20
+ import { f as resolveEasCliBin } from "./remote-cache-N3hAEaAL.mjs";
21
+ import { i as endRecordedSession } from "./device-remote-B5GiUifk.mjs";
22
+ import { n as verifyCollectorOwnership } from "./ownership-EB0ySdGK.mjs";
23
+ import { r as stopHostedIos } from "./hosted-ios-Bik035eL.mjs";
24
+ import { n as stopMacosApp } from "./stop-D0UIpZuh.mjs";
25
+ import { a as pullRequestLookup, r as endedPullRequest } from "./pull-request-IHNdMnG8.mjs";
26
+ import { a as forgetStatusMeasures, s as mergeState, t as startWarmProgress } from "./warm-progress-pFLB2e6P.mjs";
27
+ import { r as workspaceRecordingEnabled } from "./recordings-Bv8McZN4.mjs";
28
+ import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-DKaS1OM9.mjs";
29
29
  import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, utimesSync, writeFileSync } from "node:fs";
30
30
  import { basename, dirname, join, relative } from "node:path";
31
31
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
@@ -1038,16 +1038,18 @@ async function reclaimIdleProject(path, workspaceExisted, { archive, deleteOwned
1038
1038
  skippedDevices.push(remote.failed);
1039
1039
  failedDevices.push(remote.failed);
1040
1040
  }
1041
- const hosted = readMacosRecord(path)?.host;
1042
- if (hosted) try {
1043
- await stopMacosApp(path);
1044
- } catch (error) {
1045
- const failed = {
1046
- name: `hosted macOS session ${hosted.session} on ${hosted.machine}`,
1047
- reason: String(error?.message ?? error)
1048
- };
1049
- skippedDevices.push(failed);
1050
- failedDevices.push(failed);
1041
+ if (macosAppPresent(path)) {
1042
+ const hosted = readMacosRecord(path)?.host;
1043
+ try {
1044
+ await stopMacosApp(path);
1045
+ } catch (error) {
1046
+ const failed = {
1047
+ name: hosted ? `hosted macOS session ${hosted.session} on ${hosted.machine}` : "macOS app",
1048
+ reason: String(error?.message ?? error)
1049
+ };
1050
+ skippedDevices.push(failed);
1051
+ failedDevices.push(failed);
1052
+ }
1051
1053
  }
1052
1054
  const tunnel = await reclaimMetroTunnel(path, { stopMetroTunnel });
1053
1055
  if (tunnel.failed) {
@@ -1949,7 +1951,7 @@ function reportRefreshFailure(failure) {
1949
1951
  process.exitCode = 1;
1950
1952
  }
1951
1953
  function mainCheckoutAppDir(root, target) {
1952
- const app = findProjectRoot$1(process.cwd());
1954
+ const app = findProjectRoot(process.cwd());
1953
1955
  if (!app) return root;
1954
1956
  const rel = relative$1(target, app);
1955
1957
  if (!rel || rel.startsWith("..") || isAbsolute$1(rel)) return root;
@@ -1961,15 +1963,15 @@ function mainCheckoutAppDir(root, target) {
1961
1963
  * root can declare react-native without being the app.
1962
1964
  */
1963
1965
  function warmedWorkspace(root, target, cwd) {
1964
- const nearest = findProjectRoot$1(cwd);
1965
- const app = nearest && isPathPrefix(target, nearest) && appProjectProblem(nearest) === null ? nearest : null;
1966
+ const nearest = findProjectRoot(cwd);
1967
+ const app = nearest && isPathPrefix(target, nearest) && isMobileProject(nearest) ? nearest : null;
1966
1968
  if (app && app !== target) return app;
1967
1969
  const apps = /* @__PURE__ */ new Set();
1968
1970
  for (const path of Object.keys(loadConfig$1()?.projects ?? {})) {
1969
1971
  const rel = relative$1(root, path);
1970
1972
  if (rel.startsWith("..") || isAbsolute$1(rel)) continue;
1971
1973
  const mapped = resolve$1(target, rel);
1972
- if (appProjectProblem(mapped) === null) apps.add(mapped);
1974
+ if (isMobileProject(mapped)) apps.add(mapped);
1973
1975
  }
1974
1976
  return apps.size === 1 ? [...apps][0] : app;
1975
1977
  }
@@ -1986,9 +1988,10 @@ function registerWarm(worktree) {
1986
1988
  let workspace = null;
1987
1989
  try {
1988
1990
  const { root, target, common } = warmWorktreePaths(process.cwd());
1989
- const app = findProjectRoot$1(process.cwd());
1991
+ const app = findProjectRoot(process.cwd());
1990
1992
  if (app) recordWorkspaceUse(app);
1991
1993
  workspace = warmedWorkspace(root, target, process.cwd());
1994
+ if (workspace && workspace !== app) recordWorkspaceUse(workspace);
1992
1995
  if (!workspace) console.error(chalk.dim(phaseLine("project", "no single app to register here; run warm from the app directory to list it in status while it warms")));
1993
1996
  else {
1994
1997
  registerWarmedWorkspace(workspace);
@@ -1,2 +1,2 @@
1
- import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-BSYlofkq.mjs";
1
+ import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-BL4M1rhB.mjs";
2
2
  export { worktreeCommand as default, dependencyInstallCommand, excludePodChurn, excludeWatchmanCookies, matchWorktreeEntry, porcelainPath, reclaimKeys, registerRemove, registerWarm, removalBlockers, removalPath, removalRemedy, removeWorktreeTarget, warmedWorkspace };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stim",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "Stim: fast, isolated React Native environments for coding agents",
5
5
  "keywords": [
6
6
  "agent",
@@ -53,9 +53,9 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@expo/fingerprint": "^0.20.10",
56
- "@stim-cli/cache": "^1.18.0",
57
- "@stim-cli/core": "^1.18.0",
58
- "@stim-cli/metro": "^1.18.0",
56
+ "@stim-cli/cache": "^1.19.0",
57
+ "@stim-cli/core": "^1.19.0",
58
+ "@stim-cli/metro": "^1.19.0",
59
59
  "chalk": "^6.0.0",
60
60
  "commander": "^15.0.0",
61
61
  "cross-spawn": "^7.0.6",
@@ -63,7 +63,7 @@
63
63
  "ws": "^8.21.3"
64
64
  },
65
65
  "devDependencies": {
66
- "@stim-cli/expo-build-cache": "1.18.0",
66
+ "@stim-cli/expo-build-cache": "1.19.0",
67
67
  "@types/cross-spawn": "^6.0.6",
68
68
  "@types/which": "^3.0.4",
69
69
  "@types/ws": "^8.18.1",
@@ -89,7 +89,8 @@ function bundleResponseMiddleware(write, { runLsof } = {}) {
89
89
  };
90
90
  res.once('finish', () => finish(true));
91
91
  res.once('close', () => finish(false));
92
- return next();
92
+ // oxlint-disable-next-line promise/no-callback-in-promise -- Connect routes asynchronous errors through next(error).
93
+ return clientPid ? clientPid.then(() => next()).catch(next) : next();
93
94
  };
94
95
  }
95
96
 
@@ -3,4 +3,4 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
3
3
  export function bundleResponseMiddleware(
4
4
  write: (record: Record<string, unknown>) => unknown,
5
5
  options?: { runLsof?: (args: string[]) => Promise<string> },
6
- ): (req: IncomingMessage, res: ServerResponse, next: () => unknown) => unknown;
6
+ ): (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => unknown) => unknown;
@@ -141,7 +141,7 @@ function appendStore(config, defaultConfig) {
141
141
  (record) => process.stderr.write(`stim-bundle-response: ${JSON.stringify(record)}\n`),
142
142
  { runLsof: process.platform === 'darwin' ? runLsof : undefined },
143
143
  );
144
- return (req, res, next) => observe(req, res, () => enhanced(req, res, next));
144
+ return (req, res, next) => observe(req, res, (error) => (error ? next(error) : enhanced(req, res, next)));
145
145
  },
146
146
  },
147
147
  };