@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.
@@ -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 ["package.json", "package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock"]) {
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
- const projectModules = path.join(projectDir, "node_modules");
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)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",