stim 0.0.0 → 1.0.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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -0
  3. package/dist/android-cas-compiler.d.mts +1 -0
  4. package/dist/android-cas-compiler.mjs +71 -0
  5. package/dist/android-jc8MnUyL.mjs +514 -0
  6. package/dist/cache-manifest-4tH64LQ9.mjs +66 -0
  7. package/dist/cache-manifest.d.mts +27 -0
  8. package/dist/cache-manifest.mjs +2 -0
  9. package/dist/cli.d.mts +1 -0
  10. package/dist/cli.mjs +27182 -0
  11. package/dist/collector-run.d.mts +119 -0
  12. package/dist/collector-run.mjs +539 -0
  13. package/dist/config-7kmtuhO2.mjs +350 -0
  14. package/dist/errors-B6W7FkxQ.mjs +15 -0
  15. package/dist/exec-bsN9MJXb.mjs +63 -0
  16. package/dist/metro-store-COLl1pOk.mjs +1249 -0
  17. package/dist/ndjson-DcAtEx_K.mjs +131 -0
  18. package/dist/ndjson-DvHSsNU9.d.mts +16 -0
  19. package/dist/process-output-C7IlIzd7.mjs +40 -0
  20. package/dist/project-Dit1CckW.mjs +234 -0
  21. package/dist/server-bare-BmTVVmBB.mjs +351 -0
  22. package/dist/server-expo-BZJm--wA.mjs +2 -0
  23. package/dist/server-expo-CHJe1r6j.mjs +311 -0
  24. package/dist/state-2nush3MK.mjs +269 -0
  25. package/dist/supervisor-run.d.mts +85 -0
  26. package/dist/supervisor-run.mjs +210 -0
  27. package/package.json +61 -8
  28. package/shim/android-cas-pch.cmake +35 -0
  29. package/shim/android-cas.gradle +29 -0
  30. package/shim/android-cas.toolchain.cmake +12 -0
  31. package/shim/android-optimizations.gradle +30 -0
  32. package/shim/bundle-response.cjs +46 -0
  33. package/shim/bundle-response.d.cts +5 -0
  34. package/shim/expo-metro-config.cjs +188 -0
  35. package/shim/metro-cache-generation.cjs +20 -0
  36. package/shim/metro-cache-generation.d.cts +5 -0
  37. package/skill/SKILL.md +14 -0
