peachsim 0.1.646 → 0.1.648

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 (70) hide show
  1. package/cli/desktop-companion.ts +48 -8
  2. package/cli/drivers/electron.ts +1 -3
  3. package/dist-lib/agent-daemon-client.cjs +1 -1
  4. package/dist-lib/agent-events.cjs +1 -1
  5. package/dist-lib/agent-identity.cjs +1 -1
  6. package/dist-lib/agent-sessions.cjs +1 -1
  7. package/dist-lib/attached-projects.cjs +1 -1
  8. package/dist-lib/auth/shared-session.cjs +1 -1
  9. package/dist-lib/backend-origin.cjs +1 -1
  10. package/dist-lib/beta.cjs +1 -1
  11. package/dist-lib/beta.mjs +1 -1
  12. package/dist-lib/bridge-constants.cjs +1 -1
  13. package/dist-lib/bridge-contract-input.cjs +1 -1
  14. package/dist-lib/bridge-contract-input.mjs +1 -1
  15. package/dist-lib/bridge-contract.cjs +1 -1
  16. package/dist-lib/bridge-contract.mjs +1 -1
  17. package/dist-lib/capture-contract.cjs +1 -1
  18. package/dist-lib/capture-contract.mjs +1 -1
  19. package/dist-lib/cli-constants.cjs +1 -1
  20. package/dist-lib/cloud-contract.cjs +1 -1
  21. package/dist-lib/cloud-contract.mjs +1 -1
  22. package/dist-lib/cloud-test-args.cjs +1 -1
  23. package/dist-lib/cloud-test-args.mjs +1 -1
  24. package/dist-lib/cloud.cjs +1 -1
  25. package/dist-lib/cloud.mjs +1 -1
  26. package/dist-lib/config.cjs +1 -1
  27. package/dist-lib/detox/index.cjs +1 -1
  28. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  29. package/dist-lib/home-paths.cjs +1 -1
  30. package/dist-lib/host/bridge-host.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  32. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  33. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  34. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  35. package/dist-lib/host/websocket-proxy.cjs +1 -1
  36. package/dist-lib/index.cjs +1 -1
  37. package/dist-lib/jump-to-source-babel.cjs +1 -1
  38. package/dist-lib/jump-to-source-native.cjs +1 -1
  39. package/dist-lib/kotlin-host.cjs +1 -1
  40. package/dist-lib/menu.cjs +1 -1
  41. package/dist-lib/menu.mjs +1 -1
  42. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  43. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  44. package/dist-lib/metro-production-bundle.cjs +1 -1
  45. package/dist-lib/metro-production-bundle.mjs +1 -1
  46. package/dist-lib/metro.cjs +1 -1
  47. package/dist-lib/native-app-identity.cjs +1 -1
  48. package/dist-lib/native-app-identity.mjs +1 -1
  49. package/dist-lib/profiles.cjs +1 -1
  50. package/dist-lib/public-brand.cjs +1 -1
  51. package/dist-lib/react-native-host-modules.cjs +1 -1
  52. package/dist-lib/react-native-host-modules.mjs +1 -1
  53. package/dist-lib/render-mode.cjs +1 -1
  54. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  55. package/dist-lib/sdk.cjs +1 -1
  56. package/dist-lib/sdk.mjs +1 -1
  57. package/dist-lib/skills.cjs +24 -8
  58. package/dist-lib/swift-compile.cjs +15 -3
  59. package/dist-lib/swift-compile.mjs +15 -3
  60. package/dist-lib/swift-package.cjs +1 -1
  61. package/dist-lib/swift-package.mjs +1 -1
  62. package/dist-lib/swift-submit.cjs +2 -2
  63. package/dist-lib/swift-submit.mjs +2 -2
  64. package/dist-lib/swift.cjs +1 -1
  65. package/dist-lib/vite-swift.cjs +1067 -1052
  66. package/dist-lib/vite.cjs +1 -1
  67. package/package.json +1 -1
  68. package/src/swift-compile.ts +31 -7
  69. package/src/swift-submit.ts +3 -1
  70. package/src/vite-plugin-swift.ts +10 -6
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.646 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.648 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -69,1141 +69,1153 @@ function swiftEntryModuleEsm(args) {
69
69
  ].join("\n");
70
70
  }
71
71
 
72
- // src/swift-host.ts
73
- var import_node_crypto3 = require("node:crypto");
74
- var import_node_fs4 = __toESM(require("node:fs"), 1);
75
- var import_node_os3 = __toESM(require("node:os"), 1);
76
- var import_node_path5 = __toESM(require("node:path"), 1);
72
+ // src/swift-compile.ts
73
+ var import_node_child_process2 = require("node:child_process");
74
+ var import_node_crypto2 = require("node:crypto");
75
+ var import_node_fs2 = require("node:fs");
76
+ var import_node_os = __toESM(require("node:os"), 1);
77
+ var import_node_path2 = __toESM(require("node:path"), 1);
78
+ var import_node_util2 = require("node:util");
77
79
 
