@stim-cli/core 1.15.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.
- package/README.md +3 -0
- package/dist/{core-BwaxUjLX.mjs → core-DWOUn9xp.mjs} +58 -12
- package/dist/{index-DgLuTAvh.d.mts → index-DPo8Bexj.d.mts} +563 -161
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -1
- package/dist/phone-protocol.d.mts +28 -4
- package/dist/{protocol-BjnE921M.d.mts → protocol-B0KcaUee.d.mts} +35 -12
- package/dist/protocol.d.mts +2 -2
- package/dist/protocol.mjs +8 -1
- package/dist/receive-protocol.mjs +7303 -4115
- package/dist/state.d.mts +2 -2
- package/dist/state.mjs +1055 -81
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,9 @@ path layout, the config and workspace state types and readers, the settings
|
|
|
34
34
|
registry and its JSON Schema, the created-device and EAS session ledger readers,
|
|
35
35
|
NDJSON log records and queries, and the status and settings payload types. The
|
|
36
36
|
CLI owns every write to that state. The cache packages do not import it.
|
|
37
|
+
Setup journals are an exception: stim-server writes and prunes
|
|
38
|
+
`$STIM_HOME/server/setup/<sha256(ticket) hex>.json`; core owns their paths,
|
|
39
|
+
strict parser and reader.
|
|
37
40
|
|
|
38
41
|
`@stim-cli/core/oversight` holds the pure notification and needs-attention rules
|
|
39
42
|
shared by stim-server and the phone. It imports no Node APIs; mobile consumers
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { S as quotedPath, _ as releaseClaim, r as ClaimRefusedError, x as tryAcquireClaim } from "./ownership-claim-O31Y5iIb.mjs";
|
|
2
|
-
import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
|
|
2
|
+
import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path, { basename, dirname, join } from "node:path";
|
|
5
5
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
6
7
|
import { connect, createServer, isIP } from "node:net";
|
|
7
8
|
//#region dir-lock.ts
|
|
8
9
|
const DEFAULT_LOCK_WAIT_MS = 12e3;
|
|
@@ -255,27 +256,72 @@ function storeArtifact(dest, buildPath, { runFile, overwrite = false, writeMetad
|
|
|
255
256
|
}
|
|
256
257
|
//#endregion
|
|
257
258
|
//#region compiled-helper.ts
|
|
259
|
+
const RECENT_MS = 6e5;
|
|
260
|
+
const pruned = /* @__PURE__ */ new Set();
|
|
261
|
+
function isHelperName(entry, name) {
|
|
262
|
+
return entry.length === name.length + 17 && entry.startsWith(`${name}-`) && /^[0-9a-f]{16}$/.test(entry.slice(name.length + 1));
|
|
263
|
+
}
|
|
264
|
+
function selectHelpersToPrune(entries, currentName, name, running) {
|
|
265
|
+
return entries.filter((entry) => isHelperName(entry.name, name) && entry.name !== currentName).toSorted((a, b) => b.mtimeMs - a.mtimeMs || a.name.localeCompare(b.name)).slice(1).filter((entry) => !running.has(entry.name)).map((entry) => entry.name);
|
|
266
|
+
}
|
|
267
|
+
function runningExecutablePaths() {
|
|
268
|
+
const result = spawnSync("ps", ["-axo", "comm="], {
|
|
269
|
+
encoding: "utf8",
|
|
270
|
+
timeout: 500
|
|
271
|
+
});
|
|
272
|
+
if (result.error || result.status !== 0 || typeof result.stdout !== "string" || !result.stdout.trim()) return null;
|
|
273
|
+
return new Set(result.stdout.split("\n").map((line) => line.trim()).filter(Boolean));
|
|
274
|
+
}
|
|
275
|
+
function pruneCompiledHelpers(dir, currentName, name, runningPaths = runningExecutablePaths) {
|
|
276
|
+
try {
|
|
277
|
+
const entries = readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && isHelperName(entry.name, name)).map((entry) => ({
|
|
278
|
+
name: entry.name,
|
|
279
|
+
mtimeMs: statSync(join(dir, entry.name)).mtimeMs
|
|
280
|
+
}));
|
|
281
|
+
if (entries.length <= 2) return;
|
|
282
|
+
const paths = runningPaths();
|
|
283
|
+
if (paths === null) return;
|
|
284
|
+
const canonicalPaths = /* @__PURE__ */ new Set();
|
|
285
|
+
for (const path of paths) try {
|
|
286
|
+
canonicalPaths.add(realpathSync(path));
|
|
287
|
+
} catch {}
|
|
288
|
+
const running = /* @__PURE__ */ new Set();
|
|
289
|
+
for (const entry of entries) try {
|
|
290
|
+
if (canonicalPaths.has(realpathSync(join(dir, entry.name)))) running.add(entry.name);
|
|
291
|
+
} catch {
|
|
292
|
+
running.add(entry.name);
|
|
293
|
+
}
|
|
294
|
+
const recent = Date.now() - RECENT_MS;
|
|
295
|
+
for (const entry of entries) if (entry.mtimeMs > recent) running.add(entry.name);
|
|
296
|
+
for (const entry of selectHelpersToPrune(entries, currentName, name, running)) rmSync(join(dir, entry), { force: true });
|
|
297
|
+
} catch {}
|
|
298
|
+
}
|
|
258
299
|
/**
|
|
259
300
|
* Returns `<dir>/<name>-<hash>`, compiling it with `compile` first when it is missing. The hash covers `version` and
|
|
260
301
|
* each input's name and bytes, so a changed source or compiler builds a new helper beside the old one. `compile`
|
|
261
302
|
* writes to a private temporary path that is renamed into place, so concurrent builders never expose a partial file.
|
|
303
|
+
* Pruning is best effort and keeps this helper, the newest previous build, helpers modified in the last ten minutes and running helpers. It runs after a build and on the first call per process.
|
|
262
304
|
*/
|
|
263
305
|
async function compiledHelper({ dir, name, inputs, version, compile }) {
|
|
264
306
|
const hash = createHash("sha256").update(version);
|
|
265
307
|
for (const input of inputs) hash.update(basename(input)).update(readFileSync(input));
|
|
266
308
|
const helper = join(dir, `${name}-${hash.digest("hex").slice(0, 16)}`);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
309
|
+
const built = !existsSync(helper);
|
|
310
|
+
if (built) {
|
|
311
|
+
mkdirSync(dir, {
|
|
312
|
+
recursive: true,
|
|
313
|
+
mode: 448
|
|
314
|
+
});
|
|
315
|
+
const output = `${helper}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
|
|
316
|
+
try {
|
|
317
|
+
await compile(output);
|
|
318
|
+
renameSync(output, helper);
|
|
319
|
+
} finally {
|
|
320
|
+
rmSync(output, { force: true });
|
|
321
|
+
}
|
|
278
322
|
}
|
|
323
|
+
if (built || !pruned.has(`${dir}/${name}`)) pruneCompiledHelpers(dir, basename(helper), name);
|
|
324
|
+
pruned.add(`${dir}/${name}`);
|
|
279
325
|
return helper;
|
|
280
326
|
}
|
|
281
327
|
//#endregion
|