@@ -0,0 +1,514 @@
1
+ import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
+ import { A as listMountedVolumes, C as inspectProcessIdentity, g as removeProject, k as isOnMountedVolume, m as loadConfig, n as allMetroPorts, r as claimMetroPort, w as sameProcessRecord } from "./config-7kmtuhO2.mjs";
3
+ import { _ as writeWorkspaceState, m as withWorkspaceStateLock, p as readWorkspaceState } from "./state-2nush3MK.mjs";
4
+ import { realpathSync } from "node:fs";
5
+ import { existsSync as existsSync$1, readlinkSync, realpathSync as realpathSync$1 } from "fs";
6
+ import { sep } from "path";
7
+ import { request } from "http";
8
+ import { connect } from "net";
9
+ //#region src/ports.ts
10
+ function isMetroRunning(port) {
11
+ return new Promise((resolve) => {
12
+ const req = request({
13
+ hostname: "localhost",
14
+ port,
15
+ path: "/status",
16
+ timeout: 2e3
17
+ }, (res) => {
18
+ let data = "";
19
+ res.on("data", (chunk) => {
20
+ data += chunk;
21
+ });
22
+ res.on("end", () => resolve(data.includes("packager-status:running")));
23
+ });
24
+ req.on("error", () => resolve(false));
25
+ req.on("timeout", () => {
26
+ req.destroy();
27
+ resolve(false);
28
+ });
29
+ req.end();
30
+ });
31
+ }
32
+ function isPortFree(port, { timeoutMs = 400 } = {}) {
33
+ return new Promise((resolve) => {
34
+ const sock = connect({
35
+ port,
36
+ host: "127.0.0.1"
37
+ });
38
+ const done = (free) => {
39
+ sock.removeAllListeners();
40
+ sock.destroy();
41
+ resolve(free);
42
+ };
43
+ sock.setTimeout(timeoutMs);
44
+ sock.once("connect", () => done(false));
45
+ sock.once("error", () => done(true));
46
+ sock.once("timeout", () => done(false));
47
+ });
48
+ }
49
+ const FIRST_PORT = 8082;
50
+ async function computeNextPort(isFree = isPortFree) {
51
+ const taken = new Set(allMetroPorts());
52
+ for (let port = FIRST_PORT; port < 8282; port++) {
53
+ if (taken.has(port)) continue;
54
+ if (await isFree(port)) return port;
55
+ }
56
+ throw new Error(`Found no free Metro port between ${FIRST_PORT} and 8281. Free one up, or stop a stale bundler (\`stim status\`, \`stim stop <port>\`).`);
57
+ }
58
+ async function findReclaimablePort(excludeProjectPath, probe = isMetroRunning, { isMounted = isOnMountedVolume, mountedVolumes } = {}) {
59
+ const cfg = loadConfig();
60
+ if (!cfg?.projects) return null;
61
+ const mounted = mountedVolumes || listMountedVolumes();
62
+ const candidates = [];
63
+ for (const [path, proj] of Object.entries(cfg.projects)) {
64
+ if (path === excludeProjectPath) continue;
65
+ if (existsSync$1(path)) continue;
66
+ if (!isMounted(path, mounted)) continue;
67
+ if (typeof proj.metroPort === "number") candidates.push({
68
+ port: proj.metroPort,
69
+ ownerPath: path
70
+ });
71
+ }
72
+ for (const c of candidates) if (!await probe(c.port)) return c;
73
+ return null;
74
+ }
75
+ async function allocatePort(projectPath, probe = isMetroRunning, isFree = isPortFree) {
76
+ const reclaim = await findReclaimablePort(projectPath, probe);
77
+ if (reclaim && await isFree(reclaim.port)) {
78
+ removeProject(reclaim.ownerPath);
79
+ return reclaim.port;
80
+ }
81
+ return computeNextPort(isFree);
82
+ }
83
+ const RESERVE_ATTEMPTS = 5;
84
+ async function reserveMetroPort(projectPath, probe = isMetroRunning, isFree = isPortFree) {
85
+ for (let attempt = 0; attempt < RESERVE_ATTEMPTS; attempt++) {
86
+ const port = await allocatePort(projectPath, probe, isFree);
87
+ const claimed = claimMetroPort(projectPath, port);
88
+ if (claimed !== null) return claimed;
89
+ }
90
+ throw new Error(`Could not reserve a Metro port after ${RESERVE_ATTEMPTS} attempts: another Stim run claimed each one first. Retry.`);
91
+ }
92
+ //#endregion
93
+ //#region src/metro.ts
94
+ function isPidAlive(pid) {
95
+ if (!Number.isSafeInteger(pid) || pid <= 0) return false;
96
+ try {
97
+ process.kill(pid, 0);
98
+ return true;
99
+ } catch (error) {
100
+ return error.code !== "ESRCH";
101
+ }
102
+ }
103
+ function parseLsofPids(out) {
104
+ if (!out) return [];
105
+ return String(out).split("\n").map((s) => parseInt(s.trim(), 10)).filter((n) => Number.isFinite(n));
106
+ }
107
+ function parseLsofCwd(out) {
108
+ if (!out) return null;
109
+ const lines = String(out).split("\n");
110
+ const idx = lines.findIndex((l) => l === "fcwd");
111
+ if (idx === -1) return null;
112
+ const nLine = lines.slice(idx + 1).find((l) => l.startsWith("n"));
113
+ return nLine ? nLine.slice(1) : null;
114
+ }
115
+ function processCwd(pid) {
116
+ if (process.platform === "linux") try {
117
+ return readlinkSync(`/proc/${pid}/cwd`);
118
+ } catch {}
119
+ return parseLsofCwd(getExecutor().runQuiet(`lsof -a -p ${pid} -d cwd -Fn`));
120
+ }
121
+ function canonicalPath(path) {
122
+ try {
123
+ return realpathSync$1(path);
124
+ } catch {
125
+ return path;
126
+ }
127
+ }
128
+ function isInsideProject(cwd, projectPath) {
129
+ if (!cwd || !projectPath) return false;
130
+ const a = canonicalPath(cwd);
131
+ const b = canonicalPath(projectPath);
132
+ return a === b || a.startsWith(b.endsWith(sep) ? b : b + sep);
133
+ }
134
+ const NOT_OURS_UNRESPONSIVE = "unresponsive";
135
+ const NOT_OURS_UNREADABLE_CWD = "unreadable-cwd";
136
+ const NOT_OURS_FOREIGN_CWD = "foreign-cwd";
137
+ async function resolveProjectMetro(port, projectPath, { probe = isMetroRunning } = {}) {
138
+ const pid = parseLsofPids(getExecutor().runQuiet(`lsof -nP -iTCP:${port} -sTCP:LISTEN -t`))[0];
139
+ if (pid === void 0) return { missing: true };
140
+ if (!await probe(port)) return {
141
+ notOurs: `pid ${pid} on port ${port} does not answer Metro's /status`,
142
+ kind: NOT_OURS_UNRESPONSIVE,
143
+ pid
144
+ };
145
+ const cwd = processCwd(pid);
146
+ if (!cwd) return {
147
+ notOurs: `pid ${pid} on port ${port}: working directory could not be read`,
148
+ kind: NOT_OURS_UNREADABLE_CWD,
149
+ pid
150
+ };
151
+ if (!isInsideProject(cwd, projectPath)) return {
152
+ notOurs: `pid ${pid} on port ${port} runs from ${cwd}, outside ${projectPath}`,
153
+ kind: NOT_OURS_FOREIGN_CWD,
154
+ pid
155
+ };
156
+ const supervisor = readWorkspaceState(canonicalPath(projectPath))?.supervisor;
157
+ const owned = supervisor?.port === port && inspectProcessIdentity(supervisor) === "same";
158
+ return { metro: {
159
+ pid,
160
+ leader: owned ? supervisor.pid : pid,
161
+ cwd,
162
+ ...owned ? { processToken: supervisor.processToken } : {}
163
+ } };
164
+ }
165
+ function killMetroTree(leader, processToken) {
166
+ if (!leader || leader === process.pid || inspectProcessIdentity({
167
+ pid: leader,
168
+ processToken
169
+ }) !== "same") return false;
170
+ try {
171
+ process.kill(-leader, "SIGTERM");
172
+ return true;
173
+ } catch {
174
+ return false;
175
+ }
176
+ }
177
+ //#endregion
178
+ //#region src/collector/state.ts
179
+ function collectorRoot(root) {
180
+ try {
181
+ return realpathSync(root);
182
+ } catch {
183
+ return root;
184
+ }
185
+ }
186
+ function registerCollector(root, platform, record) {
187
+ root = collectorRoot(root);
188
+ return withWorkspaceStateLock(root, () => {
189
+ const collectors = {
190
+ ...readWorkspaceState(root)?.collectors,
191
+ [platform]: record
192
+ };
193
+ writeWorkspaceState(root, { collectors });
194
+ return collectors;
195
+ });
196
+ }
197
+ function unregisterCollector(root, platform, pid, processToken) {
198
+ root = collectorRoot(root);
199
+ return withWorkspaceStateLock(root, () => {
200
+ const collectors = { ...readWorkspaceState(root)?.collectors };
201
+ const record = collectors[platform];
202
+ if (!(platform in collectors) || record?.pid !== pid || record.processToken !== processToken) return collectors;
203
+ delete collectors[platform];
204
+ writeWorkspaceState(root, { collectors: Object.keys(collectors).length ? collectors : void 0 });
205
+ return collectors;
206
+ });
207
+ }
208
+ function readCollectors(root) {
209
+ return readWorkspaceState(collectorRoot(root))?.collectors || {};
210
+ }
211
+ //#endregion
212
+ //#region src/collector/ownership.ts
213
+ function collectorProcessTitle(platform, root) {
214
+ return `stim-collector-${platform} --root ${root}`;
215
+ }
216
+ function verifyCollectorOwnership({ pid, platform, root, isAlive = isPidAlive, expected }) {
217
+ const record = readCollectors(root)[platform];
218
+ if (expected !== void 0 && !sameProcessRecord(record, expected)) return {
219
+ status: "unverified",
220
+ reason: `the ${platform} collector registration changed during cleanup`
221
+ };
222
+ if (record?.pid === pid) {
223
+ const identity = inspectProcessIdentity(record);
224
+ if (identity === "same") return { status: "ours" };
225
+ if (identity === "gone" || identity === "different") return { status: "gone" };
226
+ }
227
+ return isAlive(pid) ? {
228
+ status: "unverified",
229
+ reason: `pid ${pid} has no verifiable identity recorded for this workspace's ${platform} collector`
230
+ } : { status: "gone" };
231
+ }
232
+ //#endregion
233
+ //#region src/collector/ios-device.ts
234
+ const CONSOLE_ENV = { OS_ACTIVITY_DT_MODE: "enable" };
235
+ const DEV_MENU_LAUNCH_ARGS = [
236
+ "-EXDevMenuShowsAtLaunch",
237
+ "0",
238
+ "-EXDevMenuShowFloatingActionButton",
239
+ "0"
240
+ ];
241
+ const FATAL_MARKERS = [
242
+ /^\*\*\* Terminating app due to uncaught exception/,
243
+ /^libc\+\+abi: terminating/,
244
+ /^\*\*\* Assertion failure in/,
245
+ /^(?:\S+:\d+: )?Fatal error: /
246
+ ];
247
+ const MIRROR_LINE = /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+[+-]\d{4}) (.+?)\[(\d+):(\d+)\] ?(?:\[([^\]\s]+)\] )?([\s\S]*)$/;
248
+ function deviceConsoleLevel(message) {
249
+ const text = typeof message === "string" ? message : "";
250
+ return FATAL_MARKERS.some((marker) => marker.test(text)) ? "fatal" : "info";
251
+ }
252
+ function parseDeviceConsoleLine(line, { now = Date.now } = {}) {
253
+ if (typeof line !== "string") return null;
254
+ const text = line.replace(/\r$/, "").trimEnd();
255
+ if (!text.trim()) return null;
256
+ const match = MIRROR_LINE.exec(text);
257
+ const record = {
258
+ ts: now(),
259
+ src: "device",
260
+ level: "info",
261
+ msg: text,
262
+ raw: true
263
+ };
264
+ if (!match) {
265
+ record.level = text.startsWith("ERROR: ") ? "error" : deviceConsoleLevel(text);
266
+ return record;
267
+ }
268
+ const [, timestamp, proc, pid, , category, message] = match;
269
+ if (message === void 0 || !message.trim()) return null;
270
+ const parsed = Date.parse(timestamp);
271
+ if (Number.isFinite(parsed)) record.ts = parsed;
272
+ record.msg = message;
273
+ record.level = deviceConsoleLevel(message);
274
+ record.proc = `${proc}(${pid})`;
275
+ if (category) record.category = category;
276
+ return record;
277
+ }
278
+ function deviceConsoleArgs({ udid, bundleId, payloadUrl = null }) {
279
+ const args = [
280
+ "devicectl",
281
+ "device",
282
+ "process",
283
+ "launch",
284
+ "--quiet",
285
+ "--device",
286
+ udid,
287
+ "--console",
288
+ "--terminate-existing",
289
+ "--environment-variables",
290
+ JSON.stringify(CONSOLE_ENV)
291
+ ];
292
+ if (payloadUrl) args.push("--payload-url", payloadUrl);
293
+ args.push(bundleId);
294
+ if (payloadUrl) args.push("--", ...DEV_MENU_LAUNCH_ARGS);
295
+ return args;
296
+ }
297
+ function startIosDeviceConsole({ udid, bundleId, payloadUrl = null, spawnFn = null }) {
298
+ return (spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts)))("xcrun", deviceConsoleArgs({
299
+ udid,
300
+ bundleId,
301
+ payloadUrl
302
+ }), {
303
+ stdio: [
304
+ "ignore",
305
+ "pipe",
306
+ "pipe"
307
+ ],
308
+ detached: false
309
+ });
310
+ }
311
+ //#endregion
312
+ //#region src/collector/android.ts
313
+ const LEVEL_BY_LETTER = {
314
+ V: "debug",
315
+ D: "debug",
316
+ I: "info",
317
+ W: "warn",
318
+ E: "error",
319
+ F: "fatal",
320
+ A: "fatal",
321
+ S: "debug"
322
+ };
323
+ function levelFromLogcatLetter(letter) {
324
+ return LEVEL_BY_LETTER[String(letter || "").toUpperCase()] ?? "info";
325
+ }
326
+ const NOISE_TAGS = /* @__PURE__ */ new Set([
327
+ "libEGL",
328
+ "EGL_emulation",
329
+ "eglCodecCommon",
330
+ "emuglGLESv2_enc",
331
+ "HostConnection",
332
+ "OpenGLRenderer",
333
+ "gralloc4",
334
+ "Gralloc4",
335
+ "vulkan",
336
+ "GraphicBufferAllocator",
337
+ "BufferQueueProducer",
338
+ "Surface",
339
+ "ziparchive",
340
+ "chatty"
341
+ ]);
342
+ function levelForLogcat(letter, tag) {
343
+ const level = levelFromLogcatLetter(letter);
344
+ if (level !== "error") return level;
345
+ return NOISE_TAGS.has(String(tag || "").trim()) ? "info" : level;
346
+ }
347
+ const LOGCAT_TIME = /^(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})\s+([A-Z])\/(.*?)\(\s*(\d+)\):\s?(.*)$/;
348
+ const LOGCAT_EPOCH = /^\s*(\d+)\.(\d{3,6})\s+([A-Z])\/(.*?)\(\s*(\d+)\):\s?(.*)$/;
349
+ function parseLogcatTimestamp({ month, day, hour, minute, second, millis }, now = Date.now()) {
350
+ const ref = new Date(now);
351
+ let ts = new Date(ref.getFullYear(), month - 1, day, hour, minute, second, millis).getTime();
352
+ if (ts - now > 864e5) ts = new Date(ref.getFullYear() - 1, month - 1, day, hour, minute, second, millis).getTime();
353
+ return ts;
354
+ }
355
+ function parseLogcatLine(line, { now = Date.now, clockOffsetMs = null } = {}) {
356
+ if (typeof line !== "string") return null;
357
+ const epoch = LOGCAT_EPOCH.exec(line.trimEnd());
358
+ if (epoch) {
359
+ const [, seconds, fraction, letter, tag, pid, msg] = epoch;
360
+ if (!letter || !tag || !msg?.trim()) return null;
361
+ const deviceTs = Number(seconds) * 1e3 + Number(fraction.slice(0, 3));
362
+ if (!Number.isSafeInteger(deviceTs)) return null;
363
+ return {
364
+ ts: deviceTs + (clockOffsetMs ?? 0),
365
+ deviceTs,
366
+ ...clockOffsetMs === null ? {} : { clockOffsetMs },
367
+ src: "device",
368
+ level: levelForLogcat(letter, tag),
369
+ msg,
370
+ proc: `${tag.trim()}(${pid})`
371
+ };
372
+ }
373
+ const m = LOGCAT_TIME.exec(line.trimEnd());
374
+ if (!m) return null;
375
+ const [, month, day, hour, minute, second, millis, letter, tag, pid, msg] = m;
376
+ if (letter === void 0 || tag === void 0 || msg === void 0) return null;
377
+ if (!msg.trim()) return null;
378
+ return {
379
+ ts: parseLogcatTimestamp({
380
+ month: Number(month),
381
+ day: Number(day),
382
+ hour: Number(hour),
383
+ minute: Number(minute),
384
+ second: Number(second),
385
+ millis: Number(millis)
386
+ }, now()),
387
+ src: "device",
388
+ level: levelForLogcat(letter, tag),
389
+ msg,
390
+ proc: `${tag.trim()}(${pid})`
391
+ };
392
+ }
393
+ function logcatArgs(serial, pid) {
394
+ return [
395
+ "-s",
396
+ serial,
397
+ "logcat",
398
+ "--pid",
399
+ String(pid),
400
+ "-v",
401
+ "time,epoch"
402
+ ];
403
+ }
404
+ function androidClockOffset(serial, { exec = getExecutor(), now = Date.now } = {}) {
405
+ const before = now();
406
+ try {
407
+ const output = exec.runFile("adb", [
408
+ "-s",
409
+ serial,
410
+ "shell",
411
+ "date",
412
+ "+%s%3N"
413
+ ], { timeoutMs: 1e3 }).trim();
414
+ const after = now();
415
+ if (!/^\d{13}$/.test(output) || after < before || after - before > 1e3) return null;
416
+ return Math.round((before + after) / 2) - Number(output);
417
+ } catch {
418
+ return null;
419
+ }
420
+ }
421
+ function parsePidof(text) {
422
+ const first = String(text ?? "").trim().split(/\s+/)[0];
423
+ const pid = Number(first);
424
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
425
+ }
426
+ function resolveAppPid(serial, packageName, { exec = null } = {}) {
427
+ const e = exec || getExecutor();
428
+ try {
429
+ return parsePidof(e.runFile("adb", [
430
+ "-s",
431
+ serial,
432
+ "shell",
433
+ "pidof",
434
+ "-s",
435
+ packageName
436
+ ]));
437
+ } catch {
438
+ return null;
439
+ }
440
+ }
441
+ async function waitForAppPid({ serial, packageName, timeoutMs = 3e4, pollMs = 500, exec = null, now = Date.now, sleep = defaultSleep }) {
442
+ const deadline = now() + timeoutMs;
443
+ for (;;) {
444
+ const pid = resolveAppPid(serial, packageName, { exec });
445
+ if (pid) return {
446
+ ok: true,
447
+ pid
448
+ };
449
+ if (now() >= deadline) return {
450
+ failed: true,
451
+ reason: `No process for ${packageName} appeared on ${serial} within ${Math.round(timeoutMs / 1e3)}s.`
452
+ };
453
+ await sleep(pollMs);
454
+ }
455
+ }
456
+ function defaultSleep(ms) {
457
+ return new Promise((r) => setTimeout(r, ms));
458
+ }
459
+ function startAndroidLogcat({ serial, pid, spawnFn = null }) {
460
+ return (spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts)))("adb", logcatArgs(serial, pid), {
461
+ stdio: [
462
+ "ignore",
463
+ "pipe",
464
+ "pipe"
465
+ ],
466
+ detached: false
467
+ });
468
+ }
469
+ const PID_WATCH_MS = 3e3;
470
+ function pidWatchInterval() {
471
+ const override = Number(process.env.STIM_PID_WATCH_MS);
472
+ return Number.isFinite(override) && override > 0 ? override : PID_WATCH_MS;
473
+ }
474
+ function watchAppPid({ serial, packageName, pid, intervalMs = null, exec = null, onChange, resolve = resolveAppPid, setTimer = setTimeout, clearTimer = clearTimeout }) {
475
+ const every = intervalMs ?? pidWatchInterval();
476
+ let current = pid;
477
+ let stopped = false;
478
+ let timer = null;
479
+ const tick = async () => {
480
+ timer = null;
481
+ if (stopped) return;
482
+ let next = null;
483
+ try {
484
+ next = resolve(serial, packageName, { exec });
485
+ } catch {}
486
+ if (next && next !== current) {
487
+ current = next;
488
+ try {
489
+ await onChange(next);
490
+ } catch {}
491
+ }
492
+ if (!stopped) timer = setTimer(tick, every);
493
+ };
494
+ timer = setTimer(tick, every);
495
+ return {
496
+ stop() {
497
+ stopped = true;
498
+ if (timer) clearTimer(timer);
499
+ timer = null;
500
+ },
501
+ probe() {
502
+ try {
503
+ return resolve(serial, packageName, { exec });
504
+ } catch {
505
+ return null;
506
+ }
507
+ },
508
+ get pid() {
509
+ return current;
510
+ }
511
+ };
512
+ }
513
+ //#endregion
514
+ export { killMetroTree as _, watchAppPid as a, reserveMetroPort as b, parseDeviceConsoleLine as c, verifyCollectorOwnership as d, readCollectors as f, isPidAlive as g, NOT_OURS_FOREIGN_CWD as h, waitForAppPid as i, startIosDeviceConsole as l, unregisterCollector as m, parseLogcatLine as n, DEV_MENU_LAUNCH_ARGS as o, registerCollector as p, startAndroidLogcat as r, deviceConsoleLevel as s, androidClockOffset as t, collectorProcessTitle as u, resolveProjectMetro as v, isMetroRunning as y };
@@ -0,0 +1,66 @@
1
+ import { l as getConfigDir } from "./config-7kmtuhO2.mjs";
2
+ import { existsSync } from "fs";
3
+ import { join, resolve } from "path";
4
+ import { homedir } from "os";
5
+ import { readCacheManifest, updateCacheManifest } from "@stim-cli/core";
6
+ //#region src/cache-manifest.ts
7
+ function manifestPath() {
8
+ return join(getConfigDir(), "caches.json");
9
+ }
10
+ function expand(dir) {
11
+ return resolve(dir.startsWith("~") ? join(homedir(), dir.slice(1)) : dir);
12
+ }
13
+ function readManifest(path = manifestPath()) {
14
+ return {
15
+ version: 1,
16
+ caches: cacheEntries(readCacheManifest(path).caches)
17
+ };
18
+ }
19
+ function cacheEntries(caches) {
20
+ return caches.filter((cache) => typeof cache.dir === "string");
21
+ }
22
+ function register(entry, path = manifestPath()) {
23
+ if (!entry?.dir) throw new Error("a cache registration needs a `dir`");
24
+ const dir = expand(entry.dir);
25
+ const record = {
26
+ dir,
27
+ name: entry.name || dir,
28
+ prune: entry.prune === "atomic" ? "atomic" : "entries",
29
+ entriesDepth: normalizeDepth(entry.entriesDepth),
30
+ note: entry.note || "registered by the project",
31
+ registeredBy: entry.registeredBy || process.cwd()
32
+ };
33
+ if (entry.layout) record.layout = entry.layout;
34
+ updateCacheManifest(path, (caches) => {
35
+ return [...cacheEntries(caches).filter((cache) => expand(cache.dir) !== dir), record];
36
+ });
37
+ return record;
38
+ }
39
+ function normalizeDepth(value) {
40
+ const n = Number(value);
41
+ if (!Number.isInteger(n) || n < 1) return 1;
42
+ return n;
43
+ }
44
+ function unregister(dir, path = manifestPath()) {
45
+ const target = expand(dir);
46
+ let removed = false;
47
+ updateCacheManifest(path, (caches) => {
48
+ const entries = cacheEntries(caches);
49
+ const remaining = entries.filter((cache) => expand(cache.dir) !== target);
50
+ removed = remaining.length !== entries.length;
51
+ return remaining;
52
+ });
53
+ return removed;
54
+ }
55
+ function registeredCaches(path = manifestPath()) {
56
+ return readManifest(path).caches.filter((c) => c.dir && existsSync(c.dir)).map((c) => ({
57
+ name: c.name,
58
+ dir: c.dir,
59
+ prune: c.prune === "atomic" ? "atomic" : "entries",
60
+ entriesDepth: normalizeDepth(c.entriesDepth),
61
+ note: c.note,
62
+ layout: c.layout
63
+ }));
64
+ }
65
+ //#endregion
66
+ export { unregister as a, registeredCaches as i, readManifest as n, register as r, manifestPath as t };
@@ -0,0 +1,27 @@
1
+ //#region src/cache-manifest.d.ts
2
+ interface CacheEntry {
3
+ dir: string;
4
+ name?: string;
5
+ prune?: "atomic" | "entries";
6
+ entriesDepth?: number;
7
+ note?: string;
8
+ registeredBy?: string;
9
+ layout?: string;
10
+ }
11
+ declare function manifestPath(): string;
12
+ declare function readManifest(path?: string): {
13
+ version: number;
14
+ caches: CacheEntry[];
15
+ };
16
+ declare function register(entry: CacheEntry, path?: string): CacheEntry;
17
+ declare function unregister(dir: string, path?: string): boolean;
18
+ declare function registeredCaches(path?: string): {
19
+ name: string | undefined;
20
+ dir: string;
21
+ prune: "atomic" | "entries";
22
+ entriesDepth: number;
23
+ note: string | undefined;
24
+ layout: string | undefined;
25
+ }[];
26
+ //#endregion
27
+ export { CacheEntry, manifestPath, readManifest, register, registeredCaches, unregister };
@@ -0,0 +1,2 @@
1
+ import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-4tH64LQ9.mjs";
2
+ export { manifestPath, readManifest, register, registeredCaches, unregister };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export {}