@riddledc/riddle-proof 0.5.6 → 0.5.8

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 CHANGED
@@ -78,6 +78,19 @@ way to a ready PR after proof and CI; `leave_draft: true` is only an explicit
78
78
  debug or user-request escape hatch. The notification adapter is where a host
79
79
  updates Discord, OpenClaw, GitHub, or another integration.
80
80
 
81
+ ## Runtime Scratch Space
82
+
83
+ The packaged proof-run setup uses isolated git worktrees for before and after
84
+ states. By default those worktrees now live under
85
+ `/tmp/.riddle-proof-worktrees`, with dependency caches under the matching local
86
+ temp root. This keeps repeated `node_modules` cache materialization on local
87
+ scratch storage instead of walking large dependency trees on EFS or other shared
88
+ workspace filesystems.
89
+
90
+ Set `RIDDLE_PROOF_WORKTREE_ROOT` to choose an explicit location. Set
91
+ `RIDDLE_PROOF_USE_WORKSPACE_WORKTREE_ROOT=1` to keep the previous behavior of
92
+ placing proof worktrees next to the active repository.
93
+
81
94
  ## Capture Diagnostics
82
95
 
83
96
  `@riddledc/riddle-proof/diagnostics` standardizes the evidence contract around
@@ -7,8 +7,8 @@ import {
7
7
  mkdirSync,
8
8
  readFileSync,
9
9
  renameSync,
10
+ realpathSync,
10
11
  rmSync,
11
- symlinkSync,
12
12
  unlinkSync,
13
13
  writeFileSync,
14
14
  } from "node:fs";
@@ -356,10 +356,27 @@ function copyDependencyInputs(sourceDir, targetDir) {
356
356
  }
357
357
  }
358
358
 
359
- function linkNodeModules(projectDir, sourceModules) {
359
+ function materializeNodeModules(projectDir, sourceModules) {
360
360
  const projectModules = path.join(projectDir, "node_modules");
361
361
  removePath(projectModules);
362
- symlinkSync(sourceModules, projectModules, "dir");
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";
363
380
  }
364
381
 
365
382
  function tryEnsureCachedDeps({ projectDir, fingerprint, installCmd }) {
@@ -370,7 +387,7 @@ function tryEnsureCachedDeps({ projectDir, fingerprint, installCmd }) {
370
387
  const cacheModules = path.join(cacheDir, "node_modules");
371
388
  const cacheManifest = readDepsManifest(cacheDir);
372
389
  if (cacheManifest.fingerprint === fingerprint && cacheManifest.install_cmd === installCmd && existsSync(cacheModules)) {
373
- linkNodeModules(projectDir, cacheModules);
390
+ materializeNodeModules(projectDir, cacheModules);
374
391
  return `reused_cache:${cacheDir}`;
375
392
  }
376
393
 
@@ -399,7 +416,7 @@ function tryEnsureCachedDeps({ projectDir, fingerprint, installCmd }) {
399
416
 
400
417
  const finalManifest = readDepsManifest(cacheDir);
401
418
  if (finalManifest.fingerprint === fingerprint && finalManifest.install_cmd === installCmd && existsSync(cacheModules)) {
402
- linkNodeModules(projectDir, cacheModules);
419
+ materializeNodeModules(projectDir, cacheModules);
403
420
  return `cached:${installCmd}`;
404
421
  }
405
422
  } catch {
@@ -427,7 +444,7 @@ export function ensureDeps({ projectDir, reuseFrom = "" } = {}) {
427
444
  const sourceManifest = readDepsManifest(reuseFrom);
428
445
  const sourceModules = path.join(reuseFrom, "node_modules");
429
446
  if (sourceFingerprint === fingerprint && sourceManifest.fingerprint === fingerprint && existsSync(sourceModules)) {
430
- linkNodeModules(projectDir, sourceModules);
447
+ materializeNodeModules(projectDir, sourceModules);
431
448
  return `reused_from:${reuseFrom}`;
432
449
  }
433
450
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -1,12 +1,12 @@
1
1
  """Setup: create worktrees, install deps, validate args, write state.
2
2
 
3
3
  Idempotent — safe to re-run. Creates per-run worktrees under the active
4
- workspace root by default:
5
- <workspace>/.riddle-proof-worktrees/riddle-proof-<run_id>-before
6
- <workspace>/.riddle-proof-worktrees/riddle-proof-<run_id>-after
4
+ local temp storage by default:
5
+ /tmp/.riddle-proof-worktrees/riddle-proof-<run_id>-before
6
+ /tmp/.riddle-proof-worktrees/riddle-proof-<run_id>-after
7
7
  """
8
8
 
9
- import json, subprocess as sp, os, sys, shutil, time
9
+ import json, subprocess as sp, os, sys, shutil, time, tempfile
10
10
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
11
11
  from util import load_state, save_state, git, shell_quote
12
12
 
@@ -160,8 +160,14 @@ def resolve_worktree_root(repo_dir):
160
160
  configured = (s.get('worktree_root') or os.environ.get('RIDDLE_PROOF_WORKTREE_ROOT') or '').strip()
161
161
  if configured:
162
162
  return os.path.abspath(os.path.expanduser(configured))
163
- repo_parent = os.path.dirname(os.path.abspath(repo_dir))
164
- return os.path.join(repo_parent, '.riddle-proof-worktrees')
163
+ if os.environ.get('RIDDLE_PROOF_USE_WORKSPACE_WORKTREE_ROOT', '').strip().lower() in ('1', 'true', 'yes'):
164
+ repo_parent = os.path.dirname(os.path.abspath(repo_dir))
165
+ return os.path.join(repo_parent, '.riddle-proof-worktrees')
166
+
167
+ # Proof worktrees are scratch data. Keep them on local temp storage by
168
+ # default so dependency cache materialization does not crawl across EFS or
169
+ # other shared workspace filesystems.
170
+ return os.path.join(tempfile.gettempdir(), '.riddle-proof-worktrees')
165
171
 
166
172
 
167
173
  def cleanup_legacy_branch_worktrees(repo_dir, branch_name):