stim 1.8.0 → 1.9.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 +23 -155
- package/dist/{android-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as register } from "./cache-manifest-
|
|
4
|
-
import {
|
|
5
|
-
import { a as formatElapsed } from "./command-output-
|
|
1
|
+
import { k as ownership_claim_exports, u as getConfigDir } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
3
|
+
import { r as register } from "./cache-manifest-Dg7OnMrp.mjs";
|
|
4
|
+
import { d as sharedBuildCache } from "./workspace-state-DF2gCFhx.mjs";
|
|
5
|
+
import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-gByVmIjy.mjs";
|
|
6
|
+
import { r as stopDeclaringSpawnsOn, t as declareSpawnsOn } from "./spawn-claims-Dn3C_N6w.mjs";
|
|
6
7
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
7
|
-
import { createHash } from "node:crypto";
|
|
8
|
-
import { join } from "node:path";
|
|
9
8
|
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
|
|
9
|
+
import { join } from "path";
|
|
11
10
|
import { buildCacheKey, resolveArtifact, storeArtifact } from "@stim-cli/core";
|
|
11
|
+
import { join as join$1 } from "node:path";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
12
13
|
import * as expoFingerprint from "@expo/fingerprint";
|
|
13
14
|
import { buildUploadTimeoutMs } from "@stim-cli/cache";
|
|
14
15
|
const ASSET_MANIFEST_FILE = "assets-manifest.json";
|
|
@@ -34,7 +35,7 @@ function readAssetManifest(root) {
|
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
36
37
|
for (const name of names) {
|
|
37
|
-
const child = join(abs, name);
|
|
38
|
+
const child = join$1(abs, name);
|
|
38
39
|
let stat;
|
|
39
40
|
try {
|
|
40
41
|
stat = statSync(child);
|
|
@@ -106,16 +107,16 @@ function pickGeneratedResDir(names, variant, reactChildren = []) {
|
|
|
106
107
|
return null;
|
|
107
108
|
}
|
|
108
109
|
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()];
|
|
110
|
+
const android = join$1(root, "android");
|
|
111
|
+
return ["app", ...list(android).filter((name) => name !== "app" && existsSync(join$1(android, name, "build", "generated", "res"))).toSorted()];
|
|
111
112
|
}
|
|
112
113
|
function findGeneratedResDir(root, variant, { list = safeList } = {}) {
|
|
113
114
|
for (const module of androidModuleDirs(root, { list })) {
|
|
114
|
-
const base = join(root, "android", module, "build", "generated", "res");
|
|
115
|
+
const base = join$1(root, "android", module, "build", "generated", "res");
|
|
115
116
|
const names = list(base);
|
|
116
117
|
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("/"));
|
|
118
|
+
const picked = pickGeneratedResDir(names, variant, names.includes("react") ? list(join$1(base, "react")) : []);
|
|
119
|
+
if (picked) return join$1(base, ...picked.split("/"));
|
|
119
120
|
}
|
|
120
121
|
return null;
|
|
121
122
|
}
|
|
@@ -157,7 +158,7 @@ function safeList(dir) {
|
|
|
157
158
|
//#endregion
|
|
158
159
|
//#region src/cache/build-cache.ts
|
|
159
160
|
function entryDir(platform, key, root = sharedBuildCache()) {
|
|
160
|
-
return join
|
|
161
|
+
return join(root, platform, key);
|
|
161
162
|
}
|
|
162
163
|
const FINGERPRINT_PLATFORMS = /* @__PURE__ */ new Set(["ios", "android"]);
|
|
163
164
|
/**
|
|
@@ -209,17 +210,17 @@ function storeBuild(platform, key, buildPath, rootOrOptions = {}) {
|
|
|
209
210
|
overwrite: Boolean(options.overwrite),
|
|
210
211
|
writeMetadata: (staging) => {
|
|
211
212
|
if (Array.isArray(options.sources)) try {
|
|
212
|
-
writeFileSync$1(join
|
|
213
|
+
writeFileSync$1(join(staging, SOURCES_FILE), JSON.stringify(options.sources));
|
|
213
214
|
} catch {}
|
|
214
215
|
if (options.assetManifest) try {
|
|
215
|
-
writeFileSync$1(join
|
|
216
|
+
writeFileSync$1(join(staging, ASSET_MANIFEST_FILE), JSON.stringify(options.assetManifest));
|
|
216
217
|
} catch {}
|
|
217
218
|
}
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
221
|
const PROVIDER_DOWNLOAD_DIR = "cache-provider";
|
|
221
222
|
function providerDownloadPath(workspacePath) {
|
|
222
|
-
return join
|
|
223
|
+
return join(workspacePath, PROVIDER_DOWNLOAD_DIR);
|
|
223
224
|
}
|
|
224
225
|
/**
|
|
225
226
|
* Empties and registers the scratch directory a provider downloads into. It is
|
|
@@ -275,7 +276,7 @@ function providerUploadOutcome(result, name) {
|
|
|
275
276
|
const SOURCES_FILE = "fingerprint-sources.json";
|
|
276
277
|
function storedSources(platform, key, root = sharedBuildCache()) {
|
|
277
278
|
try {
|
|
278
|
-
const parsed = JSON.parse(readFileSync$1(join
|
|
279
|
+
const parsed = JSON.parse(readFileSync$1(join(entryDir(platform, key, root), SOURCES_FILE), "utf-8"));
|
|
279
280
|
return Array.isArray(parsed) ? parsed : null;
|
|
280
281
|
} catch {
|
|
281
282
|
return null;
|
|
@@ -283,7 +284,7 @@ function storedSources(platform, key, root = sharedBuildCache()) {
|
|
|
283
284
|
}
|
|
284
285
|
function storedAssetManifest(platform, key, root = sharedBuildCache()) {
|
|
285
286
|
try {
|
|
286
|
-
return parseAssetManifest(readFileSync$1(join
|
|
287
|
+
return parseAssetManifest(readFileSync$1(join(entryDir(platform, key, root), ASSET_MANIFEST_FILE), "utf-8"));
|
|
287
288
|
} catch {
|
|
288
289
|
return null;
|
|
289
290
|
}
|
|
@@ -435,10 +436,10 @@ function segment(value) {
|
|
|
435
436
|
return String(value).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^\.+/, "") || "unknown";
|
|
436
437
|
}
|
|
437
438
|
function buildLocksDir() {
|
|
438
|
-
return join(getConfigDir(), "build-locks");
|
|
439
|
+
return join$1(getConfigDir(), "build-locks");
|
|
439
440
|
}
|
|
440
441
|
function buildLockPath(platform, key) {
|
|
441
|
-
return join(buildLocksDir(), `${segment(platform)}-${segment(key)}${LOCK_SUFFIX}`);
|
|
442
|
+
return join$1(buildLocksDir(), `${segment(platform)}-${segment(key)}${LOCK_SUFFIX}`);
|
|
442
443
|
}
|
|
443
444
|
function label(platform) {
|
|
444
445
|
return `${platform} build`;
|
|
@@ -482,6 +483,7 @@ function acquireBuildLock({ platform, key, root = null, logFile = null }) {
|
|
|
482
483
|
},
|
|
483
484
|
claim: attempt.acquired
|
|
484
485
|
};
|
|
486
|
+
declareSpawnsOn(attempt.acquired);
|
|
485
487
|
return reaped ? {
|
|
486
488
|
...handle,
|
|
487
489
|
tookOver: toRecord(reaped)
|
|
@@ -495,6 +497,7 @@ function acquireBuildLock({ platform, key, root = null, logFile = null }) {
|
|
|
495
497
|
} : { path };
|
|
496
498
|
}
|
|
497
499
|
function releaseBuildLock(handle) {
|
|
500
|
+
stopDeclaringSpawnsOn(handle?.claim);
|
|
498
501
|
return (0, ownership_claim_exports.releaseClaim)(handle?.claim);
|
|
499
502
|
}
|
|
500
503
|
function listBuildLocks() {
|
|
@@ -508,7 +511,7 @@ function listBuildLocks() {
|
|
|
508
511
|
const locks = [];
|
|
509
512
|
for (const name of names) {
|
|
510
513
|
if (!name.endsWith(LOCK_SUFFIX)) continue;
|
|
511
|
-
const path = join(dir, name);
|
|
514
|
+
const path = join$1(dir, name);
|
|
512
515
|
try {
|
|
513
516
|
if (!statSync(path).isDirectory()) continue;
|
|
514
517
|
} catch {
|
|
@@ -600,5 +603,98 @@ async function waitForBuild({ platform, key, resolve = resolveBuild, intervalMs
|
|
|
600
603
|
await sleep(intervalMs);
|
|
601
604
|
}
|
|
602
605
|
}
|
|
606
|
+
async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, command, acquire, wait, now, phase, warn, out }) {
|
|
607
|
+
const waitStarted = now();
|
|
608
|
+
let failedHolder;
|
|
609
|
+
let released = null;
|
|
610
|
+
for (;;) {
|
|
611
|
+
let attempt = null;
|
|
612
|
+
try {
|
|
613
|
+
attempt = acquire({
|
|
614
|
+
platform,
|
|
615
|
+
key,
|
|
616
|
+
root,
|
|
617
|
+
logFile
|
|
618
|
+
});
|
|
619
|
+
} catch (err) {
|
|
620
|
+
const refusal = (0, ownership_claim_exports.claimFailure)(err, command);
|
|
621
|
+
if (refusal) return { refusal };
|
|
622
|
+
warn(`could not take the build lock: ${err?.message || err}; building anyway`);
|
|
623
|
+
}
|
|
624
|
+
if (attempt?.acquired) {
|
|
625
|
+
const previous = attempt.tookOver ?? failedHolder;
|
|
626
|
+
if (previous) warn(takeoverLine(previous));
|
|
627
|
+
return {
|
|
628
|
+
refusal: null,
|
|
629
|
+
lock: attempt,
|
|
630
|
+
hit: null,
|
|
631
|
+
released
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
if (!attempt?.held) return {
|
|
635
|
+
refusal: null,
|
|
636
|
+
lock: null,
|
|
637
|
+
hit: null,
|
|
638
|
+
released
|
|
639
|
+
};
|
|
640
|
+
released = null;
|
|
641
|
+
const holder = attempt.held;
|
|
642
|
+
const who = holder.projectRoot || "another workspace";
|
|
643
|
+
phase(`${who} is already building ${shortHash(fingerprint)} (pid ${holder.pid})${holder.logFile ? ` -- tail ${holder.logFile}` : ""} -- stim guide lifecycle concurrency`);
|
|
644
|
+
let waited;
|
|
645
|
+
try {
|
|
646
|
+
const ceilingMs = WAIT_CEILING_MS - (now() - waitStarted);
|
|
647
|
+
if (ceilingMs <= 0) throw Object.assign(/* @__PURE__ */ new Error(`Waited ${formatDuration(now() - waitStarted)} for shared builds without an artifact; ${who} (pid ${holder.pid}) holds ${attempt.path}.`), {
|
|
648
|
+
code: "STIM_BUILD_WAIT_TIMEOUT",
|
|
649
|
+
lockPath: attempt.path
|
|
650
|
+
});
|
|
651
|
+
waited = await wait({
|
|
652
|
+
platform,
|
|
653
|
+
key,
|
|
654
|
+
out,
|
|
655
|
+
ceilingMs
|
|
656
|
+
});
|
|
657
|
+
} catch (err) {
|
|
658
|
+
const refusal = (0, ownership_claim_exports.claimFailure)(err, command);
|
|
659
|
+
if (refusal) return { refusal };
|
|
660
|
+
const timeout = err;
|
|
661
|
+
if (timeout?.code !== "STIM_BUILD_WAIT_TIMEOUT") throw err;
|
|
662
|
+
return { refusal: {
|
|
663
|
+
code: "STIM_BUILD_WAIT_TIMEOUT",
|
|
664
|
+
message: timeout.message,
|
|
665
|
+
remedy: `Check pid ${holder.pid}; if it is not really building, remove ${timeout.lockPath} and run \`${command}\` again.`
|
|
666
|
+
} };
|
|
667
|
+
}
|
|
668
|
+
if (waited.hit) {
|
|
669
|
+
phase(`waited ${formatDuration(waited.waitedMs)} for ${who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
|
|
670
|
+
return {
|
|
671
|
+
refusal: null,
|
|
672
|
+
lock: null,
|
|
673
|
+
hit: {
|
|
674
|
+
path: waited.hit,
|
|
675
|
+
waited: {
|
|
676
|
+
pid: holder.pid,
|
|
677
|
+
ms: waited.waitedMs
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
released
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
if (waited.lockReleased) {
|
|
684
|
+
failedHolder = void 0;
|
|
685
|
+
released = {
|
|
686
|
+
facts: {
|
|
687
|
+
pid: holder.pid,
|
|
688
|
+
ms: waited.waitedMs
|
|
689
|
+
},
|
|
690
|
+
who
|
|
691
|
+
};
|
|
692
|
+
phase(`${who}'s build lock was released; rechecking this workspace before building`);
|
|
693
|
+
} else {
|
|
694
|
+
warn(`${who}'s build ended without an artifact (${waited.builderFailed}); retrying the build lock`);
|
|
695
|
+
failedHolder = holder;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
603
699
|
//#endregion
|
|
604
|
-
export {
|
|
700
|
+
export { assetDiffReason as C, readAssetManifest as E, untrackedNativeFiles as S, compareAssetManifests as T, refingerprintAfterMutation as _, waitForBuild as a, storedAssetManifest as b, describeFingerprintMiss as c, fingerprintDiffRecord as d, fingerprintDiffSuffix as f, providerUploadOutcome as g, providerDownloadPath as h, segment as i, diffFingerprintSources as l, prepareProviderDownloadDir as m, listBuildLocks as n, waitForSharedBuild as o, fingerprintProject as p, releaseBuildLock as r, buildCacheKey as s, acquireBuildLock as t, filesystemBuildCapability as u, resolveBuild as v, captureAssetManifest as w, untrackedMissLine as x, storeBuild as y };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { k as ownership_claim_exports } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { a as updateWorkspaceState, t as clearWorkspaceStateKey } from "./workspace-state-DF2gCFhx.mjs";
|
|
3
|
+
import { a as formatElapsed, u as plural } from "./command-output-gByVmIjy.mjs";
|
|
4
|
+
//#region src/engine/build-progress.ts
|
|
5
|
+
const BUILD_PHASES = [
|
|
6
|
+
"prepare",
|
|
7
|
+
"cache-lookup",
|
|
8
|
+
"wait",
|
|
9
|
+
"prebuild",
|
|
10
|
+
"pods",
|
|
11
|
+
"compile",
|
|
12
|
+
"install",
|
|
13
|
+
"launch"
|
|
14
|
+
];
|
|
15
|
+
const ACTIVE_BUILD_KEY = "activeBuild";
|
|
16
|
+
const NO_BUILD_PROGRESS = {
|
|
17
|
+
step: () => {},
|
|
18
|
+
durations: () => ({}),
|
|
19
|
+
clear: () => {}
|
|
20
|
+
};
|
|
21
|
+
const COLD_PHASES = [
|
|
22
|
+
"prebuild",
|
|
23
|
+
"pods",
|
|
24
|
+
"compile"
|
|
25
|
+
];
|
|
26
|
+
const DEVICE_PHASES = ["install", "launch"];
|
|
27
|
+
function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
|
|
28
|
+
const startedAt = new Date(now()).toISOString();
|
|
29
|
+
const record = {
|
|
30
|
+
platform,
|
|
31
|
+
slot,
|
|
32
|
+
startedAt,
|
|
33
|
+
phase: "prepare",
|
|
34
|
+
phaseStartedAt: startedAt,
|
|
35
|
+
phases: [{
|
|
36
|
+
phase: "prepare",
|
|
37
|
+
startedAt
|
|
38
|
+
}],
|
|
39
|
+
claim: {
|
|
40
|
+
root: claim.root,
|
|
41
|
+
path: claim.path,
|
|
42
|
+
claimId: claim.claimId,
|
|
43
|
+
pid: claim.owner.pid
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
let warned = false;
|
|
47
|
+
const guard = (fn) => {
|
|
48
|
+
try {
|
|
49
|
+
fn();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (warned) return;
|
|
52
|
+
warned = true;
|
|
53
|
+
note(`Build progress could not be recorded in the workspace state: ${error?.message || error}`);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const write = () => guard(() => updateWorkspaceState(root, (state) => ({
|
|
57
|
+
...state,
|
|
58
|
+
[ACTIVE_BUILD_KEY]: record
|
|
59
|
+
})));
|
|
60
|
+
write();
|
|
61
|
+
return {
|
|
62
|
+
step(phase) {
|
|
63
|
+
if (phase === record.phase) return;
|
|
64
|
+
const at = new Date(now()).toISOString();
|
|
65
|
+
record.phase = phase;
|
|
66
|
+
record.phaseStartedAt = at;
|
|
67
|
+
record.phases.push({
|
|
68
|
+
phase,
|
|
69
|
+
startedAt: at
|
|
70
|
+
});
|
|
71
|
+
write();
|
|
72
|
+
},
|
|
73
|
+
durations() {
|
|
74
|
+
return phaseDurations(record.phases, now());
|
|
75
|
+
},
|
|
76
|
+
clear() {
|
|
77
|
+
guard(() => {
|
|
78
|
+
clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function phaseDurations(phases, now) {
|
|
84
|
+
const out = {};
|
|
85
|
+
phases.forEach(({ phase, startedAt }, index) => {
|
|
86
|
+
const start = Date.parse(startedAt);
|
|
87
|
+
const next = phases[index + 1];
|
|
88
|
+
const end = next ? Date.parse(next.startedAt) : now;
|
|
89
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) return;
|
|
90
|
+
out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
|
|
91
|
+
});
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
function parseActiveBuild(value) {
|
|
95
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
96
|
+
const record = value;
|
|
97
|
+
const claim = record.claim;
|
|
98
|
+
if (record.platform !== "ios" && record.platform !== "android") return null;
|
|
99
|
+
if (!isPhase(record.phase)) return null;
|
|
100
|
+
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
101
|
+
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
102
|
+
const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
|
|
103
|
+
return {
|
|
104
|
+
platform: record.platform,
|
|
105
|
+
slot: typeof record.slot === "string" ? record.slot : "default",
|
|
106
|
+
startedAt: record.startedAt,
|
|
107
|
+
phase: record.phase,
|
|
108
|
+
phaseStartedAt: record.phaseStartedAt,
|
|
109
|
+
phases,
|
|
110
|
+
claim: {
|
|
111
|
+
root: claim.root,
|
|
112
|
+
path: typeof claim.path === "string" ? claim.path : "",
|
|
113
|
+
claimId: claim.claimId,
|
|
114
|
+
pid: typeof claim.pid === "number" ? claim.pid : 0
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function isPhase(value) {
|
|
119
|
+
return BUILD_PHASES.includes(value);
|
|
120
|
+
}
|
|
121
|
+
function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
|
|
122
|
+
if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
|
|
123
|
+
if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
|
|
124
|
+
return survey.unresolved.length ? "unknown" : "stale";
|
|
125
|
+
}
|
|
126
|
+
function liveOutcome(record) {
|
|
127
|
+
const seen = new Set(record.phases.map((entry) => entry.phase));
|
|
128
|
+
if (COLD_PHASES.some((phase) => seen.has(phase))) return "cold";
|
|
129
|
+
if (DEVICE_PHASES.some((phase) => seen.has(phase))) return "hit";
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
function median(values) {
|
|
133
|
+
if (!values.length) return null;
|
|
134
|
+
const sorted = values.toSorted((a, b) => a - b);
|
|
135
|
+
const mid = Math.floor(sorted.length / 2);
|
|
136
|
+
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
137
|
+
}
|
|
138
|
+
function estimateBuild(history, platform, known, phase) {
|
|
139
|
+
const lists = history?.[platform];
|
|
140
|
+
const outcome = known ?? latestOutcome(lists);
|
|
141
|
+
const samples = outcome && lists?.[outcome] || [];
|
|
142
|
+
const phaseSamples = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
|
|
143
|
+
return {
|
|
144
|
+
outcome,
|
|
145
|
+
expectedMs: median(samples.map((sample) => sample.durationMs)),
|
|
146
|
+
expectedPhaseMs: median(phaseSamples),
|
|
147
|
+
basis: samples.length
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function latestOutcome(lists) {
|
|
151
|
+
let latest = null;
|
|
152
|
+
for (const outcome of ["hit", "cold"]) {
|
|
153
|
+
const last = lists?.[outcome]?.at(-1);
|
|
154
|
+
const at = last ? Date.parse(last.at) : NaN;
|
|
155
|
+
if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
|
|
156
|
+
outcome,
|
|
157
|
+
at
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return latest?.outcome ?? null;
|
|
161
|
+
}
|
|
162
|
+
function buildReport(record, { state, history }) {
|
|
163
|
+
return {
|
|
164
|
+
platform: record.platform,
|
|
165
|
+
slot: record.slot,
|
|
166
|
+
state,
|
|
167
|
+
phase: record.phase,
|
|
168
|
+
startedAt: record.startedAt,
|
|
169
|
+
phaseStartedAt: record.phaseStartedAt,
|
|
170
|
+
...estimateBuild(history, record.platform, liveOutcome(record), record.phase)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function remainingText(remainingMs) {
|
|
174
|
+
return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
|
|
175
|
+
}
|
|
176
|
+
function buildStatusLine(report, now) {
|
|
177
|
+
const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
|
|
178
|
+
if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
|
|
179
|
+
const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
|
|
180
|
+
const head = `build: ${report.platform}${slot} ${report.phase}, ${formatElapsed(elapsedMs)} elapsed`;
|
|
181
|
+
if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
|
|
182
|
+
if (report.expectedMs === null) return head;
|
|
183
|
+
const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
|
|
184
|
+
const remainingMs = report.expectedMs - elapsedMs;
|
|
185
|
+
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
export { buildStatusLine as a, buildReport as i, NO_BUILD_PROGRESS as n, parseActiveBuild as o, activeBuildState as r, startBuildProgress as s, ACTIVE_BUILD_KEY as t };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { u as getConfigDir } from "./config-
|
|
1
|
+
import { u as getConfigDir } from "./config-Cp9lM3wX.mjs";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
|
-
import {
|
|
4
|
-
import { join, resolve } from "path";
|
|
3
|
+
import { isAbsolute, join, resolve } from "path";
|
|
5
4
|
import { readCacheManifest, updateCacheManifest } from "@stim-cli/core";
|
|
5
|
+
import { homedir } from "os";
|
|
6
6
|
//#region src/cache/cache-manifest.ts
|
|
7
7
|
function manifestPath() {
|
|
8
8
|
return join(getConfigDir(), "caches.json");
|
|
@@ -53,7 +53,7 @@ function unregister(dir, path = manifestPath()) {
|
|
|
53
53
|
return removed;
|
|
54
54
|
}
|
|
55
55
|
function registeredCaches(path = manifestPath()) {
|
|
56
|
-
return readManifest(path).caches.filter((c) => c.dir && existsSync(c.dir)).map((c) => ({
|
|
56
|
+
return readManifest(path).caches.filter((c) => isAbsolute(c.dir) && existsSync(c.dir)).map((c) => ({
|
|
57
57
|
name: c.name,
|
|
58
58
|
dir: c.dir,
|
|
59
59
|
prune: c.prune === "atomic" ? "atomic" : "entries",
|
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-Dg7OnMrp.mjs";
|
|
2
2
|
export { manifestPath, readManifest, register, registeredCaches, unregister };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { _ as refuseRelativeStimPaths } from "./config-Cp9lM3wX.mjs";
|
|
2
3
|
import { readFileSync } from "node:fs";
|
|
3
4
|
import { Command } from "commander";
|
|
4
5
|
//#region bin/cli.ts
|
|
5
6
|
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
|
-
["
|
|
17
|
-
["
|
|
18
|
-
["
|
|
19
|
-
["
|
|
7
|
+
["doctor", () => import("./doctor-B_Ei3bZu.mjs")],
|
|
8
|
+
["worktree", () => import("./worktree-DKhSF0UX.mjs")],
|
|
9
|
+
["start", () => import("./start-DYkkKF0s.mjs")],
|
|
10
|
+
["ports", () => import("./ports-BNKoWVWZ.mjs")],
|
|
11
|
+
["stop", () => import("./stop-T1R-cZRz.mjs")],
|
|
12
|
+
["ios", () => import("./ios-BzUJWk1K.mjs")],
|
|
13
|
+
["android", () => import("./android-BPGizezh.mjs")],
|
|
14
|
+
["reload", () => import("./reload-ZNJUo1pl.mjs")],
|
|
15
|
+
["device", () => import("./device-D4U-xLty.mjs")],
|
|
16
|
+
["logs", () => import("./logs-CI9NQSK7.mjs")],
|
|
17
|
+
["settings", () => import("./settings-BKNh5rl4.mjs")],
|
|
18
|
+
["status", () => import("./status-S6ehL4Ui.mjs")],
|
|
19
|
+
["stats", () => import("./stats-B63-JVAY.mjs")],
|
|
20
|
+
["gc", () => import("./gc-Ckw8RQHi.mjs")],
|
|
21
|
+
["guide", () => import("./guide-BiAbhs1J.mjs")]
|
|
20
22
|
]);
|
|
21
23
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
22
24
|
const program = new Command();
|
|
23
25
|
program.name("stim").description("Isolated React Native dev environments per project/worktree").version(pkg.version);
|
|
24
26
|
try {
|
|
27
|
+
refuseRelativeStimPaths();
|
|
25
28
|
const first = process.argv[2];
|
|
26
29
|
const loadCommand = commands.get((first === "help" ? process.argv[3] : first) ?? "");
|
|
27
30
|
if (loadCommand) (await loadCommand()).default(program, pkg.version);
|
|
@@ -31,11 +34,11 @@ try {
|
|
|
31
34
|
}
|
|
32
35
|
await program.parseAsync();
|
|
33
36
|
} catch (err) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
37
|
+
const code = err?.code;
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
if (typeof code === "string" && code.startsWith("STIM_")) console.error(`${code}: ${message}`);
|
|
40
|
+
else console.error(`Unexpected error: ${message.replace(/\.$/, "")}. Report it at ${pkg.bugs.url}`);
|
|
41
|
+
process.exit(1);
|
|
39
42
|
}
|
|
40
43
|
//#endregion
|
|
41
44
|
export {};
|
package/dist/collector-run.d.mts
CHANGED
|
@@ -12,6 +12,8 @@ interface ExecOptions {
|
|
|
12
12
|
interface Executor {
|
|
13
13
|
run(cmd: string, opts?: ExecOptions): string;
|
|
14
14
|
runFile(file: string, args?: string[], opts?: ExecOptions): string;
|
|
15
|
+
/** `runFile` without blocking the event loop; rejects where `runFile` throws. */
|
|
16
|
+
runFileAsync(file: string, args?: string[], opts?: ExecOptions): Promise<string>;
|
|
15
17
|
runQuiet(cmd: string, opts?: ExecOptions): string | null;
|
|
16
18
|
runFileQuiet(file: string, args?: string[], opts?: ExecOptions): string | null;
|
|
17
19
|
spawn(cmd: string, args?: readonly string[], opts?: SpawnOptions): ChildProcess;
|
package/dist/collector-run.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
4
|
-
import {
|
|
5
|
-
import { t as createLineReader } from "./process-output-
|
|
6
|
-
import {
|
|
7
|
-
import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-
|
|
8
|
-
import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-
|
|
1
|
+
import { D as process_identity_exports, H as deviceSlotKey, J as validateDeviceSlot } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
3
|
+
import { r as createNdjsonWriter } from "./ndjson-9uFNRwfe.mjs";
|
|
4
|
+
import { b as workspaceLogsDir } from "./workspace-state-DF2gCFhx.mjs";
|
|
5
|
+
import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
6
|
+
import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-DPsSm0v_.mjs";
|
|
7
|
+
import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-D15Op8vN.mjs";
|
|
8
|
+
import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-DEgo4oCo.mjs";
|
|
9
9
|
import { existsSync } from "node:fs";
|
|
10
|
+
import { LOG_ROTATE_BYTES } from "@stim-cli/core";
|
|
10
11
|
import { isAbsolute, join, resolve } from "node:path";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
//#region src/collector/ios.ts
|
|
@@ -299,7 +300,7 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
|
|
|
299
300
|
slot,
|
|
300
301
|
deviceId: udid ?? serial
|
|
301
302
|
};
|
|
302
|
-
const writer = createNdjsonWriter(join(workspaceLogsDir(root), "device.ndjson"));
|
|
303
|
+
const writer = createNdjsonWriter(join(workspaceLogsDir(root), "device.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
303
304
|
const startedAt = new Date(now()).toISOString();
|
|
304
305
|
const processToken = (0, process_identity_exports.captureProcessToken)(process.pid);
|
|
305
306
|
if (!processToken) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as NO_PROJECT_REFUSAL } from "./project-DS112DYB.mjs";
|
|
2
|
+
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
2
3
|
import { quotedPath } from "@stim-cli/core";
|
|
4
|
+
import chalk from "chalk";
|
|
3
5
|
//#region src/diagnostics/launch-error-preview.ts
|
|
4
6
|
function framePriority(frame, root) {
|
|
5
7
|
const normalized = frame.replaceAll("\\", "/");
|
|
@@ -245,6 +247,13 @@ function releasedLeaseFact(lease) {
|
|
|
245
247
|
function phaseLine(label, text) {
|
|
246
248
|
return ` ${String(label).padEnd(LABEL_WIDTH)} ${text}`;
|
|
247
249
|
}
|
|
250
|
+
function refuseNoProject({ json }) {
|
|
251
|
+
const { code, message, remedy } = NO_PROJECT_REFUSAL;
|
|
252
|
+
console.error(chalk.red(phaseLine("error", `${code}: ${message}`)));
|
|
253
|
+
console.error(phaseLine("remedy", remedy));
|
|
254
|
+
if (json) console.log(JSON.stringify(NO_PROJECT_REFUSAL));
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
}
|
|
248
257
|
function shortUdid(udid) {
|
|
249
258
|
const text = String(udid ?? "");
|
|
250
259
|
return text.length > 4 ? `${text.slice(0, 4)}..` : text;
|
|
@@ -283,4 +292,4 @@ function stepTimer(now = Date.now) {
|
|
|
283
292
|
return () => `(${formatDuration(elapsed())})`;
|
|
284
293
|
}
|
|
285
294
|
//#endregion
|
|
286
|
-
export {
|
|
295
|
+
export { stepTimer as _, formatElapsed as a, launchErrorReport as c, quotedPath as d, refuseNoProject as f, stepClock as g, shortUdid as h, formatDuration as i, phaseLine as l, shortHash as m, appReadinessMessage as n, formatLongDuration as o, releasedLeaseFact as p, clockTime as r, isAppLaunchError as s, SLOW_STEP_MS as t, plural as u, launchErrorPreview as v };
|