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.
Files changed (152) hide show
  1. package/README.md +2 -0
  2. package/dist/activity-BxwdD81S.mjs +609 -0
  3. package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
  4. package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
  5. package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
  6. package/dist/android-cas-8U4DPqeR.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
  9. package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
  10. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  11. package/dist/budget-DjrURfQn.mjs +2700 -0
  12. package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
  13. package/dist/build-slots-rUk77xqh.mjs +132 -0
  14. package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  15. package/dist/cache-manifest.mjs +1 -1
  16. package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
  17. package/dist/cli-BkYZ_6hy.mjs +51 -0
  18. package/dist/cli.mjs +6 -42
  19. package/dist/client-BTY686R6.mjs +1368 -0
  20. package/dist/collector-run.mjs +9 -195
  21. package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
  22. package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
  23. package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
  24. package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
  25. package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
  26. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  27. package/dist/dev-client-CroAIjjj.mjs +43 -0
  28. package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
  29. package/dist/device-capacity-BHwxNBlu.mjs +136 -0
  30. package/dist/device-host-worker.d.mts +1 -0
  31. package/dist/device-host-worker.mjs +964 -0
  32. package/dist/device-ios-BadmeL2V.mjs +381 -0
  33. package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
  34. package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
  35. package/dist/device-pool-CUaEWMMm.mjs +125 -0
  36. package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
  37. package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
  38. package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
  39. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  40. package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
  41. package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
  42. package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
  43. package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
  44. package/dist/hosted-client-a-WmqE2L.mjs +197 -0
  45. package/dist/hosted-ios-CIWelIqf.mjs +220 -0
  46. package/dist/hosted-logs-D5g041Q3.mjs +187 -0
  47. package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
  48. package/dist/idle-DYVymG92.mjs +1099 -0
  49. package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
  50. package/dist/in-use-DvBw0Kxo.mjs +130 -0
  51. package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
  52. package/dist/ios-Cr1h5gnO.mjs +189 -0
  53. package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
  54. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  55. package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
  56. package/dist/ios-state-DS5UpYTH.mjs +48 -0
  57. package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
  58. package/dist/logs-CHEVK8zD.mjs +371 -0
  59. package/dist/machines-BIBUdhpj.mjs +265 -0
  60. package/dist/macos-CSYEAFmF.mjs +473 -0
  61. package/dist/macos-run.d.mts +5 -0
  62. package/dist/macos-run.mjs +2 -0
  63. package/dist/maintenance-run.d.mts +4 -0
  64. package/dist/maintenance-run.mjs +254 -0
  65. package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
  66. package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
  67. package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
  68. package/dist/native-run-NaBrRFtQ.mjs +147 -0
  69. package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
  70. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  71. package/dist/offload-worker.d.mts +122 -0
  72. package/dist/offload-worker.mjs +606 -0
  73. package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
  74. package/dist/ownership-hCkPzGmr.mjs +571 -0
  75. package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
  76. package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
  77. package/dist/prebuild-D2fsca_Z.mjs +213 -0
  78. package/dist/preview-DhVbvPAZ.mjs +318 -0
  79. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  80. package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
  81. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  82. package/dist/pull-requests.d.mts +120 -0
  83. package/dist/pull-requests.mjs +2 -0
  84. package/dist/recordings-BIXOzVnr.mjs +37 -0
  85. package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
  86. package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
  87. package/dist/run-f4vI6EnK.mjs +119 -0
  88. package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
  89. package/dist/server-expo-CVqO2c35.mjs +2 -0
  90. package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
  91. package/dist/settings-BBpMcDbD.mjs +25 -0
  92. package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
  93. package/dist/settings-oTSkkNrM.mjs +1439 -0
  94. package/dist/settings.schema.json +845 -97
  95. package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
  96. package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
  97. package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  98. package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
  99. package/dist/stage-CzaiwFsI.mjs +143 -0
  100. package/dist/start-CX8Ig-U2.mjs +2 -0
  101. package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
  102. package/dist/state-3DwSQIBK.mjs +41 -0
  103. package/dist/state-B4PQFXMW.d.mts +12 -0
  104. package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
  105. package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
  106. package/dist/stats-CEZ_i5je.mjs +77 -0
  107. package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
  108. package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
  109. package/dist/status-DlKvVJBE.mjs +49 -0
  110. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  111. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  112. package/dist/stim-footprint.swift +32 -0
  113. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  114. package/dist/stop-B0Yxtmiy.mjs +48 -0
  115. package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
  116. package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
  117. package/dist/stop-cause-CidxIqup.mjs +97 -0
  118. package/dist/supervisor-run.d.mts +43 -11
  119. package/dist/supervisor-run.mjs +363 -24
  120. package/dist/support-CAP8qDUF.mjs +316 -0
  121. package/dist/support-D4aYJniO.mjs +201 -0
  122. package/dist/teardown-CL6vDs2Y.mjs +727 -0
  123. package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
  124. package/dist/trigger-Bemu8ytw.mjs +65 -0
  125. package/dist/trigger-CXts6qt1.mjs +2 -0
  126. package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
  127. package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
  128. package/dist/web-run.mjs +310 -13
  129. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  130. package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
  131. package/dist/workspaces-BV4pdHFz.mjs +306 -0
  132. package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
  133. package/dist/worktree-jnG8Iph5.mjs +2 -0
  134. package/package.json +10 -5
  135. package/shim/bundle-response.cjs +28 -12
  136. package/dist/activity-CYVDcrt3.mjs +0 -356
  137. package/dist/budget-CGDkhvv_.mjs +0 -1745
  138. package/dist/build-progress-DxKpwnaS.mjs +0 -247
  139. package/dist/idle-DXtx3RbX.mjs +0 -191
  140. package/dist/in-use-DlqBDKqY.mjs +0 -249
  141. package/dist/logs-Civ4gbBH.mjs +0 -486
  142. package/dist/merge-state-ytFQCeh4.mjs +0 -262
  143. package/dist/server-expo-DIHDhvGg.mjs +0 -2
  144. package/dist/settings-D61iNOsB.mjs +0 -629
  145. package/dist/start-Cetfvy8l.mjs +0 -2
  146. package/dist/stats-CFpFGlJV.mjs +0 -62
  147. package/dist/stats-CX1Z8Tca.mjs +0 -368
  148. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  149. package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
  150. package/dist/worktree-BVrHsYZG.mjs +0 -752
  151. package/dist/worktree-CHWWvm5v.mjs +0 -2
  152. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -1,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  //#region src/collector/ios-device.ts
