stim 1.13.0 → 1.15.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 (133) hide show
  1. package/README.md +2 -0
  2. package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
  3. package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
  4. package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
  5. package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
  6. package/dist/android-cas-PnKfAdB2.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
  9. package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
  10. package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
  11. package/dist/build-progress-C2Jv1AtA.mjs +872 -0
  12. package/dist/build-slots-Df1ApSuH.mjs +127 -0
  13. package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  14. package/dist/cache-manifest.mjs +1 -1
  15. package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
  16. package/dist/cli-0cX5s4NM.mjs +45 -0
  17. package/dist/cli.mjs +6 -42
  18. package/dist/client-C2IS36Qf.mjs +1333 -0
  19. package/dist/collector-run.mjs +8 -7
  20. package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
  21. package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
  22. package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
  23. package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
  24. package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
  25. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  26. package/dist/dev-client-CjzLoNs0.mjs +80 -0
  27. package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
  28. package/dist/device-capacity-DMuKC7nx.mjs +136 -0
  29. package/dist/device-host-worker.d.mts +1 -0
  30. package/dist/device-host-worker.mjs +769 -0
  31. package/dist/device-ios-DMQBUPus.mjs +381 -0
  32. package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
  33. package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
  34. package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
  35. package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
  36. package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
  37. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  38. package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
  39. package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
  40. package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
  41. package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
  42. package/dist/hosted-macos-DwowNU7W.mjs +447 -0
  43. package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
  44. package/dist/in-use-CndPMilN.mjs +110 -0
  45. package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
  46. package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
  47. package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
  48. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  49. package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
  50. package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
  51. package/dist/machine-usage-D_YYMzfR.mjs +283 -0
  52. package/dist/machines-CYtOCqcj.mjs +259 -0
  53. package/dist/macos-BwtbUtTN.mjs +468 -0
  54. package/dist/macos-run.d.mts +5 -0
  55. package/dist/macos-run.mjs +2 -0
  56. package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
  57. package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
  58. package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
  59. package/dist/native-run-DFDoIRbY.mjs +147 -0
  60. package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
  61. package/dist/offload-worker.d.mts +121 -0
  62. package/dist/offload-worker.mjs +601 -0
  63. package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
  64. package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
  65. package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
  66. package/dist/prebuild-BvxDlD6C.mjs +213 -0
  67. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  68. package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
  69. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  70. package/dist/pull-requests.d.mts +120 -0
  71. package/dist/pull-requests.mjs +2 -0
  72. package/dist/recordings-GEXp4iBT.mjs +37 -0
  73. package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
  74. package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
  75. package/dist/run-B-xqRrsg.mjs +119 -0
  76. package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
  77. package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
  78. package/dist/server-expo-KJeD109I.mjs +2 -0
  79. package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
  80. package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
  81. package/dist/settings.schema.json +357 -2
  82. package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
  83. package/dist/slot-launch-BY0BrOLh.mjs +65 -0
  84. package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  85. package/dist/spawn-entry-DncpJvWL.mjs +16 -0
  86. package/dist/stage-CzaiwFsI.mjs +143 -0
  87. package/dist/start-CPO4wRg7.mjs +2 -0
  88. package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
  89. package/dist/state-B4PQFXMW.d.mts +12 -0
  90. package/dist/state-BxCgeTQu.mjs +41 -0
  91. package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
  92. package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
  93. package/dist/stats-DBLLFmKd.mjs +66 -0
  94. package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
  95. package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
  96. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  97. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  98. package/dist/stim-footprint.swift +32 -0
  99. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  100. package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
  101. package/dist/stop-Bvf1MflS.mjs +48 -0
  102. package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
  103. package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
  104. package/dist/supervisor-run.d.mts +44 -12
  105. package/dist/supervisor-run.mjs +276 -33
  106. package/dist/support-CDQbDkL5.mjs +315 -0
  107. package/dist/support-WLOzVKUv.mjs +176 -0
  108. package/dist/teardown-BYuQafiA.mjs +718 -0
  109. package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
  110. package/dist/warm-progress-DVHLN4uC.mjs +463 -0
  111. package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
  112. package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
  113. package/dist/web-run.mjs +326 -13
  114. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  115. package/dist/workspace-state-CL2V2Ons.mjs +371 -0
  116. package/dist/worktree-BT_uULFx.mjs +2 -0
  117. package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
  118. package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
  119. package/package.json +10 -5
  120. package/shim/bundle-response.cjs +55 -10
  121. package/shim/bundle-response.d.cts +1 -0
  122. package/shim/expo-metro-config.cjs +10 -2
  123. package/dist/build-progress-l7d-X-ZP.mjs +0 -247
  124. package/dist/in-use-wYEaKQM9.mjs +0 -249
  125. package/dist/ownership-PUP4Dwai.mjs +0 -1138
  126. package/dist/server-expo-BeYwP_Xy.mjs +0 -2
  127. package/dist/slot-launch-BIWEW-wI.mjs +0 -19
  128. package/dist/start-Rw2GD3nV.mjs +0 -2
  129. package/dist/stats-CaSwmsSZ.mjs +0 -62
  130. package/dist/stats-D8rUTPHd.mjs +0 -368
  131. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  132. package/dist/worktree-3cBa-bQt.mjs +0 -2
  133. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -0,0 +1,468 @@
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { E as upsertProject, u as getConcurrencyLimits } from "./config-D0DbpZtM.mjs";
3
+ import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
+ import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
5
+ import { C as workspaceLogsDir, b as workspaceDir, c as writeWorkspaceState, i as recordWorkspaceUse, p as ensureWorkspaceStorage } from "./workspace-state-CL2V2Ons.mjs";
6
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-C0c5Udwa.mjs";
7
+ import { a as findProjectRoot$1 } from "./project-CV3tDFHl.mjs";
8
+ import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
9
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
10
+ import { L as settingShapeErrors, N as resolveSettings, a as SETTING_SHAPE_REMEDY } from "./settings-CduVcoxj.mjs";
11
+ import { a as requiredMacosRecord, n as macosLogFile, r as macosProcess, t as macosDir } from "./state-BxCgeTQu.mjs";
12
+ import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-Df1ApSuH.mjs";
13
+ import { t as logLines } from "./run-B-xqRrsg.mjs";
14
+ import { i as macosToolchain } from "./toolchain-DmeYjXD9.mjs";
15
+ import { a as offloadBuild, c as placementLoad, d as OffloadRefusal, f as namedBuildMachine, i as closeOffload, l as remotePhaseText, m as resolveBuildPlacement, n as buildPlacementCandidates, p as parseBuildMachineOption, r as chooseBuildMachine, s as offloadPlacement } from "./client-C2IS36Qf.mjs";
16
+ import { n as placeHostedMacos, t as connectHost } from "./hosted-macos-DwowNU7W.mjs";
17
+ import { n as stopMacosAppHeld } from "./stop-Bvf1MflS.mjs";
18
+ import { t as spawnEntry } from "./spawn-entry-DncpJvWL.mjs";
19
+ import { n as stageBundle, r as validateInfoPlist, t as resolveBundleExtras } from "./stage-CzaiwFsI.mjs";
20
+ import { d as withNativeBuildRun } from "./native-run-DFDoIRbY.mjs";
21
+ import { createHash, randomUUID } from "node:crypto";
22
+ import { closeSync, existsSync, mkdirSync, mkdtempSync, openSync, realpathSync, renameSync, rmSync } from "node:fs";
23
+ import { join, relative, resolve } from "node:path";
24
+ import { LOG_ROTATE_BYTES } from "@stim-cli/core";
25
+ import { machineCapacity, readMacosRecord, validHostedAppArguments } from "@stim-cli/core/state";
26
+ //#region src/macos/build.ts
27
+ async function tool(root, args, writer, note, capture = false) {
28
+ const child = spawnDeclared(() => getExecutor().spawn("swift", args, {
29
+ cwd: root,
30
+ detached: true,
31
+ stdio: [
32
+ "ignore",
33
+ "pipe",
34
+ "pipe"
35
+ ]
36
+ }));
37
+ let stdout = "";
38
+ child.stdout?.on("data", (chunk) => {
39
+ if (capture) stdout += chunk.toString("utf8");
40
+ });
41
+ const write = (msg) => {
42
+ writer.write({
43
+ src: "build",
44
+ platform: "macos",
45
+ level: "debug",
46
+ msg
47
+ });
48
+ note(msg);
49
+ };
50
+ if (child.stdout) logLines(child.stdout, write);
51
+ if (child.stderr) logLines(child.stderr, write);
52
+ await new Promise((done, reject) => {
53
+ child.once("error", reject);
54
+ child.once("close", (code) => code === 0 ? done() : reject(/* @__PURE__ */ new Error(`swift ${args[0]} failed (${code}). See stim logs --source build.`)));
55
+ });
56
+ return stdout.trim();
57
+ }
58
+ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, scratch, writer, note, record, buildMachine, resources, assetCatalog }) {
59
+ if (record) record.buildMachine = buildMachine;
60
+ validateInfoPlist(root, product, infoPlist);
61
+ const repository = realpathSync(repoRoot(root) ?? root);
62
+ const extras = resolveBundleExtras(root, repository, resources, assetCatalog);
63
+ const write = (msg) => {
64
+ writer.write({
65
+ src: "build",
66
+ platform: "macos",
67
+ level: "info",
68
+ msg
69
+ });
70
+ note(msg);
71
+ };
72
+ let offloadFallback = null;
73
+ const fallBack = (reason) => {
74
+ if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, reason);
75
+ offloadFallback = reason;
76
+ if (record) record.offloadFallback = reason;
77
+ writer.write({
78
+ src: "build",
79
+ platform: "macos",
80
+ level: "warn",
81
+ event: "offload_failed",
82
+ msg: reason
83
+ });
84
+ write(`${reason} -> building here`);
85
+ write(`placement: here (${reason})`);
86
+ };
87
+ mkdirSync(macosDir(root), { recursive: true });
88
+ const staging = mkdtempSync(join(macosDir(root), "staging-"));
89
+ const promote = (path) => {
90
+ const backup = join(staging, "previous.app");
91
+ const previous = existsSync(bundle);
92
+ if (previous) renameSync(bundle, backup);
93
+ try {
94
+ renameSync(path, bundle);
95
+ } catch (error) {
96
+ if (previous) renameSync(backup, bundle);
97
+ throw error;
98
+ }
99
+ };
100
+ let choice = null;
101
+ try {
102
+ try {
103
+ const { mode, machines } = buildPlacementCandidates(buildMachine);
104
+ const here = machineCapacity();
105
+ const placement = offloadPlacement({
106
+ mode,
107
+ machines: machines.length,
108
+ here,
109
+ unsupported: null,
110
+ selected: buildMachine
111
+ });
112
+ if (placement.offload) {
113
+ const chosen = await chooseBuildMachine({
114
+ projectRoot: root,
115
+ target: {
116
+ platform: "macos",
117
+ local: macosToolchain()
118
+ },
119
+ mode,
120
+ here,
121
+ machines,
122
+ selected: buildMachine,
123
+ note: (line) => write(`offload: ${line}`)
124
+ });
125
+ if (typeof chosen === "string") throw new Error(chosen);
126
+ choice = chosen;
127
+ write(`placement: ${choice.machine} (${placement.reason}${placementLoad(choice)})`);
128
+ const outcome = await offloadBuild({
129
+ choice,
130
+ request: {
131
+ platform: "macos",
132
+ product,
133
+ infoPlist: relative(root, resolve(root, infoPlist)),
134
+ bundleId,
135
+ resources: Object.fromEntries(Object.entries(extras.resources).map(([destination, source]) => [destination, relative(repository, source)])),
136
+ assetCatalog: extras.assetCatalog ? relative(repository, extras.assetCatalog) : null
137
+ },
138
+ stagingDir: join(staging, "offload"),
139
+ onPhase: (phase, line) => note(remotePhaseText(phase, line, choice.machine)),
140
+ onEnter: (phase) => {
141
+ if (record && [
142
+ "compile",
143
+ "build",
144
+ "prebuild",
145
+ "pods"
146
+ ].includes(phase)) record.builtOn = choice.machine;
147
+ },
148
+ onRecord: (entry) => writer.write({
149
+ ...entry,
150
+ offloadedTo: choice.machine
151
+ }),
152
+ note: write
153
+ });
154
+ if (!outcome.ok) throw new Error(`${outcome.machine}: ${outcome.reason}`);
155
+ const executable = join(outcome.artifactPath, "Contents", "MacOS", product);
156
+ const plist = JSON.parse(getExecutor().runFile("plutil", [
157
+ "-convert",
158
+ "json",
159
+ "-o",
160
+ "-",
161
+ join(outcome.artifactPath, "Contents", "Info.plist")
162
+ ]));
163
+ if (plist.CFBundleIdentifier !== bundleId || plist.CFBundleExecutable !== product || !existsSync(executable)) throw new Error("The fetched macOS bundle does not match the requested identity and executable.");
164
+ for (const destination of [...Object.keys(extras.resources), ...extras.assetCatalog ? ["Assets.car"] : []]) if (!existsSync(join(outcome.artifactPath, "Contents", "Resources", destination))) throw new Error(`The fetched macOS bundle lacks declared resource ${destination}.`);
165
+ getExecutor().runFile("codesign", [
166
+ "--verify",
167
+ "--strict",
168
+ outcome.artifactPath
169
+ ]);
170
+ promote(outcome.artifactPath);
171
+ if (record) {
172
+ record.offloadedTo = outcome.machine;
173
+ record.builtOn = outcome.machine;
174
+ }
175
+ return {
176
+ bundleId,
177
+ offloadedTo: outcome.machine,
178
+ offloadFallback: null,
179
+ handoff: outcome.handoff ?? null
180
+ };
181
+ }
182
+ write(`placement: here (${placement.reason})`);
183
+ } catch (error) {
184
+ fallBack(error instanceof Error ? error.message : String(error));
185
+ } finally {
186
+ if (choice) closeOffload(choice);
187
+ }
188
+ let slot;
189
+ try {
190
+ slot = await acquireBuildSlot({
191
+ max: getConcurrencyLimits().maxBuilds,
192
+ root,
193
+ logFile: writer.file,
194
+ out: note
195
+ });
196
+ if (record) record.builtOn = "here";
197
+ await tool(root, [
198
+ "build",
199
+ "-c",
200
+ "debug",
201
+ "--product",
202
+ product,
203
+ "--scratch-path",
204
+ scratch,
205
+ "--jobs",
206
+ "2"
207
+ ], writer, note);
208
+ const bin = await tool(root, [
209
+ "build",
210
+ "-c",
211
+ "debug",
212
+ "--scratch-path",
213
+ scratch,
214
+ "--show-bin-path"
215
+ ], writer, () => {}, true);
216
+ const staged = join(staging, `${product}.app`);
217
+ stageBundle(root, product, infoPlist, bin, staged, bundleId, extras);
218
+ promote(staged);
219
+ return {
220
+ bundleId,
221
+ offloadedTo: null,
222
+ offloadFallback,
223
+ handoff: null
224
+ };
225
+ } finally {
226
+ releaseBuildSlot(slot);
227
+ }
228
+ } finally {
229
+ try {
230
+ rmSync(staging, {
231
+ recursive: true,
232
+ force: true
233
+ });
234
+ } catch {}
235
+ }
236
+ }
237
+ //#endregion
238
+ //#region src/commands/macos.ts
239
+ /**
240
+ * Builds the Debug app and launches it here, or with `remote` on that approved hosting Mac. A named host never falls
241
+ * back to a local launch.
242
+ */
243
+ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
244
+ const backend = remote?.trim().toLowerCase();
245
+ if (backend === "eas" || backend === "proxy") throw Object.assign(/* @__PURE__ */ new Error("stim macos --remote takes a hosting Mac name from hosting.machines; macOS has no eas or proxy backend."), { code: "STIM_BAD_ARG" });
246
+ if (backend === "auto") throw Object.assign(/* @__PURE__ */ new Error("stim macos --remote auto is not available yet: automatic placement has not shipped. Name a hosting Mac from hosting.machines."), { code: "STIM_BAD_ARG" });
247
+ if (process.platform !== "darwin") throw new Error("stim macos requires a Mac with Swift installed.");
248
+ root = realpathSync(root);
249
+ if (!existsSync(join(root, "Package.swift"))) throw new Error("Run stim macos from the directory containing Package.swift.");
250
+ const settings = resolveSettings({
251
+ projectPath: root,
252
+ gitCommonDir: gitCommonDir(root),
253
+ repoRoot: repoRoot(root)
254
+ });
255
+ const [shape] = settingShapeErrors(settings);
256
+ if (shape) throw new Error(`${shape} ${SETTING_SHAPE_REMEDY}`);
257
+ const selected = resolveBuildPlacement(buildMachineFlag);
258
+ if (selected.failure) throw Object.assign(new Error(selected.failure.message), selected.failure);
259
+ const buildMachine = selected.selected;
260
+ const macos = settings.macos;
261
+ if (!macos?.product || !macos.infoPlist) throw Object.assign(/* @__PURE__ */ new Error("Set macos.product and macos.infoPlist explicitly in .stim.json. See stim guide macos."), { code: "STIM_BAD_ARG" });
262
+ ensureWorkspaceStorage(root);
263
+ return withNativeBuildRun(root, {
264
+ command: "macos",
265
+ platform: "macos"
266
+ }, async () => {
267
+ return withWorkspaceProcessLock(workspaceDir(root), "macos-launch", async () => {
268
+ const previous = requiredMacosRecord(root);
269
+ if (previous?.host && previous.host.machine !== remote) throw new Error(`This workspace's macOS app runs on ${previous.host.machine}. Run stim stop first, then stim macos${remote ? ` --remote ${remote}` : ""}.`);
270
+ if (remote && !validHostedAppArguments(macos.arguments ?? [])) throw new Error("macos.arguments is too large for a hosted app: at most 32 arguments of 1024 characters (8192 in total), without NUL or line breaks.");
271
+ if (remote) (await connectHost(remote)).connection.close();
272
+ if (!previous?.host) await stopMacosAppHeld(root);
273
+ upsertProject(root, {});
274
+ recordWorkspaceUse(root);
275
+ const bundle = join(macosDir(root), `${macos.product}.app`);
276
+ const record = {
277
+ product: macos.product,
278
+ bundle,
279
+ bundleId: "",
280
+ executable: join(bundle, "Contents", "MacOS", macos.product),
281
+ launchId: randomUUID(),
282
+ arguments: macos.arguments ?? [],
283
+ supervisor: macosProcess(process.pid),
284
+ build: {
285
+ state: "running",
286
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
287
+ buildMachine
288
+ },
289
+ ...previous?.host ? {
290
+ host: previous.host,
291
+ hostLaunched: previous.hostLaunched ?? false
292
+ } : {}
293
+ };
294
+ const handoff = await buildBundle(root, macos.infoPlist, record, remote !== void 0, note, macos);
295
+ if (!remote) return launchHere(root, record);
296
+ const connection = await connectHost(remote);
297
+ const write = (patch) => writeWorkspaceState(root, { macos: {
298
+ ...record,
299
+ ...patch
300
+ } });
301
+ let placement = record.host;
302
+ try {
303
+ const run = await placeHostedMacos(connection, {
304
+ root,
305
+ bundle: record.bundle,
306
+ bundleId: record.bundleId,
307
+ handoff,
308
+ arguments: macos.arguments ?? [],
309
+ recorded: previous?.host,
310
+ reserved: (reserved) => {
311
+ placement = reserved;
312
+ write({
313
+ host: reserved,
314
+ hostLaunched: false
315
+ });
316
+ },
317
+ note
318
+ });
319
+ const placed = {
320
+ ...record,
321
+ supervisor: void 0,
322
+ arguments: run.arguments,
323
+ host: run.placement,
324
+ hostLaunched: run.launched
325
+ };
326
+ writeWorkspaceState(root, { macos: placed });
327
+ return placed;
328
+ } catch (error) {
329
+ write({
330
+ supervisor: void 0,
331
+ ...placement ? {
332
+ host: placement,
333
+ hostLaunched: false
334
+ } : {}
335
+ });
336
+ throw error;
337
+ } finally {
338
+ connection.connection.close();
339
+ }
340
+ }, {
341
+ external: true,
342
+ declareSpawns: true,
343
+ ownerPurpose: "build and launch macOS app"
344
+ });
345
+ }, { write: note });
346
+ }
347
+ async function buildBundle(root, infoPlist, record, hosted, note, extras) {
348
+ const started = Date.parse(record.build.startedAt);
349
+ const scratch = join(macosDir(root), "build");
350
+ writeWorkspaceState(root, { macos: record });
351
+ const writer = createNdjsonWriter(macosLogFile(root), { maxBytes: LOG_ROTATE_BYTES });
352
+ try {
353
+ const { bundleId: base } = validateInfoPlist(root, record.product, infoPlist);
354
+ const bundleId = hosted ? base : `${base}.stim.${createHash("sha256").update(root).digest("hex").slice(0, 12)}`;
355
+ const built = await buildMacosBundle({
356
+ root,
357
+ product: record.product,
358
+ infoPlist,
359
+ bundle: record.bundle,
360
+ bundleId,
361
+ scratch,
362
+ writer,
363
+ note,
364
+ record: record.build,
365
+ buildMachine: record.build.buildMachine,
366
+ resources: extras.resources,
367
+ assetCatalog: extras.assetCatalog
368
+ });
369
+ record.bundleId = built.bundleId;
370
+ record.bundle = realpathSync(record.bundle);
371
+ record.executable = realpathSync(join(record.bundle, "Contents", "MacOS", record.product));
372
+ record.build = {
373
+ ...record.build,
374
+ state: "ok",
375
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
376
+ durationMs: Date.now() - started
377
+ };
378
+ writeWorkspaceState(root, { macos: record });
379
+ return built.handoff;
380
+ } catch (error) {
381
+ const message = error instanceof Error ? error.message : String(error);
382
+ writer.write({
383
+ src: "build",
384
+ platform: "macos",
385
+ level: "error",
386
+ msg: message
387
+ });
388
+ writeWorkspaceState(root, { macos: {
389
+ ...record,
390
+ supervisor: void 0,
391
+ build: {
392
+ ...record.build,
393
+ state: "failed",
394
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
395
+ durationMs: Date.now() - started,
396
+ error: message,
397
+ ..."code" in Object(error) && typeof error.code === "string" ? { errorCode: error.code } : {}
398
+ }
399
+ } });
400
+ throw error;
401
+ } finally {
402
+ writer.close();
403
+ }
404
+ }
405
+ async function launchHere(root, record) {
406
+ const fd = openSync(join(workspaceLogsDir(root), "macos-supervisor.log"), "a");
407
+ let child;
408
+ try {
409
+ child = spawnDeclared(() => getExecutor().spawn(process.execPath, [
410
+ spawnEntry("macos-run"),
411
+ root,
412
+ record.launchId
413
+ ], {
414
+ cwd: root,
415
+ detached: true,
416
+ stdio: [
417
+ "ignore",
418
+ fd,
419
+ fd
420
+ ],
421
+ env: {
422
+ ...process.env,
423
+ STIM_BACKGROUND_LAUNCH: "1"
424
+ }
425
+ }));
426
+ child.unref();
427
+ } finally {
428
+ closeSync(fd);
429
+ }
430
+ const deadline = Date.now() + 2e4;
431
+ while (Date.now() < deadline) {
432
+ const current = readMacosRecord(root);
433
+ if (current?.launchId === record.launchId && current.app && current.supervisor && (0, process_identity_exports.inspectProcessIdentity)(current.app) === "same" && (0, process_identity_exports.inspectProcessIdentity)(current.supervisor) === "same") return current;
434
+ if (child.exitCode !== null || child.signalCode !== null) break;
435
+ await new Promise((done) => setTimeout(done, 100));
436
+ }
437
+ throw new Error("The macOS app did not register. See macos-supervisor.log in the workspace logs.");
438
+ }
439
+ function launchPayload(record) {
440
+ if (!record.host) return {
441
+ platform: "macos",
442
+ ...record
443
+ };
444
+ const { product, launchId, build, host } = record;
445
+ return {
446
+ platform: "macos",
447
+ product,
448
+ launchId,
449
+ build,
450
+ host
451
+ };
452
+ }
453
+ function macosCommand(program) {
454
+ program.command("macos").description("Build and launch an owned Swift Package macOS Debug app.").option("--build-machine <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "print one launch payload; build output goes to stderr").option("--remote <machine>", "run it on this approved hosting Mac from hosting.machines").action(async (options) => {
455
+ const root = findProjectRoot$1(process.cwd());
456
+ if (!root) throw new Error("Run stim macos from the Swift Package directory.");
457
+ const record = await runMacos(root, console.error, options.remote, options.buildMachine).catch((error) => {
458
+ const remedy = error.remedy;
459
+ if (typeof remedy === "string") console.error(`remedy: ${remedy}`);
460
+ throw error;
461
+ });
462
+ if (options.json) console.log(JSON.stringify(launchPayload(record)));
463
+ else if (record.host) console.log(`Started ${record.product} on ${record.host.machine} as ${record.host.bundleId}${record.hostLaunched === true ? "" : " (launch not confirmed)"}.`);
464
+ else console.log(`Started ${record.product} (pid ${record.app?.pid}).`);
465
+ });
466
+ }
467
+ //#endregion
468
+ export { macosCommand as default, runMacos };
@@ -0,0 +1,5 @@
1
+ //#region src/macos/run.d.ts
2
+ declare function logLines(stream: NodeJS.ReadableStream, write: (line: string) => void): void;
3
+ declare function runMacosSupervisor(root: string, launchId: string): Promise<void>;
4
+ //#endregion
5
+ export { logLines, runMacosSupervisor };
@@ -0,0 +1,2 @@
1
+ import { n as runMacosSupervisor, t as logLines } from "./run-B-xqRrsg.mjs";
2
+ export { logLines, runMacosSupervisor };
@@ -1,10 +1,11 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { statSync } from "node:fs";
3
3
  //#region src/workspace/merge-state.ts
