stim 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +2 -0
  2. package/dist/activity-BxwdD81S.mjs +609 -0
  3. package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
  4. package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
  5. package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
  6. package/dist/android-cas-8U4DPqeR.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
  9. package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
  10. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  11. package/dist/budget-DjrURfQn.mjs +2700 -0
  12. package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
  13. package/dist/build-slots-rUk77xqh.mjs +132 -0
  14. package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  15. package/dist/cache-manifest.mjs +1 -1
  16. package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
  17. package/dist/cli-BkYZ_6hy.mjs +51 -0
  18. package/dist/cli.mjs +6 -42
  19. package/dist/client-BTY686R6.mjs +1368 -0
  20. package/dist/collector-run.mjs +9 -195
  21. package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
  22. package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
  23. package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
  24. package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
  25. package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
  26. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  27. package/dist/dev-client-CroAIjjj.mjs +43 -0
  28. package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
  29. package/dist/device-capacity-BHwxNBlu.mjs +136 -0
  30. package/dist/device-host-worker.d.mts +1 -0
  31. package/dist/device-host-worker.mjs +964 -0
  32. package/dist/device-ios-BadmeL2V.mjs +381 -0
  33. package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
  34. package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
  35. package/dist/device-pool-CUaEWMMm.mjs +125 -0
  36. package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
  37. package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
  38. package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
  39. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  40. package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
  41. package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
  42. package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
  43. package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
  44. package/dist/hosted-client-a-WmqE2L.mjs +197 -0
  45. package/dist/hosted-ios-CIWelIqf.mjs +220 -0
  46. package/dist/hosted-logs-D5g041Q3.mjs +187 -0
  47. package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
  48. package/dist/idle-DYVymG92.mjs +1099 -0
  49. package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
  50. package/dist/in-use-DvBw0Kxo.mjs +130 -0
  51. package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
  52. package/dist/ios-Cr1h5gnO.mjs +189 -0
  53. package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
  54. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  55. package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
  56. package/dist/ios-state-DS5UpYTH.mjs +48 -0
  57. package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
  58. package/dist/logs-CHEVK8zD.mjs +371 -0
  59. package/dist/machines-BIBUdhpj.mjs +265 -0
  60. package/dist/macos-CSYEAFmF.mjs +473 -0
  61. package/dist/macos-run.d.mts +5 -0
  62. package/dist/macos-run.mjs +2 -0
  63. package/dist/maintenance-run.d.mts +4 -0
  64. package/dist/maintenance-run.mjs +254 -0
  65. package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
  66. package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
  67. package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
  68. package/dist/native-run-NaBrRFtQ.mjs +147 -0
  69. package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
  70. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  71. package/dist/offload-worker.d.mts +122 -0
  72. package/dist/offload-worker.mjs +606 -0
  73. package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
  74. package/dist/ownership-hCkPzGmr.mjs +571 -0
  75. package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
  76. package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
  77. package/dist/prebuild-D2fsca_Z.mjs +213 -0
  78. package/dist/preview-DhVbvPAZ.mjs +318 -0
  79. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  80. package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
  81. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  82. package/dist/pull-requests.d.mts +120 -0
  83. package/dist/pull-requests.mjs +2 -0
  84. package/dist/recordings-BIXOzVnr.mjs +37 -0
  85. package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
  86. package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
  87. package/dist/run-f4vI6EnK.mjs +119 -0
  88. package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
  89. package/dist/server-expo-CVqO2c35.mjs +2 -0
  90. package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
  91. package/dist/settings-BBpMcDbD.mjs +25 -0
  92. package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
  93. package/dist/settings-oTSkkNrM.mjs +1439 -0
  94. package/dist/settings.schema.json +845 -97
  95. package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
  96. package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
  97. package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  98. package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
  99. package/dist/stage-CzaiwFsI.mjs +143 -0
  100. package/dist/start-CX8Ig-U2.mjs +2 -0
  101. package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
  102. package/dist/state-3DwSQIBK.mjs +41 -0
  103. package/dist/state-B4PQFXMW.d.mts +12 -0
  104. package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
  105. package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
  106. package/dist/stats-CEZ_i5je.mjs +77 -0
  107. package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
  108. package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
  109. package/dist/status-DlKvVJBE.mjs +49 -0
  110. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  111. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  112. package/dist/stim-footprint.swift +32 -0
  113. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  114. package/dist/stop-B0Yxtmiy.mjs +48 -0
  115. package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
  116. package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
  117. package/dist/stop-cause-CidxIqup.mjs +97 -0
  118. package/dist/supervisor-run.d.mts +43 -11
  119. package/dist/supervisor-run.mjs +363 -24
  120. package/dist/support-CAP8qDUF.mjs +316 -0
  121. package/dist/support-D4aYJniO.mjs +201 -0
  122. package/dist/teardown-CL6vDs2Y.mjs +727 -0
  123. package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
  124. package/dist/trigger-Bemu8ytw.mjs +65 -0
  125. package/dist/trigger-CXts6qt1.mjs +2 -0
  126. package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
  127. package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
  128. package/dist/web-run.mjs +310 -13
  129. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  130. package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
  131. package/dist/workspaces-BV4pdHFz.mjs +306 -0
  132. package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
  133. package/dist/worktree-jnG8Iph5.mjs +2 -0
  134. package/package.json +10 -5
  135. package/shim/bundle-response.cjs +28 -12
  136. package/dist/activity-CYVDcrt3.mjs +0 -356
  137. package/dist/budget-CGDkhvv_.mjs +0 -1745
  138. package/dist/build-progress-DxKpwnaS.mjs +0 -247
  139. package/dist/idle-DXtx3RbX.mjs +0 -191
  140. package/dist/in-use-DlqBDKqY.mjs +0 -249
  141. package/dist/logs-Civ4gbBH.mjs +0 -486
  142. package/dist/merge-state-ytFQCeh4.mjs +0 -262
  143. package/dist/server-expo-DIHDhvGg.mjs +0 -2
  144. package/dist/settings-D61iNOsB.mjs +0 -629
  145. package/dist/start-Cetfvy8l.mjs +0 -2
  146. package/dist/stats-CFpFGlJV.mjs +0 -62
  147. package/dist/stats-CX1Z8Tca.mjs +0 -368
  148. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  149. package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
  150. package/dist/worktree-BVrHsYZG.mjs +0 -752
  151. package/dist/worktree-CHWWvm5v.mjs +0 -2
  152. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -1,62 +0,0 @@