3
3
  const CONSOLE_ENV = { OS_ACTIVITY_DT_MODE: "enable" };
4
4
  const DEV_MENU_LAUNCH_ARGS = [
@@ -1,6 +1,6 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { n as TOOL_ERROR_PREFIX } from "./ios-device-BiOsSVzd.mjs";
3
- import { i as INSTALL_ERROR } from "./app-install-BpgSgkJj.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { n as TOOL_ERROR_PREFIX } from "./ios-device-Ee7sDXfp.mjs";
3
+ import { i as INSTALL_ERROR } from "./app-install-CKWdbXIX.mjs";
4
4
  import { mkdtempSync, readFileSync, rmSync } from "node:fs";
5
5
  import { join } from "node:path";
6
6
  import { tmpdir } from "node:os";
@@ -38,12 +38,17 @@ function parseDevicectlDevices(payload) {
38
38
  transportType: text(connection.transportType),
39
39
  platform: text(hardware.platform),
40
40
  reality: text(hardware.reality),
41
- tunnelState: text(connection.tunnelState)
41
+ tunnelState: text(connection.tunnelState),
42
+ model: text(hardware.marketingName)
42
43
  });
43
44
  }
44
45
  return out;
45
46
  }
46
47
  function listIosDevices({ exec = null } = {}) {
48
+ return readIosDevices({ exec }) ?? [];
49
+ }
50
+ /** devicectl's device list, or null when devicectl failed or did not answer within `timeoutMs`. */
51
+ function readIosDevices({ exec = null, timeoutMs = DEVICECTL_TIMEOUT_MS } = {}) {
47
52
  const executor = exec || getExecutor();
48
53
  const dir = mkdtempSync(join(tmpdir(), "stim-devicectl-"));
49
54
  const out = join(dir, "devices.json");
@@ -54,10 +59,10 @@ function listIosDevices({ exec = null } = {}) {
54
59
  "devices",
55
60
  "-j",
56
61
  out
57
- ], { timeoutMs: DEVICECTL_TIMEOUT_MS });
62
+ ], { timeoutMs });
58
63
  return parseDevicectlDevices(readFileSync(out, "utf-8"));