4
4
  const FETCH_TIMEOUT_MS = 3e4;
5
5
  const FETCH_FRESH_MS = 6e5;
6
6
  const GIT_TIMEOUT_MS = 6e4;
7
7
  const REMOTE_PREFIX = "refs/remotes/origin/";
8
+ const MAX_MERGE_STATE_COMMITS = 2e3;
8
9
  function failure(error) {
9
10
  const { stderr, message } = error;
10
11
  const text = String(stderr ?? "").trim() || String(message ?? error);
@@ -130,7 +131,7 @@ function committedOn(path, branch, head) {
130
131
  * Anything git cannot answer is unknown, never merged. `coversUnpushed` is true for a patch-equivalent HEAD whose
131
132
  * upstream branch was deleted: its commits exist only locally, but their change is on the default branch.
132
133
  */
133
- function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS } = {}) {
134
+ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS, maxCommits = MAX_MERGE_STATE_COMMITS } = {}) {
134
135
  const git = (args, input) => getExecutor().runFile("git", [
135
136
  "--literal-pathspecs",
136
137
  "-C",
@@ -140,13 +141,14 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS } = {}) {
140
141
  timeoutMs,
141
142
  input
142
143
  });
143
- const patch = (args) => getExecutor().runFile("git", [
144
+ const patch = (args, input) => getExecutor().runFile("git", [
144
145
  "--literal-pathspecs",
145
146
  "-C",
146
147
  path,
147
148
  ...args
148
149
  ], {
149
150
  timeoutMs,
151
+ input,
150
152
  untrimmed: true
151
153
  });
152
154
  const patchIdCommits = (text) => new Map(text ? git(["patch-id", "--verbatim"], text).split("\n").flatMap((line) => {
@@ -156,11 +158,11 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS } = {}) {
156
158
  const patchIds = (text) => [...patchIdCommits(text).keys()];
157
159
  const committedAt = (commits) => {
158
160
  const times = commits.length ? git([
159
- "show",
160
- "-s",
161
- "--format=%ct",
162
- ...commits
163
- ]).split("\n").map(Number) : [];
161
+ "log",
162
+ "--no-walk",
163
+ "--stdin",
164
+ "--format=%ct"
165
+ ], commits.join("\n")).split("\n").map(Number) : [];
164
166
  if (!times.length || !times.every(Number.isFinite)) throw new Error(`no committer date for ${commits.join(" ")}`);
165
167
  return Math.max(...times) * 1e3;
166
168
  };
@@ -205,6 +207,16 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS } = {}) {
205
207
  mergedAt: committedAt([landed])
206
208
  };
207
209
  }
210
+ const aheadCount = Number(git([
211
+ "rev-list",
212
+ "--count",
213
+ `${base}..${head}`
214
+ ]));
215
+ if (aheadCount > maxCommits) return {
216
+ merged: false,
217
+ unknown: true,
218
+ detail: `merge state unknown: ${aheadCount} commits of its own ahead of the merge base with ${name} exceeds the ${maxCommits}-commit limit`
219
+ };
208
220
  const files = git([
209
221
  "diff",
210
222
  "--name-only",
@@ -220,10 +232,8 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS } = {}) {
220
232
  "--no-merges",
221
233
  ...diffOptions,
222
234
  "--format=commit %H",
223
- range,
224
- "--",
225
- ...pathspec
226
- ]);
235
+ "--stdin"
236
+ ], pathspec.length ? `${range}\n--\n${pathspec.join("\n")}\n` : `${range}\n`);
227
237
  const upstream = patchIdCommits(log(`${base}..${ref}`, files));
228
238
  const patchEquivalent = (ids) => ({
229
239
  merged: true,