@riddledc/riddle-proof 0.5.5 → 0.5.6
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/lib/workspace-core.mjs +96 -4
- package/package.json +1 -1
package/lib/workspace-core.mjs
CHANGED
|
@@ -2,9 +2,11 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import {
|
|
4
4
|
existsSync,
|
|
5
|
+
copyFileSync,
|
|
5
6
|
lstatSync,
|
|
6
7
|
mkdirSync,
|
|
7
8
|
readFileSync,
|
|
9
|
+
renameSync,
|
|
8
10
|
rmSync,
|
|
9
11
|
symlinkSync,
|
|
10
12
|
unlinkSync,
|
|
@@ -276,6 +278,7 @@ export function ensureWorktree({
|
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
const DEPS_MANIFEST = ".workspace-core-deps.json";
|
|
281
|
+
const DEPS_INPUT_FILES = ["package.json", "package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock"];
|
|
279
282
|
|
|
280
283
|
function depsManifestPath(projectDir) {
|
|
281
284
|
return path.join(projectDir, "node_modules", DEPS_MANIFEST);
|
|
@@ -285,7 +288,7 @@ export function computeDependencyFingerprint(projectDir) {
|
|
|
285
288
|
const packageJson = path.join(projectDir, "package.json");
|
|
286
289
|
if (!existsSync(packageJson)) return "";
|
|
287
290
|
const digest = createHash("sha256");
|
|
288
|
-
for (const name of
|
|
291
|
+
for (const name of DEPS_INPUT_FILES) {
|
|
289
292
|
const filePath = path.join(projectDir, name);
|
|
290
293
|
if (!existsSync(filePath)) continue;
|
|
291
294
|
digest.update(name);
|
|
@@ -318,6 +321,93 @@ function writeDepsManifest(projectDir, fingerprint, installCmd) {
|
|
|
318
321
|
writeFileSync(manifestPath, JSON.stringify({ fingerprint, install_cmd: installCmd }, null, 2));
|
|
319
322
|
}
|
|
320
323
|
|
|
324
|
+
function dependencyCacheRoot(projectDir) {
|
|
325
|
+
if (process.env.RIDDLE_PROOF_DISABLE_DEPS_CACHE === "1") return "";
|
|
326
|
+
const configured = (process.env.RIDDLE_PROOF_DEPS_CACHE_ROOT || "").trim();
|
|
327
|
+
if (configured) return path.resolve(configured);
|
|
328
|
+
|
|
329
|
+
const resolved = path.resolve(projectDir);
|
|
330
|
+
const worktreeMarker = `${path.sep}.riddle-proof-worktrees${path.sep}`;
|
|
331
|
+
const worktreeIndex = resolved.indexOf(worktreeMarker);
|
|
332
|
+
if (worktreeIndex >= 0) {
|
|
333
|
+
return path.join(resolved.slice(0, worktreeIndex), ".riddle-proof-deps-cache");
|
|
334
|
+
}
|
|
335
|
+
return path.join(path.dirname(resolved), ".riddle-proof-deps-cache");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function dependencyCacheKey(fingerprint, installCmd) {
|
|
339
|
+
const nodeMajor = (process.versions.node || "").split(".")[0] || "unknown";
|
|
340
|
+
return [
|
|
341
|
+
sanitizeFragment(installCmd, "install"),
|
|
342
|
+
process.platform,
|
|
343
|
+
process.arch,
|
|
344
|
+
`node${sanitizeFragment(nodeMajor, "unknown")}`,
|
|
345
|
+
fingerprint.slice(0, 24),
|
|
346
|
+
].join("-");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function copyDependencyInputs(sourceDir, targetDir) {
|
|
350
|
+
mkdirSync(targetDir, { recursive: true });
|
|
351
|
+
for (const name of DEPS_INPUT_FILES) {
|
|
352
|
+
const sourcePath = path.join(sourceDir, name);
|
|
353
|
+
if (existsSync(sourcePath)) {
|
|
354
|
+
copyFileSync(sourcePath, path.join(targetDir, name));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function linkNodeModules(projectDir, sourceModules) {
|
|
360
|
+
const projectModules = path.join(projectDir, "node_modules");
|
|
361
|
+
removePath(projectModules);
|
|
362
|
+
symlinkSync(sourceModules, projectModules, "dir");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function tryEnsureCachedDeps({ projectDir, fingerprint, installCmd }) {
|
|
366
|
+
const cacheRoot = dependencyCacheRoot(projectDir);
|
|
367
|
+
if (!cacheRoot) return "";
|
|
368
|
+
|
|
369
|
+
const cacheDir = path.join(cacheRoot, dependencyCacheKey(fingerprint, installCmd));
|
|
370
|
+
const cacheModules = path.join(cacheDir, "node_modules");
|
|
371
|
+
const cacheManifest = readDepsManifest(cacheDir);
|
|
372
|
+
if (cacheManifest.fingerprint === fingerprint && cacheManifest.install_cmd === installCmd && existsSync(cacheModules)) {
|
|
373
|
+
linkNodeModules(projectDir, cacheModules);
|
|
374
|
+
return `reused_cache:${cacheDir}`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const tempCacheDir = `${cacheDir}.tmp-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
378
|
+
try {
|
|
379
|
+
mkdirSync(path.dirname(cacheDir), { recursive: true });
|
|
380
|
+
removePath(tempCacheDir);
|
|
381
|
+
copyDependencyInputs(projectDir, tempCacheDir);
|
|
382
|
+
|
|
383
|
+
const installResult = runSafe(`${installCmd} 2>&1 | tail -5`, tempCacheDir, dependencyInstallTimeoutMs());
|
|
384
|
+
if (!installResult.ok) {
|
|
385
|
+
removePath(tempCacheDir);
|
|
386
|
+
return "";
|
|
387
|
+
}
|
|
388
|
+
writeDepsManifest(tempCacheDir, fingerprint, installCmd);
|
|
389
|
+
|
|
390
|
+
if (!existsSync(cacheDir)) {
|
|
391
|
+
try {
|
|
392
|
+
renameSync(tempCacheDir, cacheDir);
|
|
393
|
+
} catch {
|
|
394
|
+
removePath(tempCacheDir);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
removePath(tempCacheDir);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const finalManifest = readDepsManifest(cacheDir);
|
|
401
|
+
if (finalManifest.fingerprint === fingerprint && finalManifest.install_cmd === installCmd && existsSync(cacheModules)) {
|
|
402
|
+
linkNodeModules(projectDir, cacheModules);
|
|
403
|
+
return `cached:${installCmd}`;
|
|
404
|
+
}
|
|
405
|
+
} catch {
|
|
406
|
+
removePath(tempCacheDir);
|
|
407
|
+
}
|
|
408
|
+
return "";
|
|
409
|
+
}
|
|
410
|
+
|
|
321
411
|
function dependencyInstallTimeoutMs() {
|
|
322
412
|
const parsed = Number.parseInt(process.env.RIDDLE_PROOF_INSTALL_TIMEOUT_MS || "", 10);
|
|
323
413
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 600000;
|
|
@@ -337,15 +427,17 @@ export function ensureDeps({ projectDir, reuseFrom = "" } = {}) {
|
|
|
337
427
|
const sourceManifest = readDepsManifest(reuseFrom);
|
|
338
428
|
const sourceModules = path.join(reuseFrom, "node_modules");
|
|
339
429
|
if (sourceFingerprint === fingerprint && sourceManifest.fingerprint === fingerprint && existsSync(sourceModules)) {
|
|
340
|
-
|
|
341
|
-
removePath(projectModules);
|
|
342
|
-
symlinkSync(sourceModules, projectModules);
|
|
430
|
+
linkNodeModules(projectDir, sourceModules);
|
|
343
431
|
return `reused_from:${reuseFrom}`;
|
|
344
432
|
}
|
|
345
433
|
}
|
|
346
434
|
|
|
347
435
|
const installCmd = detectInstallCommand(projectDir);
|
|
348
436
|
if (!installCmd) return "no_install_command";
|
|
437
|
+
const cachedStatus = tryEnsureCachedDeps({ projectDir, fingerprint, installCmd });
|
|
438
|
+
if (cachedStatus) return cachedStatus;
|
|
439
|
+
|
|
440
|
+
removePath(path.join(projectDir, "node_modules"));
|
|
349
441
|
const installResult = runSafe(`${installCmd} 2>&1 | tail -5`, projectDir, dependencyInstallTimeoutMs());
|
|
350
442
|
if (!installResult.ok) {
|
|
351
443
|
throw new Error(`dependency install failed in ${projectDir}: ${installResult.output.slice(0, 300)}`);
|