peachsim 0.1.1469 → 0.1.1481

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 (102) hide show
  1. package/cli/commands/control.ts +68 -42
  2. package/cli/commands/detox.ts +15 -10
  3. package/cli/commands/flow.ts +1 -2
  4. package/cli/commands/inspect/settling.ts +5 -1
  5. package/cli/commands/setup.ts +20 -13
  6. package/cli/commands/test.ts +2 -1
  7. package/cli/dev-build-freshness.ts +14 -14
  8. package/cli/drivers/playwright-sim-host.ts +7 -2
  9. package/cli/drivers/playwright.ts +6 -6
  10. package/cli/outbound-endpoints.ts +80 -6
  11. package/detox/index.ts +27 -14
  12. package/detox/matchers.ts +17 -6
  13. package/dist-lib/agent-daemon-client.cjs +1 -1
  14. package/dist-lib/agent-events.cjs +1 -1
  15. package/dist-lib/attached-projects.cjs +1 -1
  16. package/dist-lib/auth/shared-session.cjs +1 -1
  17. package/dist-lib/backend-origin.cjs +1 -1
  18. package/dist-lib/beta.cjs +1 -1
  19. package/dist-lib/beta.mjs +1 -1
  20. package/dist-lib/bridge-constants.cjs +1 -1
  21. package/dist-lib/bridge-contract-input.cjs +1 -1
  22. package/dist-lib/bridge-contract-input.mjs +1 -1
  23. package/dist-lib/bridge-contract.cjs +1 -1
  24. package/dist-lib/bridge-contract.mjs +1 -1
  25. package/dist-lib/bundle-channel.cjs +54 -15
  26. package/dist-lib/capture-contract.cjs +1 -1
  27. package/dist-lib/capture-contract.mjs +1 -1
  28. package/dist-lib/cloud-contract.cjs +1 -1
  29. package/dist-lib/cloud-contract.mjs +1 -1
  30. package/dist-lib/cloud-test-args.cjs +1 -1
  31. package/dist-lib/cloud-test-args.mjs +1 -1
  32. package/dist-lib/cloud.cjs +1 -1
  33. package/dist-lib/cloud.mjs +1 -1
  34. package/dist-lib/config.cjs +19 -3
  35. package/dist-lib/config.mjs +19 -3
  36. package/dist-lib/detox/index.cjs +125 -52
  37. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  38. package/dist-lib/expo-swift-bundle.cjs +30 -9
  39. package/dist-lib/expo-swift-metadata.cjs +18 -6
  40. package/dist-lib/expo-swift-metadata.mjs +18 -6
  41. package/dist-lib/home-paths.cjs +1 -1
  42. package/dist-lib/host/bridge-host.cjs +621 -390
  43. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  44. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  45. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  46. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  47. package/dist-lib/host/websocket-proxy.cjs +1 -1
  48. package/dist-lib/index.cjs +46 -19
  49. package/dist-lib/jump-to-source-babel.cjs +1 -1
  50. package/dist-lib/jump-to-source-native.cjs +1 -1
  51. package/dist-lib/kotlin-host.cjs +1 -1
  52. package/dist-lib/menu.cjs +1 -1
  53. package/dist-lib/menu.mjs +1 -1
  54. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  55. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  56. package/dist-lib/metro-production-bundle.cjs +24 -6
  57. package/dist-lib/metro-production-bundle.mjs +22 -6
  58. package/dist-lib/metro.cjs +41 -18
  59. package/dist-lib/native-app-identity-project.cjs +1 -1
  60. package/dist-lib/native-app-identity-project.mjs +1 -1
  61. package/dist-lib/native-app-identity.cjs +19 -5
  62. package/dist-lib/native-app-identity.mjs +19 -5
  63. package/dist-lib/native-firebase-metadata.cjs +22 -7
  64. package/dist-lib/native-firebase-metadata.mjs +20 -7
  65. package/dist-lib/plist.cjs +1 -1
  66. package/dist-lib/plist.mjs +1 -1
  67. package/dist-lib/profiles.cjs +1 -1
  68. package/dist-lib/public-brand.cjs +1 -1
  69. package/dist-lib/react-native-host-modules.cjs +3 -1
  70. package/dist-lib/react-native-host-modules.mjs +3 -1
  71. package/dist-lib/scripts/dev-server-scanner.cjs +404 -279
  72. package/dist-lib/sdk.cjs +6 -2
  73. package/dist-lib/sdk.mjs +6 -2
  74. package/dist-lib/skills.cjs +757 -531
  75. package/dist-lib/swift-compile.cjs +7 -2
  76. package/dist-lib/swift-compile.mjs +7 -2
  77. package/dist-lib/swift-package.cjs +1 -1
  78. package/dist-lib/swift-package.mjs +1 -1
  79. package/dist-lib/swift-submit.cjs +1 -1
  80. package/dist-lib/swift-submit.mjs +1 -1
  81. package/dist-lib/swift-toolchain.cjs +1 -1
  82. package/dist-lib/swift.cjs +1 -1
  83. package/dist-lib/vite-swift.cjs +7 -2
  84. package/dist-lib/vite.cjs +1 -1
  85. package/dist-lib/worklet-executable.cjs +27 -7
  86. package/dist-lib/worklet-executable.mjs +27 -7
  87. package/package.json +1 -1
  88. package/scripts/dev-server-scanner.ts +493 -188
  89. package/src/admitted-mac-build.ts +12 -0
  90. package/src/bridge-constants.ts +5 -3
  91. package/src/bundleGlobalFooter.ts +26 -3
  92. package/src/config.ts +3 -2
  93. package/src/configured-bundle-producer.ts +2 -1
  94. package/src/expo-swift-host.ts +33 -7
  95. package/src/host/bridge-host.ts +34 -6
  96. package/src/metro-production-bundle.ts +11 -4
  97. package/src/native-app-identity.ts +3 -2
  98. package/src/native-firebase-metadata.ts +5 -3
  99. package/src/react-native-host-modules.ts +2 -0
  100. package/src/swift-compile.ts +5 -4
  101. package/src/worker-system-chunks.ts +61 -58
  102. package/src/worklet-executable.ts +38 -6
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1469 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1481 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -35,6 +35,66 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
35
35
  ));
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
 
38
+ // ../../scripts/lib/chromium-admission.ts
39
+ function readChromiumQueue(deps, verified3, own) {
40
+ const { fs: fs25, os: os10, path: path29, childProcess: childProcess2 } = deps;
41
+ const dir = path29.join(
42
+ process.platform === "win32" ? os10.tmpdir() : "/tmp",
43
+ "chromium-admission"
44
+ );
45
+ fs25.mkdirSync(dir, { recursive: true });
46
+ const limit = Math.max(2, Math.floor(os10.cpus().length / 3));
47
+ const live = (entry) => {
48
+ const match = /^(\d+)-(\d+)-/.exec(entry);
49
+ if (!match) return false;
50
+ const pid = Number(match[1]);
51
+ try {
52
+ process.kill(pid, 0);
53
+ } catch (err) {
54
+ if (!(err instanceof Error && "code" in err && err.code === "EPERM")) return false;
55
+ }
56
+ const known = verified3.get(entry);
57
+ if (known !== void 0) return known;
58
+ let same = pid === process.pid;
59
+ if (!same) {
60
+ try {
61
+ const started = childProcess2.execFileSync("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8" }).trim();
62
+ same = Math.abs(Date.parse(started) / 1e3 - Number(match[2])) <= 2;
63
+ } catch {
64
+ same = false;
65
+ }
66
+ }
67
+ verified3.set(entry, same);
68
+ return same;
69
+ };
70
+ const tickets = [];
71
+ for (const entry of fs25.readdirSync(dir)) {
72
+ if (entry !== own && !live(entry)) {
73
+ try {
74
+ fs25.unlinkSync(path29.join(dir, entry));
75
+ } catch {
76
+ }
77
+ continue;
78
+ }
79
+ try {
80
+ tickets.push({
81
+ entry,
82
+ created: fs25.statSync(path29.join(dir, entry), { bigint: true }).ctimeNs
83
+ });
84
+ } catch {
85
+ }
86
+ }
87
+ tickets.sort(
88
+ (a, b) => a.created === b.created ? a.entry < b.entry ? -1 : 1 : a.created < b.created ? -1 : 1
89
+ );
90
+ return { dir, limit, tickets: tickets.map((t) => t.entry) };
91
+ }
92
+ var init_chromium_admission = __esm({
93
+ "../../scripts/lib/chromium-admission.ts"() {
94
+ "use strict";
95
+ }
96
+ });
97
+
38
98
  // src/backend-origin.ts
39
99
  function normalizeHostname(hostname) {
40
100
  return hostname.replace(/^\[|\]$/g, "").toLowerCase();
@@ -89,6 +149,13 @@ var init_backend_origin = __esm({
89
149
  }
90
150
  });
91
151
 
152
+ // src/bundleGlobalFooter.ts
153
+ var init_bundleGlobalFooter = __esm({
154
+ "src/bundleGlobalFooter.ts"() {
155
+ "use strict";
156
+ }
157
+ });
158
+
92
159
  // src/is-record.ts
