stim 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{android-DJWiTBkz.mjs → android-DWssqHQ8.mjs} +165 -661
- package/dist/{android-sobvO9ia.mjs → android-Da-G_o3n.mjs} +646 -548
- package/dist/{android-BW8i_YxU.mjs → android-DeYdjjBP.mjs} +6 -2
- package/dist/{android-cas-CSS8gjR7.mjs → android-cas-SWIjzeuL.mjs} +54 -18
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{app-install--PAocWvq.mjs → app-install-DJg7bVv-.mjs} +36 -10
- package/dist/build-lock-CgtsB6TV.mjs +604 -0
- package/dist/{build-slots-CuPszJDu.mjs → build-slots-C-oAHRT1.mjs} +2 -2
- package/dist/{cache-manifest-uoOKhgUD.mjs → cache-manifest-CYJi8-Hx.mjs} +2 -2
- package/dist/cache-manifest.d.mts +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +14 -14
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-BuIb_ZOI.mjs → command-output-B3ycpsYv.mjs} +2 -2
- package/dist/{config-DMP7L7H6.mjs → config-B7iyKWkL.mjs} +56 -16
- package/dist/{dependency-state-CTL8A9p3.mjs → dependency-state-D0M7oKA7.mjs} +2 -2
- package/dist/{deps-BAGOnrc7.mjs → deps-oCXVNEqQ.mjs} +6 -6
- package/dist/detached-entry-Bpo6ZY_I.mjs +65 -0
- package/dist/{dev-client-BoifdqkU.mjs → dev-client-DDUkWgJL.mjs} +12 -12
- package/dist/{device-BUw4JBuH.mjs → device-CBSaC6BU.mjs} +7 -7
- package/dist/{device-DvKJ454A.mjs → device-CLeDp-KH.mjs} +17 -15
- package/dist/{device-lease-r7yEQ1R8.mjs → device-lease-Ffz_M5t0.mjs} +3 -3
- package/dist/{device-pool-DU4FQKp5.mjs → device-pool-DNSHL5z8.mjs} +4 -4
- package/dist/{device-remote-BTUqbl0i.mjs → device-remote-BprxZp-m.mjs} +11 -11
- package/dist/{doctor-Di_B26uh.mjs → doctor-CTAx9gMu.mjs} +90 -46
- package/dist/{error-diagnostics-CTePWAzW.mjs → error-diagnostics-D1Kaf-eT.mjs} +23 -17
- package/dist/{exec-CyylIdq9.mjs → exec-B29XNuhP.mjs} +14 -2
- package/dist/{gc-C20dWw_8.mjs → gc-CX0KRfLG.mjs} +17 -16
- package/dist/{guide-sAnoty2y.mjs → guide-CPmAG9me.mjs} +61 -22
- package/dist/{guide-status-BF6RsJJp.mjs → guide-status-Craq9z0t.mjs} +3 -3
- package/dist/{ios-BdpkncL6.mjs → ios-BRXYSxSc.mjs} +34 -37
- package/dist/{ios-device-DJOi9FR5.mjs → ios-device-CDbvn5H2.mjs} +2 -2
- package/dist/{ios-device-D3pzTKQE.mjs → ios-device-CFXA46ez.mjs} +1 -1
- package/dist/{ios-Deh5js5V.mjs → ios-lEJ5pKsq.mjs} +3 -3
- package/dist/{logs-BfQdIhiF.mjs → logs-CakdBTtm.mjs} +6 -6
- package/dist/{logs-query-Cdp5aaCH.mjs → logs-query-BGL-Pl12.mjs} +1 -1
- package/dist/metro-C7bcJ0uo.mjs +233 -0
- package/dist/{named-ports-DH9SXd0f.mjs → named-ports-DzMOlmaX.mjs} +57 -42
- package/dist/{ownership-CD_XnpDu.mjs → ownership-Cp52QAK1.mjs} +3 -3
- package/dist/{ownership-CVY9cqCr.mjs → ownership-D5vkdm8H.mjs} +13 -13
- package/dist/{ports-A6uTJSPj.mjs → ports-BIbJaKNW.mjs} +3 -3
- package/dist/{process-output-C7IlIzd7.mjs → process-output-Dl5uKE03.mjs} +1 -1
- package/dist/{project-B_SDt4ip.mjs → project-DDZWf_16.mjs} +3 -3
- package/dist/{reclaim-C_rB25f4.mjs → reclaim-D614jI6_.mjs} +11 -11
- package/dist/{reload-CYBJbJfI.mjs → reload-ChW46VDb.mjs} +9 -9
- package/dist/{server-bare-H3pAhbMs.mjs → server-bare-BQkyxa_b.mjs} +1 -1
- package/dist/{server-expo-Ds8_mfng.mjs → server-expo-BVAA1OqJ.mjs} +23 -11
- package/dist/server-expo-YDDG3eP7.mjs +2 -0
- package/dist/{settings-kO2ZqIKy.mjs → settings-BXXorVM2.mjs} +8 -5
- package/dist/{slot-launch-BpHiHH6A.mjs → slot-launch-DbLvyrup.mjs} +4 -4
- package/dist/{start-DiEfqEWk.mjs → start-TTVILlUi.mjs} +111 -38
- package/dist/{state-CnWzvCWP.mjs → state-DZobzxLW.mjs} +2 -2
- package/dist/{stats-Fo9ACIv7.mjs → stats-BYcZ6n1h.mjs} +1 -1
- package/dist/{stats-DHrO0frH.mjs → stats-CLg5RuDS.mjs} +4 -4
- package/dist/{status-J5LAXpag.mjs → status-DUNy_HZs.mjs} +14 -15
- package/dist/{stop-CM1fejKW.mjs → stop-CnUpnFT5.mjs} +2 -2
- package/dist/{stop-0jJNahwN.mjs → stop-ZrfODZ51.mjs} +13 -13
- package/dist/supervisor-run.mjs +7 -5
- package/dist/{teardown-CAVcWeRD.mjs → teardown-5J5UXz2P.mjs} +14 -17
- package/dist/{workspace-process-lock-Bz19_R9R.mjs → workspace-process-lock-BYfZz_S-.mjs} +1 -1
- package/dist/{workspace-state-WVwWw_hB.mjs → workspace-state-BT5E3SA2.mjs} +3 -3
- package/dist/{worktree-CeUKDAQw.mjs → worktree-BfE4lzHK.mjs} +21 -16
- package/dist/{worktree-DJnBbQZ9.mjs → worktree-FG_ZKKdb.mjs} +13 -9
- package/dist/{xcode-BqDeRkpT.mjs → xcode-B6YaWeg0.mjs} +92 -17
- package/package.json +12 -8
- package/shim/android-optimizations.gradle +6 -0
- package/dist/metro-ato6ef3J.mjs +0 -99
- package/dist/ports-BZprTJRa.mjs +0 -90
- package/dist/server-expo-CSwUVYOa.mjs +0 -2
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { E as ownership_claim_exports, u as getConfigDir } from "./config-B7iyKWkL.mjs";
|
|
3
|
+
import { r as register } from "./cache-manifest-CYJi8-Hx.mjs";
|
|
4
|
+
import { l as sharedBuildCache } from "./workspace-state-BT5E3SA2.mjs";
|
|
5
|
+
import { a as formatElapsed } from "./command-output-B3ycpsYv.mjs";
|
|
6
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
10
|
+
import { join as join$1 } from "path";
|
|
11
|
+
import { buildCacheKey, resolveArtifact, storeArtifact } from "@stim-cli/core";
|
|
12
|
+
import * as expoFingerprint from "@expo/fingerprint";
|
|
13
|
+
import { buildUploadTimeoutMs } from "@stim-cli/cache";
|
|
14
|
+
const ASSET_MANIFEST_FILE = "assets-manifest.json";
|
|
15
|
+
const MAX_DEPTH = 4;
|
|
16
|
+
function hashFile(file) {
|
|
17
|
+
try {
|
|
18
|
+
return createHash("sha256").update(readFileSync(file)).digest("hex");
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function readAssetManifest(root) {
|
|
24
|
+
if (!existsSync(root)) return null;
|
|
25
|
+
const assets = [];
|
|
26
|
+
let broken = false;
|
|
27
|
+
const walk = (abs, rel, depth) => {
|
|
28
|
+
if (depth > MAX_DEPTH || broken) return;
|
|
29
|
+
let names;
|
|
30
|
+
try {
|
|
31
|
+
names = readdirSync(abs);
|
|
32
|
+
} catch {
|
|
33
|
+
broken = true;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
for (const name of names) {
|
|
37
|
+
const child = join(abs, name);
|
|
38
|
+
let stat;
|
|
39
|
+
try {
|
|
40
|
+
stat = statSync(child);
|
|
41
|
+
} catch {
|
|
42
|
+
broken = true;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const path = rel === "" ? name : `${rel}/${name}`;
|
|
46
|
+
if (stat.isDirectory()) {
|
|
47
|
+
walk(child, path, depth + 1);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (!stat.isFile()) continue;
|
|
51
|
+
const sha256 = hashFile(child);
|
|
52
|
+
if (sha256 === null) {
|
|
53
|
+
broken = true;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
assets.push({
|
|
57
|
+
path,
|
|
58
|
+
sha256
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
walk(root, "", 0);
|
|
63
|
+
if (broken) return null;
|
|
64
|
+
assets.sort((a, b) => a.path.localeCompare(b.path));
|
|
65
|
+
return {
|
|
66
|
+
version: 1,
|
|
67
|
+
assets
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function parseAssetManifest(text) {
|
|
71
|
+
let parsed;
|
|
72
|
+
try {
|
|
73
|
+
parsed = JSON.parse(String(text));
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const obj = parsed;
|
|
78
|
+
if (!obj || obj.version !== 1 || !Array.isArray(obj.assets)) return null;
|
|
79
|
+
const assets = [];
|
|
80
|
+
for (const raw of obj.assets) {
|
|
81
|
+
const entry = raw;
|
|
82
|
+
if (typeof entry?.path !== "string" || typeof entry?.sha256 !== "string") return null;
|
|
83
|
+
assets.push({
|
|
84
|
+
path: entry.path,
|
|
85
|
+
sha256: entry.sha256
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
version: 1,
|
|
90
|
+
assets
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function pickGeneratedResDir(names, variant, reactChildren = []) {
|
|
94
|
+
const wanted = (variant ?? "").trim().toLowerCase();
|
|
95
|
+
const modern = names.filter((n) => /^createBundle.+JsAndAssets$/.test(n)).toSorted();
|
|
96
|
+
if (wanted) {
|
|
97
|
+
const match = modern.find((n) => n.toLowerCase() === `createbundle${wanted}jsandassets`);
|
|
98
|
+
if (match) return match;
|
|
99
|
+
} else if (modern.length === 1) return modern[0];
|
|
100
|
+
if (!names.includes("react")) return null;
|
|
101
|
+
const children = reactChildren.toSorted();
|
|
102
|
+
if (wanted) {
|
|
103
|
+
const match = children.find((n) => n.toLowerCase() === wanted);
|
|
104
|
+
if (match) return `react/${match}`;
|
|
105
|
+
} else if (children.length === 1) return `react/${children[0]}`;
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
function androidModuleDirs(root, { list = safeList } = {}) {
|
|
109
|
+
const android = join(root, "android");
|
|
110
|
+
return ["app", ...list(android).filter((name) => name !== "app" && existsSync(join(android, name, "build", "generated", "res"))).toSorted()];
|
|
111
|
+
}
|
|
112
|
+
function findGeneratedResDir(root, variant, { list = safeList } = {}) {
|
|
113
|
+
for (const module of androidModuleDirs(root, { list })) {
|
|
114
|
+
const base = join(root, "android", module, "build", "generated", "res");
|
|
115
|
+
const names = list(base);
|
|
116
|
+
if (names.length === 0) continue;
|
|
117
|
+
const picked = pickGeneratedResDir(names, variant, names.includes("react") ? list(join(base, "react")) : []);
|
|
118
|
+
if (picked) return join(base, ...picked.split("/"));
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function captureAssetManifest(root, { variant = null, findDir = findGeneratedResDir, read = readAssetManifest } = {}) {
|
|
123
|
+
const dir = findDir(root, variant);
|
|
124
|
+
return dir ? read(dir) : null;
|
|
125
|
+
}
|
|
126
|
+
function compareAssetManifests(fresh, stored) {
|
|
127
|
+
const left = new Map(fresh.assets.map((a) => [a.path, a.sha256]));
|
|
128
|
+
const right = new Map(stored.assets.map((a) => [a.path, a.sha256]));
|
|
129
|
+
const added = [];
|
|
130
|
+
const changed = [];
|
|
131
|
+
const removed = [];
|
|
132
|
+
for (const [path, sha256] of left) if (!right.has(path)) added.push(path);
|
|
133
|
+
else if (right.get(path) !== sha256) changed.push(path);
|
|
134
|
+
for (const path of right.keys()) if (!left.has(path)) removed.push(path);
|
|
135
|
+
added.sort();
|
|
136
|
+
changed.sort();
|
|
137
|
+
removed.sort();
|
|
138
|
+
return {
|
|
139
|
+
same: added.length === 0 && changed.length === 0 && removed.length === 0,
|
|
140
|
+
added,
|
|
141
|
+
removed,
|
|
142
|
+
changed,
|
|
143
|
+
example: added[0] ?? changed[0] ?? removed[0] ?? null
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function assetDiffReason(diff) {
|
|
147
|
+
const which = diff.added.length ? "added" : diff.changed.length ? "changed" : "removed";
|
|
148
|
+
return `this workspace emits a different asset set than the cached build did (${diff.added.length} added, ${diff.changed.length} changed, ${diff.removed.length} removed; e.g. ${which} ${diff.example})`;
|
|
149
|
+
}
|
|
150
|
+
function safeList(dir) {
|
|
151
|
+
try {
|
|
152
|
+
return readdirSync(dir);
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/cache/build-cache.ts
|
|
159
|
+
function entryDir(platform, key, root = sharedBuildCache()) {
|
|
160
|
+
return join$1(root, platform, key);
|
|
161
|
+
}
|
|
162
|
+
const FINGERPRINT_PLATFORMS = /* @__PURE__ */ new Set(["ios", "android"]);
|
|
163
|
+
/**
|
|
164
|
+
* Paths that exist in a working checkout and not in a fresh one, which
|
|
165
|
+
* @expo/fingerprint does not ignore on its own. A fingerprint that counts them
|
|
166
|
+
* cannot match across checkouts, which is the parity failure `doctor` reports.
|
|
167
|
+
*
|
|
168
|
+
* The list stays narrow on purpose: a path belongs here only when no native
|
|
169
|
+
* build on any project can read it. Anything a single project can judge --
|
|
170
|
+
* a lockfile with machine paths, a generated report -- belongs in that
|
|
171
|
+
* project's `.fingerprintignore`, which still applies on top of this.
|
|
172
|
+
*/
|
|
173
|
+
const DEFAULT_FINGERPRINT_IGNORES = ["**/android/local.properties", "**/android/.idea/**"];
|
|
174
|
+
async function fingerprintProject(projectRoot, { platform, createFingerprint = expoFingerprint.createFingerprintAsync, debug = false } = {}) {
|
|
175
|
+
const result = await createFingerprint(projectRoot, {
|
|
176
|
+
...platform && FINGERPRINT_PLATFORMS.has(platform) ? { platforms: [platform] } : void 0,
|
|
177
|
+
...debug ? { debug } : {},
|
|
178
|
+
ignorePaths: DEFAULT_FINGERPRINT_IGNORES,
|
|
179
|
+
silent: true
|
|
180
|
+
});
|
|
181
|
+
const hash = result?.hash ?? null;
|
|
182
|
+
if (!hash) return null;
|
|
183
|
+
return {
|
|
184
|
+
hash,
|
|
185
|
+
sources: Array.isArray(result?.sources) ? result.sources : []
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function registerOnce(root) {
|
|
189
|
+
try {
|
|
190
|
+
register({
|
|
191
|
+
dir: root,
|
|
192
|
+
name: "Build cache",
|
|
193
|
+
prune: "entries",
|
|
194
|
+
entriesDepth: 2,
|
|
195
|
+
note: "built .app/.apk keyed on the native fingerprint"
|
|
196
|
+
});
|
|
197
|
+
} catch {}
|
|
198
|
+
}
|
|
199
|
+
function resolveBuild(platform, key, root = sharedBuildCache()) {
|
|
200
|
+
return resolveArtifact(entryDir(platform, key, root));
|
|
201
|
+
}
|
|
202
|
+
function storeBuild(platform, key, buildPath, rootOrOptions = {}) {
|
|
203
|
+
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions || {};
|
|
204
|
+
const root = options.root || sharedBuildCache();
|
|
205
|
+
if (!buildPath || !existsSync$1(buildPath)) throw new Error(`No build to store at ${buildPath}`);
|
|
206
|
+
registerOnce(root);
|
|
207
|
+
return storeArtifact(entryDir(platform, key, root), buildPath, {
|
|
208
|
+
runFile: getExecutor().runFile,
|
|
209
|
+
overwrite: Boolean(options.overwrite),
|
|
210
|
+
writeMetadata: (staging) => {
|
|
211
|
+
if (Array.isArray(options.sources)) try {
|
|
212
|
+
writeFileSync$1(join$1(staging, SOURCES_FILE), JSON.stringify(options.sources));
|
|
213
|
+
} catch {}
|
|
214
|
+
if (options.assetManifest) try {
|
|
215
|
+
writeFileSync$1(join$1(staging, ASSET_MANIFEST_FILE), JSON.stringify(options.assetManifest));
|
|
216
|
+
} catch {}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const PROVIDER_DOWNLOAD_DIR = "cache-provider";
|
|
221
|
+
function providerDownloadPath(workspacePath) {
|
|
222
|
+
return join$1(workspacePath, PROVIDER_DOWNLOAD_DIR);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Empties and registers the scratch directory a provider downloads into. It is
|
|
226
|
+
* created only when a provider is about to be asked, and registered so `gc`
|
|
227
|
+
* reports what an interrupted run left behind.
|
|
228
|
+
*/
|
|
229
|
+
function prepareProviderDownloadDir(dir) {
|
|
230
|
+
rmSync$1(dir, {
|
|
231
|
+
recursive: true,
|
|
232
|
+
force: true
|
|
233
|
+
});
|
|
234
|
+
mkdirSync$1(dir, { recursive: true });
|
|
235
|
+
try {
|
|
236
|
+
register({
|
|
237
|
+
dir,
|
|
238
|
+
name: "Cache provider downloads",
|
|
239
|
+
prune: "entries",
|
|
240
|
+
entriesDepth: 1,
|
|
241
|
+
note: "artifacts fetched from the project cache provider; anything left here is from an interrupted run"
|
|
242
|
+
});
|
|
243
|
+
} catch {}
|
|
244
|
+
}
|
|
245
|
+
function filesystemBuildCapability({ root, sources, assetManifest, resolve = resolveBuild, store = storeBuild } = {}) {
|
|
246
|
+
const stored = {
|
|
247
|
+
...root === void 0 ? {} : { root },
|
|
248
|
+
...sources === void 0 ? {} : { sources },
|
|
249
|
+
...assetManifest === void 0 ? {} : { assetManifest }
|
|
250
|
+
};
|
|
251
|
+
return {
|
|
252
|
+
resolve: ({ platform, key }) => root === void 0 ? resolve(platform, key) : resolve(platform, key, root),
|
|
253
|
+
store: ({ platform, key, sourcePath, overwrite }) => store(platform, key, sourcePath, {
|
|
254
|
+
...stored,
|
|
255
|
+
overwrite
|
|
256
|
+
})
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function providerUploadOutcome(result, name) {
|
|
260
|
+
if (!result) return null;
|
|
261
|
+
const label = name || "the cache provider";
|
|
262
|
+
if (result.timedOut) return {
|
|
263
|
+
line: `${label} upload was cancelled after ${buildUploadTimeoutMs()}ms`,
|
|
264
|
+
warn: true
|
|
265
|
+
};
|
|
266
|
+
if (result.failed) return {
|
|
267
|
+
line: `${label} upload failed: ${result.failed}`,
|
|
268
|
+
warn: true
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
line: `uploaded (${label})`,
|
|
272
|
+
warn: false
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const SOURCES_FILE = "fingerprint-sources.json";
|
|
276
|
+
function storedSources(platform, key, root = sharedBuildCache()) {
|
|
277
|
+
try {
|
|
278
|
+
const parsed = JSON.parse(readFileSync$1(join$1(entryDir(platform, key, root), SOURCES_FILE), "utf-8"));
|
|
279
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function storedAssetManifest(platform, key, root = sharedBuildCache()) {
|
|
285
|
+
try {
|
|
286
|
+
return parseAssetManifest(readFileSync$1(join$1(entryDir(platform, key, root), ASSET_MANIFEST_FILE), "utf-8"));
|
|
287
|
+
} catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function sourceName(source) {
|
|
292
|
+
const s = source;
|
|
293
|
+
if (typeof s?.filePath === "string" && s.filePath !== "") return s.filePath;
|
|
294
|
+
if (typeof s?.id === "string" && s.id !== "") return s.id;
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
function diffItemName(item) {
|
|
298
|
+
const o = item;
|
|
299
|
+
for (const candidate of [
|
|
300
|
+
o,
|
|
301
|
+
o?.addedSource,
|
|
302
|
+
o?.removedSource,
|
|
303
|
+
o?.afterSource,
|
|
304
|
+
o?.beforeSource
|
|
305
|
+
]) {
|
|
306
|
+
const name = sourceName(candidate);
|
|
307
|
+
if (name) return name;
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
function compareSourceLists(previous, current) {
|
|
312
|
+
const previousByName = /* @__PURE__ */ new Map();
|
|
313
|
+
for (const source of previous) {
|
|
314
|
+
const name = sourceName(source);
|
|
315
|
+
if (name !== null) previousByName.set(name, source.hash ?? null);
|
|
316
|
+
}
|
|
317
|
+
const changed = [];
|
|
318
|
+
const seen = /* @__PURE__ */ new Set();
|
|
319
|
+
for (const source of current) {
|
|
320
|
+
const name = sourceName(source);
|
|
321
|
+
if (name === null || seen.has(name)) continue;
|
|
322
|
+
seen.add(name);
|
|
323
|
+
const hash = source.hash;
|
|
324
|
+
if (!previousByName.has(name) || previousByName.get(name) !== (hash ?? null)) changed.push(name);
|
|
325
|
+
}
|
|
326
|
+
for (const [name] of previousByName) if (!seen.has(name)) changed.push(name);
|
|
327
|
+
return changed;
|
|
328
|
+
}
|
|
329
|
+
function diffFingerprintSources({ previous, previousHash = null, current, differ = null }) {
|
|
330
|
+
if (typeof differ === "function") try {
|
|
331
|
+
const items = differ({
|
|
332
|
+
sources: previous,
|
|
333
|
+
hash: previousHash ?? ""
|
|
334
|
+
}, {
|
|
335
|
+
sources: current.sources,
|
|
336
|
+
hash: current.hash
|
|
337
|
+
});
|
|
338
|
+
if (Array.isArray(items)) {
|
|
339
|
+
const names = [];
|
|
340
|
+
const seen = /* @__PURE__ */ new Set();
|
|
341
|
+
for (const item of items) {
|
|
342
|
+
const name = diffItemName(item);
|
|
343
|
+
if (name !== null && !seen.has(name)) {
|
|
344
|
+
seen.add(name);
|
|
345
|
+
names.push(name);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return names;
|
|
349
|
+
}
|
|
350
|
+
} catch {}
|
|
351
|
+
return compareSourceLists(previous, current.sources);
|
|
352
|
+
}
|
|
353
|
+
function fingerprintDiffSuffix(changed) {
|
|
354
|
+
if (!changed.length) return "";
|
|
355
|
+
const shown = changed.slice(0, 3).join(", ");
|
|
356
|
+
return ` -- ${changed.length} source${changed.length === 1 ? "" : "s"} changed: ${shown}`;
|
|
357
|
+
}
|
|
358
|
+
function describeFingerprintMiss({ platform, current, lastBuild, root = sharedBuildCache(), differ = expoFingerprint.diffFingerprints }) {
|
|
359
|
+
if (!lastBuild || lastBuild.platform !== platform) return null;
|
|
360
|
+
const previousHash = typeof lastBuild.fingerprint === "string" ? lastBuild.fingerprint : null;
|
|
361
|
+
const previousKey = typeof lastBuild.cacheKey === "string" ? lastBuild.cacheKey : null;
|
|
362
|
+
if (!previousHash || !previousKey || previousHash === current.hash) return null;
|
|
363
|
+
const previous = storedSources(platform, previousKey, root);
|
|
364
|
+
if (!previous) return null;
|
|
365
|
+
const changed = diffFingerprintSources({
|
|
366
|
+
previous,
|
|
367
|
+
previousHash,
|
|
368
|
+
current,
|
|
369
|
+
differ
|
|
370
|
+
});
|
|
371
|
+
return changed.length ? {
|
|
372
|
+
changed,
|
|
373
|
+
previousHash
|
|
374
|
+
} : null;
|
|
375
|
+
}
|
|
376
|
+
async function refingerprintAfterMutation({ projectRoot, platform, previousHash, fingerprint = fingerprintProject }) {
|
|
377
|
+
let computed = null;
|
|
378
|
+
try {
|
|
379
|
+
computed = await fingerprint(projectRoot, { platform });
|
|
380
|
+
} catch {
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
if (!computed?.hash) return null;
|
|
384
|
+
return {
|
|
385
|
+
hash: computed.hash,
|
|
386
|
+
sources: computed.sources,
|
|
387
|
+
moved: computed.hash !== previousHash
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function untrackedNativeFiles({ projectRoot, exec = getExecutor() }) {
|
|
391
|
+
let out;
|
|
392
|
+
try {
|
|
393
|
+
out = exec.runFile("git", [
|
|
394
|
+
"-C",
|
|
395
|
+
projectRoot,
|
|
396
|
+
"ls-files",
|
|
397
|
+
"--others",
|
|
398
|
+
"--exclude-standard",
|
|
399
|
+
"--",
|
|
400
|
+
"ios",
|
|
401
|
+
"android"
|
|
402
|
+
]);
|
|
403
|
+
} catch {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
return String(out || "").split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
407
|
+
}
|
|
408
|
+
function untrackedMissLine(files, cap = 3) {
|
|
409
|
+
if (!Array.isArray(files) || files.length === 0) return null;
|
|
410
|
+
const shown = files.slice(0, cap);
|
|
411
|
+
const more = files.length > shown.length ? `, and ${files.length - shown.length} more` : "";
|
|
412
|
+
return `no previous entry to diff against; ${files.length} untracked file${files.length === 1 ? "" : "s"} under ios/ or android/ are hashed like any other source: ${shown.join(", ")}${more} -- list the build-irrelevant ones in .fingerprintignore`;
|
|
413
|
+
}
|
|
414
|
+
function fingerprintDiffRecord({ changed, previousHash, hash }) {
|
|
415
|
+
const shown = changed.slice(0, 20);
|
|
416
|
+
return {
|
|
417
|
+
src: "build",
|
|
418
|
+
level: "info",
|
|
419
|
+
event: "fingerprint_diff",
|
|
420
|
+
msg: `fingerprint ${previousHash} -> ${hash}: ${changed.length} source${changed.length === 1 ? "" : "s"} changed: ` + shown.join(", ") + (changed.length > shown.length ? `, and ${changed.length - shown.length} more` : ""),
|
|
421
|
+
changed: changed.length,
|
|
422
|
+
sources: shown
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/engine/build-lock.ts
|
|
427
|
+
const LOCK_SUFFIX = ".lock";
|
|
428
|
+
const WAIT_POLL_MS = 1e3;
|
|
429
|
+
const WAIT_PROGRESS_MS = 3e4;
|
|
430
|
+
const WAIT_CEILING_MS = 54e5;
|
|
431
|
+
function sleepAsync(ms) {
|
|
432
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
433
|
+
}
|
|
434
|
+
function segment(value) {
|
|
435
|
+
return String(value).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^\.+/, "") || "unknown";
|
|
436
|
+
}
|
|
437
|
+
function buildLocksDir() {
|
|
438
|
+
return join(getConfigDir(), "build-locks");
|
|
439
|
+
}
|
|
440
|
+
function buildLockPath(platform, key) {
|
|
441
|
+
return join(buildLocksDir(), `${segment(platform)}-${segment(key)}${LOCK_SUFFIX}`);
|
|
442
|
+
}
|
|
443
|
+
function label(platform) {
|
|
444
|
+
return `${platform} build`;
|
|
445
|
+
}
|
|
446
|
+
function toRecord(holder) {
|
|
447
|
+
const details = holder.details;
|
|
448
|
+
return {
|
|
449
|
+
pid: holder.owner.pid,
|
|
450
|
+
projectRoot: typeof details.projectRoot === "string" ? details.projectRoot : null,
|
|
451
|
+
startedAt: holder.startedAt || null,
|
|
452
|
+
logFile: typeof details.logFile === "string" ? details.logFile : null
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function readBuildLock(pathOrSpec) {
|
|
456
|
+
const path = typeof pathOrSpec === "string" ? pathOrSpec : buildLockPath(pathOrSpec.platform, pathOrSpec.key);
|
|
457
|
+
const survey = (0, ownership_claim_exports.readClaimSet)(path);
|
|
458
|
+
const holder = survey.live[0] ?? survey.dead[0];
|
|
459
|
+
return holder ? toRecord(holder) : null;
|
|
460
|
+
}
|
|
461
|
+
function acquireBuildLock({ platform, key, root = null, logFile = null }) {
|
|
462
|
+
const path = buildLockPath(platform, key);
|
|
463
|
+
const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
|
|
464
|
+
root: path,
|
|
465
|
+
mode: "exclusive",
|
|
466
|
+
label: label(platform),
|
|
467
|
+
details: {
|
|
468
|
+
projectRoot: root,
|
|
469
|
+
logFile
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
const reaped = attempt.reaped[0];
|
|
473
|
+
if (attempt.acquired) {
|
|
474
|
+
const handle = {
|
|
475
|
+
acquired: true,
|
|
476
|
+
path,
|
|
477
|
+
lock: {
|
|
478
|
+
pid: attempt.acquired.owner.pid,
|
|
479
|
+
projectRoot: root,
|
|
480
|
+
startedAt: attempt.acquired.startedAt,
|
|
481
|
+
logFile
|
|
482
|
+
},
|
|
483
|
+
claim: attempt.acquired
|
|
484
|
+
};
|
|
485
|
+
return reaped ? {
|
|
486
|
+
...handle,
|
|
487
|
+
tookOver: toRecord(reaped)
|
|
488
|
+
} : handle;
|
|
489
|
+
}
|
|
490
|
+
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
491
|
+
const holder = attempt.held ?? attempt.waitingFor?.[0];
|
|
492
|
+
return holder ? {
|
|
493
|
+
held: toRecord(holder),
|
|
494
|
+
path
|
|
495
|
+
} : { path };
|
|
496
|
+
}
|
|
497
|
+
function releaseBuildLock(handle) {
|
|
498
|
+
return (0, ownership_claim_exports.releaseClaim)(handle?.claim);
|
|
499
|
+
}
|
|
500
|
+
function listBuildLocks() {
|
|
501
|
+
const dir = buildLocksDir();
|
|
502
|
+
let names;
|
|
503
|
+
try {
|
|
504
|
+
names = readdirSync(dir);
|
|
505
|
+
} catch {
|
|
506
|
+
return [];
|
|
507
|
+
}
|
|
508
|
+
const locks = [];
|
|
509
|
+
for (const name of names) {
|
|
510
|
+
if (!name.endsWith(LOCK_SUFFIX)) continue;
|
|
511
|
+
const path = join(dir, name);
|
|
512
|
+
try {
|
|
513
|
+
if (!statSync(path).isDirectory()) continue;
|
|
514
|
+
} catch {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const stem = name.slice(0, -5);
|
|
518
|
+
const cut = stem.indexOf("-");
|
|
519
|
+
const survey = (0, ownership_claim_exports.readClaimSet)(path);
|
|
520
|
+
const holder = survey.live[0] ?? survey.dead[0];
|
|
521
|
+
const info = holder ? toRecord(holder) : null;
|
|
522
|
+
locks.push({
|
|
523
|
+
path,
|
|
524
|
+
name,
|
|
525
|
+
platform: cut > 0 ? stem.slice(0, cut) : stem,
|
|
526
|
+
key: cut > 0 ? stem.slice(cut + 1) : null,
|
|
527
|
+
pid: info?.pid ?? null,
|
|
528
|
+
projectRoot: info?.projectRoot ?? null,
|
|
529
|
+
startedAt: info?.startedAt ?? null,
|
|
530
|
+
logFile: info?.logFile ?? null,
|
|
531
|
+
alive: survey.live.length > 0,
|
|
532
|
+
unresolved: survey.unresolved.length > 0
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
return locks;
|
|
536
|
+
}
|
|
537
|
+
function waitingLine({ projectRoot, pid, elapsedMs, logFile }) {
|
|
538
|
+
const where = projectRoot || "another workspace";
|
|
539
|
+
const tail = logFile ? ` -- tail ${logFile}` : "";
|
|
540
|
+
return `${"build".padEnd(11)} waiting on ${where} (pid ${pid ?? "?"}, ${formatElapsed(elapsedMs)} elapsed)${tail} -- stim guide lifecycle concurrency`;
|
|
541
|
+
}
|
|
542
|
+
function takeoverLine({ projectRoot, pid, logFile, startedAt = null, now = Date.now }) {
|
|
543
|
+
const where = projectRoot || "another workspace";
|
|
544
|
+
const started = startedAt ? Date.parse(startedAt) : NaN;
|
|
545
|
+
const ago = Number.isFinite(started) ? ` (it started ${formatElapsed(now() - started)} ago)` : "";
|
|
546
|
+
const tail = logFile ? ` -- read ${logFile} before this one finishes` : "";
|
|
547
|
+
return `RETRY: ${where}'s build of this fingerprint (pid ${pid ?? "?"}) FAILED without an artifact${ago}, and this run rebuilds the SAME inputs, so expect the same failure unless something changed${tail}`;
|
|
548
|
+
}
|
|
549
|
+
async function waitForBuild({ platform, key, resolve = resolveBuild, intervalMs = WAIT_POLL_MS, progressMs = WAIT_PROGRESS_MS, ceilingMs = WAIT_CEILING_MS, out = () => {}, now = Date.now, sleep = sleepAsync }) {
|
|
550
|
+
const path = buildLockPath(platform, key);
|
|
551
|
+
const started = now();
|
|
552
|
+
let lastProgress = started;
|
|
553
|
+
let holder = readBuildLock(path);
|
|
554
|
+
for (;;) {
|
|
555
|
+
const hit = resolve(platform, key);
|
|
556
|
+
if (hit) return {
|
|
557
|
+
hit,
|
|
558
|
+
waitedMs: now() - started
|
|
559
|
+
};
|
|
560
|
+
const survey = (0, ownership_claim_exports.readClaimSet)(path);
|
|
561
|
+
const unresolved = survey.unresolved[0];
|
|
562
|
+
if (unresolved) throw new ownership_claim_exports.ClaimRefusedError({
|
|
563
|
+
claimPath: unresolved.path,
|
|
564
|
+
root: path,
|
|
565
|
+
label: label(platform),
|
|
566
|
+
reason: unresolved.reason
|
|
567
|
+
});
|
|
568
|
+
const live = survey.live[0];
|
|
569
|
+
if (live) holder = toRecord(live);
|
|
570
|
+
else {
|
|
571
|
+
const dead = survey.dead[0];
|
|
572
|
+
if (dead) return {
|
|
573
|
+
builderFailed: `the builder (pid ${dead.owner.pid}) is gone`,
|
|
574
|
+
holder: toRecord(dead),
|
|
575
|
+
waitedMs: now() - started
|
|
576
|
+
};
|
|
577
|
+
return {
|
|
578
|
+
lockReleased: true,
|
|
579
|
+
holder,
|
|
580
|
+
waitedMs: now() - started
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const elapsed = now() - started;
|
|
584
|
+
if (elapsed >= ceilingMs) {
|
|
585
|
+
const err = /* @__PURE__ */ new Error(`Waited ${formatElapsed(elapsed)} for ${holder?.projectRoot || "another workspace"}'s ${platform} build of ${key} without an artifact, and pid ${holder?.pid} is still the live holder. The lock is ${path}; remove it if that process is not really building:\n ${(0, ownership_claim_exports.claimRemoveCommand)(path)}`);
|
|
586
|
+
err.code = "STIM_BUILD_WAIT_TIMEOUT";
|
|
587
|
+
err.lockPath = path;
|
|
588
|
+
err.holder = holder ?? void 0;
|
|
589
|
+
throw err;
|
|
590
|
+
}
|
|
591
|
+
if (now() - lastProgress >= progressMs) {
|
|
592
|
+
lastProgress = now();
|
|
593
|
+
out(waitingLine({
|
|
594
|
+
projectRoot: holder.projectRoot,
|
|
595
|
+
pid: holder.pid,
|
|
596
|
+
elapsedMs: elapsed,
|
|
597
|
+
logFile: holder.logFile
|
|
598
|
+
}));
|
|
599
|
+
}
|
|
600
|
+
await sleep(intervalMs);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
//#endregion
|
|
604
|
+
export { untrackedNativeFiles as C, readAssetManifest as D, compareAssetManifests as E, untrackedMissLine as S, captureAssetManifest as T, providerUploadOutcome as _, segment as a, storeBuild as b, buildCacheKey as c, filesystemBuildCapability as d, fingerprintDiffRecord as f, providerDownloadPath as g, prepareProviderDownloadDir as h, releaseBuildLock as i, describeFingerprintMiss as l, fingerprintProject as m, acquireBuildLock as n, takeoverLine as o, fingerprintDiffSuffix as p, listBuildLocks as r, waitForBuild as s, WAIT_CEILING_MS as t, diffFingerprintSources as u, refingerprintAfterMutation as v, assetDiffReason as w, storedAssetManifest as x, resolveBuild as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as ownership_claim_exports, u as getConfigDir } from "./config-
|
|
2
|
-
import { a as formatElapsed } from "./command-output-
|
|
1
|
+
import { E as ownership_claim_exports, u as getConfigDir } from "./config-B7iyKWkL.mjs";
|
|
2
|
+
import { a as formatElapsed } from "./command-output-B3ycpsYv.mjs";
|
|
3
3
|
import { readdirSync, statSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
//#region src/engine/build-slots.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { u as getConfigDir } from "./config-
|
|
1
|
+
import { u as getConfigDir } from "./config-B7iyKWkL.mjs";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import { join, resolve } from "path";
|
|
5
5
|
import { readCacheManifest, updateCacheManifest } from "@stim-cli/core";
|
|
6
|
-
//#region src/cache-manifest.ts
|
|
6
|
+
//#region src/cache/cache-manifest.ts
|
|
7
7
|
function manifestPath() {
|
|
8
8
|
return join(getConfigDir(), "caches.json");
|
|
9
9
|
}
|
package/dist/cache-manifest.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-
|
|
1
|
+
import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-CYJi8-Hx.mjs";
|
|
2
2
|
export { manifestPath, readManifest, register, registeredCaches, unregister };
|
package/dist/cli.mjs
CHANGED
|
@@ -3,20 +3,20 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
//#region bin/cli.ts
|
|
5
5
|
const commands = /* @__PURE__ */ new Map([
|
|
6
|
-
["doctor", () => import("./doctor-
|
|
7
|
-
["worktree", () => import("./worktree-
|
|
8
|
-
["start", () => import("./start-
|
|
9
|
-
["ports", () => import("./ports-
|
|
10
|
-
["stop", () => import("./stop-
|
|
11
|
-
["ios", () => import("./ios-
|
|
12
|
-
["android", () => import("./android-
|
|
13
|
-
["reload", () => import("./reload-
|
|
14
|
-
["device", () => import("./device-
|
|
15
|
-
["logs", () => import("./logs-
|
|
16
|
-
["status", () => import("./status-
|
|
17
|
-
["stats", () => import("./stats-
|
|
18
|
-
["gc", () => import("./gc-
|
|
19
|
-
["guide", () => import("./guide-
|
|
6
|
+
["doctor", () => import("./doctor-CTAx9gMu.mjs")],
|
|
7
|
+
["worktree", () => import("./worktree-BfE4lzHK.mjs")],
|
|
8
|
+
["start", () => import("./start-TTVILlUi.mjs")],
|
|
9
|
+
["ports", () => import("./ports-BIbJaKNW.mjs")],
|
|
10
|
+
["stop", () => import("./stop-CnUpnFT5.mjs")],
|
|
11
|
+
["ios", () => import("./ios-BRXYSxSc.mjs")],
|
|
12
|
+
["android", () => import("./android-Da-G_o3n.mjs")],
|
|
13
|
+
["reload", () => import("./reload-ChW46VDb.mjs")],
|
|
14
|
+
["device", () => import("./device-CBSaC6BU.mjs")],
|
|
15
|
+
["logs", () => import("./logs-CakdBTtm.mjs")],
|
|
16
|
+
["status", () => import("./status-DUNy_HZs.mjs")],
|
|
17
|
+
["stats", () => import("./stats-CLg5RuDS.mjs")],
|
|
18
|
+
["gc", () => import("./gc-CX0KRfLG.mjs")],
|
|
19
|
+
["guide", () => import("./guide-CPmAG9me.mjs")]
|
|
20
20
|
]);
|
|
21
21
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
22
22
|
const program = new Command();
|
package/dist/collector-run.d.mts
CHANGED
|
@@ -15,6 +15,8 @@ interface Executor {
|
|
|
15
15
|
runQuiet(cmd: string, opts?: ExecOptions): string | null;
|
|
16
16
|
runFileQuiet(file: string, args?: string[], opts?: ExecOptions): string | null;
|
|
17
17
|
spawn(cmd: string, args?: readonly string[], opts?: SpawnOptions): ChildProcess;
|
|
18
|
+
/** Absolute path of `name` on PATH, or null. Windows resolves PATH through PATHEXT. */
|
|
19
|
+
findExecutable(name: string): string | null;
|
|
18
20
|
}
|
|
19
21
|
//#endregion
|
|
20
22
|
//#region src/collector/android.d.ts
|