59
64
  } catch {
60
- return [];
65
+ return null;
61
66
  } finally {
62
67
  rmSync(dir, {
63
68
  recursive: true,
@@ -507,4 +512,4 @@ function localNetworkPending(records, { since = 0, pid = null, lanOrigin }) {
507
512
  return false;
508
513
  }
509
514
  //#endregion
510
- export { iosPoolCandidates as a, listIosDevices as c, verifyIosDeviceReleaseLaunch as d, iosDeviceProcess as i, localNetworkPending as l, installIosDeviceApp as n, iosPoolNoCandidatesRefusal as o, iosDeviceBounds as r, isWirelessIosDevice as s, awaitIosDeviceLaunch as t, resolveIosPhysicalDevice as u };
515
+ export { iosPoolCandidates as a, isWirelessIosDevice as c, readIosDevices as d, resolveIosPhysicalDevice as f, iosDeviceProcess as i, listIosDevices as l, installIosDeviceApp as n, iosPoolNoCandidatesRefusal as o, verifyIosDeviceReleaseLaunch as p, iosDeviceBounds as r, isReachable as s, awaitIosDeviceLaunch as t, localNetworkPending as u };
@@ -0,0 +1,48 @@
1
+ import { a as updateWorkspaceState, r as readWorkspaceState$1 } from "./workspace-state-B8-aJ1_5.mjs";
2
+ import { HOSTED_METRO_REQUESTS_KEY, hostedIosPlacements, hostedIosRecords, hostedMetroRequests, isJsonObject, parseHostedIosPlacement, unreadableHostedIos } from "@stim-cli/core/state";
3
+ //#region src/device-host/ios-state.ts
4
+ function readHostedIos(root, slot) {
5
+ const state = readWorkspaceState$1(root);
6
+ if (slot !== void 0) {
7
+ const record = hostedIosRecords(state)[slot];
8
+ if (record !== void 0 && !parseHostedIosPlacement(record)) throw Object.assign(new Error(unreadableHostedIos(slot)), {
9
+ code: "STIM_HOSTING_REFUSED",
10
+ remedy: `Restore that slot's recorded machine and session from the host, then run stim stop${slot === "default" ? "" : ` --slot ${slot}`} to reconcile it.`
11
+ });
12
+ }
13
+ const placements = hostedIosPlacements(state);
14
+ return slot === void 0 ? placements : placements[slot] ? { [slot]: placements[slot] } : {};
15
+ }
16
+ function writeHostedIos(root, slot, host) {
17
+ updateWorkspaceState(root, (state) => {
18
+ const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
19
+ const current = slot === "default" ? state.ios : isJsonObject(slots[slot]) ? slots[slot].ios : void 0;
20
+ const record = isJsonObject(current) ? { ...current } : {};
21
+ const previous = parseHostedIosPlacement(record.host);
22
+ if (previous && previous.session !== host?.session) {
23
+ const requests = { ...hostedMetroRequests(state) };
24
+ delete requests[previous.session];
25
+ state = {
26
+ ...state,
27
+ [HOSTED_METRO_REQUESTS_KEY]: requests
28
+ };
29
+ }
30
+ if (host) record.host = host;
31
+ else delete record.host;
32
+ return slot === "default" ? {
33
+ ...state,
34
+ ios: record
35
+ } : {
36
+ ...state,
37
+ deviceSlots: {
38
+ ...slots,
39
+ [slot]: {
40
+ ...isJsonObject(slots[slot]) ? slots[slot] : {},
41
+ ios: record
42
+ }
43
+ }
44
+ };
45
+ });
46
+ }
47
+ //#endregion
48
+ export { writeHostedIos as n, readHostedIos as t };
@@ -1,8 +1,8 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { o as readNdjsonGenerations } from "./ndjson-CDY9IkVC.mjs";
3
- import { s as isAppLaunchError } from "./command-output-DVcpw6eE.mjs";
4
- import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-BiOsSVzd.mjs";
5
- import { d as deviceShellArg, n as ANDROID_DISABLE_AUTO_LAUNCH_EXTRA, o as androidAppProcess } from "./app-install-BpgSgkJj.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { s as isAppLaunchError } from "./command-output-DnJMdEY-.mjs";
3
+ import { o as readNdjsonGenerations } from "./ndjson-PclOIwVY.mjs";
4
+ import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-Ee7sDXfp.mjs";
5
+ import { f as deviceShellArg, n as ANDROID_DISABLE_AUTO_LAUNCH_EXTRA, s as androidAppProcess } from "./app-install-CKWdbXIX.mjs";
6
6
  import { join } from "node:path";
7
7
  //#region src/engine/app-readiness.ts
8
8
  const APP_READINESS_TIMEOUT_MS = 3e4;
@@ -0,0 +1,371 @@
1
+ import { H as projectDeviceSlots, V as parseDeviceSlotOption, _ as loadConfig$1, g as isPathPrefix } from "./config-D0DbpZtM.mjs";
2
+ import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
3
+ import { f as refuseNoProject, l as phaseLine, v as launchErrorPreview } from "./command-output-DnJMdEY-.mjs";
4
+ import { a as findCommandWorkspace } from "./project-Du91Ilvc.mjs";
5
+ import { r as readWorkspaceState$1, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
6
+ import { n as agentDeviceLiveness, u as readAgentDeviceRecords } from "./activity-BxwdD81S.mjs";
7
+ import { n as SOURCES, t as LEVELS } from "./ndjson-PclOIwVY.mjs";
8
+ import { o as connectHost } from "./hosted-client-a-WmqE2L.mjs";
9
+ import { n as pullHostedMacosLogs, t as pullHostedIosLogs } from "./hosted-logs-D5g041Q3.mjs";
10
+ import "./hosted-macos-BSZyIb3y.mjs";
11
+ import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-B9L4Ae0x.mjs";
12
+ import { t as readHostedIos } from "./ios-state-DS5UpYTH.mjs";
13
+ import { t as watchStdoutReader } from "./stdout-reader-C8yjre1x.mjs";
14
+ import { realpathSync } from "node:fs";
15
+ import { dirname, join, relative, resolve, sep } from "node:path";
16
+ import { agentDeviceStateDirs, buildCriteria, compileGrep, createAgentActionReader, fileSizes, followLogs, logFiles, parseSince, queryJsonLogs, queryLogs, readLogRecords, readMacosRecord, recordMatches, sortByTs } from "@stim-cli/core/state";
17
+ import { homedir } from "node:os";
18
+ import chalk from "chalk";
19
+ //#region src/devices/agent-actions.ts
20
+ function workspaceAgentTargets(project) {
21
+ const targets = [];
22
+ let slots;
23
+ try {
24
+ slots = projectDeviceSlots(project);
25
+ } catch {
26
+ return [];
27
+ }
28
+ for (const { slot, platforms } of slots) {
29
+ const { ios, android } = platforms;
30
+ if (ios?.owned && typeof ios.deviceUdid === "string") targets.push({
31
+ platform: "ios",
32
+ id: ios.deviceUdid,
33
+ slot
34
+ });
35
+ if (android?.owned && typeof android.consolePort === "number" && typeof android.avdName === "string") targets.push({
36
+ platform: "android",
37
+ id: `emulator-${android.consolePort}`,
38
+ slot,
39
+ name: android.avdName
40
+ });
41
+ }
42
+ return targets;
43
+ }
44
+ function canonicalDir(path) {
45
+ try {
46
+ return realpathSync(path);
47
+ } catch {
48
+ return resolve(path);
49
+ }
50
+ }
51
+ function createAgentActionReader$1({ targets, sinceTs, home = homedir(), now, startOf = process_identity_exports.inspectProcessStart }) {
52
+ const byId = new Map(targets.map((target) => [target.id, target]));
53
+ let claimed;
54
+ const read = createAgentActionReader({
55
+ sessionsDirs: () => agentDeviceStateDirs(home).map((root) => join(root, "sessions")),
56
+ targets,
57
+ sinceTs,
58
+ now,
59
+ claimedDevice: (session, sessionsDir) => {
60
+ claimed ??= new Map(readAgentDeviceRecords(home).filter((record) => record.kind === "claim" && record.session && record.deviceId).filter((record) => {
61
+ const target = byId.get(record.deviceId);
62
+ return target?.name === void 0 || target.name === record.deviceName;
63
+ }).filter((record) => agentDeviceLiveness(record, startOf) === "live").map((record) => [`${record.stateDir ? canonicalDir(record.stateDir) : ""}\0${record.session}`, record.deviceId]));
64
+ return claimed.get(`${canonicalDir(dirname(sessionsDir))}\0${session}`) ?? claimed.get(`\0${session}`) ?? null;
65
+ }
66
+ });
67
+ return () => {
68
+ claimed = void 0;
69
+ return read();
70
+ };
71
+ }
72
+ //#endregion
73
+ //#region src/device-host/hosted-logs-sync.ts
74
+ function warning(machine, error) {
75
+ const message = error.message.replace(/\.$/, "");
76
+ const hint = message.includes("refused device-host.logs.query") ? ` If ${machine} runs an older stim-server, update it.` : "";
77
+ return phaseLine("device", `Could not read the app's logs from ${machine}: ${message}. Showing the logs already copied here.${hint}`);
78
+ }
79
+ async function syncHostedMacosLogs(root, placement, slot, warnings) {
80
+ let host;
81
+ try {
82
+ host = await connectHost(placement.machine);
83
+ if (slot !== void 0) await pullHostedIosLogs(root, slot, placement, host);
84
+ else await pullHostedMacosLogs(root, placement, host);
85
+ return true;
86
+ } catch (error) {
87
+ if (!warnings?.has(placement.machine)) {
88
+ process.stderr.write(`${warning(placement.machine, error)}\n`);
89
+ warnings?.add(placement.machine);
90
+ }
91
+ return false;
92
+ } finally {
93
+ host?.connection.close();
94
+ }
95
+ }
96
+ function followHostedMacosLogs(root, { failing = false, intervalMs = 500, retryMs = 5e3, slot } = {}) {
97
+ let host;
98
+ let retryAt = 0;
99
+ let stopped = false;
100
+ let running = false;
101
+ const tick = async () => {
102
+ if (running || stopped || Date.now() < retryAt) return;
103
+ running = true;
104
+ try {
105
+ const placement = slot !== void 0 ? readHostedIos(root)[slot] : readMacosRecord(root)?.host;
106
+ if (!placement) {
107
+ host?.connection.close();
108
+ host = void 0;
109
+ return;
110
+ }
111
+ host ??= await connectHost(placement.machine);
112
+ if (slot !== void 0) await pullHostedIosLogs(root, slot, placement, host);
113
+ else await pullHostedMacosLogs(root, placement, host);
114
+ failing = false;
115
+ } catch (error) {
116
+ host?.connection.close();
117
+ host = void 0;
118
+ if (!failing) process.stderr.write(`${warning((slot !== void 0 ? readHostedIos(root)[slot] : readMacosRecord(root)?.host)?.machine ?? "the host", error)}\n`);
119
+ failing = true;
120
+ retryAt = Date.now() + retryMs;
121
+ } finally {
122
+ running = false;
123
+ }
124
+ };
125
+ const timer = setInterval(() => void tick(), intervalMs);
126
+ return () => {
127
+ stopped = true;
128
+ clearInterval(timer);
129
+ host?.connection.close();
130
+ };
131
+ }
132
+ async function syncHostedLogs(root) {
133
+ const macos = readMacosRecord(root)?.host;
134
+ const warnings = /* @__PURE__ */ new Set();
135
+ return (await Promise.all([...macos ? [syncHostedMacosLogs(root, macos)] : [], ...Object.entries(readHostedIos(root)).map(([slot, placement]) => syncHostedMacosLogs(root, placement, slot, warnings))])).every(Boolean);
136
+ }
137
+ function followHostedLogs(root, failing) {
138
+ const stops = /* @__PURE__ */ new Map();
139
+ const refresh = () => {
140
+ if (readMacosRecord(root)?.host && !stops.has("macos")) stops.set("macos", followHostedMacosLogs(root, { failing }));
141
+ for (const slot of Object.keys(readHostedIos(root))) {
142
+ const key = `ios:${slot}`;
143
+ if (!stops.has(key)) stops.set(key, followHostedMacosLogs(root, {
144
+ failing,
145
+ slot
146
+ }));
147
+ }
148
+ };
149
+ refresh();
150
+ const timer = setInterval(refresh, 500);
151
+ return () => {
152
+ clearInterval(timer);
153
+ for (const stop of stops.values()) stop();
154
+ };
155
+ }
156
+ //#endregion
157
+ //#region src/commands/logs.ts
158
+ const LEVEL_WIDTH = 5;
159
+ const SRC_WIDTH = 6;
160
+ const INDENT = " ";
161
+ function padTimePart(value, width = 2) {
162
+ return String(value).padStart(width, "0");
163
+ }
164
+ function formatTime(ts) {
165
+ if (typeof ts !== "number" || !Number.isFinite(ts)) return "--:--:--.---";
166
+ const d = new Date(ts);
167
+ return `${padTimePart(d.getHours())}:${padTimePart(d.getMinutes())}:${padTimePart(d.getSeconds())}.${padTimePart(d.getMilliseconds(), 3)}`;
168
+ }
169
+ function formatStackFrame(frame) {
170
+ if (!frame || typeof frame !== "object") return null;
171
+ const where = [
172
+ frame.file,
173
+ frame.line,
174
+ frame.column
175
+ ].filter((p) => p !== void 0 && p !== null && p !== "").join(":");
176
+ if (frame.fn && where) return `at ${frame.fn} (${where})`;
177
+ if (frame.fn) return `at ${frame.fn}`;
178
+ if (where) return `at ${where}`;
179
+ return null;
180
+ }
181
+ function formatRecord(record, { paint } = {}) {
182
+ const colour = paint || ((t) => t);
183
+ const level = String(record?.level ?? "").padEnd(LEVEL_WIDTH);
184
+ const src = String(record?.src ?? "").padEnd(SRC_WIDTH);
185
+ const [first, ...rest] = (record?.msg === void 0 || record?.msg === null ? "" : String(record.msg)).split("\n");
186
+ const lines = [`${formatTime(record?.ts)} ${colour(level)} ${src} ${first}`];
187
+ for (const line of rest) lines.push(`${INDENT}${line}`);
188
+ for (const frame of Array.isArray(record?.stack) ? record.stack : []) {
189
+ const rendered = formatStackFrame(frame);
190
+ if (rendered) lines.push(`${INDENT}${rendered}`);
191
+ }
192
+ return lines.join("\n");
193
+ }
194
+ function parseTail(value) {
195
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0) return { n: value };
196
+ if (typeof value !== "string" || !/^\d+$/.test(value.trim())) return { error: `Invalid --tail value ${JSON.stringify(value)}. Use a non-negative whole number, e.g. --tail 50.` };
197
+ return { n: parseInt(value.trim(), 10) };
198
+ }
199
+ function validateSources(sources) {
200
+ if (sources === void 0 || sources === null) return { sources: void 0 };
201
+ const list = Array.isArray(sources) ? sources : [sources];
202
+ if (list.includes("all")) return { sources: [...SOURCES] };
203
+ const unknown = list.filter((s) => !SOURCES.includes(s));
204
+ if (unknown.length > 0) return { error: `Unknown --source value(s): ${unknown.join(", ")}. Use one or more of: ${SOURCES.join(", ")}, or all.` };
205
+ return { sources: list };
206
+ }
207
+ function validateLevel(level) {
208
+ if (LEVELS.includes(level)) return { level };
209
+ return { error: `Invalid --level value ${JSON.stringify(level)}. Use one of: ${LEVELS.join(", ")}.` };
210
+ }
211
+ const ERRORS_PRINT_CAP = 20;
212
+ function nearestRegisteredLogsProject(root, candidates) {
213
+ return candidates.filter((candidate) => candidate !== root && isPathPrefix(root, candidate)).toSorted((a, b) => {
214
+ const depth = (path) => relative(root, path).split(sep).length;
215
+ return depth(a) - depth(b) || a.length - b.length || a.localeCompare(b);
216
+ })[0] ?? null;
217
+ }
218
+ function registeredDescendantWithLogs(root) {
219
+ const candidates = Object.keys(loadConfig$1()?.projects ?? {}).flatMap((path) => {
220
+ try {
221
+ const canonical = realpathSync(path);
222
+ return logFiles(workspaceLogsDir$1(canonical)).length > 0 ? [canonical] : [];
223
+ } catch {
224
+ return [];
225
+ }
226
+ });
227
+ return nearestRegisteredLogsProject(root, [...new Set(candidates)]);
228
+ }
229
+ function requireLogsWorkspace(root, dir) {
230
+ if (logFiles(dir).length > 0) return;
231
+ const descendant = registeredDescendantWithLogs(root);
232
+ fail(`STIM_NO_PROJECT: No Stim workspace has run in ${root}.${descendant ? ` The nearest registered app with logs is ${descendant}; run this command from there.` : " Run `stim start`, `stim ios`, or `stim android` in the app first."}`);
233
+ }
234
+ const LEVEL_COLOURS = {
235
+ debug: chalk.dim,
236
+ info: chalk.reset,
237
+ warn: chalk.yellow,
238
+ error: chalk.red,
239
+ fatal: chalk.bgRed
240
+ };
241
+ function logsCommand(program) {
242
+ program.command("logs").description("Query this workspace's merged NDJSON log timeline (bundler, client, device, build, agent actions, maintenance). Prints and exits; an existing timeline with nothing matching is a successful, empty result. Use --follow to stream.").option("--slot <name>", "Only this device slot's records, plus the shared Metro and app client records once it has launched", parseDeviceSlotOption).option("--source <s...>", "Only these sources: metro, client, device, build, agent, maintenance, or all").option("--level <l>", `Minimum level: ${LEVELS.join(", ")}`).option("--since <d>", "Only records newer than this, e.g. 30s, 5m, 2h").option("--grep <re>", "Only records whose message matches this regular expression").option("--tail <n>", "Only the last n matching records").option("--errors", "Errors and fatals since the last marker, from metro, client and build, plus confirmed native app-crash reports and stim web browser errors. Add --source maintenance for maintenance failures, or --source device or --source all for general device errors.").option("--follow", "Keep streaming new records until interrupted").option("--json", "Emit the raw records, one per line (valid NDJSON; zero matches is zero bytes, exit 0)").action(async (opts) => {
243
+ const root = findCommandWorkspace(process.cwd());
244
+ if (!root) {
245
+ refuseNoProject({ json: false });
246
+ return;
247
+ }
248
+ const dir = workspaceLogsDir$1(root);
249
+ let sources;
250
+ if (opts.source !== void 0) {
251
+ const checked = validateSources(opts.source);
252
+ if (checked.error) fail(checked.error);
253
+ sources = checked.sources;
254
+ }
255
+ let minLevel;
256
+ if (opts.level !== void 0) {
257
+ const checked = validateLevel(opts.level);
258
+ if (checked.error) fail(checked.error);
259
+ minLevel = checked.level;
260
+ }
261
+ if (opts.since !== void 0) {
262
+ const parsed = parseSince(opts.since);
263
+ if (parsed.error) fail(parsed.error);
264
+ }
265
+ let tail;
266
+ if (opts.tail !== void 0) {
267
+ const parsed = parseTail(opts.tail);
268
+ if (parsed.error) fail(parsed.error);
269
+ tail = parsed.n;
270
+ }
271
+ if (opts.grep !== void 0) {
272
+ const compiled = compileGrep(opts.grep);
273
+ if (compiled.error) fail(compiled.error);
274
+ }
275
+ requireLogsWorkspace(root, dir);
276
+ const hostedReachable = await syncHostedLogs(root);
277
+ const query = {
278
+ slot: opts.slot,
279
+ dir,
280
+ sources,
281
+ minLevel,
282
+ since: opts.since,
283
+ grep: opts.grep,
284
+ tail,
285
+ errorsOnly: Boolean(opts.errors),
286
+ errorContext: Boolean(opts.errors && !opts.json && !opts.follow)
287
+ };
288
+ const emit = (record) => {
289
+ if (opts.json) {
290
+ console.log(JSON.stringify(record));
291
+ return;
292
+ }
293
+ const rendered = {
294
+ ...record,
295
+ msg: launchErrorPreview([record], root, { full: true }).join("\n"),
296
+ stack: void 0
297
+ };
298
+ console.log(formatRecord(rendered, { paint: record?.level ? LEVEL_COLOURS[record.level] : void 0 }));
299
+ };
300
+ const captured = captureWorkspaceCrashes(root, dir);
301
+ const offsets = opts.follow ? fileSizes(dir) : null;
302
+ const workspaceTimeline = opts.follow ? readLogRecords(dir) : captured;
303
+ const agentSince = workspaceTimeline[0]?.ts ?? (opts.follow ? Date.now() : void 0);
304
+ const readAgent = (sources ? sources.includes("agent") : !opts.errors) && agentSince !== void 0 ? createAgentActionReader$1({
305
+ targets: workspaceAgentTargets(loadConfig$1()?.projects?.[root]),
306
+ sinceTs: agentSince
307
+ }) : null;
308
+ const timeline = readAgent ? sortByTs([...workspaceTimeline, ...readAgent()]) : workspaceTimeline;
309
+ const rawRecords = (opts.json ? queryJsonLogs : queryLogs)({
310
+ ...query,
311
+ records: timeline
312
+ });
313
+ const supervisorPort = readWorkspaceState$1(root)?.supervisor?.port;
314
+ const records = opts.json ? rawRecords : await errorDiagnostics(rawRecords, {
315
+ root,
316
+ logsDir: dir,
317
+ port: typeof supervisorPort === "number" ? supervisorPort : null,
318
+ allowRequest: true,
319
+ timeline
320
+ });
321
+ const errorCount = records.filter((record) => record.errorContext !== true).length;
322
+ let seenErrors = 0;
323
+ const capped = opts.errors && !opts.json && tail === void 0 && errorCount > 20 ? records.filter((record) => {
324
+ if (record.errorContext === true) return seenErrors <= 20;
325
+ seenErrors += 1;
326
+ return seenErrors <= 20;
327
+ }) : records;
328
+ for (const record of capped) emit(record);
329
+ const hidden = errorCount - capped.filter((record) => record.errorContext !== true).length;
330
+ if (hidden > 0) console.log(chalk.dim(`Showing 20 of ${errorCount} matching error records; ${hidden} not shown. Add --tail ${rawRecords.length} to include all captured records before grouping, or --json for raw records. Stacks are shown in full.`));
331
+ if (!opts.follow) {
332
+ if (records.length === 0 && !opts.json) console.error(chalk.dim(`No matching log records in ${dir}`));
333
+ return;
334
+ }
335
+ const criteria = buildCriteria({
336
+ slot: opts.slot,
337
+ sources,
338
+ minLevel,
339
+ since: opts.since,
340
+ grep: opts.grep,
341
+ errorsOnly: Boolean(opts.errors)
342
+ });
343
+ const stop = followLogs({
344
+ dir,
345
+ offsets,
346
+ criteria,
347
+ onRecord: emit,
348
+ errorContext: opts.errors ? opts.json ? "field" : "msg" : void 0
349
+ });
350
+ const agentTimer = readAgent ? setInterval(() => {
351
+ for (const record of readAgent()) if (recordMatches(record, criteria)) emit(record);
352
+ }, 500) : null;
353
+ const stopHosted = followHostedLogs(root, !hostedReachable);
354
+ const finish = () => {
355
+ stop();
356
+ stopHosted?.();
357
+ stopReader();
358
+ if (agentTimer) clearInterval(agentTimer);
359
+ process.exit(0);
360
+ };
361
+ const stopReader = watchStdoutReader(finish);
362
+ process.on("SIGINT", finish);
363
+ process.on("SIGTERM", finish);
364
+ });
365
+ }
366
+ function fail(message) {
367
+ console.error(chalk.red(message));
368
+ process.exit(1);
369
+ }
370
+ //#endregion
371
+ export { ERRORS_PRINT_CAP, logsCommand as default, formatRecord, formatStackFrame, formatTime, parseTail, validateLevel, validateSources };