93
160
  function isRecord(value) {
94
161
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -395,7 +462,7 @@ var init_optional_demo_registry = __esm({
395
462
  function rnxHomeDir() {
396
463
  const override = process.env[PEACH_HOME_ENV];
397
464
  if (override && override.length > 0) return import_node_path4.default.resolve(override);
398
- return import_node_path4.default.join((0, import_node_os.homedir)(), ".peach");
465
+ return import_node_path4.default.join((0, import_node_os2.homedir)(), ".peach");
399
466
  }
400
467
  function isSootsimDevCheckout() {
401
468
  if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
@@ -736,13 +803,13 @@ function removeDevBridgeLockfile(owner) {
736
803
  } catch {
737
804
  }
738
805
  }
739
- var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, PEACH_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, FETCH_TRANSPORT_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
806
+ var import_node_crypto, import_node_fs3, import_node_os2, import_node_path4, PEACH_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, FETCH_TRANSPORT_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
740
807
  var init_home_paths = __esm({
741
808
  "src/home-paths.ts"() {
742
809
  "use strict";
743
810
  import_node_crypto = require("node:crypto");
744
811
  import_node_fs3 = __toESM(require("node:fs"), 1);
745
- import_node_os = require("node:os");
812
+ import_node_os2 = require("node:os");
746
813
  import_node_path4 = __toESM(require("node:path"), 1);
747
814
  PEACH_HOME_ENV = "PEACH_HOME";
748
815
  ACTIVE_RUNTIME_FILE = "active";
@@ -3231,11 +3298,11 @@ async function serveKotlinRequest(pathname, res, app) {
3231
3298
  }
3232
3299
  return true;
3233
3300
  }
3234
- var import_node_child_process13, import_node_crypto14, import_node_fs30, import_node_module2, import_node_path31, import_node_url4, import_node_util4, import_acorn, run4, KOTLIN_ARTIFACT_PREFIX, toolchainReady, SKIP_DIRS, BUILD_FORMAT, builds, expoTypeScans, argb, escapes, literal, CONTENT_TYPES, KOTLIN_PACKAGE_PATH;
3301
+ var import_node_child_process12, import_node_crypto14, import_node_fs30, import_node_module2, import_node_path31, import_node_url4, import_node_util4, import_acorn, run4, KOTLIN_ARTIFACT_PREFIX, toolchainReady, SKIP_DIRS, BUILD_FORMAT, builds, expoTypeScans, argb, escapes, literal, CONTENT_TYPES, KOTLIN_PACKAGE_PATH;
3235
3302
  var init_kotlin_host = __esm({
3236
3303
  "src/kotlin-host.ts"() {
3237
3304
  "use strict";
3238
- import_node_child_process13 = require("node:child_process");
3305
+ import_node_child_process12 = require("node:child_process");
3239
3306
  import_node_crypto14 = require("node:crypto");
3240
3307
  import_node_fs30 = __toESM(require("node:fs"), 1);
3241
3308
  import_node_module2 = require("node:module");
@@ -3246,7 +3313,7 @@ var init_kotlin_host = __esm({
3246
3313
  init_home_paths();
3247
3314
  init_is_record();
3248
3315
  init_kotlin_view_models();
3249
- run4 = (0, import_node_util4.promisify)(import_node_child_process13.execFile);
3316
+ run4 = (0, import_node_util4.promisify)(import_node_child_process12.execFile);
3250
3317
  KOTLIN_ARTIFACT_PREFIX = "/__peach/kotlin-artifact/";
3251
3318
  SKIP_DIRS = /* @__PURE__ */ new Set([
3252
3319
  "node_modules",
@@ -3432,11 +3499,11 @@ async function handleExpoKotlinRequest(req, res) {
3432
3499
  }
3433
3500
  return true;
3434
3501
  }
3435
- var import_node_child_process14, import_node_fs31, import_node_module3, import_node_path32, import_node_util5, run5, scriptEnv2, EXPO_KOTLIN_ROUTE, MODULE_ROOT, compiling2;
3502
+ var import_node_child_process13, import_node_fs31, import_node_module3, import_node_path32, import_node_util5, run5, scriptEnv2, EXPO_KOTLIN_ROUTE, MODULE_ROOT, compiling2;
3436
3503
  var init_expo_kotlin_host = __esm({
3437
3504
  "src/expo-kotlin-host.ts"() {
3438
3505
  "use strict";
3439
- import_node_child_process14 = require("node:child_process");
3506
+ import_node_child_process13 = require("node:child_process");
3440
3507
  import_node_fs31 = __toESM(require("node:fs"), 1);
3441
3508
  import_node_module3 = require("node:module");
3442
3509
  import_node_path32 = __toESM(require("node:path"), 1);
@@ -3444,7 +3511,7 @@ var init_expo_kotlin_host = __esm({
3444
3511
  init_internal_child();
3445
3512
  init_backend_origin();
3446
3513
  init_is_record();
3447
- run5 = (0, import_node_util5.promisify)(import_node_child_process14.execFile);
3514
+ run5 = (0, import_node_util5.promisify)(import_node_child_process13.execFile);
3448
3515
  scriptEnv2 = { ...process.env, [RNX_FORKED_SCRIPT_ENV]: "1" };
3449
3516
  EXPO_KOTLIN_ROUTE = "/__peach/expo-kotlin";
3450
3517
  MODULE_ROOT = import_node_path32.default.resolve(__sootsim_import_meta_dirname, "../kotlin");
@@ -3738,6 +3805,7 @@ function rotateDevice(device, side) {
3738
3805
  frameCornerRadius: device.frameCornerRadius ? rotateCorners(device.frameCornerRadius, side) : void 0,
3739
3806
  cornerRadius: rotateCorners(device.cornerRadius, side),
3740
3807
  continuousCornerRadius: rotateCorners(device.continuousCornerRadius, side),
3808
+ systemCornerRadius: device.systemCornerRadius ? rotateCorners(device.systemCornerRadius, side) : void 0,
3741
3809
  housing: device.housing ? {
3742
3810
  rail: rotateFrameInsets(device.housing.rail, side),
3743
3811
  // the rotated barrel is accounted for in frameInsets.
@@ -4552,6 +4620,7 @@ var RNX_METRO_MODULE_IDENTITY_VERSION;
4552
4620
  var init_metro_production_bundle = __esm({
4553
4621
  "src/metro-production-bundle.ts"() {
4554
4622
  "use strict";
4623
+ init_bundleGlobalFooter();
4555
4624
  RNX_METRO_MODULE_IDENTITY_VERSION = 2;
4556
4625
  }
4557
4626
  });
@@ -4617,6 +4686,7 @@ function quotedEnd(text3, start, end) {
4617
4686
  return end;
4618
4687
  }
4619
4688
  function decodeSingleQuoted(contents) {
4689
+ if (!contents.includes("\\")) return contents;
4620
4690
  let value = "";
4621
4691
  for (let cursor = 0; cursor < contents.length; cursor++) {
4622
4692
  const character = contents[cursor];
@@ -5029,13 +5099,21 @@ function metroAssetDataUri(type, bytes) {
5029
5099
  return `data:${metroAssetContentType(type)};base64,${base64FromBytes(bytes)}`;
5030
5100
  }
5031
5101
  async function sha256HexBytes(bytes) {
5032
- const buffer = bytes.buffer instanceof ArrayBuffer && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes.buffer : bytes.slice().buffer;
5033
- const digest = await crypto.subtle.digest("SHA-256", buffer);
5102
+ const digest = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer);
5034
5103
  let hex = "";
5035
5104
  for (const byte of new Uint8Array(digest)) hex += byte.toString(16).padStart(2, "0");
5036
5105
  return hex;
5037
5106
  }
5038
5107
  async function assertSelfContainedMetroArtifactAssets(bundle) {
5108
+ return visitVerifiedMetroArtifactAssets(
5109
+ bundle,
5110
+ () => {
5111
+ },
5112
+ () => {
5113
+ }
5114
+ );
5115
+ }
5116
+ async function visitVerifiedMetroArtifactAssets(bundle, acceptVariant, acceptSite) {
5039
5117
  const seen = /* @__PURE__ */ new Set();
5040
5118
  const manifestLines = [];
5041
5119
  let descriptorsCount = 0;
@@ -5046,7 +5124,10 @@ async function assertSelfContainedMetroArtifactAssets(bundle) {
5046
5124
  for (const site of iterateAssetDescriptorSites(bundle)) {
5047
5125
  const descriptor = site.descriptor;
5048
5126
  const key2 = assetDescriptorKey(descriptor);
5049
- if (seen.has(key2)) continue;
5127
+ if (seen.has(key2)) {
5128
+ acceptSite(site);
5129
+ continue;
5130
+ }
5050
5131
  seen.add(key2);
5051
5132
  descriptorsCount++;
5052
5133
  const label = `${descriptor.httpServerLocation}/${descriptor.name}.${descriptor.type}`;
@@ -5081,11 +5162,13 @@ async function assertSelfContainedMetroArtifactAssets(bundle) {
5081
5162
  `peach ios --remote bundle is not self-contained: ${label} scale ${descriptor.scales[index]} bytes do not match their content hash`
5082
5163
  );
5083
5164
  }
5165
+ acceptVariant(descriptor, index, decoded);
5084
5166
  variants++;
5085
5167
  bytes += decoded.byteLength;
5086
5168
  descriptorBytes += decoded.byteLength;
5087
5169
  }
5088
5170
  sizes.push({ asset: label, bytes: descriptorBytes });
5171
+ acceptSite(site);
5089
5172
  }
5090
5173
  } catch (error) {
5091
5174
  if (error instanceof Error && error.message.startsWith("peach ios --remote bundle is not self-contained:")) {
@@ -5107,52 +5190,48 @@ async function assertSelfContainedMetroArtifactAssets(bundle) {
5107
5190
  };
5108
5191
  }
5109
5192
  async function separateMetroArtifactAssets(bundle) {
5110
- const assets2 = await assertSelfContainedMetroArtifactAssets(bundle);
5111
- const sites = scanAssetDescriptorSites(bundle);
5112
5193
  const resources = /* @__PURE__ */ new Map();
5113
5194
  const entries = /* @__PURE__ */ new Map();
5114
- for (const site of sites) {
5115
- const descriptor = site.descriptor;
5116
- const key2 = assetDescriptorKey(descriptor);
5117
- if (entries.has(key2)) continue;
5118
- const contentType = metroAssetContentType(descriptor.type);
5119
- const prefix = `data:${contentType};base64,`;
5120
- const fileUris = [];
5121
- const fileHashes = [];
5122
- for (let index = 0; index < descriptor.scales.length; index++) {
5123
- const dataUri = descriptor.fileUris?.[index];
5195
+ const pieces = [];
5196
+ let cursor = 0;
5197
+ const assets2 = await visitVerifiedMetroArtifactAssets(
5198
+ bundle,
5199
+ (descriptor, index, bytes) => {
5200
+ const key2 = assetDescriptorKey(descriptor);
5201
+ let entry = entries.get(key2);
5202
+ if (!entry) {
5203
+ entry = { fileUris: [], fileHashes: [], scales: descriptor.scales };
5204
+ entries.set(key2, entry);
5205
+ }
5124
5206
  const sha256 = descriptor.fileHashes?.[index];
5125
- if (!dataUri || !sha256) throw new Error("verified Metro asset is incomplete");
5126
5207
  const scale = descriptor.scales[index];
5127
- if (scale === void 0) throw new Error("verified Metro asset scale is missing");
5208
+ if (!sha256 || scale === void 0) {
5209
+ throw new Error("verified Metro asset variant is incomplete");
5210
+ }
5128
5211
  const filename = metroAssetScaleFilename(descriptor.name, descriptor.type, scale);
5129
5212
  const uri = `${PEACH_BUNDLE_ASSET_PREFIX}${sha256}/${encodeURIComponent(filename)}`;
5130
5213
  if (!resources.has(uri)) {
5131
- const bytes = decodeBase64ToBytes(dataUri.slice(prefix.length));
5132
5214
  resources.set(uri, {
5133
5215
  uri,
5134
5216
  sha256,
5135
- contentType,
5217
+ contentType: metroAssetContentType(descriptor.type),
5136
5218
  bytes,
5137
5219
  byteLength: bytes.byteLength
5138
5220
  });
5139
5221
  }
5140
- fileUris.push(uri);
5141
- fileHashes.push(sha256);
5222
+ entry.fileUris.push(uri);
5223
+ entry.fileHashes.push(sha256);
5224
+ },
5225
+ (site) => {
5226
+ const entry = entries.get(assetDescriptorKey(site.descriptor));
5227
+ if (!entry) throw new Error("verified Metro asset descriptor is missing");
5228
+ pieces.push(
5229
+ bundle.slice(cursor, site.start),
5230
+ rewriteDescriptorObject(bundle, site, entry)
5231
+ );
5232
+ cursor = site.end;
5142
5233
  }
5143
- entries.set(key2, { fileUris, fileHashes, scales: descriptor.scales });
5144
- }
5145
- const pieces = [];
5146
- let cursor = 0;
5147
- for (const site of sites) {
5148
- const entry = entries.get(assetDescriptorKey(site.descriptor));
5149
- if (!entry) throw new Error("verified Metro asset descriptor is missing");
5150
- pieces.push(
5151
- bundle.slice(cursor, site.start),
5152
- rewriteDescriptorObject(bundle, site, entry)
5153
- );
5154
- cursor = site.end;
5155
- }
5234
+ );
5156
5235
  pieces.push(bundle.slice(cursor));
5157
5236
  return { code: pieces.join(""), assets: assets2, resources: [...resources.values()] };
5158
5237
  }
@@ -10492,11 +10571,13 @@ __export(bridge_host_exports, {
10492
10571
  injectSharedConfigIntoHtml: () => injectSharedConfigIntoHtml
10493
10572
  });
10494
10573
  module.exports = __toCommonJS(bridge_host_exports);
10495
- var import_child_process3 = require("child_process");
10574
+ var import_child_process3 = __toESM(require("child_process"), 1);
10496
10575
  var import_fs2 = __toESM(require("fs"), 1);
10497
10576
  var import_http4 = require("http");
10577
+ var import_os = __toESM(require("os"), 1);
10498
10578
  var import_path2 = __toESM(require("path"), 1);
10499
10579
  var import_ws = require("ws");
10580
+ init_chromium_admission();
10500
10581
 
10501
10582
  // scripts/dev-server-scanner.ts
10502
10583
  var import_child_process = require("child_process");
@@ -10504,162 +10585,8 @@ var import_promises2 = require("fs/promises");
10504
10585
  var import_http = __toESM(require("http"), 1);
10505
10586
  var import_net = __toESM(require("net"), 1);
10506
10587
  var import_node_fs2 = require("node:fs");
10588
+ var import_node_os = require("node:os");
10507
10589
  var import_node_path3 = require("node:path");
10508
-
10509
- // ../contrast/src/runtime/process-group.ts
10510
- var import_node_child_process = require("node:child_process");
10511
-
10512
- // ../contrast/src/sleep.ts
10513
- function sleep(ms) {
10514
- return new Promise((resolve5) => setTimeout(resolve5, ms));
10515
- }
10516
-
10517
- // ../contrast/src/runtime/process-group.ts
10518
- var GRACEFUL_TIMEOUT_MS = 3e3;
10519
- var FORCED_EXIT_TIMEOUT_MS = 1e3;
10520
- function signalProcessGroup(child, signal) {
10521
- if (!child.pid) return;
10522
- try {
10523
- process.kill(-child.pid, signal);
10524
- } catch {
10525
- try {
10526
- process.kill(child.pid, signal);
10527
- } catch {
10528
- }
10529
- }
10530
- }
10531
- function runningPids(pids) {
10532
- return pids.filter((pid) => {
10533
- try {
10534
- process.kill(pid, 0);
10535
- return true;
10536
- } catch (error) {
10537
- return error instanceof Error && "code" in error && error.code === "EPERM";
10538
- }
10539
- });
10540
- }
10541
- function groupIsEmpty(pgid) {
10542
- try {
10543
- process.kill(-pgid, 0);
10544
- } catch (error) {
10545
- if (!(error instanceof Error && "code" in error && error.code === "EPERM"))
10546
- return true;
10547
- }
10548
- const result = (0, import_node_child_process.spawnSync)("ps", ["-A", "-o", "pgid=,stat="], {
10549
- encoding: "utf8",
10550
- stdio: ["ignore", "pipe", "pipe"]
10551
- });
10552
- if (result.error || result.status !== 0) return false;
10553
- return !result.stdout.split("\n").some((line) => {
10554
- const [group, state] = line.trim().split(/\s+/);
10555
- return Number(group) === pgid && state !== void 0 && !state.startsWith("Z");
10556
- });
10557
- }
10558
- async function waitForExit(pids, pgid, timeoutMs) {
10559
- const deadline = Date.now() + timeoutMs;
10560
- const gone = () => runningPids(pids).length === 0 && groupIsEmpty(pgid);
10561
- while (Date.now() < deadline) {
10562
- if (gone()) return true;
10563
- await sleep(50);
10564
- }
10565
- return gone();
10566
- }
10567
- async function terminateProcessGroup(child, signal = "SIGTERM", gracefulTimeoutMs = GRACEFUL_TIMEOUT_MS) {
10568
- if (!child.pid) {
10569
- try {
10570
- child.kill(signal);
10571
- } catch {
10572
- }
10573
- return;
10574
- }
10575
- signalProcessGroup(child, "SIGSTOP");
10576
- const descendants = /* @__PURE__ */ new Set();
10577
- let parents = [child.pid];
10578
- let inspectionError = null;
10579
- while (parents.length > 0) {
10580
- const result = (0, import_node_child_process.spawnSync)("pgrep", ["-P", parents.join(",")], {
10581
- encoding: "utf8",
10582
- stdio: ["ignore", "pipe", "pipe"]
10583
- });
10584
- if (result.error || result.status !== 0 && result.status !== 1) {
10585
- inspectionError = new Error(
10586
- `could not inspect descendants of processes ${parents.join(",")}: ${result.error?.message || result.stderr.trim() || `pgrep exited ${result.status}`}`
10587
- );
10588
- break;
10589
- }
10590
- const next = [];
10591
- for (const line of result.stdout.split("\n")) {
10592
- const descendantPid = Number(line.trim());
10593
- if (Number.isInteger(descendantPid) && descendantPid > 1 && !descendants.has(descendantPid)) {
10594
- descendants.add(descendantPid);
10595
- next.push(descendantPid);
10596
- try {
10597
- process.kill(descendantPid, "SIGSTOP");
10598
- } catch {
10599
- }
10600
- }
10601
- }
10602
- parents = next;
10603
- }
10604
- const pids = [child.pid, ...descendants];
10605
- const gracefulDeadline = Date.now() + gracefulTimeoutMs;
10606
- try {
10607
- process.kill(child.pid, signal);
10608
- } catch {
10609
- }
10610
- signalProcessGroup(child, "SIGCONT");
10611
- for (const pid of descendants) {
10612
- try {
10613
- process.kill(pid, "SIGCONT");
10614
- } catch {
10615
- }
10616
- }
10617
- let rootExited = child.exitCode !== null || child.signalCode !== null;
10618
- if (!rootExited) {
10619
- rootExited = await new Promise((resolveExit) => {
10620
- const onExit = () => {
10621
- clearTimeout(deadlineTimer);
10622
- resolveExit(true);
10623
- };
10624
- const deadlineTimer = setTimeout(
10625
- () => {
10626
- child.removeListener("exit", onExit);
10627
- resolveExit(false);
10628
- },
10629
- Math.max(0, gracefulDeadline - Date.now())
10630
- );
10631
- child.once("exit", onExit);
10632
- if (child.exitCode !== null || child.signalCode !== null) {
10633
- child.removeListener("exit", onExit);
10634
- onExit();
10635
- }
10636
- });
10637
- }
10638
- if (rootExited) {
10639
- signalProcessGroup(child, signal);
10640
- for (const pid of descendants) {
10641
- try {
10642
- process.kill(pid, signal);
10643
- } catch {
10644
- }
10645
- }
10646
- }
10647
- if (await waitForExit(pids, child.pid, Math.max(0, gracefulDeadline - Date.now()))) {
10648
- if (inspectionError) throw inspectionError;
10649
- return;
10650
- }
10651
- for (const pid of pids) {
10652
- try {
10653
- process.kill(pid, "SIGKILL");
10654
- } catch {
10655
- }
10656
- }
10657
- signalProcessGroup(child, "SIGKILL");
10658
- await waitForExit(pids, child.pid, FORCED_EXIT_TIMEOUT_MS);
10659
- if (inspectionError) throw inspectionError;
10660
- }
10661
-
10662
- // scripts/dev-server-scanner.ts
10663
10590
  init_backend_origin();
10664
10591
 
10665
10592
  // ../contrast-runtime-delivery/src/version.ts
@@ -10668,6 +10595,7 @@ function isValidRuntimeVersion(value) {
10668
10595
  }
10669
10596
 
10670
10597
  // src/config.ts
10598
+ init_bundleGlobalFooter();
10671
10599
  init_is_record();
10672
10600
  var PEACH_CONFIG_QUERY_PARAM = "peachConfig";
10673
10601
  function hasOwnKeys(value) {
@@ -11154,52 +11082,211 @@ function parseSwiftHostDiscovery(value) {
11154
11082
 
11155
11083
  // scripts/dev-server-scanner.ts
11156
11084
  init_optional_demo_registry();
11157
- function execGuarded(command, timeout, extra = {}) {
11158
- const maxBuffer = extra.maxBuffer ?? 1024 * 1024;
11159
- return new Promise((resolve5, reject) => {
11160
- const child = (0, import_child_process.spawn)("/bin/sh", ["-c", command], {
11161
- detached: true,
11162
- stdio: ["ignore", "pipe", "ignore"]
11163
- });
11164
- let stdout = "";
11165
- let settled = false;
11166
- let killing = false;
11167
- const settle = (err) => {
11168
- if (settled) return;
11169
- settled = true;
11170
- clearTimeout(deadline);
11171
- if (err) reject(err);
11172
- else resolve5({ stdout });
11173
- };
11174
- const killThenSettle = (err) => {
11175
- if (killing) return;
11176
- killing = true;
11177
- clearTimeout(deadline);
11178
- terminateProcessGroup(child, "SIGKILL", 0).finally(() => settle(err));
11179
- };
11180
- const deadline = setTimeout(() => {
11181
- killThenSettle(
11182
- Object.assign(new Error(`\`${command}\` did not exit within ${timeout}ms`), {
11183
- killed: true
11184
- })
11185
- );
11186
- }, timeout);
11187
- child.stdout.setEncoding("utf8");
11188
- child.stdout.on("data", (chunk) => {
11189
- stdout += chunk;
11190
- if (stdout.length > maxBuffer) {
11191
- killThenSettle(new Error(`\`${command}\` exceeded maxBuffer ${maxBuffer}`));
11192
- }
11193
- });
11194
- child.on("error", (err) => {
11195
- if (!killing) settle(err);
11196
- });
11197
- child.on("close", (code) => {
11198
- if (killing) return;
11199
- settle(code === 0 ? null : new Error(`\`${command}\` exited with ${code}`));
11200
- });
11085
+ var LISTENER_LOCK_PATH = (0, import_node_path3.join)((0, import_node_os.tmpdir)(), "peach-listener-scan.lock");
11086
+ var LISTENER_RESULT_PATH = (0, import_node_path3.join)((0, import_node_os.tmpdir)(), "peach-listener-scan.result");
11087
+ var LISTENER_LOCK_STALE_MS = 25e3;
11088
+ var LISTENER_LOCK_WAIT_MS = 8e3;
11089
+ function sleep(ms) {
11090
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
11091
+ }
11092
+ function pidIsAlive(pid) {
11093
+ if (!Number.isInteger(pid) || pid <= 0) return false;
11094
+ try {
11095
+ process.kill(pid, 0);
11096
+ return true;
11097
+ } catch (error) {
11098
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
11099
+ return code !== "ESRCH";
11100
+ }
11101
+ }
11102
+ function readLockOwner() {
11103
+ try {
11104
+ const raw2 = (0, import_node_fs2.readFileSync)(LISTENER_LOCK_PATH, "utf8");
11105
+ const mtimeMs = (0, import_node_fs2.statSync)(LISTENER_LOCK_PATH).mtimeMs;
11106
+ const pid = Number(raw2.split("-")[0]);
11107
+ return { raw: raw2, pid: Number.isInteger(pid) ? pid : -1, mtimeMs };
11108
+ } catch {
11109
+ return null;
11110
+ }
11111
+ }
11112
+ function lockIsAbandoned(owner) {
11113
+ if (owner.pid <= 0 || !pidIsAlive(owner.pid)) return true;
11114
+ return Date.now() - owner.mtimeMs > LISTENER_LOCK_STALE_MS;
11115
+ }
11116
+ function clearLock(raw2) {
11117
+ try {
11118
+ if ((0, import_node_fs2.readFileSync)(LISTENER_LOCK_PATH, "utf8") !== raw2) return;
11119
+ (0, import_node_fs2.unlinkSync)(LISTENER_LOCK_PATH);
11120
+ } catch {
11121
+ }
11122
+ }
11123
+ function readResult() {
11124
+ try {
11125
+ const parsed = JSON.parse(
11126
+ (0, import_node_fs2.readFileSync)(LISTENER_RESULT_PATH, "utf8")
11127
+ );
11128
+ if (!parsed || typeof parsed.token !== "string" || typeof parsed.key !== "string")
11129
+ return null;
11130
+ return parsed;
11131
+ } catch {
11132
+ return null;
11133
+ }
11134
+ }
11135
+ function publishResult(payload) {
11136
+ const tmp = `${LISTENER_RESULT_PATH}.${process.pid}.tmp`;
11137
+ (0, import_node_fs2.writeFileSync)(tmp, JSON.stringify(payload));
11138
+ (0, import_node_fs2.renameSync)(tmp, LISTENER_RESULT_PATH);
11139
+ }
11140
+ function throwPublished(payload) {
11141
+ throw Object.assign(new Error(payload.message || "listener scan failed"), {
11142
+ killed: payload.killed === true
11201
11143
  });
11202
11144
  }
11145
+ async function waitForSharedResult(owner, key2) {
11146
+ const cap = Date.now() + LISTING_TIMEOUT_MS;
11147
+ let current = owner;
11148
+ while (Date.now() < cap) {
11149
+ const published = readResult();
11150
+ if (published && published.token === current.raw) {
11151
+ if (published.key !== key2) return { kind: "retry" };
11152
+ if (!published.ok) throwPublished(published);
11153
+ return { kind: "value", value: published.value };
11154
+ }
11155
+ const latest = readLockOwner();
11156
+ if (!latest) {
11157
+ const again = readResult();
11158
+ if (again && again.token === current.raw && again.key === key2) {
11159
+ if (!again.ok) throwPublished(again);
11160
+ return { kind: "value", value: again.value };
11161
+ }
11162
+ return { kind: "retry" };
11163
+ }
11164
+ if (latest.raw !== current.raw) current = latest;
11165
+ if (lockIsAbandoned(latest)) {
11166
+ clearLock(latest.raw);
11167
+ return { kind: "retry" };
11168
+ }
11169
+ await sleep(25);
11170
+ }
11171
+ throw Object.assign(new Error("listener scan lock was held past the wait"), {
11172
+ killed: true
11173
+ });
11174
+ }
11175
+ async function withListenerLock(key2, body) {
11176
+ const token = `${process.pid}-${Date.now()}-${Math.random()}`;
11177
+ const deadline = Date.now() + LISTENER_LOCK_WAIT_MS;
11178
+ for (; ; ) {
11179
+ let fd = null;
11180
+ try {
11181
+ fd = (0, import_node_fs2.openSync)(LISTENER_LOCK_PATH, "wx");
11182
+ } catch (error) {
11183
+ const code = error instanceof Error && "code" in error ? error.code : "";
11184
+ if (code !== "EEXIST") throw error;
11185
+ const owner = readLockOwner();
11186
+ if (!owner || lockIsAbandoned(owner)) {
11187
+ if (owner) clearLock(owner.raw);
11188
+ else {
11189
+ try {
11190
+ (0, import_node_fs2.unlinkSync)(LISTENER_LOCK_PATH);
11191
+ } catch {
11192
+ }
11193
+ }
11194
+ continue;
11195
+ }
11196
+ if (Date.now() >= deadline) {
11197
+ const shared = await waitForSharedResult(owner, key2);
11198
+ if (shared.kind === "value") return shared.value;
11199
+ continue;
11200
+ }
11201
+ await sleep(25);
11202
+ continue;
11203
+ }
11204
+ if (fd === null) continue;
11205
+ try {
11206
+ (0, import_node_fs2.writeSync)(fd, token);
11207
+ try {
11208
+ const value = await body();
11209
+ publishResult({ token, key: key2, ok: true, value });
11210
+ return value;
11211
+ } catch (error) {
11212
+ publishResult({
11213
+ token,
11214
+ key: key2,
11215
+ ok: false,
11216
+ message: error instanceof Error ? error.message : String(error),
11217
+ killed: !!(error && typeof error === "object" && error.killed)
11218
+ });
11219
+ throw error;
11220
+ }
11221
+ } finally {
11222
+ try {
11223
+ (0, import_node_fs2.closeSync)(fd);
11224
+ } catch {
11225
+ }
11226
+ clearLock(token);
11227
+ }
11228
+ }
11229
+ }
11230
+ function spawnReaped(file, args, timeoutMs, maxBuffer = 1024 * 1024) {
11231
+ return withListenerLock(
11232
+ `${file}\0${args.join("\0")}`,
11233
+ () => new Promise((resolvePromise, reject) => {
11234
+ const child = (0, import_child_process.spawn)(file, args, {
11235
+ stdio: ["ignore", "pipe", "pipe"]
11236
+ });
11237
+ let stdout = "";
11238
+ let settled = false;
11239
+ let timedOut = false;
11240
+ let overflow = false;
11241
+ let spawnError = null;
11242
+ const timeoutError = () => Object.assign(new Error(`\`${file}\` did not exit within ${timeoutMs}ms`), {
11243
+ killed: true
11244
+ });
11245
+ const finish = (err, code) => {
11246
+ if (settled) return;
11247
+ settled = true;
11248
+ clearTimeout(deadline);
11249
+ clearTimeout(backup);
11250
+ if (err) reject(err);
11251
+ else resolvePromise({ stdout, code });
11252
+ };
11253
+ const killChild = () => {
11254
+ if (child.exitCode !== null || child.signalCode !== null) return;
11255
+ try {
11256
+ child.kill("SIGKILL");
11257
+ } catch {
11258
+ }
11259
+ };
11260
+ let backup;
11261
+ const deadline = setTimeout(() => {
11262
+ timedOut = true;
11263
+ killChild();
11264
+ backup = setTimeout(() => finish(timeoutError(), null), 1e3);
11265
+ }, timeoutMs);
11266
+ child.stdout?.setEncoding("utf8");
11267
+ child.stderr?.on("data", () => {
11268
+ });
11269
+ child.stdout?.on("data", (chunk) => {
11270
+ stdout += chunk;
11271
+ if (stdout.length > maxBuffer) {
11272
+ overflow = true;
11273
+ killChild();
11274
+ }
11275
+ });
11276
+ child.on("error", (err) => {
11277
+ spawnError = err;
11278
+ killChild();
11279
+ });
11280
+ child.on("close", (code) => {
11281
+ if (timedOut) finish(timeoutError(), code);
11282
+ else if (overflow)
11283
+ finish(new Error(`\`${file}\` exceeded maxBuffer ${maxBuffer}`), code);
11284
+ else if (spawnError && !stdout) finish(spawnError, code);
11285
+ else finish(null, code);
11286
+ });
11287
+ })
11288
+ );
11289
+ }
11203
11290
  var TIMEOUT_MS = 250;
11204
11291
  var MANIFEST_TIMEOUT_MS = 1500;
11205
11292
  var TCP_GATE_MS = 120;
@@ -11315,118 +11402,221 @@ async function scanListeningProcesses(excludePorts = []) {
11315
11402
  processes: listing.processes.filter((p) => acceptPort(p.port, excluded))
11316
11403
  };
11317
11404
  }
11405
+ var LISTENER_CACHE_MS = 2e3;
11406
+ var listenerCache = null;
11318
11407
  var inflightListing = null;
11408
+ var listenerHolds = 0;
11409
+ function cachedPidsAlive(scan) {
11410
+ if (scan.state !== "looked") return true;
11411
+ return scan.processes.every((entry) => entry.pid <= 0 || pidIsAlive(entry.pid));
11412
+ }
11413
+ async function cachedPortsStillHeld(scan) {
11414
+ if (scan.state !== "looked") return true;
11415
+ const owned = scan.processes.filter((entry) => entry.pid > 0);
11416
+ if (owned.length === 0) return true;
11417
+ const pids = [...new Set(owned.map((entry) => entry.pid))];
11418
+ try {
11419
+ const { stdout, code } = await spawnReaped(
11420
+ "lsof",
11421
+ ["-nP", "-b", "-w", "-a", "-p", pids.join(","), "-iTCP", "-sTCP:LISTEN", "-Fpcn"],
11422
+ 8e3,
11423
+ 16 * 1024 * 1024
11424
+ );
11425
+ if (code !== 0 && code !== 1) return false;
11426
+ const live = new Set(
11427
+ parseLsofListeners(stdout).map((entry) => `${entry.port}:${entry.pid}`)
11428
+ );
11429
+ return owned.every((entry) => live.has(`${entry.port}:${entry.pid}`));
11430
+ } catch {
11431
+ return false;
11432
+ }
11433
+ }
11319
11434
  function listListenersShared() {
11320
- inflightListing ??= listListeners().finally(() => {
11435
+ inflightListing ??= loadListeners().finally(() => {
11321
11436
  inflightListing = null;
11322
11437
  });
11323
11438
  return inflightListing;
11324
11439
  }
11440
+ async function loadListeners() {
11441
+ const cached3 = listenerCache;
11442
+ if (cached3 && (listenerHolds > 0 || Date.now() - cached3.at < LISTENER_CACHE_MS) && cachedPidsAlive(cached3.scan) && await cachedPortsStillHeld(cached3.scan)) {
11443
+ return cached3.scan;
11444
+ }
11445
+ listenerCache = null;
11446
+ const scan = await listListeners();
11447
+ listenerCache = { at: Date.now(), scan };
11448
+ return scan;
11449
+ }
11450
+ function isSpawnMissing(err) {
11451
+ return !!(err && typeof err === "object" && err.code === "ENOENT");
11452
+ }
11453
+ function parseLsofListeners(stdout) {
11454
+ const seen = /* @__PURE__ */ new Map();
11455
+ let pid = 0;
11456
+ let command = "";
11457
+ for (const line of stdout.split("\n")) {
11458
+ if (line.startsWith("p")) {
11459
+ pid = Number(line.slice(1));
11460
+ command = "";
11461
+ continue;
11462
+ }
11463
+ if (line.startsWith("c")) {
11464
+ command = line.slice(1);
11465
+ continue;
11466
+ }
11467
+ if (!line.startsWith("n") || pid <= 0) continue;
11468
+ if (!/^(node|bun|peach|vite)/.test(command)) continue;
11469
+ const match = line.match(/:(\d+)$/);
11470
+ if (!match) continue;
11471
+ const port = Number(match[1]);
11472
+ if (!seen.has(port)) seen.set(port, pid);
11473
+ }
11474
+ return [...seen.entries()].map(([port, owner]) => ({ port, pid: owner }));
11475
+ }
11476
+ function parseSsListeners(stdout) {
11477
+ const seen = /* @__PURE__ */ new Map();
11478
+ for (const line of stdout.split("\n")) {
11479
+ if (!/"(node|bun|peach|vite)/.test(line)) continue;
11480
+ const portMatch = line.match(/:(\d+)\s/);
11481
+ const pidMatch = line.match(/pid=(\d+)/);
11482
+ if (!portMatch) continue;
11483
+ const port = Number(portMatch[1]);
11484
+ const pid = pidMatch ? Number(pidMatch[1]) : 0;
11485
+ if (!seen.has(port)) seen.set(port, pid);
11486
+ }
11487
+ return [...seen.entries()].map(([port, pid]) => ({ port, pid }));
11488
+ }
11325
11489
  async function listListeners() {
11326
11490
  let timedOut = false;
11327
11491
  try {
11328
- const { stdout } = await execGuarded(
11329
- `lsof -a -c node -c bun -c peach -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep -E '^(node|bun|peach)'`,
11330
- LISTING_TIMEOUT_MS
11492
+ const { stdout, code } = await spawnReaped(
11493
+ "lsof",
11494
+ [
11495
+ "-nP",
11496
+ "-a",
11497
+ "-c",
11498
+ "node",
11499
+ "-c",
11500
+ "bun",
11501
+ "-c",
11502
+ "peach",
11503
+ "-c",
11504
+ "vite",
11505
+ "-iTCP",
11506
+ "-sTCP:LISTEN",
11507
+ "-Fpcn"
11508
+ ],
11509
+ LISTING_TIMEOUT_MS,
11510
+ 16 * 1024 * 1024
11331
11511
  );
11332
- const seen = /* @__PURE__ */ new Map();
11333
- for (const line of stdout.trim() ? stdout.trim().split("\n") : []) {
11334
- const parts = line.trim().split(/\s+/);
11335
- if (parts.length < 9) continue;
11336
- const pid = Number(parts[1]);
11337
- const m = parts[8].match(/:(\d+)$/);
11338
- if (!m) continue;
11339
- const port = Number(m[1]);
11340
- if (!seen.has(port)) seen.set(port, pid);
11512
+ if (code === 0 || code === 1) {
11513
+ return { state: "looked", processes: parseLsofListeners(stdout) };
11341
11514
  }
11342
- return {
11343
- state: "looked",
11344
- processes: [...seen.entries()].map(([port, pid]) => ({ port, pid }))
11345
- };
11346
11515
  } catch (err) {
11347
11516
  if (wasKilledByTimeout(err)) timedOut = true;
11517
+ else if (!isSpawnMissing(err)) return { state: "could-not-look" };
11348
11518
  }
11349
- try {
11350
- const { stdout } = await execGuarded(
11351
- `ss -tlnp 2>/dev/null | grep -E '"(node|bun|peach)"'`,
11352
- LISTING_TIMEOUT_MS
11353
- );
11354
- const seen = /* @__PURE__ */ new Map();
11355
- for (const line of stdout.trim() ? stdout.trim().split("\n") : []) {
11356
- const portMatch = line.match(/:(\d+)\s/);
11357
- const pidMatch = line.match(/pid=(\d+)/);
11358
- if (!portMatch) continue;
11359
- const port = Number(portMatch[1]);
11360
- const pid = pidMatch ? Number(pidMatch[1]) : 0;
11361
- if (!seen.has(port)) seen.set(port, pid);
11519
+ if (!timedOut) {
11520
+ try {
11521
+ const { stdout, code } = await spawnReaped(
11522
+ "ss",
11523
+ ["-H", "-ltnp"],
11524
+ LISTING_TIMEOUT_MS,
11525
+ 16 * 1024 * 1024
11526
+ );
11527
+ if (code === 0 || code === 1) {
11528
+ return { state: "looked", processes: parseSsListeners(stdout) };
11529
+ }
11530
+ } catch (err) {
11531
+ if (wasKilledByTimeout(err)) timedOut = true;
11532
+ else if (!isSpawnMissing(err)) return { state: "could-not-look" };
11362
11533
  }
11363
- return {
11364
- state: "looked",
11365
- processes: [...seen.entries()].map(([port, pid]) => ({ port, pid }))
11366
- };
11367
- } catch (err) {
11368
- if (wasKilledByTimeout(err)) timedOut = true;
11369
11534
  }
11370
11535
  if (timedOut) return { state: "could-not-look" };
11371
11536
  return { state: "looked", processes: FALLBACK_PORTS };
11372
11537
  }
11373
11538
  async function resolveListeningPid(port) {
11374
11539
  if (!Number.isInteger(port) || port <= 0) return null;
11375
- if (process.platform === "darwin") {
11376
- try {
11377
- const { stdout } = await execGuarded(
11378
- `lsof -nP -a -iTCP:${port} -sTCP:LISTEN -t 2>/dev/null`,
11379
- 8e3
11380
- );
11381
- const pids = [...new Set(stdout.trim().split(/\s+/).map(Number))];
11382
- return pids.length === 1 && Number.isInteger(pids[0]) && pids[0] > 0 ? pids[0] : null;
11383
- } catch {
11384
- return null;
11385
- }
11386
- }
11387
- try {
11388
- const { stdout } = await execGuarded(`ss -tlnp 2>/dev/null`, 8e3, {
11389
- maxBuffer: 16 * 1024 * 1024
11390
- });
11391
- for (const line of stdout.split("\n")) {
11392
- if (!new RegExp(`:${port}\\s`).test(line)) continue;
11393
- const pid = Number(line.match(/pid=(\d+)/)?.[1]);
11394
- if (pid > 0) return pid;
11395
- }
11396
- } catch {
11397
- }
11398
- return null;
11540
+ const scan = await listListenersShared();
11541
+ if (scan.state !== "looked") return null;
11542
+ const pids = [
11543
+ ...new Set(
11544
+ scan.processes.filter((entry) => entry.port === port && entry.pid > 0).map((entry) => entry.pid)
11545
+ )
11546
+ ];
11547
+ return pids.length === 1 && pids[0] !== void 0 ? pids[0] : null;
11399
11548
  }
11400
11549
  var cwdByPid = /* @__PURE__ */ new Map();
11401
- async function resolveProcessCwd(pid) {
11402
- if (pid <= 0) return null;
11403
- const cached3 = cwdByPid.get(pid);
11404
- if (cached3) return cached3;
11405
- try {
11406
- const cwd = await (0, import_promises2.readlink)(`/proc/${pid}/cwd`);
11407
- if (cwd) {
11408
- cwdByPid.set(pid, cwd);
11409
- return cwd;
11410
- }
11411
- } catch {
11412
- }
11413
- try {
11414
- const { stdout } = await execGuarded(
11415
- `lsof -b -w -p ${pid} -a -d cwd -Fn 2>/dev/null`,
11416
- 8e3
11550
+ var cwdQueue = [];
11551
+ var cwdFlushing = false;
11552
+ function kickCwdFlush() {
11553
+ if (cwdFlushing || cwdQueue.length === 0) return;
11554
+ cwdFlushing = true;
11555
+ void flushCwdQueue().finally(() => {
11556
+ cwdFlushing = false;
11557
+ kickCwdFlush();
11558
+ });
11559
+ }
11560
+ async function flushCwdQueue() {
11561
+ await Promise.resolve();
11562
+ while (cwdQueue.length > 0) {
11563
+ const batch = cwdQueue.splice(0, cwdQueue.length);
11564
+ const pending = [...new Set(batch.map((waiter) => waiter.pid))].filter(
11565
+ (pid) => !cwdByPid.has(pid)
11417
11566
  );
11418
- for (const line of stdout.split("\n")) {
11419
- if (line.startsWith("n") && line.length > 1) {
11420
- const cwd = line.slice(1).trim();
11567
+ const needLsof = [];
11568
+ for (const pid of pending) {
11569
+ try {
11570
+ const cwd = await (0, import_promises2.readlink)(`/proc/${pid}/cwd`);
11421
11571
  if (cwd) {
11422
11572
  cwdByPid.set(pid, cwd);
11423
- return cwd;
11573
+ continue;
11424
11574
  }
11575
+ } catch {
11425
11576
  }
11577
+ needLsof.push(pid);
11426
11578
  }
11427
- } catch {
11579
+ if (needLsof.length > 0) {
11580
+ let looked = false;
11581
+ try {
11582
+ const { stdout, code } = await spawnReaped(
11583
+ "lsof",
11584
+ ["-b", "-w", "-nP", "-a", "-d", "cwd", "-p", needLsof.join(","), "-Fn"],
11585
+ 8e3,
11586
+ 4 * 1024 * 1024
11587
+ );
11588
+ if (code === 0 || code === 1) {
11589
+ looked = true;
11590
+ let current = 0;
11591
+ for (const line of stdout.split("\n")) {
11592
+ if (line.startsWith("p")) {
11593
+ current = Number(line.slice(1));
11594
+ continue;
11595
+ }
11596
+ if (!line.startsWith("n") || line.length <= 1 || !needLsof.includes(current))
11597
+ continue;
11598
+ const cwd = line.slice(1).trim();
11599
+ if (cwd) cwdByPid.set(current, cwd);
11600
+ }
11601
+ }
11602
+ } catch {
11603
+ }
11604
+ if (looked) {
11605
+ for (const pid of needLsof) {
11606
+ if (!cwdByPid.has(pid)) cwdByPid.set(pid, null);
11607
+ }
11608
+ }
11609
+ }
11610
+ for (const waiter of batch) waiter.resolve(cwdByPid.get(waiter.pid) ?? null);
11428
11611
  }
11429
- return null;
11612
+ }
11613
+ function resolveProcessCwd(pid) {
11614
+ if (pid <= 0) return Promise.resolve(null);
11615
+ if (cwdByPid.has(pid)) return Promise.resolve(cwdByPid.get(pid) ?? null);
11616
+ return new Promise((resolveCwd) => {
11617
+ cwdQueue.push({ pid, resolve: resolveCwd });
11618
+ kickCwdFlush();
11619
+ });
11430
11620
  }
11431
11621
  function makeResult(hostname, port, framework, owner) {
11432
11622
  return {
@@ -11841,6 +12031,7 @@ async function scanDevServers(opts = {}) {
11841
12031
  const scan = await scanListeningProcesses(opts.excludePorts);
11842
12032
  if (scan.state === "could-not-look") throw new DevServerScanUnavailableError();
11843
12033
  const processes = scan.processes;
12034
+ await Promise.all(processes.map((entry) => resolveProcessCwd(entry.pid)));
11844
12035
  const currentPorts = new Set(processes.map((p) => p.port));
11845
12036
  for (const p of [...portCache.keys()]) {
11846
12037
  if (!currentPorts.has(p)) portCache.delete(p);
@@ -11975,15 +12166,15 @@ function getCliVersion() {
11975
12166
  }
11976
12167
 
11977
12168
  // src/desktop-host-delivery.ts
11978
- var import_node_child_process3 = require("node:child_process");
12169
+ var import_node_child_process2 = require("node:child_process");
11979
12170
  var import_node_fs8 = __toESM(require("node:fs"), 1);
11980
12171
  var import_node_path8 = __toESM(require("node:path"), 1);
11981
12172
 
11982
12173
  // ../contrast-runtime-delivery/src/index.ts
11983
- var import_node_child_process2 = require("node:child_process");
12174
+ var import_node_child_process = require("node:child_process");
11984
12175
  var import_node_crypto2 = __toESM(require("node:crypto"), 1);
11985
12176
  var import_node_fs7 = __toESM(require("node:fs"), 1);
11986
- var import_node_os2 = __toESM(require("node:os"), 1);
12177
+ var import_node_os3 = __toESM(require("node:os"), 1);
11987
12178
  var import_node_path7 = __toESM(require("node:path"), 1);
11988
12179
  var import_node_stream = require("node:stream");
11989
12180
  var import_promises3 = require("node:stream/promises");
@@ -12326,7 +12517,7 @@ function createRuntimeDelivery(product) {
12326
12517
  }
12327
12518
  async function installVerifiedTarball(tarball) {
12328
12519
  const { url, digest, destDir, installedMarker, label } = tarball;
12329
- const downloadDir = import_node_fs7.default.mkdtempSync(import_node_path7.default.join(import_node_os2.default.tmpdir(), "runtime-delivery-download-"));
12520
+ const downloadDir = import_node_fs7.default.mkdtempSync(import_node_path7.default.join(import_node_os3.default.tmpdir(), "runtime-delivery-download-"));
12330
12521
  const archivePath = import_node_path7.default.join(downloadDir, "archive");
12331
12522
  import_node_fs7.default.mkdirSync(import_node_path7.default.dirname(destDir), { recursive: true });
12332
12523
  const tmpDir = import_node_fs7.default.mkdtempSync(
@@ -12414,7 +12605,7 @@ function extractTarball(tarPath, destDir, stripComponents) {
12414
12605
  }
12415
12606
  function runExtractor(command, args) {
12416
12607
  return new Promise((resolve5, reject) => {
12417
- const child = (0, import_node_child_process2.spawn)(command, args, {
12608
+ const child = (0, import_node_child_process.spawn)(command, args, {
12418
12609
  stdio: ["ignore", "inherit", "inherit"]
12419
12610
  });
12420
12611
  child.on("error", reject);
@@ -12438,7 +12629,7 @@ function desktopHostExecutable() {
12438
12629
  var MAC_HOST_APP = "/Applications/Peach.app";
12439
12630
  var HOST_BUNDLE_ID = "dev.contrast.peach-desktop";
12440
12631
  function bundleValue(app, key2) {
12441
- const read = (0, import_node_child_process3.spawnSync)(
12632
+ const read = (0, import_node_child_process2.spawnSync)(
12442
12633
  "plutil",
12443
12634
  ["-extract", key2, "raw", "-o", "-", import_node_path8.default.join(app, "Contents/Info.plist")],
12444
12635
  { encoding: "utf8" }
@@ -12464,24 +12655,29 @@ function activeDesktopHostApp() {
12464
12655
  }
12465
12656
 
12466
12657
  // src/expo-swift-host.ts
12467
- var import_node_child_process10 = require("node:child_process");
12658
+ var import_node_child_process9 = require("node:child_process");
12468
12659
  var import_node_crypto9 = require("node:crypto");
12469
12660
  var import_node_fs21 = __toESM(require("node:fs"), 1);
12470
12661
  var import_node_module = require("node:module");
12471
- var import_node_os9 = __toESM(require("node:os"), 1);
12662
+ var import_node_os10 = __toESM(require("node:os"), 1);
12472
12663
  var import_node_path22 = __toESM(require("node:path"), 1);
12473
12664
  var import_node_util3 = require("node:util");
12474
12665
  init_internal_child();
12475
12666
  init_backend_origin();
12476
12667
 
12477
12668
  // src/swift-compile.ts
12478
- var import_node_child_process5 = require("node:child_process");
12669
+ var import_node_child_process4 = require("node:child_process");
12479
12670
  var import_node_crypto4 = require("node:crypto");
12480
12671
  var import_node_fs10 = require("node:fs");
12481
- var import_node_os3 = __toESM(require("node:os"), 1);
12672
+ var import_node_os4 = __toESM(require("node:os"), 1);
12482
12673
  var import_node_path10 = __toESM(require("node:path"), 1);
12483
12674
  var import_node_util2 = require("node:util");
12484
12675
 
12676
+ // src/admitted-mac-build.ts
12677
+ function admittedMacBuilderSlot(env = process.env) {
12678
+ return env.CONTRAST_REMOTE_BUILD === "mac" && env.REMOTE_MAC_SLOT_HELD === "1" && env.CONTRAST_HEAVY_ADMITTED === "1";
12679
+ }
12680
+
12485
12681
  // src/swift-distribution-contract.ts
12486
12682
  init_is_record();
12487
12683
  var SWIFT_DISTRIBUTION_MANIFEST = "distribution.json";
@@ -12549,13 +12745,13 @@ function swiftDistributionKey(id, host2) {
12549
12745
  }
12550
12746
 
12551
12747
  // src/swift-icu.ts
12552
- var import_node_child_process4 = require("node:child_process");
12748
+ var import_node_child_process3 = require("node:child_process");
12553
12749
  var import_node_crypto3 = require("node:crypto");
12554
12750
  var import_node_fs9 = require("node:fs");
12555
12751
  var import_node_path9 = __toESM(require("node:path"), 1);
12556
12752
  var import_node_util = require("node:util");
12557
12753
  var import_node_zlib = require("node:zlib");
12558
- var run = (0, import_node_util.promisify)(import_node_child_process4.execFile);
12754
+ var run = (0, import_node_util.promisify)(import_node_child_process3.execFile);
12559
12755
  var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
12560
12756
  var ARCHIVE = "wasi/lib_FoundationICU.a";
12561
12757
  var MEMBER = "icu_packaged_data.cpp.obj";
@@ -12897,9 +13093,9 @@ function isSwiftMetalLibrarySources(value) {
12897
13093
  }
12898
13094
 
12899
13095
  // src/swift-compile.ts
12900
- var run2 = (0, import_node_util2.promisify)(import_node_child_process5.execFile);
13096
+ var run2 = (0, import_node_util2.promisify)(import_node_child_process4.execFile);
12901
13097
  var WASM_TRIPLE = "wasm32-unknown-wasip1";
12902
- var cores = import_node_os3.default.availableParallelism();
13098
+ var cores = import_node_os4.default.availableParallelism();
12903
13099
  var BUILD_ENV = {
12904
13100
  ...process.env,
12905
13101
  BINARYEN_CORES: String(Math.min(4, cores))
@@ -13160,7 +13356,7 @@ function swiftSdkPaths(moduleRoot, toolchainBin) {
13160
13356
  const key2 = `${toolchainBin}\0${sdk}`;
13161
13357
  const cached3 = sdkPaths.get(key2);
13162
13358
  if (cached3) return cached3;
13163
- const configuration = (0, import_node_child_process5.execFileSync)(
13359
+ const configuration = (0, import_node_child_process4.execFileSync)(
13164
13360
  import_node_path10.default.join(toolchainBin, "swift"),
13165
13361
  ["sdk", "configure", "--show-configuration", sdk, "wasm32-unknown-wasip1"],
13166
13362
  { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
@@ -14787,7 +14983,7 @@ function compileSwiftProjectUnit(input, options) {
14787
14983
  };
14788
14984
  const hash = swiftArtifactHash(input, options.release, moduleRoot);
14789
14985
  return serialize(root, async () => {
14790
- if (process.platform === "darwin" && process.env.TM_SESSION && !process.env.CONTRAST_REMOTE_BUILD && process.env.CI !== "true" && moduleRoot === import_node_path10.default.resolve(__sootsim_import_meta_dirname, "../../sootsim-swift") && !swiftDistributionAt(moduleRoot)) {
14986
+ if (process.platform === "darwin" && process.env.TM_SESSION && !admittedMacBuilderSlot() && process.env.CI !== "true" && moduleRoot === import_node_path10.default.resolve(__sootsim_import_meta_dirname, "../../sootsim-swift") && !swiftDistributionAt(moduleRoot)) {
14791
14987
  const requestRoot = (0, import_node_fs10.mkdtempSync)(import_node_path10.default.join(root, ".builder-request-"));
14792
14988
  const output = import_node_path10.default.join(requestRoot, "output");
14793
14989
  const request = import_node_path10.default.join(requestRoot, "request.json");
@@ -15049,16 +15245,16 @@ var swift_distribution_lock_default = {
15049
15245
  };
15050
15246
 
15051
15247
  // src/swift-toolchain.ts
15052
- var import_node_child_process6 = require("node:child_process");
15248
+ var import_node_child_process5 = require("node:child_process");
15053
15249
  var import_node_fs11 = __toESM(require("node:fs"), 1);
15054
- var import_node_os4 = __toESM(require("node:os"), 1);
15250
+ var import_node_os5 = __toESM(require("node:os"), 1);
15055
15251
  var import_node_path11 = __toESM(require("node:path"), 1);
15056
15252
  function swiftCompilerRelease(release) {
15057
15253
  return release.replace(/^swift-(\d+\.\d+)\.0-RELEASE$/, "swift-$1-RELEASE");
15058
15254
  }
15059
15255
  function swiftToolchainBin(release) {
15060
15256
  if (process.platform === "darwin") {
15061
- const dirs = [import_node_os4.default.homedir(), "/"].map(
15257
+ const dirs = [import_node_os5.default.homedir(), "/"].map(
15062
15258
  (base) => import_node_path11.default.join(base, `Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`)
15063
15259
  );
15064
15260
  return dirs.find((dir) => import_node_fs11.default.existsSync(import_node_path11.default.join(dir, "swift"))) ?? dirs[0];
@@ -15076,7 +15272,7 @@ function swiftToolchain(release, sdk) {
15076
15272
  if (cached3) return cached3;
15077
15273
  const bin = swiftToolchainBin(release);
15078
15274
  const swift = import_node_path11.default.join(bin, "swift");
15079
- const version = import_node_fs11.default.existsSync(swift) ? (0, import_node_child_process6.execFileSync)(swift, ["--version"], {
15275
+ const version = import_node_fs11.default.existsSync(swift) ? (0, import_node_child_process5.execFileSync)(swift, ["--version"], {
15080
15276
  encoding: "utf8",
15081
15277
  stdio: ["ignore", "pipe", "pipe"]
15082
15278
  }) : "";
@@ -15087,7 +15283,7 @@ function swiftToolchain(release, sdk) {
15087
15283
  ${swiftInstallSteps(release, sdk)}`
15088
15284
  );
15089
15285
  }
15090
- const sdks = (0, import_node_child_process6.execFileSync)(swift, ["sdk", "list"], {
15286
+ const sdks = (0, import_node_child_process5.execFileSync)(swift, ["sdk", "list"], {
15091
15287
  encoding: "utf8",
15092
15288
  stdio: ["ignore", "pipe", "pipe"]
15093
15289
  });
@@ -15195,7 +15391,7 @@ function swiftModuleToolchain(root) {
15195
15391
  // src/swift-host.ts
15196
15392
  var import_node_crypto8 = require("node:crypto");
15197
15393
  var import_node_fs20 = __toESM(require("node:fs"), 1);
15198
- var import_node_os8 = __toESM(require("node:os"), 1);
15394
+ var import_node_os9 = __toESM(require("node:os"), 1);
15199
15395
  var import_node_path21 = __toESM(require("node:path"), 1);
15200
15396
 
15201
15397
  // ../sootsim-swift/src/bundleAssets.ts
@@ -15798,9 +15994,9 @@ var ios_sdk_frameworks_default = {
15798
15994
  // src/swift-binary-modules.ts
15799
15995
  var import_node_crypto5 = require("node:crypto");
15800
15996
  var import_node_fs14 = __toESM(require("node:fs"), 1);
15801
- var import_node_os5 = __toESM(require("node:os"), 1);
15997
+ var import_node_os6 = __toESM(require("node:os"), 1);
15802
15998
  var import_node_path14 = __toESM(require("node:path"), 1);
15803
- var cacheDir2 = import_node_path14.default.join(import_node_os5.default.tmpdir(), "peach-swift-binary-modules");
15999
+ var cacheDir2 = import_node_path14.default.join(import_node_os6.default.tmpdir(), "peach-swift-binary-modules");
15804
16000
  function frameworkModules(paths) {
15805
16001
  const modules = /* @__PURE__ */ new Set();
15806
16002
  for (const file of paths) {
@@ -15878,10 +16074,10 @@ async function swiftBinaryModules(binary2) {
15878
16074
  }
15879
16075
 
15880
16076
  // src/swift-package-manifest.ts
15881
- var import_node_child_process7 = require("node:child_process");
16077
+ var import_node_child_process6 = require("node:child_process");
15882
16078
  var import_node_crypto6 = require("node:crypto");
15883
16079
  var import_node_fs15 = __toESM(require("node:fs"), 1);
15884
- var import_node_os6 = __toESM(require("node:os"), 1);
16080
+ var import_node_os7 = __toESM(require("node:os"), 1);
15885
16081
  var import_node_path15 = __toESM(require("node:path"), 1);
15886
16082
  var TARGET_TYPES = [
15887
16083
  "regular",
@@ -15899,7 +16095,7 @@ var string = (value) => typeof value === "string" ? value : void 0;
15899
16095
  function swiftCommand() {
15900
16096
  return process.platform === "darwin" ? { file: "xcrun", args: ["swift"] } : { file: import_node_path15.default.join(swiftToolchainBin(swift_distribution_lock_default.release), "swift"), args: [] };
15901
16097
  }
15902
- var cacheDir3 = import_node_path15.default.join(import_node_os6.default.tmpdir(), "peach-swift-manifests");
16098
+ var cacheDir3 = import_node_path15.default.join(import_node_os7.default.tmpdir(), "peach-swift-manifests");
15903
16099
  var evaluated = /* @__PURE__ */ new Map();
15904
16100
  function dump(dir) {
15905
16101
  const manifests = import_node_fs15.default.readdirSync(dir).filter((name2) => /^Package(@swift-[\d.]+)?\.swift$/.test(name2)).sort();
@@ -15912,7 +16108,7 @@ function dump(dir) {
15912
16108
  return { key: key2, raw: record(JSON.parse(import_node_fs15.default.readFileSync(cached3, "utf8"))) };
15913
16109
  let output;
15914
16110
  try {
15915
- output = (0, import_node_child_process7.execFileSync)(
16111
+ output = (0, import_node_child_process6.execFileSync)(
15916
16112
  command.file,
15917
16113
  [
15918
16114
  ...command.args,
@@ -16102,7 +16298,7 @@ function swiftTargetFiles(manifest, target) {
16102
16298
  }
16103
16299
 
16104
16300
  // src/swift-packages.ts
16105
- var import_node_child_process8 = require("node:child_process");
16301
+ var import_node_child_process7 = require("node:child_process");
16106
16302
  var import_node_fs16 = __toESM(require("node:fs"), 1);
16107
16303
  var import_node_path16 = __toESM(require("node:path"), 1);
16108
16304
  var REMOTE_CHECKOUTS = import_node_path16.default.join(".build", "peach", "checkouts");
@@ -16129,7 +16325,7 @@ function checkout(checkouts, identity, pin) {
16129
16325
  const dir = import_node_path16.default.join(checkouts, identity);
16130
16326
  const key2 = `${dir}\0${pin.revision}`;
16131
16327
  if (verified2.has(key2)) return dir;
16132
- const git = (...args) => (0, import_node_child_process8.execFileSync)("git", ["-C", dir, ...args], {
16328
+ const git = (...args) => (0, import_node_child_process7.execFileSync)("git", ["-C", dir, ...args], {
16133
16329
  encoding: "utf8",
16134
16330
  stdio: ["ignore", "pipe", "pipe"]
16135
16331
  }).trim();
@@ -16368,10 +16564,10 @@ function readPackageFile(root, file, maxBytes) {
16368
16564
  }
16369
16565
 
16370
16566
  // src/swift-standins.ts
16371
- var import_node_child_process9 = require("node:child_process");
16567
+ var import_node_child_process8 = require("node:child_process");
16372
16568
  var import_node_crypto7 = require("node:crypto");
16373
16569
  var import_node_fs18 = __toESM(require("node:fs"), 1);
16374
- var import_node_os7 = __toESM(require("node:os"), 1);
16570
+ var import_node_os8 = __toESM(require("node:os"), 1);
16375
16571
  var import_node_path18 = __toESM(require("node:path"), 1);
16376
16572
 
16377
16573
  // src/swift-standin-emit.ts
@@ -17088,9 +17284,9 @@ function stripDefaults(decl) {
17088
17284
 
17089
17285
  // src/swift-standins.ts
17090
17286
  var TRIPLE = "wasm32-unknown-wasip1";
17091
- var cacheDir4 = import_node_path18.default.join(import_node_os7.default.tmpdir(), "peach-swift-standins");
17287
+ var cacheDir4 = import_node_path18.default.join(import_node_os8.default.tmpdir(), "peach-swift-standins");
17092
17288
  function exec(file, args, cwd) {
17093
- return (0, import_node_child_process9.execFileSync)(file, args, {
17289
+ return (0, import_node_child_process8.execFileSync)(file, args, {
17094
17290
  cwd,
17095
17291
  encoding: "utf8",
17096
17292
  maxBuffer: 256 * 1024 * 1024,
@@ -17350,7 +17546,7 @@ function swiftStandin(surface, binary2, toolchain, work) {
17350
17546
  plain
17351
17547
  });
17352
17548
  import_node_fs18.default.writeFileSync(file, source);
17353
- const check = (0, import_node_child_process9.spawnSync)(
17549
+ const check = (0, import_node_child_process8.spawnSync)(
17354
17550
  import_node_path18.default.join(toolchain.toolchainBin, "swiftc"),
17355
17551
  [
17356
17552
  "-typecheck",
@@ -17679,7 +17875,7 @@ function standinLibrary(binary2, searchRoot) {
17679
17875
  if (!library) return null;
17680
17876
  const manifest = crateFor(searchRoot, library.slice("lib".length, -".a".length));
17681
17877
  if (!manifest) return null;
17682
- const result = (0, import_node_child_process9.spawnSync)(
17878
+ const result = (0, import_node_child_process8.spawnSync)(
17683
17879
  "cargo",
17684
17880
  [
17685
17881
  "build",
@@ -17724,7 +17920,7 @@ function standinLibrary(binary2, searchRoot) {
17724
17920
  }
17725
17921
  function sourceBinaryStandins(binary2, toolchain, provided) {
17726
17922
  const repo = import_node_path18.default.resolve(toolchain.moduleRoot, "../..");
17727
- const work = import_node_fs18.default.mkdtempSync(import_node_path18.default.join(import_node_os7.default.tmpdir(), "peach-standin-request-"));
17923
+ const work = import_node_fs18.default.mkdtempSync(import_node_path18.default.join(import_node_os8.default.tmpdir(), "peach-standin-request-"));
17728
17924
  try {
17729
17925
  const artifact = xcframework(binary2);
17730
17926
  const local = { ...binary2, dir: artifact.dir, url: null, checksum: null };
@@ -17741,7 +17937,7 @@ function sourceBinaryStandins(binary2, toolchain, provided) {
17741
17937
  callerToolchainBin: toolchain.toolchainBin
17742
17938
  })
17743
17939
  );
17744
- (0, import_node_child_process9.execFileSync)(
17940
+ (0, import_node_child_process8.execFileSync)(
17745
17941
  "bash",
17746
17942
  [
17747
17943
  import_node_path18.default.join(repo, "scripts/build/remote.sh"),
@@ -17857,7 +18053,7 @@ function binaryStandins(binary2, toolchain, provided) {
17857
18053
  built.set(id, value);
17858
18054
  return value;
17859
18055
  }
17860
- const work = import_node_fs18.default.mkdtempSync(import_node_path18.default.join(import_node_os7.default.tmpdir(), "peach-standin-"));
18056
+ const work = import_node_fs18.default.mkdtempSync(import_node_path18.default.join(import_node_os8.default.tmpdir(), "peach-standin-"));
17861
18057
  let result;
17862
18058
  try {
17863
18059
  result = process.platform === "darwin" && process.env.TM_SESSION && process.env.CI !== "true" && toolchain.moduleRoot === import_node_path18.default.resolve(__sootsim_import_meta_dirname, "../../sootsim-swift") && !swiftDistributionAt(toolchain.moduleRoot) ? sourceBinaryStandins(binary2, toolchain, provided) : found.map((surface) => {
@@ -19861,7 +20057,7 @@ async function compile(packagePath, stamp, moduleRootOverride, hosted, snapshot)
19861
20057
  // each app and module checkout gets its own root, which keeps the same
19862
20058
  // app's incremental build across restarts.
19863
20059
  buildRoot: process.env.CONTRAST_SWIFT_BUILD_ROOT ?? import_node_path21.default.join(
19864
- import_node_os8.default.tmpdir(),
20060
+ import_node_os9.default.tmpdir(),
19865
20061
  "contrast-swift-build",
19866
20062
  (0, import_node_crypto8.createHash)("sha256").update(`${moduleRoot}\0${import_node_path21.default.resolve(packagePath)}`).digest("hex").slice(0, 16)
19867
20063
  ),
@@ -20142,7 +20338,7 @@ function serveSwiftPackageAsset(pathname, res) {
20142
20338
  }
20143
20339
 
20144
20340
  // src/expo-swift-host.ts
20145
- var run3 = (0, import_node_util3.promisify)(import_node_child_process10.execFile);
20341
+ var run3 = (0, import_node_util3.promisify)(import_node_child_process9.execFile);
20146
20342
  var scriptEnv = { ...process.env, [RNX_FORKED_SCRIPT_ENV]: "1" };
20147
20343
  var EXPO_SWIFT_ROUTE = "/__peach/expo-swift";
20148
20344
  var EXPO_SWIFT_ENTRY = "Sources/PeachExpoApp/PeachExpoEntry.swift";
@@ -20317,7 +20513,20 @@ ${[...new Set(units.map((unit) => unit.namespace))].map((namespace) => `import $
20317
20513
  `;
20318
20514
  }
20319
20515
  var compiling = /* @__PURE__ */ new Map();
20320
- var failedCompilations = /* @__PURE__ */ new Map();
20516
+ function failureRecordPath(packagePath) {
20517
+ return `${packagePath}.failed.json`;
20518
+ }
20519
+ function readFailedCompilation(packagePath) {
20520
+ let record2;
20521
+ try {
20522
+ record2 = JSON.parse(import_node_fs21.default.readFileSync(failureRecordPath(packagePath), "utf8"));
20523
+ } catch {
20524
+ return null;
20525
+ }
20526
+ if (typeof record2 !== "object" || record2 === null || !("stamp" in record2) || !("diagnostic" in record2) || typeof record2.stamp !== "string" || typeof record2.diagnostic !== "string")
20527
+ return null;
20528
+ return { stamp: record2.stamp, diagnostic: record2.diagnostic };
20529
+ }
20321
20530
  async function compileExpoSwiftModules(root, base, publishArtifact) {
20322
20531
  const units = await collectExpoSwiftSources(root);
20323
20532
  if (!units) return null;
@@ -20342,7 +20551,7 @@ async function compileExpoSwiftModules(root, base, publishArtifact) {
20342
20551
  const candidates = [];
20343
20552
  const stamps = /* @__PURE__ */ new Map();
20344
20553
  for (const unit of units) {
20345
- const packagePath = import_node_path22.default.join(import_node_os9.default.tmpdir(), "peach-expo-swift", key2, unit.moduleId);
20554
+ const packagePath = import_node_path22.default.join(import_node_os10.default.tmpdir(), "peach-expo-swift", key2, unit.moduleId);
20346
20555
  syncSwiftTree(
20347
20556
  packagePath,
20348
20557
  new Map(
@@ -20353,12 +20562,12 @@ async function compileExpoSwiftModules(root, base, publishArtifact) {
20353
20562
  )
20354
20563
  );
20355
20564
  const stamp = sourceStamp(packagePath, module2.root);
20356
- const failed = failedCompilations.get(packagePath);
20565
+ const failed = readFailedCompilation(packagePath);
20357
20566
  if (failed?.stamp === stamp) {
20358
20567
  failures.set(unit.moduleId, failed.diagnostic);
20359
20568
  continue;
20360
20569
  }
20361
- failedCompilations.delete(packagePath);
20570
+ import_node_fs21.default.rmSync(failureRecordPath(packagePath), { force: true });
20362
20571
  stamps.set(unit, stamp);
20363
20572
  candidates.push(unit);
20364
20573
  }
@@ -20380,7 +20589,7 @@ async function compileExpoSwiftModules(root, base, publishArtifact) {
20380
20589
  import PackageDescription
20381
20590
  let package = Package(name: "PeachExpo", targets: [${targets.map((name2) => `.target(name: ${JSON.stringify(name2)}, path: ${JSON.stringify(`Sources/${name2}`)})`).join(", ")}, .executableTarget(name: "PeachExpoApp", path: "Sources/PeachExpoApp")])
20382
20591
  `;
20383
- const packagePath = import_node_path22.default.join(import_node_os9.default.tmpdir(), "peach-expo-swift", key2, "linked-app");
20592
+ const packagePath = import_node_path22.default.join(import_node_os10.default.tmpdir(), "peach-expo-swift", key2, "linked-app");
20384
20593
  syncSwiftTree(
20385
20594
  packagePath,
20386
20595
  new Map(
@@ -20400,7 +20609,7 @@ let package = Package(name: "PeachExpo", targets: [${targets.map((name2) => `.ta
20400
20609
  } catch (linkError) {
20401
20610
  linked = [];
20402
20611
  for (const unit of candidates) {
20403
- const packagePath = import_node_path22.default.join(import_node_os9.default.tmpdir(), "peach-expo-swift", key2, unit.moduleId);
20612
+ const packagePath = import_node_path22.default.join(import_node_os10.default.tmpdir(), "peach-expo-swift", key2, unit.moduleId);
20404
20613
  try {
20405
20614
  await artifactFor(projectFor(packagePath), EXPO_SWIFT_ENTRY, module2.root);
20406
20615
  linked.push(unit);
@@ -20422,10 +20631,13 @@ let package = Package(name: "PeachExpo", targets: [${targets.map((name2) => `.ta
20422
20631
  throw error;
20423
20632
  const missing = error instanceof SwiftMissingModulesError;
20424
20633
  if ((sourceErrors.length && sourceErrors.length === errors.length || missing) && sourceStamp(packagePath, module2.root) === stamps.get(unit)) {
20425
- failedCompilations.set(packagePath, {
20426
- stamp: stamps.get(unit),
20427
- diagnostic: missing ? diagnostic : sourceErrors.join("\n")
20428
- });
20634
+ import_node_fs21.default.writeFileSync(
20635
+ failureRecordPath(packagePath),
20636
+ JSON.stringify({
20637
+ stamp: stamps.get(unit),
20638
+ diagnostic: missing ? diagnostic : sourceErrors.join("\n")
20639
+ })
20640
+ );
20429
20641
  }
20430
20642
  failures.set(
20431
20643
  unit.moduleId,
@@ -20647,7 +20859,7 @@ var import_node_fs25 = __toESM(require("node:fs"), 1);
20647
20859
  var import_node_path26 = __toESM(require("node:path"), 1);
20648
20860
 
20649
20861
  // src/agent-sessions.ts
20650
- var import_node_child_process11 = require("node:child_process");
20862
+ var import_node_child_process10 = require("node:child_process");
20651
20863
  var import_node_crypto11 = require("node:crypto");
20652
20864
  var import_node_fs24 = __toESM(require("node:fs"), 1);
20653
20865
  var import_node_path25 = __toESM(require("node:path"), 1);
@@ -21021,7 +21233,7 @@ function eventsFifoPath(sessionId) {
21021
21233
  function transcriptPath(sessionId) {
21022
21234
  return import_node_path25.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
21023
21235
  }
21024
- function pidIsAlive(pid, sessionId) {
21236
+ function pidIsAlive2(pid, sessionId) {
21025
21237
  if (!pid) return false;
21026
21238
  try {
21027
21239
  process.kill(pid, 0);
@@ -21201,7 +21413,7 @@ function mkfifoSync(p) {
21201
21413
  import_node_fs24.default.unlinkSync(p);
21202
21414
  }
21203
21415
  }
21204
- const result = (0, import_node_child_process11.spawnSync)("mkfifo", ["-m", "600", p]);
21416
+ const result = (0, import_node_child_process10.spawnSync)("mkfifo", ["-m", "600", p]);
21205
21417
  if (result.status !== 0) {
21206
21418
  throw new Error(
21207
21419
  `mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
@@ -21223,7 +21435,7 @@ async function startSession(opts) {
21223
21435
  const provider = opts.provider || project.preferredProvider || "codex";
21224
21436
  return withStartLock(project.id, provider, async () => {
21225
21437
  const existingLive = listSessions(project.id).find(
21226
- (s) => s.provider === provider && s.status !== "ended" && pidIsAlive(s.wrapperPid, s.id)
21438
+ (s) => s.provider === provider && s.status !== "ended" && pidIsAlive2(s.wrapperPid, s.id)
21227
21439
  );
21228
21440
  if (existingLive) {
21229
21441
  throw new AgentSessionError(
@@ -21276,7 +21488,7 @@ async function startSession(opts) {
21276
21488
  if (claudeSessionUuid) {
21277
21489
  wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
21278
21490
  }
21279
- const child = (0, import_node_child_process11.spawn)(executable, wrapperArgs, {
21491
+ const child = (0, import_node_child_process10.spawn)(executable, wrapperArgs, {
21280
21492
  detached: true,
21281
21493
  stdio: "ignore",
21282
21494
  env: {
@@ -21319,7 +21531,7 @@ async function sendPrompt(sessionId, prompt) {
21319
21531
  if (!session) {
21320
21532
  throw new AgentSessionError("NO_SESSION", `no session with id=${sessionId}`);
21321
21533
  }
21322
- if (!pidIsAlive(session.wrapperPid, sessionId)) {
21534
+ if (!pidIsAlive2(session.wrapperPid, sessionId)) {
21323
21535
  updateSessionStatus(sessionId, { status: "ended" });
21324
21536
  throw new AgentSessionError(
21325
21537
  "NOT_ALIVE",
@@ -21350,7 +21562,7 @@ async function endSession(sessionId) {
21350
21562
  if (!session) {
21351
21563
  throw new AgentSessionError("NO_SESSION", `no session with id=${sessionId}`);
21352
21564
  }
21353
- if (pidIsAlive(session.wrapperPid, sessionId)) {
21565
+ if (pidIsAlive2(session.wrapperPid, sessionId)) {
21354
21566
  try {
21355
21567
  process.kill(session.wrapperPid, "SIGTERM");
21356
21568
  } catch {
@@ -22688,7 +22900,7 @@ async function dispatchPlaneCommand(plane, type, msg, mutationOptions) {
22688
22900
  }
22689
22901
 
22690
22902
  // cli/commands/box/checkout-plane.ts
22691
- var import_node_child_process12 = require("node:child_process");
22903
+ var import_node_child_process11 = require("node:child_process");
22692
22904
  var import_node_fs27 = __toESM(require("node:fs"), 1);
22693
22905
  var import_node_path28 = __toESM(require("node:path"), 1);
22694
22906
  var CheckoutRequiresGitError = class extends Error {
@@ -22730,7 +22942,7 @@ var CheckoutFilePlane = class {
22730
22942
  }
22731
22943
  listFiles() {
22732
22944
  const args = this.trackedOnly ? ["ls-files", "-z"] : ["ls-files", "-co", "--exclude-standard", "-z"];
22733
- const stdout = (0, import_node_child_process12.execFileSync)("git", args, {
22945
+ const stdout = (0, import_node_child_process11.execFileSync)("git", args, {
22734
22946
  cwd: this.root,
22735
22947
  encoding: "utf8",
22736
22948
  maxBuffer: 64 * 1024 * 1024,
@@ -23021,7 +23233,7 @@ function normalize(p) {
23021
23233
  if (trailingSlash) joined += "/";
23022
23234
  return absolute ? "/" + joined : joined;
23023
23235
  }
23024
- function join6(...parts) {
23236
+ function join7(...parts) {
23025
23237
  const present = parts.filter((part) => part.length > 0);
23026
23238
  if (present.length === 0) return ".";
23027
23239
  return normalize(present.join("/"));
@@ -23078,7 +23290,7 @@ var posix = {
23078
23290
  delimiter,
23079
23291
  isAbsolute,
23080
23292
  normalize,
23081
- join: join6,
23293
+ join: join7,
23082
23294
  resolve: resolve3,
23083
23295
  dirname: dirname4,
23084
23296
  basename: basename4,
@@ -25140,6 +25352,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
25140
25352
  }
25141
25353
  reapIdleSims(now = Date.now()) {
25142
25354
  const attachedSimIds = new Set(this.cliSimBySocket.values());
25355
+ let reclaimable = null;
25143
25356
  for (const sim of this.sims.values()) {
25144
25357
  if (attachedSimIds.has(sim.id)) continue;
25145
25358
  const automation = this.isAutomationSim(sim);
@@ -25148,9 +25361,27 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
25148
25361
  continue;
25149
25362
  }
25150
25363
  const idleMs = now - Math.max(sim.lastActiveAt, sim.connectedAt);
25151
- const ttl = automation ? AUTOMATION_SIM_IDLE_REAP_TTL_MS : _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
25152
- if (idleMs >= ttl) this.closeSimSocketFromHost(sim.ws);
25364
+ if (automation) {
25365
+ if (idleMs >= AUTOMATION_SIM_IDLE_REAP_TTL_MS && idleMs > (reclaimable?.idleMs ?? 0))
25366
+ reclaimable = { ws: sim.ws, idleMs };
25367
+ continue;
25368
+ }
25369
+ if (idleMs >= _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS)
25370
+ this.closeSimSocketFromHost(sim.ws);
25153
25371
  }
25372
+ if (reclaimable && this.chromiumLaunchWaiting())
25373
+ this.closeSimSocketFromHost(reclaimable.ws);
25374
+ }
25375
+ chromiumQueueVerified = /* @__PURE__ */ new Map();
25376
+ chromiumLaunchWaiting() {
25377
+ const queue = readChromiumQueue(
25378
+ { fs: import_fs2.default, os: import_os.default, path: import_path2.default, childProcess: import_child_process3.default },
25379
+ this.chromiumQueueVerified
25380
+ );
25381
+ const live = new Set(queue.tickets);
25382
+ for (const entry of this.chromiumQueueVerified.keys())
25383
+ if (!live.has(entry)) this.chromiumQueueVerified.delete(entry);
25384
+ return queue.tickets.length > queue.limit;
25154
25385
  }
25155
25386
  // ping every connected ws; if the previous round's ping went unanswered,
25156
25387
  // terminate the socket so 'close' fires and the sim cleanup path