@bookedsolid/rea 0.47.0 → 0.48.0
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/MIGRATING.md +88 -0
- package/THREAT_MODEL.md +140 -0
- package/dist/policy/loader.d.ts +13 -0
- package/dist/policy/loader.js +36 -0
- package/dist/policy/types.d.ts +52 -0
- package/hooks/_lib/shim-cache.sh +650 -0
- package/hooks/_lib/shim-runtime.sh +293 -3
- package/package.json +1 -1
- package/scripts/profile-hooks.mjs +10 -1
- package/templates/_lib_shim-cache.dogfood-staged.sh +650 -0
- package/templates/_lib_shim-runtime.dogfood-staged.sh +293 -3
|
@@ -137,6 +137,15 @@
|
|
|
137
137
|
|
|
138
138
|
set -uo pipefail
|
|
139
139
|
|
|
140
|
+
# Source the per-session cache helper (0.48.0). This must be sourced
|
|
141
|
+
# at the top of shim-runtime.sh because `shim_run` needs all of the
|
|
142
|
+
# `shim_cache_*` functions available. The helper itself fails safe —
|
|
143
|
+
# no operations fire unless `shim_run` calls them.
|
|
144
|
+
# shellcheck source=shim-cache.sh
|
|
145
|
+
_SHIM_RUNTIME_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
146
|
+
# shellcheck source=shim-cache.sh
|
|
147
|
+
. "$_SHIM_RUNTIME_DIR/shim-cache.sh"
|
|
148
|
+
|
|
140
149
|
# -----------------------------------------------------------------------------
|
|
141
150
|
# Defaults — applied by `shim_run` when the shim hasn't set them. We use
|
|
142
151
|
# the `:=` operator to assign-if-unset so callers can override.
|
|
@@ -303,6 +312,241 @@ shim_run() {
|
|
|
303
312
|
# 4. Resolve CLI.
|
|
304
313
|
shim_resolve_cli
|
|
305
314
|
|
|
315
|
+
# 4b. Per-session cache lookup (0.48.0). When the cache is enabled
|
|
316
|
+
# AND the resolved CLI matches a recent same-session entry, the
|
|
317
|
+
# sandbox check (step 5) AND version probe (step 8) can both be
|
|
318
|
+
# skipped — those answers do not change for a stable CLI inside a
|
|
319
|
+
# stable session. Cache MISS / disabled / corrupt → fall through
|
|
320
|
+
# to the existing uncached hot path. NEVER fail closed on a cache
|
|
321
|
+
# error (see hooks/_lib/shim-cache.sh header for the security
|
|
322
|
+
# contract). The cache check runs AFTER `shim_is_relevant` (per
|
|
323
|
+
# design memo concern #3) so we never pay a stat-per-fire cost
|
|
324
|
+
# for irrelevant payloads.
|
|
325
|
+
local _shim_cache_hit=0
|
|
326
|
+
local _shim_cache_key=""
|
|
327
|
+
local _shim_cache_cli_real=""
|
|
328
|
+
local _shim_cache_cli_mtime=""
|
|
329
|
+
local _shim_cache_cli_size=""
|
|
330
|
+
local _shim_cache_pkg_real=""
|
|
331
|
+
local _shim_cache_pkg_mtime=""
|
|
332
|
+
local _shim_cache_pkg_size=""
|
|
333
|
+
local _shim_cache_dist_mtime=""
|
|
334
|
+
local _shim_cache_node_real=""
|
|
335
|
+
local _shim_cache_node_mtime=""
|
|
336
|
+
if [ "${#REA_ARGV[@]}" -gt 0 ] && ! shim_cache_disabled; then
|
|
337
|
+
local _stat_out=""
|
|
338
|
+
local _proj_real=""
|
|
339
|
+
local _euid=""
|
|
340
|
+
local _session_tok=""
|
|
341
|
+
_stat_out=$(shim_cache_mtime_size "$RESOLVED_CLI_PATH" 2>/dev/null || true)
|
|
342
|
+
# 0.48.0 codex round-4 P1 + round-7 P2: capture the ACTUAL node
|
|
343
|
+
# interpreter realpath + mtime via `process.execPath` (node's own
|
|
344
|
+
# path to itself). Pre-round-7 we resolved `command -v node` via
|
|
345
|
+
# `fs.realpathSync` — but version managers like Volta and asdf
|
|
346
|
+
# use STABLE shim scripts (e.g. ~/.volta/bin/node) that resolve
|
|
347
|
+
# to themselves; only the spawned node's `process.execPath`
|
|
348
|
+
# reveals which concrete Node binary the shim ultimately
|
|
349
|
+
# launched (e.g. /Users/foo/.volta/tools/image/node/22.x.x/bin/
|
|
350
|
+
# node). Using execPath catches `volta pin`/`nvm use` interpreter
|
|
351
|
+
# swaps correctly. The mtime field is captured at second
|
|
352
|
+
# precision (consistent with the other mtime fields) — switching
|
|
353
|
+
# Node versions changes the realpath so the mtime alone is not
|
|
354
|
+
# load-bearing.
|
|
355
|
+
_shim_cache_node_real=$(node -e 'process.stdout.write(require("fs").realpathSync(process.execPath))' 2>/dev/null || true)
|
|
356
|
+
if [ -n "$_shim_cache_node_real" ]; then
|
|
357
|
+
local _node_stat=""
|
|
358
|
+
_node_stat=$(shim_cache_mtime_size "$_shim_cache_node_real" 2>/dev/null || true)
|
|
359
|
+
if [ -n "$_node_stat" ]; then
|
|
360
|
+
_shim_cache_node_mtime="${_node_stat%% *}"
|
|
361
|
+
fi
|
|
362
|
+
fi
|
|
363
|
+
_shim_cache_cli_real=$(node -e 'try { process.stdout.write(require("fs").realpathSync(process.argv[1])); } catch (e) { process.exit(1); }' -- "$RESOLVED_CLI_PATH" 2>/dev/null || true)
|
|
364
|
+
_proj_real=$(node -e 'try { process.stdout.write(require("fs").realpathSync(process.argv[1])); } catch (e) { process.exit(1); }' -- "$proj" 2>/dev/null || true)
|
|
365
|
+
_euid=$(id -u 2>/dev/null || true)
|
|
366
|
+
_session_tok=$(shim_cache_session_token 2>/dev/null || true)
|
|
367
|
+
# 0.48.0 codex round-3 P2: ALSO capture the ancestor package.json
|
|
368
|
+
# path + mtime/size. The sandbox check walks upward to find a
|
|
369
|
+
# package.json whose `name` is `@bookedsolid/rea`; without it in
|
|
370
|
+
# the key, a same-session edit to that package.json (renaming, or
|
|
371
|
+
# removing the `name` field) would still see warm cache hits even
|
|
372
|
+
# though the uncached sandbox check would reject the new state.
|
|
373
|
+
# Codex round-3 P1: ALSO capture the dist/cli/ DIR mtime so a
|
|
374
|
+
# rebuild that adds/removes files (most fresh tsc runs after a
|
|
375
|
+
# source-tree change) invalidates the key even if dist/cli/
|
|
376
|
+
# index.js content happens to round to the same ns.
|
|
377
|
+
_shim_cache_pkg_real=$(node -e '
|
|
378
|
+
try {
|
|
379
|
+
const fs = require("fs");
|
|
380
|
+
const path = require("path");
|
|
381
|
+
const real = fs.realpathSync(process.argv[1]);
|
|
382
|
+
let cur = path.dirname(path.dirname(path.dirname(real)));
|
|
383
|
+
for (let i = 0; i < 20 && cur && cur !== path.dirname(cur); i++) {
|
|
384
|
+
const pj = path.join(cur, "package.json");
|
|
385
|
+
if (fs.existsSync(pj)) {
|
|
386
|
+
try {
|
|
387
|
+
const data = JSON.parse(fs.readFileSync(pj, "utf8"));
|
|
388
|
+
if (data && data.name === "@bookedsolid/rea") {
|
|
389
|
+
process.stdout.write(pj);
|
|
390
|
+
process.exit(0);
|
|
391
|
+
}
|
|
392
|
+
} catch (e) {}
|
|
393
|
+
}
|
|
394
|
+
cur = path.dirname(cur);
|
|
395
|
+
}
|
|
396
|
+
process.exit(1);
|
|
397
|
+
} catch (e) { process.exit(1); }
|
|
398
|
+
' -- "$RESOLVED_CLI_PATH" 2>/dev/null || true)
|
|
399
|
+
if [ -n "$_shim_cache_pkg_real" ]; then
|
|
400
|
+
local _pkg_stat=""
|
|
401
|
+
_pkg_stat=$(shim_cache_mtime_size "$_shim_cache_pkg_real" 2>/dev/null || true)
|
|
402
|
+
if [ -n "$_pkg_stat" ]; then
|
|
403
|
+
_shim_cache_pkg_mtime="${_pkg_stat%% *}"
|
|
404
|
+
_shim_cache_pkg_size="${_pkg_stat##* }"
|
|
405
|
+
fi
|
|
406
|
+
fi
|
|
407
|
+
# 0.48.0 codex round-5/7/9 — the cache key incorporates a hash of
|
|
408
|
+
# every `*.js` file's mtime across the FULL dist tree, not just
|
|
409
|
+
# dist/cli/. Pre-round-9 the hash covered only dist/cli/*.js, but
|
|
410
|
+
# `rea hook` actually executes a much larger module graph:
|
|
411
|
+
# dist/cli/hook.js imports ../hooks/**, ../policy/loader.js,
|
|
412
|
+
# ../audit/**, etc. A same-session rebuild that rewrote one of
|
|
413
|
+
# those imported files in place without touching a top-level
|
|
414
|
+
# dist/cli/*.js file would leave the hash unchanged, the warm
|
|
415
|
+
# cache would survive, and shim_run would skip the version probe
|
|
416
|
+
# against a changed CLI runtime. Hashing dist/**/*.js closes the
|
|
417
|
+
# gap. Cost: ~15ms on the rea dist (141 files) via `find -exec
|
|
418
|
+
# stat +` batched into a single subprocess call.
|
|
419
|
+
local _dist_root=""
|
|
420
|
+
# dist root is two parents above dist/cli/index.js
|
|
421
|
+
_dist_root=$(dirname "$(dirname "$RESOLVED_CLI_PATH")" 2>/dev/null || true)
|
|
422
|
+
if [ -n "$_dist_root" ] && [ -d "$_dist_root" ]; then
|
|
423
|
+
# 0.48.0 codex round-6 P2: pick a hasher that exists. macOS
|
|
424
|
+
# ships `shasum` (perl); GNU coreutils provides `sha256sum`.
|
|
425
|
+
local _hasher=""
|
|
426
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
427
|
+
_hasher="shasum -a 256"
|
|
428
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
429
|
+
_hasher="sha256sum"
|
|
430
|
+
fi
|
|
431
|
+
if [ -n "$_hasher" ]; then
|
|
432
|
+
# 0.48.0 codex round-7 P2: ns-precision mtime so a
|
|
433
|
+
# same-second rewrite is caught. Try macOS `-f` form first;
|
|
434
|
+
# fall through to GNU `-c` on failure. `find -exec stat +`
|
|
435
|
+
# batches all paths into ONE stat call (~15ms total instead
|
|
436
|
+
# of the per-file 365ms loop).
|
|
437
|
+
local _stat_macos=""
|
|
438
|
+
local _stat_gnu=""
|
|
439
|
+
_stat_macos=$(find "$_dist_root" -name '*.js' -type f -exec stat -f "%Fm %z %N" {} + 2>/dev/null || true)
|
|
440
|
+
if [ -n "$_stat_macos" ]; then
|
|
441
|
+
_shim_cache_dist_mtime=$(printf '%s' "$_stat_macos" | sort | $_hasher 2>/dev/null | awk '{print $1}' | cut -c1-32)
|
|
442
|
+
else
|
|
443
|
+
_stat_gnu=$(find "$_dist_root" -name '*.js' -type f -exec stat -c "%.Y %s %n" {} + 2>/dev/null || true)
|
|
444
|
+
if [ -n "$_stat_gnu" ]; then
|
|
445
|
+
_shim_cache_dist_mtime=$(printf '%s' "$_stat_gnu" | sort | $_hasher 2>/dev/null | awk '{print $1}' | cut -c1-32)
|
|
446
|
+
fi
|
|
447
|
+
fi
|
|
448
|
+
fi
|
|
449
|
+
# Last-ditch fallback: just the dist/cli/ dir mtime (round-3
|
|
450
|
+
# behavior). Keeps the cache functional even when find / stat /
|
|
451
|
+
# shasum / sha256sum are all unavailable (truly stripped
|
|
452
|
+
# container) — though that's already the case where the cache
|
|
453
|
+
# layer should fall back to disabled via the session token.
|
|
454
|
+
if [ -z "$_shim_cache_dist_mtime" ]; then
|
|
455
|
+
local _cli_dir=""
|
|
456
|
+
_cli_dir=$(dirname "$RESOLVED_CLI_PATH" 2>/dev/null || true)
|
|
457
|
+
if [ -n "$_cli_dir" ] && [ -d "$_cli_dir" ]; then
|
|
458
|
+
local _dir_stat=""
|
|
459
|
+
_dir_stat=$(shim_cache_mtime_size "$_cli_dir" 2>/dev/null || true)
|
|
460
|
+
if [ -n "$_dir_stat" ]; then
|
|
461
|
+
_shim_cache_dist_mtime="${_dir_stat%% *}"
|
|
462
|
+
fi
|
|
463
|
+
fi
|
|
464
|
+
fi
|
|
465
|
+
fi
|
|
466
|
+
if [ -n "$_stat_out" ] && [ -n "$_shim_cache_cli_real" ] && [ -n "$_proj_real" ] \
|
|
467
|
+
&& [ -n "$_euid" ] && [ -n "$_session_tok" ] \
|
|
468
|
+
&& [ -n "$_shim_cache_pkg_real" ] && [ -n "$_shim_cache_pkg_mtime" ] \
|
|
469
|
+
&& [ -n "$_shim_cache_dist_mtime" ] \
|
|
470
|
+
&& [ -n "$_shim_cache_node_real" ] && [ -n "$_shim_cache_node_mtime" ]; then
|
|
471
|
+
_shim_cache_cli_mtime="${_stat_out%% *}"
|
|
472
|
+
_shim_cache_cli_size="${_stat_out##* }"
|
|
473
|
+
# 0.48.0 codex round-1 P1: the key MUST include SHIM_NAME because
|
|
474
|
+
# step 8's version probe is `rea hook $SHIM_NAME --help` — it's
|
|
475
|
+
# hook-specific. Without SHIM_NAME in the key, a cache-warm shim
|
|
476
|
+
# could let a sibling shim with the SAME (session, project, CLI,
|
|
477
|
+
# mtime, size, euid, shape) skip its OWN version-skew check and
|
|
478
|
+
# forward straight to a CLI that does not implement that hook
|
|
479
|
+
# (realistic on a 0.32 CLI + newer secret-scanner shim mismatch).
|
|
480
|
+
#
|
|
481
|
+
# 0.48.0 codex round-3 P1+P2: 3 new key fields cover (a) ancestor
|
|
482
|
+
# package.json mtime/size — invalidates if the rea package.json
|
|
483
|
+
# is renamed or its `name` field is edited; (b) dist/cli/ dir
|
|
484
|
+
# mtime — invalidates when any file in that directory is
|
|
485
|
+
# added/removed (most fresh `tsc` rebuilds do both); (c) the
|
|
486
|
+
# package.json realpath is implicitly part of the key via these
|
|
487
|
+
# mtime/size fields plus the project realpath above.
|
|
488
|
+
_shim_cache_key=$(shim_cache_key "v1" "$_session_tok" "$_proj_real" "$_shim_cache_cli_real" \
|
|
489
|
+
"$_shim_cache_cli_mtime" "$_shim_cache_cli_size" "$_euid" \
|
|
490
|
+
"$SHIM_ENFORCE_CLI_SHAPE" "$SHIM_NAME" \
|
|
491
|
+
"$_shim_cache_pkg_mtime" "$_shim_cache_pkg_size" \
|
|
492
|
+
"$_shim_cache_dist_mtime" \
|
|
493
|
+
"$_shim_cache_node_real" "$_shim_cache_node_mtime" \
|
|
494
|
+
2>/dev/null || true)
|
|
495
|
+
if [ -n "$_shim_cache_key" ]; then
|
|
496
|
+
local _cache_json=""
|
|
497
|
+
_cache_json=$(shim_cache_read "$_shim_cache_key" 2>/dev/null || true)
|
|
498
|
+
if [ -n "$_cache_json" ]; then
|
|
499
|
+
# Parse + validate the entry. Failure → treat as miss.
|
|
500
|
+
local _cache_validate=""
|
|
501
|
+
_cache_validate=$(node -e '
|
|
502
|
+
try {
|
|
503
|
+
const e = JSON.parse(process.argv[1]);
|
|
504
|
+
const now = Math.floor(Date.now() / 1000);
|
|
505
|
+
const ttl = Number(e.ttl_seconds);
|
|
506
|
+
const cachedAt = Number(e.cached_at_unix);
|
|
507
|
+
const cliMtime = String(e.cli_mtime);
|
|
508
|
+
const cliSize = String(e.cli_size_bytes);
|
|
509
|
+
const cliReal = String(e.cli_realpath);
|
|
510
|
+
const pkgMtime = String(e.pkg_mtime);
|
|
511
|
+
const pkgSize = String(e.pkg_size_bytes);
|
|
512
|
+
const distMtime = String(e.dist_mtime);
|
|
513
|
+
const sandboxOk = e.sandbox_ok === true;
|
|
514
|
+
const shapeOk = e.shape_ok === true;
|
|
515
|
+
if (e.schema_version !== "v1") process.exit(1);
|
|
516
|
+
if (!Number.isFinite(ttl) || ttl <= 0 || ttl > 3600) process.exit(1);
|
|
517
|
+
if (!Number.isFinite(cachedAt)) process.exit(1);
|
|
518
|
+
if ((cachedAt + ttl) < now) process.exit(1);
|
|
519
|
+
if (cliMtime !== process.argv[2]) process.exit(1);
|
|
520
|
+
if (cliSize !== process.argv[3]) process.exit(1);
|
|
521
|
+
if (cliReal !== process.argv[4]) process.exit(1);
|
|
522
|
+
// 0.48.0 codex round-3 P1+P2: re-check the package.json
|
|
523
|
+
// mtime/size and the dist/cli/ dir mtime in addition to
|
|
524
|
+
// the CLI itself. Defense-in-depth against an entry
|
|
525
|
+
// whose key happened to collide but whose disk state
|
|
526
|
+
// has drifted.
|
|
527
|
+
if (pkgMtime !== process.argv[5]) process.exit(1);
|
|
528
|
+
if (pkgSize !== process.argv[6]) process.exit(1);
|
|
529
|
+
if (distMtime !== process.argv[7]) process.exit(1);
|
|
530
|
+
// 0.48.0 codex round-4 P1: re-check the resolved node
|
|
531
|
+
// binary realpath + mtime. A same-session interpreter
|
|
532
|
+
// swap (nvm use, volta pin) would otherwise let the
|
|
533
|
+
// warm entry silently forward through a different node.
|
|
534
|
+
const nodeReal = String(e.node_realpath);
|
|
535
|
+
const nodeMtime = String(e.node_mtime);
|
|
536
|
+
if (nodeReal !== process.argv[8]) process.exit(1);
|
|
537
|
+
if (nodeMtime !== process.argv[9]) process.exit(1);
|
|
538
|
+
if (!sandboxOk || !shapeOk) process.exit(1);
|
|
539
|
+
process.stdout.write("ok");
|
|
540
|
+
} catch (e) { process.exit(1); }
|
|
541
|
+
' -- "$_cache_json" "$_shim_cache_cli_mtime" "$_shim_cache_cli_size" "$_shim_cache_cli_real" "$_shim_cache_pkg_mtime" "$_shim_cache_pkg_size" "$_shim_cache_dist_mtime" "$_shim_cache_node_real" "$_shim_cache_node_mtime" 2>/dev/null || true)
|
|
542
|
+
if [ "$_cache_validate" = "ok" ]; then
|
|
543
|
+
_shim_cache_hit=1
|
|
544
|
+
fi
|
|
545
|
+
fi
|
|
546
|
+
fi
|
|
547
|
+
fi
|
|
548
|
+
fi
|
|
549
|
+
|
|
306
550
|
# 5. Sandbox check (when CLI was resolved). On failure clear REA_ARGV
|
|
307
551
|
# + stash the reason so the eventual CLI-required branch can emit
|
|
308
552
|
# the correct banner. Running the sandbox check BEFORE the policy
|
|
@@ -318,7 +562,7 @@ shim_run() {
|
|
|
318
562
|
local sandbox_result=""
|
|
319
563
|
local sandbox_failed=0
|
|
320
564
|
local node_missing=0
|
|
321
|
-
if [ "${#REA_ARGV[@]}" -gt 0 ]; then
|
|
565
|
+
if [ "${#REA_ARGV[@]}" -gt 0 ] && [ "$_shim_cache_hit" -eq 0 ]; then
|
|
322
566
|
if ! command -v node >/dev/null 2>&1; then
|
|
323
567
|
# 0.38.1 round-2 P2 fix: pre-fix this branch exited 0/2 IMMEDIATELY
|
|
324
568
|
# without ever calling shim_policy_short_circuit, so a blocking-
|
|
@@ -399,8 +643,10 @@ shim_run() {
|
|
|
399
643
|
# 8. Version probe (skipped when SHIM_SKIP_VERSION_PROBE=1, used by
|
|
400
644
|
# delegation-capture whose pre-port body had no probe — a stale
|
|
401
645
|
# CLI drops the signal silently rather than spamming the operator
|
|
402
|
-
# on every Agent/Skill dispatch).
|
|
403
|
-
|
|
646
|
+
# on every Agent/Skill dispatch). Also skipped on cache hit — the
|
|
647
|
+
# probe answer was recorded when the entry was written and the
|
|
648
|
+
# cache key invalidates if mtime / size / realpath changes.
|
|
649
|
+
if [ "$SHIM_SKIP_VERSION_PROBE" -eq 0 ] && [ "$_shim_cache_hit" -eq 0 ]; then
|
|
404
650
|
local probe_out probe_status
|
|
405
651
|
probe_out=$("${REA_ARGV[@]}" hook "$SHIM_NAME" --help 2>&1)
|
|
406
652
|
probe_status=$?
|
|
@@ -414,6 +660,50 @@ shim_run() {
|
|
|
414
660
|
fi
|
|
415
661
|
fi
|
|
416
662
|
|
|
663
|
+
# 8b. Cache write (0.48.0). At this point sandbox + probe both
|
|
664
|
+
# succeeded — record the answers for the next fire in this
|
|
665
|
+
# session. Cache write failure NEVER blocks the gate; we ignore
|
|
666
|
+
# the return value. Skipped on a cache hit (we just used the
|
|
667
|
+
# entry; rewriting it would be wasted work AND would refresh
|
|
668
|
+
# `cached_at_unix` past the TTL ceiling, defeating the staleness
|
|
669
|
+
# bound).
|
|
670
|
+
if [ "$_shim_cache_hit" -eq 0 ] && [ -n "$_shim_cache_key" ]; then
|
|
671
|
+
local _write_payload=""
|
|
672
|
+
_write_payload=$(node -e '
|
|
673
|
+
const args = process.argv.slice(1);
|
|
674
|
+
const now = Math.floor(Date.now() / 1000);
|
|
675
|
+
const entry = {
|
|
676
|
+
schema_version: "v1",
|
|
677
|
+
cli_realpath: args[0],
|
|
678
|
+
cli_mtime: args[1],
|
|
679
|
+
cli_size_bytes: args[2],
|
|
680
|
+
// 0.48.0 codex round-3 P1+P2: record the ancestor package.json
|
|
681
|
+
// mtime/size + dist/cli/ dir mtime so the read-side validator
|
|
682
|
+
// can re-check them on every hit. The cache key includes
|
|
683
|
+
// these too, so a drifted state produces a different key —
|
|
684
|
+
// but persisting them in the entry lets the validator catch
|
|
685
|
+
// a key collision as a stale-entry miss instead of trusting
|
|
686
|
+
// it.
|
|
687
|
+
pkg_mtime: args[3],
|
|
688
|
+
pkg_size_bytes: args[4],
|
|
689
|
+
dist_mtime: args[5],
|
|
690
|
+
// 0.48.0 codex round-4 P1: record the resolved node binary
|
|
691
|
+
// realpath + mtime so the read-side validator can re-check
|
|
692
|
+
// them and refuse a hit when the interpreter swapped.
|
|
693
|
+
node_realpath: args[6],
|
|
694
|
+
node_mtime: args[7],
|
|
695
|
+
sandbox_ok: true,
|
|
696
|
+
shape_ok: true,
|
|
697
|
+
cached_at_unix: now,
|
|
698
|
+
ttl_seconds: 3600,
|
|
699
|
+
};
|
|
700
|
+
process.stdout.write(JSON.stringify(entry));
|
|
701
|
+
' -- "$_shim_cache_cli_real" "$_shim_cache_cli_mtime" "$_shim_cache_cli_size" "$_shim_cache_pkg_mtime" "$_shim_cache_pkg_size" "$_shim_cache_dist_mtime" "$_shim_cache_node_real" "$_shim_cache_node_mtime" 2>/dev/null || true)
|
|
702
|
+
if [ -n "$_write_payload" ]; then
|
|
703
|
+
shim_cache_write "$_shim_cache_key" "$_write_payload" >/dev/null 2>&1 || true
|
|
704
|
+
fi
|
|
705
|
+
fi
|
|
706
|
+
|
|
417
707
|
# 9. Forward stdin.
|
|
418
708
|
if declare -F shim_forward >/dev/null 2>&1; then
|
|
419
709
|
shim_forward
|