@riddledc/riddle-proof 0.5.5 → 0.5.7
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 +114 -5
- package/package.json +1 -1
package/lib/workspace-core.mjs
CHANGED
|
@@ -2,11 +2,13 @@ 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,
|
|
10
|
+
realpathSync,
|
|
8
11
|
rmSync,
|
|
9
|
-
symlinkSync,
|
|
10
12
|
unlinkSync,
|
|
11
13
|
writeFileSync,
|
|
12
14
|
} from "node:fs";
|
|
@@ -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,110 @@ 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 materializeNodeModules(projectDir, sourceModules) {
|
|
360
|
+
const projectModules = path.join(projectDir, "node_modules");
|
|
361
|
+
removePath(projectModules);
|
|
362
|
+
const resolvedSource = realpathSync(sourceModules);
|
|
363
|
+
const hardlinkResult = runSafe(
|
|
364
|
+
`cp -al ${shellQuote(resolvedSource)} ${shellQuote(projectModules)}`,
|
|
365
|
+
undefined,
|
|
366
|
+
dependencyInstallTimeoutMs(),
|
|
367
|
+
);
|
|
368
|
+
if (hardlinkResult.ok && existsSync(projectModules)) return "hardlinked";
|
|
369
|
+
|
|
370
|
+
removePath(projectModules);
|
|
371
|
+
const copyResult = runSafe(
|
|
372
|
+
`cp -a ${shellQuote(resolvedSource)} ${shellQuote(projectModules)}`,
|
|
373
|
+
undefined,
|
|
374
|
+
dependencyInstallTimeoutMs(),
|
|
375
|
+
);
|
|
376
|
+
if (!copyResult.ok || !existsSync(projectModules)) {
|
|
377
|
+
throw new Error(`dependency materialization failed in ${projectDir}: ${copyResult.output.slice(0, 300)}`);
|
|
378
|
+
}
|
|
379
|
+
return "copied";
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function tryEnsureCachedDeps({ projectDir, fingerprint, installCmd }) {
|
|
383
|
+
const cacheRoot = dependencyCacheRoot(projectDir);
|
|
384
|
+
if (!cacheRoot) return "";
|
|
385
|
+
|
|
386
|
+
const cacheDir = path.join(cacheRoot, dependencyCacheKey(fingerprint, installCmd));
|
|
387
|
+
const cacheModules = path.join(cacheDir, "node_modules");
|
|
388
|
+
const cacheManifest = readDepsManifest(cacheDir);
|
|
389
|
+
if (cacheManifest.fingerprint === fingerprint && cacheManifest.install_cmd === installCmd && existsSync(cacheModules)) {
|
|
390
|
+
materializeNodeModules(projectDir, cacheModules);
|
|
391
|
+
return `reused_cache:${cacheDir}`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const tempCacheDir = `${cacheDir}.tmp-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
395
|
+
try {
|
|
396
|
+
mkdirSync(path.dirname(cacheDir), { recursive: true });
|
|
397
|
+
removePath(tempCacheDir);
|
|
398
|
+
copyDependencyInputs(projectDir, tempCacheDir);
|
|
399
|
+
|
|
400
|
+
const installResult = runSafe(`${installCmd} 2>&1 | tail -5`, tempCacheDir, dependencyInstallTimeoutMs());
|
|
401
|
+
if (!installResult.ok) {
|
|
402
|
+
removePath(tempCacheDir);
|
|
403
|
+
return "";
|
|
404
|
+
}
|
|
405
|
+
writeDepsManifest(tempCacheDir, fingerprint, installCmd);
|
|
406
|
+
|
|
407
|
+
if (!existsSync(cacheDir)) {
|
|
408
|
+
try {
|
|
409
|
+
renameSync(tempCacheDir, cacheDir);
|
|
410
|
+
} catch {
|
|
411
|
+
removePath(tempCacheDir);
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
removePath(tempCacheDir);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const finalManifest = readDepsManifest(cacheDir);
|
|
418
|
+
if (finalManifest.fingerprint === fingerprint && finalManifest.install_cmd === installCmd && existsSync(cacheModules)) {
|
|
419
|
+
materializeNodeModules(projectDir, cacheModules);
|
|
420
|
+
return `cached:${installCmd}`;
|
|
421
|
+
}
|
|
422
|
+
} catch {
|
|
423
|
+
removePath(tempCacheDir);
|
|
424
|
+
}
|
|
425
|
+
return "";
|
|
426
|
+
}
|
|
427
|
+
|
|
321
428
|
function dependencyInstallTimeoutMs() {
|
|
322
429
|
const parsed = Number.parseInt(process.env.RIDDLE_PROOF_INSTALL_TIMEOUT_MS || "", 10);
|
|
323
430
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 600000;
|
|
@@ -337,15 +444,17 @@ export function ensureDeps({ projectDir, reuseFrom = "" } = {}) {
|
|
|
337
444
|
const sourceManifest = readDepsManifest(reuseFrom);
|
|
338
445
|
const sourceModules = path.join(reuseFrom, "node_modules");
|
|
339
446
|
if (sourceFingerprint === fingerprint && sourceManifest.fingerprint === fingerprint && existsSync(sourceModules)) {
|
|
340
|
-
|
|
341
|
-
removePath(projectModules);
|
|
342
|
-
symlinkSync(sourceModules, projectModules);
|
|
447
|
+
materializeNodeModules(projectDir, sourceModules);
|
|
343
448
|
return `reused_from:${reuseFrom}`;
|
|
344
449
|
}
|
|
345
450
|
}
|
|
346
451
|
|
|
347
452
|
const installCmd = detectInstallCommand(projectDir);
|
|
348
453
|
if (!installCmd) return "no_install_command";
|
|
454
|
+
const cachedStatus = tryEnsureCachedDeps({ projectDir, fingerprint, installCmd });
|
|
455
|
+
if (cachedStatus) return cachedStatus;
|
|
456
|
+
|
|
457
|
+
removePath(path.join(projectDir, "node_modules"));
|
|
349
458
|
const installResult = runSafe(`${installCmd} 2>&1 | tail -5`, projectDir, dependencyInstallTimeoutMs());
|
|
350
459
|
if (!installResult.ok) {
|
|
351
460
|
throw new Error(`dependency install failed in ${projectDir}: ${installResult.output.slice(0, 300)}`);
|