1
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BVrHsYZG.mjs";
2
- import { a as findProjectRoot } from "./project-CWlvEaeN.mjs";
3
- import { o as formatLongDuration } from "./command-output-DVcpw6eE.mjs";
4
- import { a as statsProjectKey, r as readStats } from "./stats-CX1Z8Tca.mjs";
5
- import chalk from "chalk";
6
- //#region src/commands/stats.ts
7
- const PLATFORMS = ["ios", "android"];
8
- const PLATFORM_WIDTH = 9;
9
- function statsCommand(program) {
10
- program.command("stats").description("Show how many `ios` and `android` runs this project and this machine have recorded, how many hit the build cache, and an estimate of the time that cache saved.").option("--json", "print the aggregates as JSON").action((opts) => {
11
- const root = findProjectRoot(process.cwd());
12
- const key = root ? statsProjectKey({
13
- root,
14
- commonDir: gitCommonDir(root),
15
- repoRoot: repoRoot(root)
16
- }) : null;
17
- const { record, note } = readStats();
18
- if (note) console.error(chalk.dim(note));
19
- const machine = record?.machine ?? {};
20
- const project = key ? record?.projects?.[key] ?? {} : {};
21
- if (opts.json) {
22
- console.log(JSON.stringify({
23
- version: 1,
24
- project: key ? {
25
- key,
26
- ios: project.ios ?? null,
27
- android: project.android ?? null
28
- } : null,
29
- machine: {
30
- ios: machine.ios ?? null,
31
- android: machine.android ?? null
32
- }
33
- }));
34
- return;
35
- }
36
- const lines = [];
37
- if (key) lines.push(`project ${key}`, ...sectionLines(project));
38
- lines.push("machine", ...sectionLines(machine));
39
- for (const line of lines) console.log(line);
40
- });
41
- }
42
- function sectionLines(scope) {
43
- const lines = PLATFORMS.filter((platform) => scope[platform]).map((platform) => bucketLine(platform, scope[platform]));
44
- return lines.length ? lines : [chalk.dim(" no runs recorded")];
45
- }
46
- function bucketLine(platform, bucket) {
47
- const finished = bucket.runs - bucket.failed;
48
- const cells = [
49
- `${bucket.runs} runs${bucket.failed > 0 ? ` (${bucket.failed} failed)` : ""}`,
50
- `${bucket.hits} hits (${finished > 0 ? `${Math.round(bucket.hits / finished * 100)}%` : "-"})`,
51
- `cold run ${average(bucket.coldRunMs, bucket.coldRuns)} avg`,
52
- `hit run ${average(bucket.hitRunMs, bucket.hitRuns)} avg`,
53
- `saved ~${formatLongDuration(bucket.timeSavedMs)} (estimated)`,
54
- `since ${bucket.firstRunAt.slice(0, 10)}`
55
- ];
56
- return ` ${platform.padEnd(PLATFORM_WIDTH)}${cells.join(" ")}`;
57
- }
58
- function average(totalMs, runs) {
59
- return runs > 0 ? formatLongDuration(Math.round(totalMs / runs)) : "-";
60
- }
61
- //#endregion
62
- export { statsCommand as default };
@@ -1,368 +0,0 @@
1
- import { E as withConfigLock, d as getConfigDir } from "./config-lvc7d3C2.mjs";
2
- import { readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
- import { basename, dirname, join, relative, resolve } from "node:path";
4
- const PLATFORMS = ["ios", "android"];
5
- const OUTCOMES = ["hit", "cold"];
6
- function statsFile() {
7
- return join(getConfigDir(), "stats.json");
8
- }
9
- function emptyStats() {
10
- return {
11
- version: 1,
12
- machine: {},
13
- projects: {}
14
- };
15
- }
16
- function statsProjectKey({ root, commonDir, repoRoot }) {
17
- if (commonDir && repoRoot && basename(commonDir) === ".git") return canonical(join(dirname(commonDir), relative(repoRoot, root)));
18
- return canonical(root);
19
- }
20
- function updateStats(record, run, now) {
21
- const at = new Date(now).toISOString();
22
- const durationMs = wholeMs(run.durationMs);
23
- const phases = {
24
- coldBuildMs: wholeMs(run.coldBuildMs),
25
- podsMs: wholeMs(run.podsMs)
26
- };
27
- const projects = { ...record.projects };
28
- const scope = { ...projects[run.projectKey] };
29
- const machine = { ...record.machine };
30
- const before = scope[run.platform] ?? null;
31
- const credit = creditMs(before, run, durationMs);
32
- scope[run.platform] = applyRun(before, run, {
33
- at,
34
- durationMs,
35
- credit,
36
- phases
37
- });
38
- projects[run.projectKey] = scope;
39
- machine[run.platform] = applyRun(machine[run.platform] ?? null, run, {
40
- at,
41
- durationMs,
42
- credit,
43
- phases
44
- });
45
- const history = { ...record.history };
46
- if (run.phases && !run.failed && !run.waitedForBuild) {
47
- const outcome = isHit(run.cacheHit) ? "hit" : "cold";
48
- const project = { ...history[run.projectKey] };
49
- const lists = { ...project[run.platform] };
50
- const sample = {
51
- at,
52
- durationMs,
53
- phases: wholePhases(run.phases)
54
- };
55
- lists[outcome] = [...lists[outcome] ?? [], sample].slice(-10);
56
- project[run.platform] = lists;
57
- history[run.projectKey] = project;
58
- }
59
- return {
60
- version: 1,
61
- machine,
62
- projects,
63
- ...Object.keys(history).length ? { history } : {}
64
- };
65
- }
66
- function readStats() {
67
- const path = statsFile();
68
- let text;
69
- try {
70
- text = readFileSync(path, "utf-8");
71
- } catch {
72
- return {
73
- record: null,
74
- note: null
75
- };
76
- }
77
- const parsed = parseRecord(text);
78
- if (!parsed) return {
79
- record: null,
80
- note: `Run statistics at ${path} could not be read; the next ios or android run moves them aside and starts a new file.`
81
- };
82
- if (parsed.version > 1) return {
83
- record: null,
84
- note: `Run statistics at ${path} are version ${parsed.version}, which this Stim does not understand, so none are shown.`
85
- };
86
- return {
87
- record: normalize(parsed),
88
- note: null
89
- };
90
- }
91
- function projectEstimates(record, projectKey, platform) {
92
- const bucket = record?.projects?.[projectKey]?.[platform] ?? null;
93
- return {
94
- coldBuildMs: positive(bucket?.lastColdBuildMs),
95
- podsMs: positive(bucket?.lastPodsMs)
96
- };
97
- }
98
- function readRunEstimates({ projectKey, platform, read = readStats }) {
99
- if (!projectKey) return {
100
- coldBuildMs: null,
101
- podsMs: null
102
- };
103
- try {
104
- return projectEstimates(read().record, projectKey, platform);
105
- } catch {
106
- return {
107
- coldBuildMs: null,
108
- podsMs: null
109
- };
110
- }
111
- }
112
- function recordRunStats(run, now) {
113
- return withConfigLock(() => {
114
- const path = statsFile();
115
- const loaded = loadForUpdate(path, now);
116
- if (loaded.newerVersion !== null) return {
117
- recorded: false,
118
- note: `Run statistics at ${path} are version ${loaded.newerVersion}, which this Stim does not understand, so this run was not recorded.`
119
- };
120
- writeStats(path, updateStats(loaded.record, run, now));
121
- return {
122
- recorded: true,
123
- note: loaded.note
124
- };
125
- });
126
- }
127
- function createRunRecorder({ platform, write, now, note, phases }) {
128
- let projectKey = null;
129
- let cacheKey = null;
130
- let coldBuildMs = 0;
131
- let podsMs = 0;
132
- let recorded = false;
133
- return {
134
- setProject(key) {
135
- projectKey = key;
136
- },
137
- setCacheKey(key) {
138
- cacheKey = key;
139
- },
140
- setBuildMs(ms) {
141
- coldBuildMs = wholeMs(ms);
142
- },
143
- setPodsMs(ms) {
144
- podsMs = wholeMs(ms);
145
- },
146
- record({ failed, cacheHit = false, waited = null, durationMs }) {
147
- if (!projectKey || !cacheKey || recorded) return;
148
- recorded = true;
149
- const ran = failed ? {} : phases?.() ?? {};
150
- try {
151
- const outcome = write({
152
- platform,
153
- projectKey,
154
- failed,
155
- cacheHit,
156
- waitedForBuild: Boolean(waited),
157
- durationMs,
158
- ...coldBuildMs > 0 ? { coldBuildMs } : {},
159
- ...podsMs > 0 ? { podsMs } : {},
160
- ...Object.keys(ran).length ? { phases: ran } : {}
161
- }, now());
162
- if (outcome?.note) note(outcome.note);
163
- } catch (error) {
164
- note(`Run statistics could not be recorded: ${error?.message || error}`);
165
- }
166
- }
167
- };
168
- }
169
- function loadForUpdate(path, now) {
170
- let text;
171
- try {
172
- text = readFileSync(path, "utf-8");
173
- } catch {
174
- return {
175
- record: emptyStats(),
176
- note: null,
177
- newerVersion: null
178
- };
179
- }
180
- const parsed = parseRecord(text);
181
- if (!parsed) {
182
- const aside = `${path}.corrupt-${now}`;
183
- renameSync(path, aside);
184
- return {
185
- record: emptyStats(),
186
- note: `Run statistics at ${path} could not be read, so they were moved to ${aside} and a new file was started.`,
187
- newerVersion: null
188
- };
189
- }
190
- if (parsed.version > 1) return {
191
- record: emptyStats(),
192
- note: null,
193
- newerVersion: parsed.version
194
- };
195
- return {
196
- record: normalize(parsed),
197
- note: null,
198
- newerVersion: null
199
- };
200
- }
201
- function writeStats(path, record) {
202
- const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
203
- writeFileSync(tmp, `${JSON.stringify(record)}\n`);
204
- try {
205
- renameSync(tmp, path);
206
- } catch (error) {
207
- rmSync(tmp, { force: true });
208
- throw error;
209
- }
210
- }
211
- function parseRecord(text) {
212
- let parsed;
213
- try {
214
- parsed = JSON.parse(text);
215
- } catch {
216
- return null;
217
- }
218
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
219
- const version = parsed.version;
220
- if (typeof version !== "number" || !Number.isInteger(version)) return null;
221
- return parsed;
222
- }
223
- function normalize(record) {
224
- const projects = {};
225
- const source = record.projects;
226
- if (source && typeof source === "object" && !Array.isArray(source)) for (const [key, scope] of Object.entries(source)) projects[key] = normalizeScope(scope);
227
- const history = {};
228
- if (isObject(record.history)) for (const [key, scope] of Object.entries(record.history)) {
229
- const normalized = normalizeHistory(scope);
230
- if (Object.keys(normalized).length) history[key] = normalized;
231
- }
232
- return {
233
- version: 1,
234
- machine: normalizeScope(record.machine),
235
- projects,
236
- ...Object.keys(history).length ? { history } : {}
237
- };
238
- }
239
- function isObject(value) {
240
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
241
- }
242
- function normalizeHistory(scope) {
243
- const history = {};
244
- if (!isObject(scope)) return history;
245
- for (const platform of PLATFORMS) {
246
- const lists = scope[platform];
247
- if (!isObject(lists)) continue;
248
- const normalized = {};
249
- for (const outcome of OUTCOMES) {
250
- const samples = lists[outcome];
251
- if (!Array.isArray(samples)) continue;
252
- const kept = samples.filter(isObject).flatMap((sample) => {
253
- const durationMs = wholeMs(sample.durationMs);
254
- if (durationMs <= 0) return [];
255
- return [{
256
- at: timestamp(sample.at),
257
- durationMs,
258
- phases: wholePhases(sample.phases)
259
- }];
260
- });
261
- if (kept.length) normalized[outcome] = kept.slice(-10);
262
- }
263
- if (Object.keys(normalized).length) history[platform] = normalized;
264
- }
265
- return history;
266
- }
267
- function wholePhases(phases) {
268
- const out = {};
269
- if (!isObject(phases)) return out;
270
- for (const [name, ms] of Object.entries(phases)) {
271
- const value = Number(ms);
272
- if (Number.isFinite(value) && value >= 0) out[name] = Math.round(value);
273
- }
274
- return out;
275
- }
276
- function normalizeScope(scope) {
277
- const normalized = {};
278
- if (!scope || typeof scope !== "object" || Array.isArray(scope)) return normalized;
279
- for (const platform of PLATFORMS) {
280
- const bucket = scope[platform];
281
- if (bucket && typeof bucket === "object" && !Array.isArray(bucket)) normalized[platform] = normalizeBucket(bucket);
282
- }
283
- return normalized;
284
- }
285
- function normalizeBucket(bucket) {
286
- return {
287
- runs: count(bucket.runs),
288
- failed: count(bucket.failed),
289
- hits: count(bucket.hits),
290
- misses: count(bucket.misses),
291
- coldRuns: count(bucket.coldRuns),
292
- coldRunMs: count(bucket.coldRunMs),
293
- hitRuns: count(bucket.hitRuns),
294
- hitRunMs: count(bucket.hitRunMs),
295
- timeSavedMs: count(bucket.timeSavedMs),
296
- firstRunAt: timestamp(bucket.firstRunAt),
297
- lastRunAt: timestamp(bucket.lastRunAt),
298
- ...count(bucket.lastColdBuildMs) > 0 ? { lastColdBuildMs: count(bucket.lastColdBuildMs) } : {},
299
- ...count(bucket.lastPodsMs) > 0 ? { lastPodsMs: count(bucket.lastPodsMs) } : {}
300
- };
301
- }
302
- function applyRun(bucket, run, { at, durationMs, credit, phases }) {
303
- const next = bucket ? { ...bucket } : {
304
- runs: 0,
305
- failed: 0,
306
- hits: 0,
307
- misses: 0,
308
- coldRuns: 0,
309
- coldRunMs: 0,
310
- hitRuns: 0,
311
- hitRunMs: 0,
312
- timeSavedMs: 0,
313
- firstRunAt: at,
314
- lastRunAt: at
315
- };
316
- next.runs += 1;
317
- next.lastRunAt = at;
318
- if (phases.coldBuildMs > 0) next.lastColdBuildMs = phases.coldBuildMs;
319
- if (phases.podsMs > 0) next.lastPodsMs = phases.podsMs;
320
- if (run.failed) {
321
- next.failed += 1;
322
- return next;
323
- }
324
- if (isHit(run.cacheHit)) {
325
- next.hits += 1;
326
- if (!run.waitedForBuild) {
327
- next.hitRuns += 1;
328
- next.hitRunMs += durationMs;
329
- next.timeSavedMs += credit;
330
- }
331
- return next;
332
- }
333
- next.misses += 1;
334
- next.coldRuns += 1;
335
- next.coldRunMs += durationMs;
336
- return next;
337
- }
338
- function creditMs(bucket, run, durationMs) {
339
- if (run.failed || !isHit(run.cacheHit) || run.waitedForBuild) return 0;
340
- if (!bucket || bucket.coldRuns <= 0) return 0;
341
- return Math.max(0, Math.round(bucket.coldRunMs / bucket.coldRuns) - durationMs);
342
- }
343
- function isHit(cacheHit) {
344
- return cacheHit === "local" || cacheHit === "remote";
345
- }
346
- function positive(value) {
347
- const ms = wholeMs(value);
348
- return ms > 0 ? ms : null;
349
- }
350
- function wholeMs(value) {
351
- const ms = Number(value);
352
- return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : 0;
353
- }
354
- function count(value) {
355
- return wholeMs(value);
356
- }
357
- function timestamp(value) {
358
- return typeof value === "string" && value !== "" ? value : (/* @__PURE__ */ new Date(0)).toISOString();
359
- }
360
- function canonical(path) {
361
- try {
362
- return realpathSync(path);
363
- } catch {
364
- return resolve(path);
365
- }
366
- }
367
- //#endregion
368
- export { statsProjectKey as a, recordRunStats as i, readRunEstimates as n, readStats as r, createRunRecorder as t };
@@ -1,40 +0,0 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- //#region src/devices/stim-desktop.ts
3
- const LAUNCH_SERVICES_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationWithBundleIdentifier('dev.stim.desktop'); url.isNil() ? '' : url.path.js`;
4
- const STIM_DESKTOP_INSTALLED = "Stim Desktop installed";
5
- /**
6
- * macOS `open` passes its environment to an app it launches, so Stim Desktop
7
- * started by a command run under a scoped `STIM_HOME` would serve that home.
8
- */
9
- const STIM_DESKTOP_OPEN_OPTIONS = {
10
- timeoutMs: 5e3,
11
- killSignal: "SIGKILL",
12
- omitEnv: ["STIM_HOME"]
13
- };
14
- /** Stim Desktop sets `STIM_DESKTOP_APP` to its bundle path for every command it runs; a non-empty value means Desktop is installed. */
15
- function stimDesktopInstalled(platform = process.platform, env = process.env) {
16
- if (platform !== "darwin") return false;
17
- if (env.STIM_DESKTOP_APP) return true;
18
- const found = getExecutor().runFileQuiet("osascript", [
19
- "-l",
20
- "JavaScript",
21
- "-e",
22
- LAUNCH_SERVICES_LOOKUP
23
- ], {
24
- timeoutMs: 5e3,
25
- killSignal: "SIGKILL"
26
- });
27
- return Boolean(found);
28
- }
29
- function settingDefault(setting, desktopInstalled = stimDesktopInstalled) {
30
- if (setting.desktopDefault !== void 0 && desktopInstalled()) return {
31
- value: setting.desktopDefault,
32
- reason: STIM_DESKTOP_INSTALLED
33
- };
34
- return {
35
- value: setting.default,
36
- reason: null
37
- };
38
- }
39
- //#endregion
40
- export { settingDefault as n, stimDesktopInstalled as r, STIM_DESKTOP_OPEN_OPTIONS as t };