@riddledc/riddle-proof 0.5.11 → 0.5.12
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 +7 -0
- package/package.json +1 -1
- package/runtime/lib/setup.py +112 -0
package/README.md
CHANGED
|
@@ -91,6 +91,13 @@ Set `RIDDLE_PROOF_WORKTREE_ROOT` to choose an explicit location. Set
|
|
|
91
91
|
`RIDDLE_PROOF_USE_WORKSPACE_WORKTREE_ROOT=1` to keep the previous behavior of
|
|
92
92
|
placing proof worktrees next to the active repository.
|
|
93
93
|
|
|
94
|
+
When local scratch storage is low, setup prunes stale
|
|
95
|
+
`riddle-proof-*` worktrees from the scratch root before creating the next run.
|
|
96
|
+
This preserves the dependency cache for speed while avoiding old failed runs
|
|
97
|
+
filling `/tmp`. Set `RIDDLE_PROOF_KEEP_SCRATCH_WORKTREES=1` to disable that
|
|
98
|
+
cleanup for debugging, or tune the low-space threshold with
|
|
99
|
+
`RIDDLE_PROOF_MIN_SCRATCH_FREE_MB`.
|
|
100
|
+
|
|
94
101
|
## Capture Diagnostics
|
|
95
102
|
|
|
96
103
|
`@riddledc/riddle-proof/diagnostics` standardizes the evidence contract around
|
package/package.json
CHANGED
package/runtime/lib/setup.py
CHANGED
|
@@ -170,6 +170,113 @@ def resolve_worktree_root(repo_dir):
|
|
|
170
170
|
return os.path.join(tempfile.gettempdir(), '.riddle-proof-worktrees')
|
|
171
171
|
|
|
172
172
|
|
|
173
|
+
def env_flag(name, default=False):
|
|
174
|
+
raw = os.environ.get(name, '').strip().lower()
|
|
175
|
+
if raw in ('1', 'true', 'yes', 'on'):
|
|
176
|
+
return True
|
|
177
|
+
if raw in ('0', 'false', 'no', 'off'):
|
|
178
|
+
return False
|
|
179
|
+
return default
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def env_int(name, default):
|
|
183
|
+
raw = os.environ.get(name, '').strip()
|
|
184
|
+
try:
|
|
185
|
+
value = int(raw)
|
|
186
|
+
except Exception:
|
|
187
|
+
return default
|
|
188
|
+
return value if value > 0 else default
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def disk_free_bytes(path):
|
|
192
|
+
probe = path
|
|
193
|
+
while probe and not os.path.exists(probe):
|
|
194
|
+
parent = os.path.dirname(probe)
|
|
195
|
+
if parent == probe:
|
|
196
|
+
break
|
|
197
|
+
probe = parent
|
|
198
|
+
try:
|
|
199
|
+
return shutil.disk_usage(probe or tempfile.gettempdir()).free
|
|
200
|
+
except Exception:
|
|
201
|
+
return 0
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def prune_scratch_worktrees(worktree_root, keep_dirs, repo_dir):
|
|
205
|
+
report = {
|
|
206
|
+
'requested': True,
|
|
207
|
+
'worktree_root': worktree_root,
|
|
208
|
+
'removed': [],
|
|
209
|
+
'errors': [],
|
|
210
|
+
}
|
|
211
|
+
if env_flag('RIDDLE_PROOF_KEEP_SCRATCH_WORKTREES', False):
|
|
212
|
+
report['skipped'] = 'RIDDLE_PROOF_KEEP_SCRATCH_WORKTREES'
|
|
213
|
+
return report
|
|
214
|
+
if not worktree_root:
|
|
215
|
+
report['skipped'] = 'missing_worktree_root'
|
|
216
|
+
return report
|
|
217
|
+
|
|
218
|
+
root = os.path.abspath(os.path.expanduser(worktree_root))
|
|
219
|
+
temp_root = os.path.abspath(tempfile.gettempdir())
|
|
220
|
+
if root in ('/', temp_root) or not root.endswith('.riddle-proof-worktrees'):
|
|
221
|
+
report['skipped'] = 'unsafe_worktree_root'
|
|
222
|
+
return report
|
|
223
|
+
if not os.path.isdir(root):
|
|
224
|
+
report['skipped'] = 'worktree_root_missing'
|
|
225
|
+
return report
|
|
226
|
+
|
|
227
|
+
min_free_bytes = env_int('RIDDLE_PROOF_MIN_SCRATCH_FREE_MB', 2048) * 1024 * 1024
|
|
228
|
+
free_before = disk_free_bytes(root)
|
|
229
|
+
report['free_before_bytes'] = free_before
|
|
230
|
+
report['min_free_bytes'] = min_free_bytes
|
|
231
|
+
if free_before >= min_free_bytes:
|
|
232
|
+
report['skipped'] = 'enough_free_space'
|
|
233
|
+
return report
|
|
234
|
+
|
|
235
|
+
keep = set(os.path.abspath(os.path.expanduser(p)) for p in keep_dirs if p)
|
|
236
|
+
candidates = []
|
|
237
|
+
for name in os.listdir(root):
|
|
238
|
+
if not name.startswith('riddle-proof-'):
|
|
239
|
+
continue
|
|
240
|
+
path = os.path.join(root, name)
|
|
241
|
+
resolved = os.path.abspath(path)
|
|
242
|
+
if resolved in keep or not os.path.isdir(path):
|
|
243
|
+
continue
|
|
244
|
+
try:
|
|
245
|
+
mtime = os.path.getmtime(path)
|
|
246
|
+
except Exception:
|
|
247
|
+
mtime = 0
|
|
248
|
+
candidates.append((mtime, path))
|
|
249
|
+
candidates.sort()
|
|
250
|
+
|
|
251
|
+
for _, path in candidates:
|
|
252
|
+
if disk_free_bytes(root) >= min_free_bytes:
|
|
253
|
+
break
|
|
254
|
+
removed_by_git = False
|
|
255
|
+
git_error = ''
|
|
256
|
+
if repo_dir and os.path.exists(os.path.join(repo_dir, '.git')):
|
|
257
|
+
remove_result = sp.run(
|
|
258
|
+
'git worktree remove --force ' + shell_quote(path),
|
|
259
|
+
shell=True,
|
|
260
|
+
cwd=repo_dir,
|
|
261
|
+
capture_output=True,
|
|
262
|
+
text=True,
|
|
263
|
+
)
|
|
264
|
+
removed_by_git = remove_result.returncode == 0
|
|
265
|
+
if remove_result.returncode != 0 and os.path.exists(path):
|
|
266
|
+
git_error = (remove_result.stderr or remove_result.stdout or '')[:300]
|
|
267
|
+
if os.path.exists(path):
|
|
268
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
269
|
+
if not os.path.exists(path):
|
|
270
|
+
report['removed'].append({'path': path, 'via': 'git' if removed_by_git else 'filesystem'})
|
|
271
|
+
elif git_error:
|
|
272
|
+
report['errors'].append({'path': path, 'git_error': git_error})
|
|
273
|
+
|
|
274
|
+
if repo_dir and os.path.exists(os.path.join(repo_dir, '.git')):
|
|
275
|
+
git('git worktree prune', repo_dir)
|
|
276
|
+
report['free_after_bytes'] = disk_free_bytes(root)
|
|
277
|
+
return report
|
|
278
|
+
|
|
279
|
+
|
|
173
280
|
def cleanup_legacy_branch_worktrees(repo_dir, branch_name):
|
|
174
281
|
if not repo_dir or not os.path.exists(os.path.join(repo_dir, '.git')):
|
|
175
282
|
return
|
|
@@ -370,6 +477,11 @@ s['worktree_root'] = WORKTREE_ROOT
|
|
|
370
477
|
save_state(s)
|
|
371
478
|
print('Prepared workspace via ' + setup.get('source', 'workspace_core') + ': ' + repo_dir)
|
|
372
479
|
os.makedirs(WORKTREE_ROOT, exist_ok=True)
|
|
480
|
+
scratch_cleanup = prune_scratch_worktrees(WORKTREE_ROOT, (BEFORE_DIR, AFTER_DIR), repo_dir)
|
|
481
|
+
if scratch_cleanup.get('removed') or scratch_cleanup.get('errors'):
|
|
482
|
+
print('Scratch cleanup: removed ' + str(len(scratch_cleanup.get('removed') or [])) + ' stale proof worktree(s)')
|
|
483
|
+
s['scratch_cleanup'] = scratch_cleanup
|
|
484
|
+
save_state(s)
|
|
373
485
|
cleanup_legacy_branch_worktrees(repo_dir, base_branch)
|
|
374
486
|
|
|
375
487
|
# Clean any stale worktrees for this run and the legacy fixed paths
|