78
- // ../sootsim-swift/src/bundleAssets.ts
79
- var import_svgpath = __toESM(require("svgpath"), 1);
80
- var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
81
- ".avif",
82
- ".bmp",
83
- ".gif",
84
- ".ico",
85
- ".jpeg",
86
- ".jpg",
87
- ".png",
88
- ".webp"
89
- ]);
90
- function extOf(file) {
91
- const dot = file.lastIndexOf(".");
92
- return dot < 0 ? "" : file.slice(dot).toLowerCase();
80
+ // src/swift-icu.ts
81
+ var import_node_child_process = require("node:child_process");
82
+ var import_node_crypto = require("node:crypto");
83
+ var import_node_fs = require("node:fs");
84
+ var import_node_path = __toESM(require("node:path"), 1);
85
+ var import_node_util = require("node:util");
86
+ var import_node_zlib = require("node:zlib");
87
+ var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
88
+ var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
89
+ var ARCHIVE = "wasi/lib_FoundationICU.a";
90
+ var MEMBER = "icu_packaged_data.cpp.obj";
91
+ var raw = /* @__PURE__ */ new Map();
92
+ var assets = /* @__PURE__ */ new Map();
93
+ function memo(cache, key, load2) {
94
+ let pending = cache.get(key);
95
+ if (!pending) {
96
+ pending = load2();
97
+ pending.catch(() => cache.delete(key));
98
+ cache.set(key, pending);
99
+ }
100
+ return pending;
93
101
  }
94
- function baseOf(file) {
95
- const slash = file.lastIndexOf("/");
96
- return slash < 0 ? file : file.slice(slash + 1);
102
+ function swiftIcuData(toolchainBin, release) {
103
+ return memo(raw, `${toolchainBin}\0${release}`, () => load(toolchainBin, release));
97
104
  }
98
- function pickImagesetFile(images) {
99
- const rasters = images.filter(
100
- (image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
101
- );
102
- if (rasters.length === 0) return null;
103
- const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
104
- const pick = [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0];
105
- return {
106
- filename: pick.filename,
107
- scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
108
- };
105
+ function swiftIcuAsset(toolchainBin, release) {
106
+ return memo(assets, `${toolchainBin}\0${release}`, async () => {
107
+ const zipped = await deflate(await swiftIcuData(toolchainBin, release));
108
+ return { sha256: (0, import_node_crypto.createHash)("sha256").update(zipped).digest("hex"), gzip: zipped };
109
+ });
109
110
  }
110
- function flatScale(path6) {
111
- const match = /@([23])x\.[^./]+$/.exec(path6);
112
- return match ? Number(match[1]) : 1;
111
+ async function load(toolchainBin, release) {
112
+ const { stdout } = await run(import_node_path.default.join(toolchainBin, "swift"), [
113
+ "sdk",
114
+ "configure",
115
+ "--show-configuration",
116
+ `${release}_wasm`,
117
+ "wasm32-unknown-wasip1"
118
+ ]);
119
+ const resources = /^swiftStaticResourcesPath: (.+)$/m.exec(stdout)?.[1]?.trim();
120
+ if (!resources) throw new Error(`swift-icu: ${release}_wasm names no static resources`);
121
+ return Buffer.from(
122
+ icuSegment(archiveMember((0, import_node_fs.readFileSync)(import_node_path.default.join(resources, ARCHIVE)), MEMBER))
123
+ );
113
124
  }
114
- function providesNamespace(text) {
115
- if (text === null) return false;
116
- try {
117
- const parsed = JSON.parse(text);
118
- return parsed?.properties?.["provides-namespace"] === true;
119
- } catch {
120
- return false;
125
+ function archiveMember(archive, name) {
126
+ if (archive.toString("latin1", 0, 8) !== "!<arch>\n")
127
+ throw new Error("swift-icu: not an ar archive");
128
+ let names = "";
129
+ for (let at = 8; at + 60 <= archive.length; ) {
130
+ const raw2 = archive.toString("latin1", at, at + 16).trimEnd();
131
+ const size = Number(archive.toString("latin1", at + 48, at + 58).trim());
132
+ const body = archive.subarray(at + 60, at + 60 + size);
133
+ if (raw2 === "//") names = body.toString("latin1");
134
+ const member = /^\/\d+$/.test(raw2) ? names.slice(Number(raw2.slice(1)), names.indexOf("/\n", Number(raw2.slice(1)))) : raw2.replace(/\/$/, "");
135
+ if (member === name) return body;
136
+ at += 60 + size + size % 2;
121
137
  }
138
+ throw new Error(`swift-icu: ${name} is not in the sdk's icu archive`);
122
139
  }
123
- function catalogEntryName(contentsPath, kind, readText) {
124
- const parts = contentsPath.split("/");
125
- const leaf = parts[parts.length - 2] ?? "";
126
- if (!leaf.endsWith(kind)) return null;
127
- const short = leaf.slice(0, -kind.length) || null;
128
- if (short === null) return null;
129
- const segments = [short];
130
- for (let depth = parts.length - 3; depth >= 0; depth -= 1) {
131
- const dir = parts[depth] ?? "";
132
- if (dir.endsWith(".xcassets") || dir === "" || dir === "." || dir === "..") break;
133
- const folderContents = [...parts.slice(0, depth + 1), "Contents.json"].join("/");
134
- if (providesNamespace(readText(folderContents))) segments.unshift(dir);
140
+ function icuSegment(object) {
141
+ let at = 8;
142
+ const leb = () => {
143
+ let result = 0;
144
+ let shift = 0;
145
+ let byte;
146
+ do {
147
+ byte = object[at++];
148
+ result += (byte & 127) * 2 ** shift;
149
+ shift += 7;
150
+ } while (byte & 128);
151
+ return result;
152
+ };
153
+ const found = [];
154
+ while (at < object.length) {
155
+ const id = object[at++];
156
+ const size = leb();
157
+ const end = at + size;
158
+ if (id === 11) {
159
+ for (let count = leb(); count > 0; count--) {
160
+ if (leb() !== 0) throw new Error("swift-icu: unexpected data segment kind");
161
+ at++;
162
+ leb();
163
+ at++;
164
+ const length = leb();
165
+ const bytes = object.subarray(at, at + length);
166
+ if (bytes[2] === 218 && bytes[3] === 39) found.push(bytes);
167
+ at += length;
168
+ }
169
+ }
170
+ at = end;
135
171
  }
136
- return segments.join("/");
137
- }
138
- function isFlatResourceImage(path6) {
139
- return path6.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path6));
172
+ if (found.length !== 1)
173
+ throw new Error(`swift-icu: expected one icu data segment, found ${found.length}`);
174
+ return found[0];
140
175
  }
141
- function enumerateBundleImages(paths, readText) {
142
- const table = [];
143
- const seen = /* @__PURE__ */ new Set();
144
- const catalogs = paths.filter((path6) => baseOf(path6) === "Contents.json");
145
- for (const contentsPath of catalogs) {
146
- const name = catalogEntryName(contentsPath, ".imageset", readText);
147
- if (name === null || seen.has(name)) continue;
148
- let parsed;
149
- try {
150
- const text = readText(contentsPath);
151
- if (text === null) continue;
152
- parsed = JSON.parse(text);
153
- } catch {
154
- continue;
176
+
177
+ // src/swift-package.ts
178
+ function swiftManifestTargets(manifest) {
179
+ const code = manifest.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
180
+ const targets = [];
181
+ const pattern = /\.(executableTarget|target)\s*\(/g;
182
+ let match;
183
+ while ((match = pattern.exec(code)) !== null) {
184
+ const executable = match[1] === "executableTarget";
185
+ let depth = 1;
186
+ const start = pattern.lastIndex;
187
+ let i = start;
188
+ let inString = false;
189
+ let escaped = false;
190
+ let flat = "";
191
+ while (i < code.length && depth > 0) {
192
+ const ch = code[i];
193
+ if (inString) {
194
+ if (escaped) escaped = false;
195
+ else if (ch === "\\") escaped = true;
196
+ else if (ch === '"') inString = false;
197
+ if (depth === 1) flat += ch;
198
+ } else if (ch === '"') {
199
+ inString = true;
200
+ if (depth === 1) flat += ch;
201
+ } else if (ch === "(") {
202
+ depth++;
203
+ if (depth === 1) flat += ch;
204
+ } else if (ch === ")") {
205
+ depth--;
206
+ if (depth >= 1) flat += ch;
207
+ } else if (depth === 1) {
208
+ flat += ch;
209
+ }
210
+ i++;
155
211
  }
156
- const images = parsed?.images;
157
- if (!Array.isArray(images)) continue;
158
- const dir = contentsPath.split("/").slice(0, -1).join("/");
159
- const pick = pickImagesetFile(images);
160
- if (pick === null || pick.filename.includes("/") || pick.filename.includes("\\"))
161
- continue;
162
- seen.add(name);
163
- table.push({ name, file: `${dir}/${pick.filename}`, scale: pick.scale });
164
- }
165
- for (const path6 of paths) {
166
- if (!isFlatResourceImage(path6)) continue;
167
- const name = baseOf(path6).slice(0, -extOf(path6).length);
168
- if (name === "" || seen.has(name)) continue;
169
- seen.add(name);
170
- table.push({ name, file: path6, scale: flatScale(path6) });
212
+ const name = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
213
+ if (!name) continue;
214
+ const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
215
+ const targetPath = rawPath == null || rawPath === "" ? `Sources/${name}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
216
+ const call = code.slice(start, i);
217
+ const languageMode = Number(
218
+ /\.swiftLanguageMode\(\s*\.v(\d+)\s*\)/.exec(call)?.[1] ?? "5"
219
+ );
220
+ const mainActorIsolation = /\.defaultIsolation\(\s*MainActor\.self\s*\)/.test(call);
221
+ const resources = /\bresources\s*:/.test(flat);
222
+ targets.push({
223
+ name,
224
+ path: targetPath,
225
+ executable,
226
+ languageMode,
227
+ mainActorIsolation,
228
+ resources
229
+ });
171
230
  }
172
- return table;
231
+ return targets;
173
232
  }
174
- function colorComponent(value) {
175
- if (typeof value !== "string") return null;
176
- const parsed = value.startsWith("0x") ? Number.parseInt(value.slice(2), 16) / 255 : value.includes(".") ? Number.parseFloat(value) : Number.parseInt(value, 10) / 255;
177
- return Number.isFinite(parsed) ? parsed : null;
233
+ function swiftPackagePartition(manifest) {
234
+ const targets = swiftManifestTargets(manifest);
235
+ return targets.length === 1 && targets[0].executable && targets[0].path === "." ? [] : targets;
178
236
  }
179
- function colorsetValue(color) {
180
- if (typeof color !== "object" || color === null) return null;
181
- const reference = Reflect.get(color, "reference");
182
- if (typeof reference === "string") {
183
- return { system: reference.replace(/Color$/, "") };
184
- }
185
- const space = Reflect.get(color, "color-space");
186
- if (space !== "srgb" && space !== "extended-srgb") return null;
187
- const components = Reflect.get(color, "components");
188
- if (typeof components !== "object" || components === null) return null;
189
- const [red, green, blue, alpha] = ["red", "green", "blue", "alpha"].map(
190
- (key) => colorComponent(Reflect.get(components, key))
191
- );
192
- if (red === null || green === null || blue === null || alpha === null) return null;
193
- if (![red, green, blue].every((value) => value >= 0 && value <= 1)) return null;
194
- const byte = (value) => Math.round(value * 255);
195
- return `rgba(${byte(red)}, ${byte(green)}, ${byte(blue)}, ${alpha})`;
196
- }
197
- function enumerateBundleColors(paths, readText) {
198
- const table = {};
199
- for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
200
- const name = catalogEntryName(contentsPath, ".colorset", readText);
201
- if (name === null || name in table) continue;
202
- let colors;
203
- try {
204
- const text = readText(contentsPath);
205
- if (text === null) continue;
206
- colors = Reflect.get(JSON.parse(text), "colors");
207
- } catch {
208
- continue;
237
+
238
+ // src/swift-compile.ts
239
+ var run2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
240
+ var WASM_TRIPLE = "wasm32-unknown-wasip1";
241
+ var cores = import_node_os.default.availableParallelism();
242
+ var BUILD_ENV = { ...process.env, BINARYEN_CORES: String(Math.min(4, cores)) };
243
+ var BUILD_JOBS = String(Math.max(1, Math.floor(cores / 2)));
244
+ function swiftModuleInputFiles(root) {
245
+ const files = [
246
+ "Package.swift",
247
+ "scripts/contrast-app-Package.swift",
248
+ "toolchain.json"
249
+ ];
250
+ const walk = (dir) => {
251
+ for (const entry of (0, import_node_fs2.readdirSync)(import_node_path2.default.join(root, dir), { withFileTypes: true })) {
252
+ const relative = `${dir}/${entry.name}`;
253
+ if (entry.isDirectory()) walk(relative);
254
+ else if (/\.(swift|c|h)$/.test(entry.name)) files.push(relative);
209
255
  }
210
- if (!Array.isArray(colors)) continue;
211
- let light = null;
212
- let dark = null;
213
- for (const entry of colors) {
214
- if (typeof entry !== "object" || entry === null) continue;
215
- const idiom = Reflect.get(entry, "idiom");
216
- if (idiom !== "universal" && idiom !== "iphone") continue;
217
- const appearances = Reflect.get(entry, "appearances");
218
- const list = Array.isArray(appearances) ? appearances : [];
219
- if (list.some((item) => Reflect.get(item, "appearance") === "contrast")) continue;
220
- const isDark = list.some(
221
- (item) => Reflect.get(item, "appearance") === "luminosity" && Reflect.get(item, "value") === "dark"
222
- );
223
- if (list.length > 0 && !isDark) continue;
224
- const value = colorsetValue(Reflect.get(entry, "color"));
225
- if (value === null) continue;
226
- if (isDark) dark = value;
227
- else light = value;
256
+ };
257
+ walk("Sources");
258
+ return files.sort();
259
+ }
260
+ async function ensureMacroPlugins(moduleRoot, toolchainBin) {
261
+ const dir = import_node_path2.default.join(moduleRoot, ".build/host/RnxPreviewMacros");
262
+ const ext = process.platform === "darwin" ? "dylib" : "so";
263
+ const plugins = [
264
+ {
265
+ library: import_node_path2.default.join(dir, `libRnxPreviewMacros.${ext}`),
266
+ source: import_node_path2.default.join(moduleRoot, "Sources/RnxPreviewMacros/PreviewMacro.swift")
267
+ },
268
+ {
269
+ library: import_node_path2.default.join(dir, `libFoundationMacros.${ext}`),
270
+ source: import_node_path2.default.join(moduleRoot, "Sources/FoundationMacros/PredicateMacro.swift")
228
271
  }
229
- if (light === null) continue;
230
- if (typeof light === "object") table[name] = light;
231
- else table[name] = { light, dark: typeof dark === "string" ? dark : light };
272
+ ];
273
+ const stale = plugins.some(
274
+ ({ library, source }) => !(0, import_node_fs2.existsSync)(library) || (0, import_node_fs2.statSync)(source).mtimeMs > (0, import_node_fs2.statSync)(library).mtimeMs
275
+ );
276
+ if (stale) {
277
+ await run2("sh", [
278
+ import_node_path2.default.join(moduleRoot, "scripts/build-preview-plugin.sh"),
279
+ toolchainBin,
280
+ plugins[0].library
281
+ ]);
232
282
  }
233
- return table;
283
+ return plugins.map(({ library }) => library);
234
284
  }
235
- var SYMBOL_CAP_HEIGHT_EM = 1443 / 2048;
236
- function axisExtremes(points) {
237
- const [a = 0, b = 0, c = 0, d] = points;
238
- const out = [a, d ?? c];
239
- const within = (t) => t > 0 && t < 1;
240
- if (d === void 0) {
241
- const denom = a - 2 * b + c;
242
- const t = denom === 0 ? -1 : (a - b) / denom;
243
- if (within(t)) out.push((1 - t) ** 2 * a + 2 * (1 - t) * t * b + t ** 2 * c);
244
- return out;
285
+ var linkedModuleDigests = /* @__PURE__ */ new Map();
286
+ function linkedModuleDigest(root) {
287
+ const files = swiftModuleInputFiles(root);
288
+ const stampHash = (0, import_node_crypto2.createHash)("sha256");
289
+ for (const file of files) {
290
+ const stat = (0, import_node_fs2.statSync)(import_node_path2.default.join(root, file), { bigint: true });
291
+ stampHash.update(file);
292
+ stampHash.update(
293
+ `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
294
+ `
295
+ );
245
296
  }
246
- const qa = 3 * (-a + 3 * b - 3 * c + d);
247
- const qb = 6 * (a - 2 * b + c);
248
- const qc = 3 * (b - a);
249
- const roots = Math.abs(qa) < 1e-12 ? qb === 0 ? [] : [-qc / qb] : (() => {
250
- const disc = qb * qb - 4 * qa * qc;
251
- if (disc < 0) return [];
252
- const root = Math.sqrt(disc);
253
- return [(-qb + root) / (2 * qa), (-qb - root) / (2 * qa)];
254
- })();
255
- for (const t of roots.filter(within))
256
- out.push(
257
- (1 - t) ** 3 * a + 3 * (1 - t) ** 2 * t * b + 3 * (1 - t) * t ** 2 * c + t ** 3 * d
297
+ const stamp = stampHash.digest("hex");
298
+ const cached = linkedModuleDigests.get(root);
299
+ if (cached?.stamp === stamp) return cached.digest;
300
+ const hash = (0, import_node_crypto2.createHash)("sha256");
301
+ for (const file of files) {
302
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
303
+ hash.update(
304
+ (0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs2.readFileSync)(import_node_path2.default.join(root, file))).digest()
258
305
  );
259
- return out;
306
+ }
307
+ const digest = hash.digest();
308
+ linkedModuleDigests.set(root, { stamp, digest });
309
+ return digest;
260
310
  }
261
- function pathBounds(d) {
262
- const xs = [];
263
- const ys = [];
264
- for (const path6 of d)
265
- (0, import_svgpath.default)(path6).abs().unshort().unarc().iterate((segment, _index, x, y) => {
266
- const [command, ...args] = segment;
267
- if (command === "M" || command === "L") {
268
- xs.push(Number(args[0]));
269
- ys.push(Number(args[1]));
270
- } else if (command === "H") xs.push(Number(args[0]));
271
- else if (command === "V") ys.push(Number(args[0]));
272
- else if (command === "Q" || command === "C") {
273
- const n = args.map(Number);
274
- xs.push(...axisExtremes([x, ...n.filter((_, i) => i % 2 === 0)]));
275
- ys.push(...axisExtremes([y, ...n.filter((_, i) => i % 2 === 1)]));
276
- }
277
- });
311
+ function compileTargets(input) {
312
+ const manifest = input.files["Package.swift"];
313
+ return manifest === void 0 ? [] : swiftPackagePartition(manifest);
314
+ }
315
+ function withNativeSourceGlue(input, glue) {
316
+ const targets = compileTargets(input);
317
+ if (targets.length > 1) {
318
+ throw new Error("swift native modules need one SwiftPM target");
319
+ }
320
+ const targetPath = targets[0]?.path === "." ? "" : targets[0]?.path ?? "";
278
321
  return {
279
- minX: Math.min(...xs),
280
- maxX: Math.max(...xs),
281
- minY: Math.min(...ys),
282
- maxY: Math.max(...ys)
322
+ ...input,
323
+ files: {
324
+ ...input.files,
325
+ [import_node_path2.default.posix.join(targetPath, "OneNativeSource.generated.swift")]: glue
326
+ },
327
+ oneModule: true
283
328
  };
284
329
  }
285
- function guide(svg, id, axis) {
286
- const line = new RegExp(`<line[^>]*id="${id}"[^>]*>`).exec(svg)?.[0];
287
- const value = line === void 0 ? void 0 : new RegExp(`${axis}="([-0-9.]+)"`).exec(line)?.[1];
288
- return value === void 0 ? null : Number(value);
289
- }
290
- function enumerateBundleSymbols(paths, readText) {
291
- const table = {};
292
- for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
293
- const name = catalogEntryName(contentsPath, ".symbolset", readText);
294
- if (name === null || name in table) continue;
295
- let symbols;
296
- try {
297
- symbols = Reflect.get(JSON.parse(readText(contentsPath) ?? "null") ?? {}, "symbols");
298
- } catch {
299
- continue;
330
+ function swiftSiblingDependencies(files, targets) {
331
+ const names = new Set(targets.map((target) => target.name));
332
+ const siblings = /* @__PURE__ */ new Map();
333
+ for (const target of targets) {
334
+ const prefix = `${target.path}/`;
335
+ const deps = /* @__PURE__ */ new Set();
336
+ for (const [file, contents] of Object.entries(files)) {
337
+ if (file === "Package.swift" || !file.startsWith(prefix)) continue;
338
+ for (const match of contents.matchAll(
339
+ /^\s*(?:@\w+(?:\([^)]*\))?\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm
340
+ )) {
341
+ if (names.has(match[1]) && match[1] !== target.name) deps.add(match[1]);
342
+ }
300
343
  }
301
- const file = Array.isArray(symbols) ? symbols.map((entry) => Reflect.get(entry ?? {}, "filename")).find((f) => typeof f === "string") : void 0;
302
- if (typeof file !== "string") continue;
303
- if (file.includes("/") || file.includes("\\")) continue;
304
- const svg = readText(`${contentsPath.split("/").slice(0, -1).join("/")}/${file}`);
305
- if (svg === null) continue;
306
- const group = /<g id="Regular-M"[^>]*>([\s\S]*?)<\/g>/.exec(svg)?.[1];
307
- const baseline = guide(svg, "Baseline-M", "y1");
308
- const capline = guide(svg, "Capline-M", "y1");
309
- const left = guide(svg, "left-margin-Regular-M", "x1") ?? guide(svg, "left-margin", "x1");
310
- const right = guide(svg, "right-margin-Regular-M", "x1") ?? guide(svg, "right-margin", "x1");
311
- if (group === void 0 || baseline === null || capline === null || left === null || right === null)
312
- continue;
313
- const d = [...group.matchAll(/ d="([^"]+)"/g)].map((match) => match[1] ?? "");
314
- if (d.length === 0 || baseline <= capline) continue;
315
- const scale = 24 * SYMBOL_CAP_HEIGHT_EM / (baseline - capline);
316
- const box = pathBounds(d);
317
- const translateX = 12 - (box.minX + box.maxX) * scale / 2;
318
- const translateY = 12 - (box.minY + box.maxY) * scale / 2;
319
- const advance = Math.round((right - left) * scale * 1e3) / 1e3;
320
- const tall = (box.maxY - box.minY) * scale + 0.175 * 24;
321
- table[name] = {
322
- viewBox: "0 0 24 24",
323
- advance,
324
- box: [12 - advance / 2, 12 - tall / 2, advance, tall],
325
- layers: d.map((path6) => ({
326
- d: (0, import_svgpath.default)(path6).abs().scale(scale).translate(translateX, translateY).round(3).toString()
327
- }))
328
- };
344
+ siblings.set(target.name, [...deps].sort());
329
345
  }
330
- return table;
346
+ return siblings;
331
347
  }
332
- function enumerateBundleJson(paths) {
333
- const found = [];
334
- const seen = /* @__PURE__ */ new Set();
335
- const ordered = [...paths].filter(
336
- (path6) => path6.split("/").includes("Resources") && path6.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path6) === ".json" || extOf(path6) === ".xcstrings")
337
- ).sort((a, b) => {
338
- const aDepth = a.split("/").length;
339
- const bDepth = b.split("/").length;
340
- return aDepth - bDepth || (a < b ? -1 : a > b ? 1 : 0);
341
- });
342
- for (const file of ordered) {
343
- const base = baseOf(file);
344
- if (seen.has(base)) continue;
345
- seen.add(base);
346
- found.push({ base, file });
348
+ var ONE_PRODUCT = '.product(name: "One", package: "sootsim-swift")';
349
+ var OBJC_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "PeachObjC"';
350
+ var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"';
351
+ var MULTI_MANIFEST_VERSION = 6;
352
+ function swiftArtifactHash(input, release, moduleRoot) {
353
+ const hash = (0, import_node_crypto2.createHash)("sha256");
354
+ hash.update(`swift-compile/v6
355
+ ${release}
356
+ `);
357
+ if (input.oneModule) hash.update("one-module\n");
358
+ hash.update(linkedModuleDigest(moduleRoot));
359
+ for (const file of Object.keys(input.files).sort()) {
360
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
361
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(input.files[file]).digest());
347
362
  }
348
- return found;
349
- }
350
-
351
- // src/auth/shared-session.ts
352
- var import_node_fs = require("node:fs");
353
- var import_node_path2 = require("node:path");
354
-
355
- // src/home-paths.ts
356
- var import_node_os = require("node:os");
357
- var import_node_path = __toESM(require("node:path"), 1);
358
- var PEACH_HOME_ENV = "PEACH_HOME";
359
- function rnxHomeDir() {
360
- const override = process.env[PEACH_HOME_ENV];
361
- if (override && override.length > 0) return import_node_path.default.resolve(override);
362
- return import_node_path.default.join((0, import_node_os.homedir)(), ".peach");
363
- }
364
- function electronDir() {
365
- return import_node_path.default.join(rnxHomeDir(), "electron");
366
- }
367
- function electronUserDataDir() {
368
- return import_node_path.default.join(electronDir(), "userData");
369
- }
370
- var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
371
-
372
- // src/auth/shared-session.ts
373
- function sharedDesktopAuthAccounts(user) {
374
- return [
375
- ...user?.personalAccountId ? [{ id: user.personalAccountId, name: "Personal" }] : [],
376
- ...(user?.teams ?? []).map((team) => ({ id: team.id, name: team.name }))
377
- ];
378
- }
379
- var SESSION_VERSION = 1;
380
- var SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
381
- var DEFAULT_ORIGIN = "https://contrast.dev";
382
- function getBaseDir() {
383
- const explicit = process.env[SESSION_FILE_ENV];
384
- if (explicit?.trim()) {
385
- return (0, import_node_path2.dirname)((0, import_node_path2.resolve)(explicit));
363
+ for (const base of Object.keys(input.resources ?? {}).sort()) {
364
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(base).digest());
365
+ hash.update(
366
+ (0, import_node_crypto2.createHash)("sha256").update(input.resources?.[base] ?? "").digest()
367
+ );
386
368
  }
387
- return electronUserDataDir();
388
- }
389
- function getSharedDesktopAuthFilePath() {
390
- const explicit = process.env[SESSION_FILE_ENV];
391
- if (explicit?.trim()) return (0, import_node_path2.resolve)(explicit);
392
- return (0, import_node_path2.join)(getBaseDir(), "desktop-auth.json");
369
+ for (const name of Object.keys(input.images ?? {}).sort()) {
370
+ const image = input.images?.[name];
371
+ if (!image) continue;
372
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(name).digest());
373
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(image.file).digest());
374
+ hash.update((0, import_node_crypto2.createHash)("sha256").update(image.data).digest());
375
+ }
376
+ const targets = compileTargets(input);
377
+ if (targets.length > 0) {
378
+ hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}
379
+ `);
380
+ hash.update(
381
+ JSON.stringify({
382
+ targets,
383
+ siblings: [...swiftSiblingDependencies(input.files, targets)].sort(
384
+ (a, b) => String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0
385
+ )
386
+ })
387
+ );
388
+ }
389
+ return hash.digest("hex");
393
390
  }
394
- function normalizeUser(input) {
395
- if (!input || typeof input !== "object") return null;
396
- const value = input;
397
- if (typeof value.id !== "string" || !value.id.trim()) return null;
398
- return {
399
- id: value.id.trim(),
400
- name: typeof value.name === "string" ? value.name : void 0,
401
- email: typeof value.email === "string" ? value.email : void 0,
402
- image: typeof value.image === "string" ? value.image : void 0,
403
- githubUsername: typeof value.githubUsername === "string" ? value.githubUsername : void 0,
404
- personalAccountId: typeof value.personalAccountId === "string" && value.personalAccountId.trim() ? value.personalAccountId.trim() : void 0,
405
- isAdmin: value.isAdmin === true,
406
- teams: Array.isArray(value.teams) ? value.teams.map((team) => {
407
- if (!team || typeof team !== "object") return null;
408
- const t = team;
409
- if (typeof t.id !== "string" || typeof t.name !== "string") return null;
410
- return {
411
- id: t.id,
412
- name: t.name,
413
- role: t.role === "owner" ? "owner" : "member",
414
- githubOrg: typeof t.githubOrg === "string" ? t.githubOrg : null
415
- };
416
- }).filter((team) => !!team) : void 0
391
+ function emitSwiftPackageManifest(args) {
392
+ const { targets, siblings, moduleRoot, oneModule } = args;
393
+ const executable = targets.find((target) => target.executable);
394
+ if (!executable) throw new Error("swift-compile: no executable target to emit");
395
+ const stanza = (target) => {
396
+ const isolation = target.mainActorIsolation ? " .defaultIsolation(MainActor.self)," : "";
397
+ const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation} .unsafeFlags(["-Osize"${OBJC_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ""}])]`;
398
+ const deps = [
399
+ '.product(name: "SwiftUI", package: "sootsim-swift")',
400
+ ...oneModule ? [ONE_PRODUCT] : [],
401
+ ...(siblings.get(target.name) ?? []).map((sibling) => `"${sibling}"`)
402
+ ].join(", ");
403
+ const kind = target.executable ? ".executableTarget" : ".target";
404
+ const link = target.executable ? `,
405
+ linkerSettings: [
406
+ .unsafeFlags([
407
+ "-Xclang-linker", "-mexec-model=reactor",
408
+ "-Xlinker", "--export-if-defined=__main_argc_argv",
409
+ ]),
410
+ .unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
411
+ ]` : "";
412
+ return [
413
+ ` ${kind}(`,
414
+ ` name: "${target.name}",`,
415
+ ` dependencies: [${deps}],`,
416
+ ` path: "${target.path}",`,
417
+ ` ${swiftSettings}${link}`,
418
+ ` ),`
419
+ ].join("\n");
417
420
  };
421
+ return [
422
+ "// swift-tools-version: 6.2",
423
+ "import PackageDescription",
424
+ "",
425
+ "// generated by swift-compile from the project package partition.",
426
+ "let package = Package(",
427
+ ' name: "app",',
428
+ ` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
429
+ ` dependencies: [.package(path: "${moduleRoot}")],`,
430
+ " targets: [",
431
+ ...targets.map(stanza),
432
+ " ]",
433
+ ")",
434
+ ""
435
+ ].join("\n");
418
436
  }
419
- function normalizeSession(input) {
420
- if (!input || typeof input !== "object") return null;
421
- const value = input;
422
- if (value.version !== SESSION_VERSION) return null;
423
- if (typeof value.token !== "string" || !value.token.trim()) return null;
424
- const origin = typeof value.origin === "string" && value.origin.trim() ? value.origin.trim() : DEFAULT_ORIGIN;
425
- const source = value.source === "cli" || value.source === "electron" || value.source === "browser" || value.source === "unknown" ? value.source : "unknown";
426
- const updatedAt = typeof value.updatedAt === "string" && value.updatedAt ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
427
- const validatedAt = typeof value.validatedAt === "string" && value.validatedAt ? value.validatedAt : void 0;
428
- const accountId = typeof value.accountId === "string" && value.accountId.trim() ? value.accountId.trim() : void 0;
429
- return {
430
- version: SESSION_VERSION,
431
- token: value.token.trim(),
432
- user: normalizeUser(value.user),
433
- origin,
434
- source,
435
- updatedAt,
436
- validatedAt,
437
- accountId
437
+ function syncSwiftTree(base, files) {
438
+ (0, import_node_fs2.mkdirSync)(base, { recursive: true });
439
+ const walk = (dir) => {
440
+ for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
441
+ const full = import_node_path2.default.join(dir, entry.name);
442
+ if (dir === base && entry.name === ".build") continue;
443
+ if (entry.isDirectory()) walk(full);
444
+ else if (!files.has(full)) (0, import_node_fs2.rmSync)(full, { force: true });
445
+ }
438
446
  };
447
+ walk(base);
448
+ for (const [full, contents] of files) {
449
+ if ((0, import_node_fs2.existsSync)(full) && (0, import_node_fs2.readFileSync)(full, "utf8") === contents) continue;
450
+ (0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(full), { recursive: true });
451
+ (0, import_node_fs2.writeFileSync)(full, contents, "utf8");
452
+ }
439
453
  }
440
- function readSharedDesktopAuthSession() {
441
- const filepath = getSharedDesktopAuthFilePath();
442
- if (!(0, import_node_fs.existsSync)(filepath)) return null;
443
- try {
444
- const parsed = JSON.parse((0, import_node_fs.readFileSync)(filepath, "utf8"));
445
- const normalized = normalizeSession(parsed);
446
- if (!normalized) {
447
- (0, import_node_fs.rmSync)(filepath, { force: true });
448
- return null;
454
+ var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
455
+ var OS_IOS = /\bos\(\s*iOS\s*\)/g;
456
+ var OBJC_ATTRIBUTE = /^@(?:objcMembers\b|objc\b(?:(\s*)\(([^()]*)\))?|IBAction\b)/;
457
+ var SELECTOR = /^#selector\b/;
458
+ var DELEGATE_CLASS = /^class\s+[A-Za-z_]\w*\s*(?:<[^>{]*>)?\s*:[^{]*\b(?:UIApplicationDelegate|UISceneDelegate|UIWindowSceneDelegate)\b[^{]*\{/;
459
+ function swiftSourceAsIOS(source) {
460
+ const { lineStarts, tokens } = swiftCodeScan(source);
461
+ let offset = 0;
462
+ const conditioned = source.split("\n").map((line) => {
463
+ const start = offset;
464
+ offset += line.length + 1;
465
+ if (!lineStarts.has(start) || !DIRECTIVE.test(line)) return line;
466
+ return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
467
+ }).join("\n");
468
+ let out = "";
469
+ let copied = 0;
470
+ for (const at of tokens) {
471
+ const rest = conditioned.slice(at, at + 400);
472
+ if (rest.startsWith("class")) {
473
+ const modifiers = conditioned.slice(conditioned.lastIndexOf("\n", at - 1) + 1, at);
474
+ if (DELEGATE_CLASS.test(rest) && !/\b(?:final|open)\b/.test(modifiers)) {
475
+ out += `${conditioned.slice(copied, at)}final `;
476
+ copied = at;
477
+ }
478
+ continue;
449
479
  }
450
- return normalized;
451
- } catch {
452
- (0, import_node_fs.rmSync)(filepath, { force: true });
453
- return null;
480
+ const selector = SELECTOR.exec(rest);
481
+ const match = selector ?? OBJC_ATTRIBUTE.exec(rest);
482
+ if (!match) continue;
483
+ let replacement = "@ObjC";
484
+ if (selector) replacement = "#Selector";
485
+ else if (match[0] === "@objcMembers") replacement = "@ObjCMembers";
486
+ else if (match[0] === "@IBAction") replacement = "@ObjC".padEnd(match[0].length);
487
+ else if (match[2] !== void 0)
488
+ replacement = `@ObjC${match[1]}("${match[2].trim()}")`;
489
+ out += conditioned.slice(copied, at) + replacement;
490
+ copied = at + match[0].length;
454
491
  }
492
+ return out + conditioned.slice(copied);
455
493
  }
456
-
457
- // cli/run-rnx.ts
458
- var import_node_async_hooks = require("node:async_hooks");
459
- var sinks = new import_node_async_hooks.AsyncLocalStorage();
460
-
461
- // cli/auth.ts
462
- var GITHUB_TOKEN_PREFIXES = ["ghs_", "ghp_", "gho_", "ghu_", "github_pat_"];
463
- function looksLikeGitHubToken(token) {
464
- return Boolean(
465
- token && token.length >= 20 && GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix))
466
- );
467
- }
468
- function resolveGitHubActionsAuth() {
469
- const contrastRunnerToken = process.env.CONTRAST_INSTALLATION_TOKEN?.trim();
470
- const githubActionsToken = process.env.GITHUB_TOKEN?.trim();
471
- const token = contrastRunnerToken || githubActionsToken;
472
- if (!looksLikeGitHubToken(token)) return null;
473
- const repoSlug = (process.env.CONTRAST_REPO || process.env.GITHUB_REPOSITORY || "").trim();
474
- if (!repoSlug) return null;
475
- const [owner, repo] = repoSlug.includes("/") ? repoSlug.split("/", 2) : [null, null];
476
- const repositoryId = (process.env.CONTRAST_REPO_ID || process.env.GITHUB_REPOSITORY_ID || "").trim();
477
- const installationId = (process.env.CONTRAST_INSTALLATION_ID || process.env.GITHUB_APP_INSTALLATION_ID || "").trim();
478
- return {
479
- kind: "github",
480
- token,
481
- repoId: repoSlug,
482
- repositoryId: repositoryId || null,
483
- owner: owner || null,
484
- repo: repo || null,
485
- installationId: installationId || null,
486
- source: contrastRunnerToken ? "contrast-runner" : "github-actions"
494
+ function swiftCodeScan(source) {
495
+ const starts = /* @__PURE__ */ new Set();
496
+ const tokens = [];
497
+ const stack = [{ kind: "code", parens: 0 }];
498
+ const hashesAt = (at) => {
499
+ let end = at;
500
+ while (source[end] === "#") end++;
501
+ return end - at;
487
502
  };
503
+ const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
504
+ let i = 0;
505
+ while (i < source.length) {
506
+ const top = stack[stack.length - 1];
507
+ if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
508
+ starts.add(i);
509
+ const char = source[i];
510
+ if (top.kind === "block") {
511
+ if (source.startsWith("/*", i)) {
512
+ top.depth++;
513
+ i += 2;
514
+ } else if (source.startsWith("*/", i)) {
515
+ if (--top.depth === 0) stack.pop();
516
+ i += 2;
517
+ } else i++;
518
+ continue;
519
+ }
520
+ if (top.kind === "string") {
521
+ if (char === "\\" && closes(i + 1, top.hashes)) {
522
+ const after = i + 1 + top.hashes;
523
+ if (source[after] === "(") {
524
+ stack.push({ kind: "code", parens: 0 });
525
+ i = after + 1;
526
+ } else i = after + 1;
527
+ continue;
528
+ }
529
+ const quote = top.multiline ? '"""' : '"';
530
+ if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
531
+ stack.pop();
532
+ i += quote.length + top.hashes;
533
+ } else i++;
534
+ continue;
535
+ }
536
+ if (top.kind === "regex") {
537
+ if (char === "/" && closes(i + 1, top.hashes)) {
538
+ stack.pop();
539
+ i += 1 + top.hashes;
540
+ } else i++;
541
+ continue;
542
+ }
543
+ if (source.startsWith("//", i)) {
544
+ const end = source.indexOf("\n", i);
545
+ i = end === -1 ? source.length : end;
546
+ } else if (source.startsWith("/*", i)) {
547
+ stack.push({ kind: "block", depth: 1 });
548
+ i += 2;
549
+ } else if (char === '"' || char === "#") {
550
+ const hashes = hashesAt(i);
551
+ const at = i + hashes;
552
+ if (source.startsWith('"""', at)) {
553
+ stack.push({ kind: "string", hashes, multiline: true });
554
+ i = at + 3;
555
+ } else if (source[at] === '"') {
556
+ stack.push({ kind: "string", hashes, multiline: false });
557
+ i = at + 1;
558
+ } else if (hashes > 0 && source[at] === "/") {
559
+ stack.push({ kind: "regex", hashes });
560
+ i = at + 1;
561
+ } else {
562
+ if (hashes > 0) tokens.push(at - 1);
563
+ i = Math.max(at, i + 1);
564
+ }
565
+ } else if (char === "(") {
566
+ top.parens++;
567
+ i++;
568
+ } else if (char === ")") {
569
+ if (top.parens === 0 && stack.length > 1) stack.pop();
570
+ else top.parens--;
571
+ i++;
572
+ } else if (source.startsWith("class", i) && !/[\w$]/.test(source[i - 1] ?? "") && !/[\w$]/.test(source[i + 5] ?? "")) {
573
+ tokens.push(i);
574
+ i += 5;
575
+ } else {
576
+ if (char === "@") tokens.push(i);
577
+ i++;
578
+ }
579
+ }
580
+ return { lineStarts: starts, tokens };
488
581
  }
489
- function isCliApiKeySecret(secret) {
490
- return secret.startsWith("sk_rnx_");
491
- }
492
- function readApiKeyFromEnv() {
493
- const envName = "PEACH_API_KEY";
494
- const secret = process.env[envName]?.trim();
495
- return secret && isCliApiKeySecret(secret) ? { secret, envName } : null;
496
- }
497
- function resolveCliAuth() {
498
- const envKey = readApiKeyFromEnv();
499
- if (envKey) {
500
- return {
501
- kind: "api-key",
502
- secret: envKey.secret,
503
- source: "env",
504
- envName: envKey.envName
505
- };
506
- }
507
- const githubAuth = resolveGitHubActionsAuth();
508
- if (githubAuth) return githubAuth;
509
- const session = readSharedDesktopAuthSession();
510
- if (session?.token) {
511
- const accounts = sharedDesktopAuthAccounts(session.user);
512
- return {
513
- kind: "session",
514
- token: session.token,
515
- origin: session.origin,
516
- accountId: session.accountId ?? (accounts.length === 1 ? accounts[0]?.id ?? null : null)
517
- };
518
- }
519
- return null;
520
- }
521
- function authHeaderValue(auth) {
522
- return auth.kind === "api-key" ? `Bearer ${auth.secret}` : `Bearer ${auth.token}`;
523
- }
524
-
525
- // src/backend-origin.ts
526
- var DEFAULT_CONTRAST_BACKEND_ORIGIN = "https://contrast.dev";
527
- function normalizeHostname(hostname) {
528
- return hostname.replace(/^\[|\]$/g, "").toLowerCase();
529
- }
530
- function isLoopbackHost(hostname) {
531
- const normalized = normalizeHostname(hostname);
532
- return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
533
- }
534
- function isContrastBackendHost(hostname) {
535
- const normalized = normalizeHostname(hostname);
536
- return isLoopbackHost(normalized) || normalized === "contrast.dev" || normalized.endsWith(".contrast.dev");
537
- }
538
- function resolveContrastBackendOrigin(currentOrigin) {
539
- const origin = currentOrigin?.trim();
540
- if (!origin) return DEFAULT_CONTRAST_BACKEND_ORIGIN;
541
- try {
542
- const parsed = new URL(origin);
543
- if (isLoopbackHost(parsed.hostname) || isContrastBackendHost(parsed.hostname)) {
544
- return parsed.origin;
582
+ var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
583
+ function writeSwiftProject(layout, input, moduleRoot) {
584
+ const targets = compileTargets(input);
585
+ const files = /* @__PURE__ */ new Map();
586
+ if (targets.length === 0) {
587
+ for (const [file, contents] of Object.entries(input.files)) {
588
+ if (file === "Package.swift") continue;
589
+ files.set(import_node_path2.default.join(layout.sources, file), compiledSource(file, contents));
545
590
  }
546
- } catch {
591
+ let manifest = (0, import_node_fs2.readFileSync)(
592
+ import_node_path2.default.join(moduleRoot, "scripts/contrast-app-Package.swift"),
593
+ "utf8"
594
+ ).replaceAll("__SOOTSIM_SWIFT_PACKAGE__", moduleRoot);
595
+ if (input.oneModule) {
596
+ const product = '.product(name: "CoreLocation", package: "sootsim-swift"),';
597
+ const flags = `"-Osize"${OBJC_IMPLICIT_FLAGS}`;
598
+ if (!manifest.includes(product) || !manifest.includes(flags)) {
599
+ throw new Error(
600
+ "scripts/contrast-app-Package.swift lost the lines the One module links at"
601
+ );
602
+ }
603
+ manifest = manifest.replace(product, `${product}
604
+ ${ONE_PRODUCT},`).replace(flags, `${flags}${ONE_IMPLICIT_FLAGS}`);
605
+ }
606
+ files.set(import_node_path2.default.join(layout.root, "Package.swift"), manifest);
607
+ } else {
608
+ for (const [file, contents] of Object.entries(input.files)) {
609
+ if (file === "Package.swift") continue;
610
+ files.set(import_node_path2.default.join(layout.root, file), compiledSource(file, contents));
611
+ }
612
+ for (const target of targets) {
613
+ if (!target.resources) continue;
614
+ files.set(
615
+ import_node_path2.default.join(layout.root, target.path, "ResourceBundleAccessor.generated.swift"),
616
+ [
617
+ "import Foundation",
618
+ "",
619
+ "extension Foundation.Bundle {",
620
+ " static let module: Bundle = Bundle.main",
621
+ "}",
622
+ ""
623
+ ].join("\n")
624
+ );
625
+ }
626
+ files.set(
627
+ import_node_path2.default.join(layout.root, "Package.swift"),
628
+ emitSwiftPackageManifest({
629
+ targets,
630
+ siblings: swiftSiblingDependencies(input.files, targets),
631
+ moduleRoot,
632
+ oneModule: input.oneModule
633
+ })
634
+ );
547
635
  }
548
- return DEFAULT_CONTRAST_BACKEND_ORIGIN;
636
+ syncSwiftTree(layout.root, files);
549
637
  }
550
-
551
- // src/swift-compile.ts
552
- var import_node_child_process2 = require("node:child_process");
553
- var import_node_crypto2 = require("node:crypto");
554
- var import_node_fs3 = require("node:fs");
555
- var import_node_os2 = __toESM(require("node:os"), 1);
556
- var import_node_path4 = __toESM(require("node:path"), 1);
557
- var import_node_util2 = require("node:util");
558
-
559
- // src/swift-icu.ts
560
- var import_node_child_process = require("node:child_process");
561
- var import_node_crypto = require("node:crypto");
562
- var import_node_fs2 = require("node:fs");
563
- var import_node_path3 = __toESM(require("node:path"), 1);
564
- var import_node_util = require("node:util");
565
- var import_node_zlib = require("node:zlib");
566
- var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
567
- var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
568
- var ARCHIVE = "wasi/lib_FoundationICU.a";
569
- var MEMBER = "icu_packaged_data.cpp.obj";
570
- var raw = /* @__PURE__ */ new Map();
571
- var assets = /* @__PURE__ */ new Map();
572
- function memo(cache, key, load2) {
573
- let pending = cache.get(key);
574
- if (!pending) {
575
- pending = load2();
576
- pending.catch(() => cache.delete(key));
577
- cache.set(key, pending);
638
+ function streamText(value) {
639
+ if (typeof value === "string") return value.trim();
640
+ if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
641
+ return "";
642
+ }
643
+ function outputOf(error) {
644
+ if (error && typeof error === "object") {
645
+ const streams = [
646
+ streamText(Reflect.get(error, "stdout")),
647
+ streamText(Reflect.get(error, "stderr"))
648
+ ].filter(Boolean);
649
+ if (streams.length > 0) return streams.join("\n");
578
650
  }
579
- return pending;
651
+ return error instanceof Error ? error.message : String(error);
580
652
  }
581
- function swiftIcuData(toolchainBin, release) {
582
- return memo(raw, `${toolchainBin}\0${release}`, () => load(toolchainBin, release));
653
+ function builtArtifact(layout) {
654
+ const binDir = import_node_path2.default.join(layout.root, ".build", WASM_TRIPLE, "release");
655
+ const manifest = (0, import_node_fs2.readFileSync)(import_node_path2.default.join(layout.root, "Package.swift"), "utf8");
656
+ const executable = swiftManifestTargets(manifest).find((target) => target.executable);
657
+ if (executable === void 0) {
658
+ throw new Error("swift-compile: the written manifest names no executable target");
659
+ }
660
+ const file = import_node_path2.default.join(binDir, `${executable.name}.wasm`);
661
+ if (!(0, import_node_fs2.existsSync)(file)) {
662
+ const found = (0, import_node_fs2.existsSync)(binDir) ? (0, import_node_fs2.readdirSync)(binDir).filter((name) => name.endsWith(".wasm")).sort() : [];
663
+ throw new Error(
664
+ `swift-compile: the build produced no ${executable.name}.wasm (found: ${found.join(", ") || "none"})`
665
+ );
666
+ }
667
+ return file;
583
668
  }
584
- function swiftIcuAsset(toolchainBin, release) {
585
- return memo(assets, `${toolchainBin}\0${release}`, async () => {
586
- const zipped = await deflate(await swiftIcuData(toolchainBin, release));
587
- return { sha256: (0, import_node_crypto.createHash)("sha256").update(zipped).digest("hex"), gzip: zipped };
588
- });
669
+ function projectDiagnostic(output, layout) {
670
+ const base = layout.multi ? layout.root : layout.sources;
671
+ const prefix = `${base}${import_node_path2.default.sep}`;
672
+ return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
589
673
  }
590
- async function load(toolchainBin, release) {
591
- const { stdout } = await run(import_node_path3.default.join(toolchainBin, "swift"), [
592
- "sdk",
593
- "configure",
594
- "--show-configuration",
595
- `${release}_wasm`,
596
- "wasm32-unknown-wasip1"
597
- ]);
598
- const resources = /^swiftStaticResourcesPath: (.+)$/m.exec(stdout)?.[1]?.trim();
599
- if (!resources) throw new Error(`swift-icu: ${release}_wasm names no static resources`);
600
- return Buffer.from(
601
- icuSegment(archiveMember((0, import_node_fs2.readFileSync)(import_node_path3.default.join(resources, ARCHIVE)), MEMBER))
674
+ var ROOT_LOCKS = Symbol.for("peachsim.swiftCompile.rootLocks");
675
+ var host = globalThis;
676
+ var rootLocks = host[ROOT_LOCKS] ??= /* @__PURE__ */ new Map();
677
+ function serialize(root, work) {
678
+ const current = rootLocks.get(root) ?? Promise.resolve();
679
+ const next = current.then(work, work);
680
+ rootLocks.set(
681
+ root,
682
+ next.catch(() => {
683
+ })
602
684
  );
685
+ return next;
603
686
  }
604
- function archiveMember(archive, name) {
605
- if (archive.toString("latin1", 0, 8) !== "!<arch>\n")
606
- throw new Error("swift-icu: not an ar archive");
607
- let names = "";
608
- for (let at = 8; at + 60 <= archive.length; ) {
609
- const raw2 = archive.toString("latin1", at, at + 16).trimEnd();
610
- const size = Number(archive.toString("latin1", at + 48, at + 58).trim());
611
- const body = archive.subarray(at + 60, at + 60 + size);
612
- if (raw2 === "//") names = body.toString("latin1");
613
- const member = /^\/\d+$/.test(raw2) ? names.slice(Number(raw2.slice(1)), names.indexOf("/\n", Number(raw2.slice(1)))) : raw2.replace(/\/$/, "");
614
- if (member === name) return body;
615
- at += 60 + size + size % 2;
616
- }
617
- throw new Error(`swift-icu: ${name} is not in the sdk's icu archive`);
618
- }
619
- function icuSegment(object) {
620
- let at = 8;
621
- const leb = () => {
622
- let result = 0;
623
- let shift = 0;
624
- let byte;
625
- do {
626
- byte = object[at++];
627
- result += (byte & 127) * 2 ** shift;
628
- shift += 7;
629
- } while (byte & 128);
630
- return result;
687
+ function compileSwiftProjectUnit(input, options) {
688
+ (0, import_node_fs2.mkdirSync)(options.buildRoot, { recursive: true });
689
+ const root = (0, import_node_fs2.realpathSync)(options.buildRoot);
690
+ const moduleRoot = import_node_path2.default.resolve(options.moduleRoot);
691
+ const layout = {
692
+ root,
693
+ sources: import_node_path2.default.join(root, "Sources", "App"),
694
+ multi: compileTargets(input).length > 0
631
695
  };
632
- const found = [];
633
- while (at < object.length) {
634
- const id = object[at++];
635
- const size = leb();
636
- const end = at + size;
637
- if (id === 11) {
638
- for (let count = leb(); count > 0; count--) {
639
- if (leb() !== 0) throw new Error("swift-icu: unexpected data segment kind");
640
- at++;
641
- leb();
642
- at++;
643
- const length = leb();
644
- const bytes = object.subarray(at, at + length);
645
- if (bytes[2] === 218 && bytes[3] === 39) found.push(bytes);
646
- at += length;
647
- }
696
+ const hash = swiftArtifactHash(input, options.release, moduleRoot);
697
+ return serialize(root, async () => {
698
+ writeSwiftProject(layout, input, moduleRoot);
699
+ const swift = import_node_path2.default.join(options.toolchainBin, "swift");
700
+ if (!(0, import_node_fs2.existsSync)(swift)) {
701
+ throw new Error(
702
+ `swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
703
+ );
648
704
  }
649
- at = end;
650
- }
651
- if (found.length !== 1)
652
- throw new Error(`swift-icu: expected one icu data segment, found ${found.length}`);
653
- return found[0];
705
+ const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin);
706
+ const icu = swiftIcuAsset(options.toolchainBin, options.release);
707
+ try {
708
+ await run2(
709
+ swift,
710
+ [
711
+ "build",
712
+ "-j",
713
+ BUILD_JOBS,
714
+ "--package-path",
715
+ root,
716
+ "--swift-sdk",
717
+ `${options.release}_wasm`,
718
+ "-c",
719
+ "release",
720
+ "-Xswiftc",
721
+ "-Osize",
722
+ ...macroPlugins.flatMap((plugin) => [
723
+ "-Xswiftc",
724
+ "-load-plugin-library",
725
+ "-Xswiftc",
726
+ plugin
727
+ ])
728
+ ],
729
+ { env: BUILD_ENV, maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
730
+ );
731
+ } catch (error) {
732
+ throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
733
+ }
734
+ return {
735
+ hash,
736
+ bytes: (0, import_node_fs2.readFileSync)(builtArtifact(layout)),
737
+ icu: await icu
738
+ };
739
+ });
654
740
  }
655
741
 
656
- // src/swift-package.ts
657
- function swiftManifestTargets(manifest) {
658
- const code = manifest.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
659
- const targets = [];
660
- const pattern = /\.(executableTarget|target)\s*\(/g;
661
- let match;
662
- while ((match = pattern.exec(code)) !== null) {
663
- const executable = match[1] === "executableTarget";
664
- let depth = 1;
665
- const start = pattern.lastIndex;
666
- let i = start;
667
- let inString = false;
668
- let escaped = false;
669
- let flat = "";
670
- while (i < code.length && depth > 0) {
671
- const ch = code[i];
672
- if (inString) {
673
- if (escaped) escaped = false;
674
- else if (ch === "\\") escaped = true;
675
- else if (ch === '"') inString = false;
676
- if (depth === 1) flat += ch;
677
- } else if (ch === '"') {
678
- inString = true;
679
- if (depth === 1) flat += ch;
680
- } else if (ch === "(") {
681
- depth++;
682
- if (depth === 1) flat += ch;
683
- } else if (ch === ")") {
684
- depth--;
685
- if (depth >= 1) flat += ch;
686
- } else if (depth === 1) {
687
- flat += ch;
688
- }
689
- i++;
690
- }
691
- const name = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
692
- if (!name) continue;
693
- const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
694
- const targetPath = rawPath == null || rawPath === "" ? `Sources/${name}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
695
- const call = code.slice(start, i);
696
- const languageMode = Number(
697
- /\.swiftLanguageMode\(\s*\.v(\d+)\s*\)/.exec(call)?.[1] ?? "5"
698
- );
699
- const mainActorIsolation = /\.defaultIsolation\(\s*MainActor\.self\s*\)/.test(call);
700
- const resources = /\bresources\s*:/.test(flat);
701
- targets.push({
702
- name,
703
- path: targetPath,
704
- executable,
705
- languageMode,
706
- mainActorIsolation,
707
- resources
708
- });
709
- }
710
- return targets;
742
+ // src/swift-host.ts
743
+ var import_node_crypto3 = require("node:crypto");
744
+ var import_node_fs4 = __toESM(require("node:fs"), 1);
745
+ var import_node_os3 = __toESM(require("node:os"), 1);
746
+ var import_node_path5 = __toESM(require("node:path"), 1);
747
+
748
+ // ../sootsim-swift/src/bundleAssets.ts
749
+ var import_svgpath = __toESM(require("svgpath"), 1);
750
+ var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
751
+ ".avif",
752
+ ".bmp",
753
+ ".gif",
754
+ ".ico",
755
+ ".jpeg",
756
+ ".jpg",
757
+ ".png",
758
+ ".webp"
759
+ ]);
760
+ function extOf(file) {
761
+ const dot = file.lastIndexOf(".");
762
+ return dot < 0 ? "" : file.slice(dot).toLowerCase();
711
763
  }
712
- function swiftPackagePartition(manifest) {
713
- const targets = swiftManifestTargets(manifest);
714
- return targets.length === 1 && targets[0].executable && targets[0].path === "." ? [] : targets;
764
+ function baseOf(file) {
765
+ const slash = file.lastIndexOf("/");
766
+ return slash < 0 ? file : file.slice(slash + 1);
715
767
  }
716
-
717
- // src/swift-compile.ts
718
- var run2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
719
- var WASM_TRIPLE = "wasm32-unknown-wasip1";
720
- var cores = import_node_os2.default.availableParallelism();
721
- var BUILD_ENV = { ...process.env, BINARYEN_CORES: String(Math.min(4, cores)) };
722
- var BUILD_JOBS = String(Math.max(1, Math.floor(cores / 2)));
723
- function swiftModuleInputFiles(root) {
724
- const files = [
725
- "Package.swift",
726
- "scripts/contrast-app-Package.swift",
727
- "toolchain.json"
728
- ];
729
- const walk = (dir) => {
730
- for (const entry of (0, import_node_fs3.readdirSync)(import_node_path4.default.join(root, dir), { withFileTypes: true })) {
731
- const relative = `${dir}/${entry.name}`;
732
- if (entry.isDirectory()) walk(relative);
733
- else if (/\.(swift|c|h)$/.test(entry.name)) files.push(relative);
734
- }
768
+ function pickImagesetFile(images) {
769
+ const rasters = images.filter(
770
+ (image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
771
+ );
772
+ if (rasters.length === 0) return null;
773
+ const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
774
+ const pick = [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0];
775
+ return {
776
+ filename: pick.filename,
777
+ scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
735
778
  };
736
- walk("Sources");
737
- return files.sort();
738
779
  }
739
- async function ensureMacroPlugins(moduleRoot, toolchainBin) {
740
- const dir = import_node_path4.default.join(moduleRoot, ".build/host/RnxPreviewMacros");
741
- const ext = process.platform === "darwin" ? "dylib" : "so";
742
- const plugins = [
743
- {
744
- library: import_node_path4.default.join(dir, `libRnxPreviewMacros.${ext}`),
745
- source: import_node_path4.default.join(moduleRoot, "Sources/RnxPreviewMacros/PreviewMacro.swift")
746
- },
747
- {
748
- library: import_node_path4.default.join(dir, `libFoundationMacros.${ext}`),
749
- source: import_node_path4.default.join(moduleRoot, "Sources/FoundationMacros/PredicateMacro.swift")
750
- }
751
- ];
752
- const stale = plugins.some(
753
- ({ library, source }) => !(0, import_node_fs3.existsSync)(library) || (0, import_node_fs3.statSync)(source).mtimeMs > (0, import_node_fs3.statSync)(library).mtimeMs
754
- );
755
- if (stale) {
756
- await run2("sh", [
757
- import_node_path4.default.join(moduleRoot, "scripts/build-preview-plugin.sh"),
758
- toolchainBin,
759
- plugins[0].library
760
- ]);
761
- }
762
- return plugins.map(({ library }) => library);
780
+ function flatScale(path6) {
781
+ const match = /@([23])x\.[^./]+$/.exec(path6);
782
+ return match ? Number(match[1]) : 1;
763
783
  }
764
- var linkedModuleDigests = /* @__PURE__ */ new Map();
765
- function linkedModuleDigest(root) {
766
- const files = swiftModuleInputFiles(root);
767
- const stampHash = (0, import_node_crypto2.createHash)("sha256");
768
- for (const file of files) {
769
- const stat = (0, import_node_fs3.statSync)(import_node_path4.default.join(root, file), { bigint: true });
770
- stampHash.update(file);
771
- stampHash.update(
772
- `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
773
- `
774
- );
775
- }
776
- const stamp = stampHash.digest("hex");
777
- const cached = linkedModuleDigests.get(root);
778
- if (cached?.stamp === stamp) return cached.digest;
779
- const hash = (0, import_node_crypto2.createHash)("sha256");
780
- for (const file of files) {
781
- hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
782
- hash.update(
783
- (0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs3.readFileSync)(import_node_path4.default.join(root, file))).digest()
784
- );
784
+ function providesNamespace(text) {
785
+ if (text === null) return false;
786
+ try {
787
+ const parsed = JSON.parse(text);
788
+ return parsed?.properties?.["provides-namespace"] === true;
789
+ } catch {
790
+ return false;
785
791
  }
786
- const digest = hash.digest();
787
- linkedModuleDigests.set(root, { stamp, digest });
788
- return digest;
789
- }
790
- function compileTargets(input) {
791
- const manifest = input.files["Package.swift"];
792
- return manifest === void 0 ? [] : swiftPackagePartition(manifest);
793
792
  }
794
- function withNativeSourceGlue(input, glue) {
795
- const targets = compileTargets(input);
796
- if (targets.length > 1) {
797
- throw new Error("swift native modules need one SwiftPM target");
793
+ function catalogEntryName(contentsPath, kind, readText) {
794
+ const parts = contentsPath.split("/");
795
+ const leaf = parts[parts.length - 2] ?? "";
796
+ if (!leaf.endsWith(kind)) return null;
797
+ const short = leaf.slice(0, -kind.length) || null;
798
+ if (short === null) return null;
799
+ const segments = [short];
800
+ for (let depth = parts.length - 3; depth >= 0; depth -= 1) {
801
+ const dir = parts[depth] ?? "";
802
+ if (dir.endsWith(".xcassets") || dir === "" || dir === "." || dir === "..") break;
803
+ const folderContents = [...parts.slice(0, depth + 1), "Contents.json"].join("/");
804
+ if (providesNamespace(readText(folderContents))) segments.unshift(dir);
798
805
  }
799
- const targetPath = targets[0]?.path === "." ? "" : targets[0]?.path ?? "";
800
- return {
801
- ...input,
802
- files: {
803
- ...input.files,
804
- [import_node_path4.default.posix.join(targetPath, "OneNativeSource.generated.swift")]: glue
805
- },
806
- oneModule: true
807
- };
806
+ return segments.join("/");
808
807
  }
809
- function swiftSiblingDependencies(files, targets) {
810
- const names = new Set(targets.map((target) => target.name));
811
- const siblings = /* @__PURE__ */ new Map();
812
- for (const target of targets) {
813
- const prefix = `${target.path}/`;
814
- const deps = /* @__PURE__ */ new Set();
815
- for (const [file, contents] of Object.entries(files)) {
816
- if (file === "Package.swift" || !file.startsWith(prefix)) continue;
817
- for (const match of contents.matchAll(
818
- /^\s*(?:@\w+(?:\([^)]*\))?\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm
819
- )) {
820
- if (names.has(match[1]) && match[1] !== target.name) deps.add(match[1]);
821
- }
808
+ function isFlatResourceImage(path6) {
809
+ return path6.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path6));
810
+ }
811
+ function enumerateBundleImages(paths, readText) {
812
+ const table = [];
813
+ const seen = /* @__PURE__ */ new Set();
814
+ const catalogs = paths.filter((path6) => baseOf(path6) === "Contents.json");
815
+ for (const contentsPath of catalogs) {
816
+ const name = catalogEntryName(contentsPath, ".imageset", readText);
817
+ if (name === null || seen.has(name)) continue;
818
+ let parsed;
819
+ try {
820
+ const text = readText(contentsPath);
821
+ if (text === null) continue;
822
+ parsed = JSON.parse(text);
823
+ } catch {
824
+ continue;
822
825
  }
823
- siblings.set(target.name, [...deps].sort());
826
+ const images = parsed?.images;
827
+ if (!Array.isArray(images)) continue;
828
+ const dir = contentsPath.split("/").slice(0, -1).join("/");
829
+ const pick = pickImagesetFile(images);
830
+ if (pick === null || pick.filename.includes("/") || pick.filename.includes("\\"))
831
+ continue;
832
+ seen.add(name);
833
+ table.push({ name, file: `${dir}/${pick.filename}`, scale: pick.scale });
824
834
  }
825
- return siblings;
835
+ for (const path6 of paths) {
836
+ if (!isFlatResourceImage(path6)) continue;
837
+ const name = baseOf(path6).slice(0, -extOf(path6).length);
838
+ if (name === "" || seen.has(name)) continue;
839
+ seen.add(name);
840
+ table.push({ name, file: path6, scale: flatScale(path6) });
841
+ }
842
+ return table;
826
843
  }
827
- var ONE_PRODUCT = '.product(name: "One", package: "sootsim-swift")';
828
- var OBJC_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "PeachObjC"';
829
- var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"';
830
- var MULTI_MANIFEST_VERSION = 6;
831
- function swiftArtifactHash(input, release, moduleRoot) {
832
- const hash = (0, import_node_crypto2.createHash)("sha256");
833
- hash.update(`swift-compile/v5
834
- ${release}
835
- `);
836
- if (input.oneModule) hash.update("one-module\n");
837
- hash.update(linkedModuleDigest(moduleRoot));
838
- for (const file of Object.keys(input.files).sort()) {
839
- hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
840
- hash.update((0, import_node_crypto2.createHash)("sha256").update(input.files[file]).digest());
844
+ function colorComponent(value) {
845
+ if (typeof value !== "string") return null;
846
+ const parsed = value.startsWith("0x") ? Number.parseInt(value.slice(2), 16) / 255 : value.includes(".") ? Number.parseFloat(value) : Number.parseInt(value, 10) / 255;
847
+ return Number.isFinite(parsed) ? parsed : null;
848
+ }
849
+ function colorsetValue(color) {
850
+ if (typeof color !== "object" || color === null) return null;
851
+ const reference = Reflect.get(color, "reference");
852
+ if (typeof reference === "string") {
853
+ return { system: reference.replace(/Color$/, "") };
841
854
  }
842
- for (const base of Object.keys(input.resources ?? {}).sort()) {
843
- hash.update((0, import_node_crypto2.createHash)("sha256").update(base).digest());
844
- hash.update(
845
- (0, import_node_crypto2.createHash)("sha256").update(input.resources?.[base] ?? "").digest()
846
- );
855
+ const space = Reflect.get(color, "color-space");
856
+ if (space !== "srgb" && space !== "extended-srgb") return null;
857
+ const components = Reflect.get(color, "components");
858
+ if (typeof components !== "object" || components === null) return null;
859
+ const [red, green, blue, alpha] = ["red", "green", "blue", "alpha"].map(
860
+ (key) => colorComponent(Reflect.get(components, key))
861
+ );
862
+ if (red === null || green === null || blue === null || alpha === null) return null;
863
+ if (![red, green, blue].every((value) => value >= 0 && value <= 1)) return null;
864
+ const byte = (value) => Math.round(value * 255);
865
+ return `rgba(${byte(red)}, ${byte(green)}, ${byte(blue)}, ${alpha})`;
866
+ }
867
+ function enumerateBundleColors(paths, readText) {
868
+ const table = {};
869
+ for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
870
+ const name = catalogEntryName(contentsPath, ".colorset", readText);
871
+ if (name === null || name in table) continue;
872
+ let colors;
873
+ try {
874
+ const text = readText(contentsPath);
875
+ if (text === null) continue;
876
+ colors = Reflect.get(JSON.parse(text), "colors");
877
+ } catch {
878
+ continue;
879
+ }
880
+ if (!Array.isArray(colors)) continue;
881
+ let light = null;
882
+ let dark = null;
883
+ for (const entry of colors) {
884
+ if (typeof entry !== "object" || entry === null) continue;
885
+ const idiom = Reflect.get(entry, "idiom");
886
+ if (idiom !== "universal" && idiom !== "iphone") continue;
887
+ const appearances = Reflect.get(entry, "appearances");
888
+ const list = Array.isArray(appearances) ? appearances : [];
889
+ if (list.some((item) => Reflect.get(item, "appearance") === "contrast")) continue;
890
+ const isDark = list.some(
891
+ (item) => Reflect.get(item, "appearance") === "luminosity" && Reflect.get(item, "value") === "dark"
892
+ );
893
+ if (list.length > 0 && !isDark) continue;
894
+ const value = colorsetValue(Reflect.get(entry, "color"));
895
+ if (value === null) continue;
896
+ if (isDark) dark = value;
897
+ else light = value;
898
+ }
899
+ if (light === null) continue;
900
+ if (typeof light === "object") table[name] = light;
901
+ else table[name] = { light, dark: typeof dark === "string" ? dark : light };
847
902
  }
848
- for (const name of Object.keys(input.images ?? {}).sort()) {
849
- const image = input.images?.[name];
850
- if (!image) continue;
851
- hash.update((0, import_node_crypto2.createHash)("sha256").update(name).digest());
852
- hash.update((0, import_node_crypto2.createHash)("sha256").update(image.file).digest());
853
- hash.update((0, import_node_crypto2.createHash)("sha256").update(image.data).digest());
903
+ return table;
904
+ }
905
+ var SYMBOL_CAP_HEIGHT_EM = 1443 / 2048;
906
+ function axisExtremes(points) {
907
+ const [a = 0, b = 0, c = 0, d] = points;
908
+ const out = [a, d ?? c];
909
+ const within = (t) => t > 0 && t < 1;
910
+ if (d === void 0) {
911
+ const denom = a - 2 * b + c;
912
+ const t = denom === 0 ? -1 : (a - b) / denom;
913
+ if (within(t)) out.push((1 - t) ** 2 * a + 2 * (1 - t) * t * b + t ** 2 * c);
914
+ return out;
854
915
  }
855
- const targets = compileTargets(input);
856
- if (targets.length > 0) {
857
- hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}
858
- `);
859
- hash.update(
860
- JSON.stringify({
861
- targets,
862
- siblings: [...swiftSiblingDependencies(input.files, targets)].sort(
863
- (a, b) => String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0
864
- )
865
- })
916
+ const qa = 3 * (-a + 3 * b - 3 * c + d);
917
+ const qb = 6 * (a - 2 * b + c);
918
+ const qc = 3 * (b - a);
919
+ const roots = Math.abs(qa) < 1e-12 ? qb === 0 ? [] : [-qc / qb] : (() => {
920
+ const disc = qb * qb - 4 * qa * qc;
921
+ if (disc < 0) return [];
922
+ const root = Math.sqrt(disc);
923
+ return [(-qb + root) / (2 * qa), (-qb - root) / (2 * qa)];
924
+ })();
925
+ for (const t of roots.filter(within))
926
+ out.push(
927
+ (1 - t) ** 3 * a + 3 * (1 - t) ** 2 * t * b + 3 * (1 - t) * t ** 2 * c + t ** 3 * d
866
928
  );
867
- }
868
- return hash.digest("hex");
929
+ return out;
869
930
  }
870
- function emitSwiftPackageManifest(args) {
871
- const { targets, siblings, moduleRoot, oneModule } = args;
872
- const executable = targets.find((target) => target.executable);
873
- if (!executable) throw new Error("swift-compile: no executable target to emit");
874
- const stanza = (target) => {
875
- const isolation = target.mainActorIsolation ? " .defaultIsolation(MainActor.self)," : "";
876
- const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation} .unsafeFlags(["-Osize"${OBJC_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ""}])]`;
877
- const deps = [
878
- '.product(name: "SwiftUI", package: "sootsim-swift")',
879
- ...oneModule ? [ONE_PRODUCT] : [],
880
- ...(siblings.get(target.name) ?? []).map((sibling) => `"${sibling}"`)
881
- ].join(", ");
882
- const kind = target.executable ? ".executableTarget" : ".target";
883
- const link = target.executable ? `,
884
- linkerSettings: [
885
- .unsafeFlags([
886
- "-Xclang-linker", "-mexec-model=reactor",
887
- "-Xlinker", "--export-if-defined=__main_argc_argv",
888
- ]),
889
- .unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
890
- ]` : "";
891
- return [
892
- ` ${kind}(`,
893
- ` name: "${target.name}",`,
894
- ` dependencies: [${deps}],`,
895
- ` path: "${target.path}",`,
896
- ` ${swiftSettings}${link}`,
897
- ` ),`
898
- ].join("\n");
931
+ function pathBounds(d) {
932
+ const xs = [];
933
+ const ys = [];
934
+ for (const path6 of d)
935
+ (0, import_svgpath.default)(path6).abs().unshort().unarc().iterate((segment, _index, x, y) => {
936
+ const [command, ...args] = segment;
937
+ if (command === "M" || command === "L") {
938
+ xs.push(Number(args[0]));
939
+ ys.push(Number(args[1]));
940
+ } else if (command === "H") xs.push(Number(args[0]));
941
+ else if (command === "V") ys.push(Number(args[0]));
942
+ else if (command === "Q" || command === "C") {
943
+ const n = args.map(Number);
944
+ xs.push(...axisExtremes([x, ...n.filter((_, i) => i % 2 === 0)]));
945
+ ys.push(...axisExtremes([y, ...n.filter((_, i) => i % 2 === 1)]));
946
+ }
947
+ });
948
+ return {
949
+ minX: Math.min(...xs),
950
+ maxX: Math.max(...xs),
951
+ minY: Math.min(...ys),
952
+ maxY: Math.max(...ys)
899
953
  };
900
- return [
901
- "// swift-tools-version: 6.2",
902
- "import PackageDescription",
903
- "",
904
- "// generated by swift-compile from the project package partition.",
905
- "let package = Package(",
906
- ' name: "app",',
907
- ` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
908
- ` dependencies: [.package(path: "${moduleRoot}")],`,
909
- " targets: [",
910
- ...targets.map(stanza),
911
- " ]",
912
- ")",
913
- ""
914
- ].join("\n");
915
954
  }
916
- function syncSwiftTree(base, files) {
917
- (0, import_node_fs3.mkdirSync)(base, { recursive: true });
918
- const walk = (dir) => {
919
- for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
920
- const full = import_node_path4.default.join(dir, entry.name);
921
- if (dir === base && entry.name === ".build") continue;
922
- if (entry.isDirectory()) walk(full);
923
- else if (!files.has(full)) (0, import_node_fs3.rmSync)(full, { force: true });
955
+ function guide(svg, id, axis) {
956
+ const line = new RegExp(`<line[^>]*id="${id}"[^>]*>`).exec(svg)?.[0];
957
+ const value = line === void 0 ? void 0 : new RegExp(`${axis}="([-0-9.]+)"`).exec(line)?.[1];
958
+ return value === void 0 ? null : Number(value);
959
+ }
960
+ function enumerateBundleSymbols(paths, readText) {
961
+ const table = {};
962
+ for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
963
+ const name = catalogEntryName(contentsPath, ".symbolset", readText);
964
+ if (name === null || name in table) continue;
965
+ let symbols;
966
+ try {
967
+ symbols = Reflect.get(JSON.parse(readText(contentsPath) ?? "null") ?? {}, "symbols");
968
+ } catch {
969
+ continue;
924
970
  }
925
- };
926
- walk(base);
927
- for (const [full, contents] of files) {
928
- if ((0, import_node_fs3.existsSync)(full) && (0, import_node_fs3.readFileSync)(full, "utf8") === contents) continue;
929
- (0, import_node_fs3.mkdirSync)(import_node_path4.default.dirname(full), { recursive: true });
930
- (0, import_node_fs3.writeFileSync)(full, contents, "utf8");
971
+ const file = Array.isArray(symbols) ? symbols.map((entry) => Reflect.get(entry ?? {}, "filename")).find((f) => typeof f === "string") : void 0;
972
+ if (typeof file !== "string") continue;
973
+ if (file.includes("/") || file.includes("\\")) continue;
974
+ const svg = readText(`${contentsPath.split("/").slice(0, -1).join("/")}/${file}`);
975
+ if (svg === null) continue;
976
+ const group = /<g id="Regular-M"[^>]*>([\s\S]*?)<\/g>/.exec(svg)?.[1];
977
+ const baseline = guide(svg, "Baseline-M", "y1");
978
+ const capline = guide(svg, "Capline-M", "y1");
979
+ const left = guide(svg, "left-margin-Regular-M", "x1") ?? guide(svg, "left-margin", "x1");
980
+ const right = guide(svg, "right-margin-Regular-M", "x1") ?? guide(svg, "right-margin", "x1");
981
+ if (group === void 0 || baseline === null || capline === null || left === null || right === null)
982
+ continue;
983
+ const d = [...group.matchAll(/ d="([^"]+)"/g)].map((match) => match[1] ?? "");
984
+ if (d.length === 0 || baseline <= capline) continue;
985
+ const scale = 24 * SYMBOL_CAP_HEIGHT_EM / (baseline - capline);
986
+ const box = pathBounds(d);
987
+ const translateX = 12 - (box.minX + box.maxX) * scale / 2;
988
+ const translateY = 12 - (box.minY + box.maxY) * scale / 2;
989
+ const advance = Math.round((right - left) * scale * 1e3) / 1e3;
990
+ const tall = (box.maxY - box.minY) * scale + 0.175 * 24;
991
+ table[name] = {
992
+ viewBox: "0 0 24 24",
993
+ advance,
994
+ box: [12 - advance / 2, 12 - tall / 2, advance, tall],
995
+ layers: d.map((path6) => ({
996
+ d: (0, import_svgpath.default)(path6).abs().scale(scale).translate(translateX, translateY).round(3).toString()
997
+ }))
998
+ };
931
999
  }
1000
+ return table;
932
1001
  }
933
- var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
934
- var OS_IOS = /\bos\(\s*iOS\s*\)/g;
935
- var OBJC_ATTRIBUTE = /^@(?:objcMembers\b|objc\b(?:(\s*)\(([^()]*)\))?|IBAction\b)/;
936
- var SELECTOR = /^#selector\b/;
937
- function swiftSourceAsIOS(source) {
938
- const { lineStarts, tokens } = swiftCodeScan(source);
939
- let offset = 0;
940
- const conditioned = source.split("\n").map((line) => {
941
- const start = offset;
942
- offset += line.length + 1;
943
- if (!lineStarts.has(start) || !DIRECTIVE.test(line)) return line;
944
- return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
945
- }).join("\n");
946
- let out = "";
947
- let copied = 0;
948
- for (const at of tokens) {
949
- const rest = conditioned.slice(at, at + 200);
950
- const selector = SELECTOR.exec(rest);
951
- const match = selector ?? OBJC_ATTRIBUTE.exec(rest);
952
- if (!match) continue;
953
- let replacement = "@ObjC";
954
- if (selector) replacement = "#Selector";
955
- else if (match[0] === "@objcMembers") replacement = "@ObjCMembers";
956
- else if (match[0] === "@IBAction") replacement = "@ObjC".padEnd(match[0].length);
957
- else if (match[2] !== void 0)
958
- replacement = `@ObjC${match[1]}("${match[2].trim()}")`;
959
- out += conditioned.slice(copied, at) + replacement;
960
- copied = at + match[0].length;
1002
+ function enumerateBundleJson(paths) {
1003
+ const found = [];
1004
+ const seen = /* @__PURE__ */ new Set();
1005
+ const ordered = [...paths].filter(
1006
+ (path6) => path6.split("/").includes("Resources") && path6.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path6) === ".json" || extOf(path6) === ".xcstrings")
1007
+ ).sort((a, b) => {
1008
+ const aDepth = a.split("/").length;
1009
+ const bDepth = b.split("/").length;
1010
+ return aDepth - bDepth || (a < b ? -1 : a > b ? 1 : 0);
1011
+ });
1012
+ for (const file of ordered) {
1013
+ const base = baseOf(file);
1014
+ if (seen.has(base)) continue;
1015
+ seen.add(base);
1016
+ found.push({ base, file });
961
1017
  }
962
- return out + conditioned.slice(copied);
1018
+ return found;
963
1019
  }
964
- function swiftCodeScan(source) {
965
- const starts = /* @__PURE__ */ new Set();
966
- const tokens = [];
967
- const stack = [{ kind: "code", parens: 0 }];
968
- const hashesAt = (at) => {
969
- let end = at;
970
- while (source[end] === "#") end++;
971
- return end - at;
972
- };
973
- const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
974
- let i = 0;
975
- while (i < source.length) {
976
- const top = stack[stack.length - 1];
977
- if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
978
- starts.add(i);
979
- const char = source[i];
980
- if (top.kind === "block") {
981
- if (source.startsWith("/*", i)) {
982
- top.depth++;
983
- i += 2;
984
- } else if (source.startsWith("*/", i)) {
985
- if (--top.depth === 0) stack.pop();
986
- i += 2;
987
- } else i++;
988
- continue;
989
- }
990
- if (top.kind === "string") {
991
- if (char === "\\" && closes(i + 1, top.hashes)) {
992
- const after = i + 1 + top.hashes;
993
- if (source[after] === "(") {
994
- stack.push({ kind: "code", parens: 0 });
995
- i = after + 1;
996
- } else i = after + 1;
997
- continue;
998
- }
999
- const quote = top.multiline ? '"""' : '"';
1000
- if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
1001
- stack.pop();
1002
- i += quote.length + top.hashes;
1003
- } else i++;
1004
- continue;
1005
- }
1006
- if (top.kind === "regex") {
1007
- if (char === "/" && closes(i + 1, top.hashes)) {
1008
- stack.pop();
1009
- i += 1 + top.hashes;
1010
- } else i++;
1011
- continue;
1012
- }
1013
- if (source.startsWith("//", i)) {
1014
- const end = source.indexOf("\n", i);
1015
- i = end === -1 ? source.length : end;
1016
- } else if (source.startsWith("/*", i)) {
1017
- stack.push({ kind: "block", depth: 1 });
1018
- i += 2;
1019
- } else if (char === '"' || char === "#") {
1020
- const hashes = hashesAt(i);
1021
- const at = i + hashes;
1022
- if (source.startsWith('"""', at)) {
1023
- stack.push({ kind: "string", hashes, multiline: true });
1024
- i = at + 3;
1025
- } else if (source[at] === '"') {
1026
- stack.push({ kind: "string", hashes, multiline: false });
1027
- i = at + 1;
1028
- } else if (hashes > 0 && source[at] === "/") {
1029
- stack.push({ kind: "regex", hashes });
1030
- i = at + 1;
1031
- } else {
1032
- if (hashes > 0) tokens.push(at - 1);
1033
- i = Math.max(at, i + 1);
1034
- }
1035
- } else if (char === "(") {
1036
- top.parens++;
1037
- i++;
1038
- } else if (char === ")") {
1039
- if (top.parens === 0 && stack.length > 1) stack.pop();
1040
- else top.parens--;
1041
- i++;
1042
- } else {
1043
- if (char === "@") tokens.push(i);
1044
- i++;
1045
- }
1020
+
1021
+ // src/auth/shared-session.ts
1022
+ var import_node_fs3 = require("node:fs");
1023
+ var import_node_path4 = require("node:path");
1024
+
1025
+ // src/home-paths.ts
1026
+ var import_node_os2 = require("node:os");
1027
+ var import_node_path3 = __toESM(require("node:path"), 1);
1028
+ var PEACH_HOME_ENV = "PEACH_HOME";
1029
+ function rnxHomeDir() {
1030
+ const override = process.env[PEACH_HOME_ENV];
1031
+ if (override && override.length > 0) return import_node_path3.default.resolve(override);
1032
+ return import_node_path3.default.join((0, import_node_os2.homedir)(), ".peach");
1033
+ }
1034
+ function electronDir() {
1035
+ return import_node_path3.default.join(rnxHomeDir(), "electron");
1036
+ }
1037
+ function electronUserDataDir() {
1038
+ return import_node_path3.default.join(electronDir(), "userData");
1039
+ }
1040
+ var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
1041
+
1042
+ // src/auth/shared-session.ts
1043
+ function sharedDesktopAuthAccounts(user) {
1044
+ return [
1045
+ ...user?.personalAccountId ? [{ id: user.personalAccountId, name: "Personal" }] : [],
1046
+ ...(user?.teams ?? []).map((team) => ({ id: team.id, name: team.name }))
1047
+ ];
1048
+ }
1049
+ var SESSION_VERSION = 1;
1050
+ var SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
1051
+ var DEFAULT_ORIGIN = "https://contrast.dev";
1052
+ function getBaseDir() {
1053
+ const explicit = process.env[SESSION_FILE_ENV];
1054
+ if (explicit?.trim()) {
1055
+ return (0, import_node_path4.dirname)((0, import_node_path4.resolve)(explicit));
1046
1056
  }
1047
- return { lineStarts: starts, tokens };
1057
+ return electronUserDataDir();
1058
+ }
1059
+ function getSharedDesktopAuthFilePath() {
1060
+ const explicit = process.env[SESSION_FILE_ENV];
1061
+ if (explicit?.trim()) return (0, import_node_path4.resolve)(explicit);
1062
+ return (0, import_node_path4.join)(getBaseDir(), "desktop-auth.json");
1063
+ }
1064
+ function normalizeUser(input) {
1065
+ if (!input || typeof input !== "object") return null;
1066
+ const value = input;
1067
+ if (typeof value.id !== "string" || !value.id.trim()) return null;
1068
+ return {
1069
+ id: value.id.trim(),
1070
+ name: typeof value.name === "string" ? value.name : void 0,
1071
+ email: typeof value.email === "string" ? value.email : void 0,
1072
+ image: typeof value.image === "string" ? value.image : void 0,
1073
+ githubUsername: typeof value.githubUsername === "string" ? value.githubUsername : void 0,
1074
+ personalAccountId: typeof value.personalAccountId === "string" && value.personalAccountId.trim() ? value.personalAccountId.trim() : void 0,
1075
+ isAdmin: value.isAdmin === true,
1076
+ teams: Array.isArray(value.teams) ? value.teams.map((team) => {
1077
+ if (!team || typeof team !== "object") return null;
1078
+ const t = team;
1079
+ if (typeof t.id !== "string" || typeof t.name !== "string") return null;
1080
+ return {
1081
+ id: t.id,
1082
+ name: t.name,
1083
+ role: t.role === "owner" ? "owner" : "member",
1084
+ githubOrg: typeof t.githubOrg === "string" ? t.githubOrg : null
1085
+ };
1086
+ }).filter((team) => !!team) : void 0
1087
+ };
1048
1088
  }
1049
- var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
1050
- function writeSwiftProject(layout, input, moduleRoot) {
1051
- const targets = compileTargets(input);
1052
- const files = /* @__PURE__ */ new Map();
1053
- if (targets.length === 0) {
1054
- for (const [file, contents] of Object.entries(input.files)) {
1055
- if (file === "Package.swift") continue;
1056
- files.set(import_node_path4.default.join(layout.sources, file), compiledSource(file, contents));
1057
- }
1058
- let manifest = (0, import_node_fs3.readFileSync)(
1059
- import_node_path4.default.join(moduleRoot, "scripts/contrast-app-Package.swift"),
1060
- "utf8"
1061
- ).replaceAll("__SOOTSIM_SWIFT_PACKAGE__", moduleRoot);
1062
- if (input.oneModule) {
1063
- const product = '.product(name: "CoreLocation", package: "sootsim-swift"),';
1064
- const flags = `"-Osize"${OBJC_IMPLICIT_FLAGS}`;
1065
- if (!manifest.includes(product) || !manifest.includes(flags)) {
1066
- throw new Error(
1067
- "scripts/contrast-app-Package.swift lost the lines the One module links at"
1068
- );
1069
- }
1070
- manifest = manifest.replace(product, `${product}
1071
- ${ONE_PRODUCT},`).replace(flags, `${flags}${ONE_IMPLICIT_FLAGS}`);
1072
- }
1073
- files.set(import_node_path4.default.join(layout.root, "Package.swift"), manifest);
1074
- } else {
1075
- for (const [file, contents] of Object.entries(input.files)) {
1076
- if (file === "Package.swift") continue;
1077
- files.set(import_node_path4.default.join(layout.root, file), compiledSource(file, contents));
1078
- }
1079
- for (const target of targets) {
1080
- if (!target.resources) continue;
1081
- files.set(
1082
- import_node_path4.default.join(layout.root, target.path, "ResourceBundleAccessor.generated.swift"),
1083
- [
1084
- "import Foundation",
1085
- "",
1086
- "extension Foundation.Bundle {",
1087
- " static let module: Bundle = Bundle.main",
1088
- "}",
1089
- ""
1090
- ].join("\n")
1091
- );
1089
+ function normalizeSession(input) {
1090
+ if (!input || typeof input !== "object") return null;
1091
+ const value = input;
1092
+ if (value.version !== SESSION_VERSION) return null;
1093
+ if (typeof value.token !== "string" || !value.token.trim()) return null;
1094
+ const origin = typeof value.origin === "string" && value.origin.trim() ? value.origin.trim() : DEFAULT_ORIGIN;
1095
+ const source = value.source === "cli" || value.source === "electron" || value.source === "browser" || value.source === "unknown" ? value.source : "unknown";
1096
+ const updatedAt = typeof value.updatedAt === "string" && value.updatedAt ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
1097
+ const validatedAt = typeof value.validatedAt === "string" && value.validatedAt ? value.validatedAt : void 0;
1098
+ const accountId = typeof value.accountId === "string" && value.accountId.trim() ? value.accountId.trim() : void 0;
1099
+ return {
1100
+ version: SESSION_VERSION,
1101
+ token: value.token.trim(),
1102
+ user: normalizeUser(value.user),
1103
+ origin,
1104
+ source,
1105
+ updatedAt,
1106
+ validatedAt,
1107
+ accountId
1108
+ };
1109
+ }
1110
+ function readSharedDesktopAuthSession() {
1111
+ const filepath = getSharedDesktopAuthFilePath();
1112
+ if (!(0, import_node_fs3.existsSync)(filepath)) return null;
1113
+ try {
1114
+ const parsed = JSON.parse((0, import_node_fs3.readFileSync)(filepath, "utf8"));
1115
+ const normalized = normalizeSession(parsed);
1116
+ if (!normalized) {
1117
+ (0, import_node_fs3.rmSync)(filepath, { force: true });
1118
+ return null;
1092
1119
  }
1093
- files.set(
1094
- import_node_path4.default.join(layout.root, "Package.swift"),
1095
- emitSwiftPackageManifest({
1096
- targets,
1097
- siblings: swiftSiblingDependencies(input.files, targets),
1098
- moduleRoot,
1099
- oneModule: input.oneModule
1100
- })
1101
- );
1120
+ return normalized;
1121
+ } catch {
1122
+ (0, import_node_fs3.rmSync)(filepath, { force: true });
1123
+ return null;
1102
1124
  }
1103
- syncSwiftTree(layout.root, files);
1104
1125
  }
1105
- function streamText(value) {
1106
- if (typeof value === "string") return value.trim();
1107
- if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
1108
- return "";
1126
+
1127
+ // cli/run-rnx.ts
1128
+ var import_node_async_hooks = require("node:async_hooks");
1129
+ var sinks = new import_node_async_hooks.AsyncLocalStorage();
1130
+
1131
+ // cli/auth.ts
1132
+ var GITHUB_TOKEN_PREFIXES = ["ghs_", "ghp_", "gho_", "ghu_", "github_pat_"];
1133
+ function looksLikeGitHubToken(token) {
1134
+ return Boolean(
1135
+ token && token.length >= 20 && GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix))
1136
+ );
1109
1137
  }
1110
- function outputOf(error) {
1111
- if (error && typeof error === "object") {
1112
- const streams = [
1113
- streamText(Reflect.get(error, "stdout")),
1114
- streamText(Reflect.get(error, "stderr"))
1115
- ].filter(Boolean);
1116
- if (streams.length > 0) return streams.join("\n");
1117
- }
1118
- return error instanceof Error ? error.message : String(error);
1138
+ function resolveGitHubActionsAuth() {
1139
+ const contrastRunnerToken = process.env.CONTRAST_INSTALLATION_TOKEN?.trim();
1140
+ const githubActionsToken = process.env.GITHUB_TOKEN?.trim();
1141
+ const token = contrastRunnerToken || githubActionsToken;
1142
+ if (!looksLikeGitHubToken(token)) return null;
1143
+ const repoSlug = (process.env.CONTRAST_REPO || process.env.GITHUB_REPOSITORY || "").trim();
1144
+ if (!repoSlug) return null;
1145
+ const [owner, repo] = repoSlug.includes("/") ? repoSlug.split("/", 2) : [null, null];
1146
+ const repositoryId = (process.env.CONTRAST_REPO_ID || process.env.GITHUB_REPOSITORY_ID || "").trim();
1147
+ const installationId = (process.env.CONTRAST_INSTALLATION_ID || process.env.GITHUB_APP_INSTALLATION_ID || "").trim();
1148
+ return {
1149
+ kind: "github",
1150
+ token,
1151
+ repoId: repoSlug,
1152
+ repositoryId: repositoryId || null,
1153
+ owner: owner || null,
1154
+ repo: repo || null,
1155
+ installationId: installationId || null,
1156
+ source: contrastRunnerToken ? "contrast-runner" : "github-actions"
1157
+ };
1119
1158
  }
1120
- function builtArtifact(layout) {
1121
- const binDir = import_node_path4.default.join(layout.root, ".build", WASM_TRIPLE, "release");
1122
- const manifest = (0, import_node_fs3.readFileSync)(import_node_path4.default.join(layout.root, "Package.swift"), "utf8");
1123
- const executable = swiftManifestTargets(manifest).find((target) => target.executable);
1124
- if (executable === void 0) {
1125
- throw new Error("swift-compile: the written manifest names no executable target");
1159
+ function isCliApiKeySecret(secret) {
1160
+ return secret.startsWith("sk_rnx_");
1161
+ }
1162
+ function readApiKeyFromEnv() {
1163
+ const envName = "PEACH_API_KEY";
1164
+ const secret = process.env[envName]?.trim();
1165
+ return secret && isCliApiKeySecret(secret) ? { secret, envName } : null;
1166
+ }
1167
+ function resolveCliAuth() {
1168
+ const envKey = readApiKeyFromEnv();
1169
+ if (envKey) {
1170
+ return {
1171
+ kind: "api-key",
1172
+ secret: envKey.secret,
1173
+ source: "env",
1174
+ envName: envKey.envName
1175
+ };
1126
1176
  }
1127
- const file = import_node_path4.default.join(binDir, `${executable.name}.wasm`);
1128
- if (!(0, import_node_fs3.existsSync)(file)) {
1129
- const found = (0, import_node_fs3.existsSync)(binDir) ? (0, import_node_fs3.readdirSync)(binDir).filter((name) => name.endsWith(".wasm")).sort() : [];
1130
- throw new Error(
1131
- `swift-compile: the build produced no ${executable.name}.wasm (found: ${found.join(", ") || "none"})`
1132
- );
1177
+ const githubAuth = resolveGitHubActionsAuth();
1178
+ if (githubAuth) return githubAuth;
1179
+ const session = readSharedDesktopAuthSession();
1180
+ if (session?.token) {
1181
+ const accounts = sharedDesktopAuthAccounts(session.user);
1182
+ return {
1183
+ kind: "session",
1184
+ token: session.token,
1185
+ origin: session.origin,
1186
+ accountId: session.accountId ?? (accounts.length === 1 ? accounts[0]?.id ?? null : null)
1187
+ };
1133
1188
  }
1134
- return file;
1189
+ return null;
1135
1190
  }
1136
- function projectDiagnostic(output, layout) {
1137
- const base = layout.multi ? layout.root : layout.sources;
1138
- const prefix = `${base}${import_node_path4.default.sep}`;
1139
- return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
1191
+ function authHeaderValue(auth) {
1192
+ return auth.kind === "api-key" ? `Bearer ${auth.secret}` : `Bearer ${auth.token}`;
1140
1193
  }
1141
- var ROOT_LOCKS = Symbol.for("peachsim.swiftCompile.rootLocks");
1142
- var host = globalThis;
1143
- var rootLocks = host[ROOT_LOCKS] ??= /* @__PURE__ */ new Map();
1144
- function serialize(root, work) {
1145
- const current = rootLocks.get(root) ?? Promise.resolve();
1146
- const next = current.then(work, work);
1147
- rootLocks.set(
1148
- root,
1149
- next.catch(() => {
1150
- })
1151
- );
1152
- return next;
1194
+
1195
+ // src/backend-origin.ts
1196
+ var DEFAULT_CONTRAST_BACKEND_ORIGIN = "https://contrast.dev";
1197
+ function normalizeHostname(hostname) {
1198
+ return hostname.replace(/^\[|\]$/g, "").toLowerCase();
1153
1199
  }
1154
- function compileSwiftProjectUnit(input, options) {
1155
- (0, import_node_fs3.mkdirSync)(options.buildRoot, { recursive: true });
1156
- const root = (0, import_node_fs3.realpathSync)(options.buildRoot);
1157
- const moduleRoot = import_node_path4.default.resolve(options.moduleRoot);
1158
- const layout = {
1159
- root,
1160
- sources: import_node_path4.default.join(root, "Sources", "App"),
1161
- multi: compileTargets(input).length > 0
1162
- };
1163
- const hash = swiftArtifactHash(input, options.release, moduleRoot);
1164
- return serialize(root, async () => {
1165
- writeSwiftProject(layout, input, moduleRoot);
1166
- const swift = import_node_path4.default.join(options.toolchainBin, "swift");
1167
- if (!(0, import_node_fs3.existsSync)(swift)) {
1168
- throw new Error(
1169
- `swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
1170
- );
1171
- }
1172
- const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin);
1173
- const icu = swiftIcuAsset(options.toolchainBin, options.release);
1174
- try {
1175
- await run2(
1176
- swift,
1177
- [
1178
- "build",
1179
- "-j",
1180
- BUILD_JOBS,
1181
- "--package-path",
1182
- root,
1183
- "--swift-sdk",
1184
- `${options.release}_wasm`,
1185
- "-c",
1186
- "release",
1187
- "-Xswiftc",
1188
- "-Osize",
1189
- ...macroPlugins.flatMap((plugin) => [
1190
- "-Xswiftc",
1191
- "-load-plugin-library",
1192
- "-Xswiftc",
1193
- plugin
1194
- ])
1195
- ],
1196
- { env: BUILD_ENV, maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
1197
- );
1198
- } catch (error) {
1199
- throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
1200
+ function isLoopbackHost(hostname) {
1201
+ const normalized = normalizeHostname(hostname);
1202
+ return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
1203
+ }
1204
+ function isContrastBackendHost(hostname) {
1205
+ const normalized = normalizeHostname(hostname);
1206
+ return isLoopbackHost(normalized) || normalized === "contrast.dev" || normalized.endsWith(".contrast.dev");
1207
+ }
1208
+ function resolveContrastBackendOrigin(currentOrigin) {
1209
+ const origin = currentOrigin?.trim();
1210
+ if (!origin) return DEFAULT_CONTRAST_BACKEND_ORIGIN;
1211
+ try {
1212
+ const parsed = new URL(origin);
1213
+ if (isLoopbackHost(parsed.hostname) || isContrastBackendHost(parsed.hostname)) {
1214
+ return parsed.origin;
1200
1215
  }
1201
- return {
1202
- hash,
1203
- bytes: (0, import_node_fs3.readFileSync)(builtArtifact(layout)),
1204
- icu: await icu
1205
- };
1206
- });
1216
+ } catch {
1217
+ }
1218
+ return DEFAULT_CONTRAST_BACKEND_ORIGIN;
1207
1219
  }
1208
1220
 
1209
1221
  // src/swift-submit.ts
@@ -1216,7 +1228,7 @@ var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
1216
1228
  var MAX_SWIFT_COMPILE_IMAGES = 128;
1217
1229
  var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
1218
1230
  var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
1219
- var SWIFT_HOST_ABI = 2;
1231
+ var SWIFT_HOST_ABI = 3;
1220
1232
  var POLL_INTERVAL_MS = 1500;
1221
1233
  function swiftNativeEntry(native, file) {
1222
1234
  return {
@@ -1996,9 +2008,12 @@ function swiftPlugin(options = {}) {
1996
2008
  ])
1997
2009
  this.addWatchFile(source);
1998
2010
  this.addWatchFile(import_node_path6.default.join(packagePath, "Package.swift"));
1999
- for (const root of linkedModuleRoots(packagePath)) {
2000
- for (const source of sourceFiles(root)) this.addWatchFile(source);
2001
- }
2011
+ const moduleRoot = linkedModuleRoots(packagePath).find(
2012
+ (root) => import_node_fs5.default.existsSync(import_node_path6.default.join(root, "toolchain.json"))
2013
+ );
2014
+ if (moduleRoot)
2015
+ for (const relative of swiftModuleInputFiles(moduleRoot))
2016
+ this.addWatchFile(import_node_path6.default.join(moduleRoot, relative));
2002
2017
  let artifact;
2003
2018
  try {
2004
2019
  artifact = await artifactFor(project, entry);