tamperward 2.39.3 → 2.39.5

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +183 -106
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -10885,8 +10885,8 @@ var init_policy_load = __esm({
10885
10885
 
10886
10886
  // src/signoff.ts
10887
10887
  import { createHash as createHash3 } from "node:crypto";
10888
- import { appendFileSync, mkdirSync, readFileSync as readFileSync6, existsSync as existsSync6 } from "node:fs";
10889
- import { dirname as dirname2, join as join9 } from "node:path";
10888
+ import { appendFileSync, closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, lstatSync as lstatSync3, mkdirSync, openSync as openSync2, readFileSync as readFileSync6 } from "node:fs";
10889
+ import { dirname as dirname2, join as join9, posix as posix4 } from "node:path";
10890
10890
  function compactOobToken(want, head) {
10891
10891
  const normalizedHead = head.trim().toLowerCase();
10892
10892
  if (!want || !FULL_OBJECT_ID.test(normalizedHead)) return null;
@@ -10905,17 +10905,75 @@ function fingerprint(rule, file, evidence) {
10905
10905
  return createHash3("sha256").update(`${rule}\0${file ?? ""}\0${evidence}`).digest("hex").slice(0, 16);
10906
10906
  }
10907
10907
  function ledgerPath(cwd, policy) {
10908
- const rel = policy.signoff?.ledger ?? ".tamperward/ledger.jsonl";
10908
+ const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
10909
10909
  if (!ledgerInsideRepo(rel)) {
10910
10910
  throw new PolicyError(`signoff.ledger must be a relative path inside the repository, got ${JSON.stringify(rel)}`);
10911
10911
  }
10912
10912
  return join9(cwd, rel);
10913
10913
  }
10914
+ function lstatOrAbsent(rel, shown, path) {
10915
+ try {
10916
+ return lstatSync3(path);
10917
+ } catch (e) {
10918
+ if (errnoCode(e) === "ENOENT") return null;
10919
+ throw new PolicyError(
10920
+ `signoff.ledger ${JSON.stringify(rel)}: cannot stat ${shown} (${errorMessage(e)}); refusing to treat the sign-off ledger as absent`
10921
+ );
10922
+ }
10923
+ }
10924
+ function kindOf(st) {
10925
+ if (st.isSymbolicLink()) return "a symbolic link";
10926
+ if (st.isDirectory()) return "a directory";
10927
+ if (st.isFIFO()) return "a FIFO";
10928
+ if (st.isSocket()) return "a socket";
10929
+ if (st.isCharacterDevice() || st.isBlockDevice()) return "a device";
10930
+ return "not a regular file";
10931
+ }
10932
+ function ledgerOnDisk(cwd, policy) {
10933
+ const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
10934
+ ledgerPath(cwd, policy);
10935
+ const parts = posix4.normalize(rel.replace(/\\/g, "/")).split("/").filter((part) => part && part !== ".");
10936
+ let path = cwd;
10937
+ for (let i = 0; i < parts.length; i++) {
10938
+ const next = join9(path, parts[i]);
10939
+ const shown = parts.slice(0, i + 1).join("/");
10940
+ const st = lstatOrAbsent(rel, shown, next);
10941
+ if (st === null) return { rel, path: join9(cwd, ...parts), exists: false };
10942
+ const last = i === parts.length - 1;
10943
+ if (st.isSymbolicLink() || (last ? !st.isFile() : !st.isDirectory())) {
10944
+ throw new PolicyError(
10945
+ `signoff.ledger ${JSON.stringify(rel)}: ${shown} is ${kindOf(st)}; the sign-off ledger is honored only as a regular file inside the repository, reached without following a link`
10946
+ );
10947
+ }
10948
+ path = next;
10949
+ }
10950
+ return { rel, path, exists: true };
10951
+ }
10952
+ function openLedger(rel, path, flags) {
10953
+ let fd;
10954
+ try {
10955
+ fd = openSync2(path, flags | (constants3.O_NOFOLLOW ?? 0), 420);
10956
+ } catch (e) {
10957
+ throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot open ${path} (${e instanceof Error ? e.message : String(e)})`);
10958
+ }
10959
+ if (!fstatSync2(fd).isFile()) {
10960
+ closeSync2(fd);
10961
+ throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: ${path} is not a regular file; refusing to use it`);
10962
+ }
10963
+ return fd;
10964
+ }
10914
10965
  function readLedger(cwd, policy) {
10915
- const p = ledgerPath(cwd, policy);
10916
- if (!existsSync6(p)) return [];
10966
+ const { rel, path, exists } = ledgerOnDisk(cwd, policy);
10967
+ if (!exists) return [];
10968
+ const fd = openLedger(rel, path, constants3.O_RDONLY);
10969
+ let text;
10970
+ try {
10971
+ text = readFileSync6(fd, "utf8");
10972
+ } finally {
10973
+ closeSync2(fd);
10974
+ }
10917
10975
  const out3 = [];
10918
- for (const line of readFileSync6(p, "utf8").split("\n")) {
10976
+ for (const line of text.split("\n")) {
10919
10977
  if (!line.trim()) continue;
10920
10978
  try {
10921
10979
  const e = ledgerEntryFrom(JSON.parse(line));
@@ -10926,15 +10984,27 @@ function readLedger(cwd, policy) {
10926
10984
  return out3;
10927
10985
  }
10928
10986
  function appendEntry(cwd, policy, e) {
10929
- const p = ledgerPath(cwd, policy);
10930
- mkdirSync(dirname2(p), { recursive: true });
10931
- appendFileSync(p, JSON.stringify(e) + "\n");
10987
+ const { rel, path } = ledgerOnDisk(cwd, policy);
10988
+ try {
10989
+ mkdirSync(dirname2(path), { recursive: true });
10990
+ } catch (err3) {
10991
+ throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot create ${dirname2(path)} (${errorMessage(err3)})`);
10992
+ }
10993
+ const fd = openLedger(rel, path, constants3.O_WRONLY | constants3.O_APPEND | constants3.O_CREAT);
10994
+ try {
10995
+ appendFileSync(fd, JSON.stringify(e) + "\n");
10996
+ } finally {
10997
+ closeSync2(fd);
10998
+ }
10932
10999
  }
10933
11000
  function makeEntry(f, reason, now, ttlMs = DEFAULT_TTL_MS) {
10934
11001
  return { rule: f.rule, file: f.file, fingerprint: fingerprintOf(f), reason, recordedAt: now, expiresAt: now + ttlMs };
10935
11002
  }
11003
+ function honoredAt(e, now) {
11004
+ return e.expiresAt > now && e.recordedAt <= now && e.expiresAt - e.recordedAt <= LEDGER_TTL_MS;
11005
+ }
10936
11006
  function applyLocalSignoffs(findings, cwd, policy, now = Date.now()) {
10937
- const ledger = readLedger(cwd, policy).filter((e) => e.expiresAt > now);
11007
+ const ledger = readLedger(cwd, policy).filter((e) => honoredAt(e, now));
10938
11008
  const valid = new Set(ledger.map((e) => e.fingerprint));
10939
11009
  const cleared = [];
10940
11010
  const remaining = [];
@@ -10985,13 +11055,15 @@ function oobHeadFromEnv(env = process.env) {
10985
11055
  function oobFromEnv(env = process.env) {
10986
11056
  return (env.TAMPERWARD_OOB_SIGNOFF ?? "").split(",").map((s) => s.trim().replace(/^tamperward:allow:/, "")).filter(Boolean);
10987
11057
  }
10988
- var DEFAULT_TTL_MS, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
11058
+ var LEDGER_TTL_MS, DEFAULT_TTL_MS, DEFAULT_LEDGER, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
10989
11059
  var init_signoff = __esm({
10990
11060
  "src/signoff.ts"() {
10991
11061
  "use strict";
10992
11062
  init_policy_load();
10993
11063
  init_narrow();
10994
- DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
11064
+ LEDGER_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
11065
+ DEFAULT_TTL_MS = LEDGER_TTL_MS;
11066
+ DEFAULT_LEDGER = ".tamperward/ledger.jsonl";
10995
11067
  COMPACT_OOB_PREFIX = "tw1:";
10996
11068
  FULL_OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;
10997
11069
  fingerprintOf = (f) => fingerprint(f.rule, f.file, f.evidence);
@@ -11437,7 +11509,7 @@ var init_deny = __esm({
11437
11509
  });
11438
11510
 
11439
11511
  // src/session.ts
11440
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync7, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
11512
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync7, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
11441
11513
  import { dirname as dirname3, join as join10 } from "node:path";
11442
11514
  function writeBaseline(p, sha3) {
11443
11515
  mkdirSync2(dirname3(p), { recursive: true });
@@ -11463,7 +11535,7 @@ function turnBaseline(cwd, sessionId) {
11463
11535
  const p = baselinePath(cwd, sessionId);
11464
11536
  if (!p) return null;
11465
11537
  try {
11466
- if (existsSync7(p)) {
11538
+ if (existsSync6(p)) {
11467
11539
  const v = readFileSync7(p, "utf8").trim();
11468
11540
  if (SHA.test(v)) return v;
11469
11541
  }
@@ -11507,7 +11579,7 @@ var init_session = __esm({
11507
11579
 
11508
11580
  // src/effect.ts
11509
11581
  import { createHash as createHash4 } from "node:crypto";
11510
- import { existsSync as existsSync8, lstatSync as lstatSync3, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
11582
+ import { existsSync as existsSync7, lstatSync as lstatSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
11511
11583
  import { join as join11 } from "node:path";
11512
11584
  function ptreeFrom(value) {
11513
11585
  if (!isRecord(value)) return null;
@@ -11572,7 +11644,7 @@ function snapshotProtected(cwd, policy, prev, cache3) {
11572
11644
  if (pruned.has(r)) continue;
11573
11645
  let st;
11574
11646
  try {
11575
- st = lstatSync3(join11(cwd, r));
11647
+ st = lstatSync4(join11(cwd, r));
11576
11648
  } catch {
11577
11649
  continue;
11578
11650
  }
@@ -11599,7 +11671,7 @@ function driftBetween(expected, current) {
11599
11671
  return { changed, deleted, added };
11600
11672
  }
11601
11673
  function loadTree(p) {
11602
- if (!p || !existsSync8(p)) return null;
11674
+ if (!p || !existsSync7(p)) return null;
11603
11675
  try {
11604
11676
  return ptreeFrom(JSON.parse(readFileSync8(p, "utf8")));
11605
11677
  } catch {
@@ -11654,7 +11726,7 @@ var init_effect = __esm({
11654
11726
  });
11655
11727
 
11656
11728
  // src/cli/watch.ts
11657
- import { appendFileSync as appendFileSync3, lstatSync as lstatSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync9, readdirSync as readdirSync2, watch, writeFileSync as writeFileSync4 } from "node:fs";
11729
+ import { appendFileSync as appendFileSync3, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync9, readdirSync as readdirSync2, watch, writeFileSync as writeFileSync4 } from "node:fs";
11658
11730
  import { join as join12 } from "node:path";
11659
11731
  import { createHash as createHash5 } from "node:crypto";
11660
11732
  function snap(abs) {
@@ -11757,7 +11829,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
11757
11829
  const child = rel ? `${rel}/${String(fname)}` : String(fname);
11758
11830
  cb(kind, child);
11759
11831
  try {
11760
- if (lstatSync4(join12(dir, child)).isDirectory()) addDir(child);
11832
+ if (lstatSync5(join12(dir, child)).isDirectory()) addDir(child);
11761
11833
  } catch {
11762
11834
  }
11763
11835
  });
@@ -11793,7 +11865,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
11793
11865
  const child = rel ? `${rel}/${name}` : name;
11794
11866
  if (SKIP2.test(child + "/")) continue;
11795
11867
  try {
11796
- if (lstatSync4(join12(dir, child)).isDirectory()) walk2(child);
11868
+ if (lstatSync5(join12(dir, child)).isDirectory()) walk2(child);
11797
11869
  } catch {
11798
11870
  }
11799
11871
  }
@@ -11944,7 +12016,7 @@ var init_watch = __esm({
11944
12016
  });
11945
12017
 
11946
12018
  // src/detectors/fs-events.ts
11947
- import { closeSync as closeSync2, openSync as openSync2, readSync as readSync2, statSync as statSync2 } from "node:fs";
12019
+ import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync2 } from "node:fs";
11948
12020
  function fsEventFrom(line) {
11949
12021
  let value;
11950
12022
  try {
@@ -11991,12 +12063,12 @@ function readEvents(log, offset, maxBytes = MAX_EVENT_READ_BYTES, io = DEFAULT_E
11991
12063
  const available = size - start;
11992
12064
  const requested = Math.min(available, cap);
11993
12065
  const buffer = Buffer.allocUnsafe(requested);
11994
- const fd = openSync2(log, "r");
12066
+ const fd = openSync3(log, "r");
11995
12067
  let bytesRead = 0;
11996
12068
  try {
11997
12069
  bytesRead = io.read(fd, buffer, 0, requested, start);
11998
12070
  } finally {
11999
- closeSync2(fd);
12071
+ closeSync3(fd);
12000
12072
  }
12001
12073
  if (bytesRead <= 0) {
12002
12074
  return {
@@ -12201,7 +12273,7 @@ var init_fs_events = __esm({
12201
12273
 
12202
12274
  // src/cli/audit.ts
12203
12275
  import { createHash as createHash6, randomBytes } from "node:crypto";
12204
- import { appendFileSync as appendFileSync4, closeSync as closeSync3, existsSync as existsSync9, mkdirSync as mkdirSync5, openSync as openSync3, readSync as readSync3 } from "node:fs";
12276
+ import { appendFileSync as appendFileSync4, closeSync as closeSync4, existsSync as existsSync8, mkdirSync as mkdirSync5, openSync as openSync4, readSync as readSync3 } from "node:fs";
12205
12277
  import { dirname as dirname4, isAbsolute as isAbsolute8, join as join13, resolve as resolve4 } from "node:path";
12206
12278
  function sessionHash(sessionId) {
12207
12279
  if (!sessionId) return void 0;
@@ -12321,7 +12393,7 @@ function parseAuditLine(line, lineNumber) {
12321
12393
  return parseAuditEvent(value, lineNumber);
12322
12394
  }
12323
12395
  function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
12324
- const fd = openSync3(file, "r");
12396
+ const fd = openSync4(file, "r");
12325
12397
  try {
12326
12398
  const chunk = Buffer.allocUnsafe(64 * 1024);
12327
12399
  let pending = [];
@@ -12359,7 +12431,7 @@ function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
12359
12431
  }
12360
12432
  if (pending.length) emit3(pending);
12361
12433
  } finally {
12362
- closeSync3(fd);
12434
+ closeSync4(fd);
12363
12435
  }
12364
12436
  }
12365
12437
  function parseSince(value, nowMs = Date.now()) {
@@ -12460,7 +12532,7 @@ function runStats(opts = {}) {
12460
12532
  const file = opts.file ? isAbsolute8(opts.file) ? opts.file : resolve4(cwd, opts.file) : configured && configured !== "auto" ? isAbsolute8(configured) ? configured : resolve4(cwd, configured) : defaultAuditPath(cwd);
12461
12533
  const cutoff = opts.since ? parseSince(opts.since) : null;
12462
12534
  if (!file) throw new Error("stats needs --file outside a Git repository");
12463
- if (!existsSync9(file)) {
12535
+ if (!existsSync8(file)) {
12464
12536
  if (explicitFile) throw new Error(`audit file not found: ${file}`);
12465
12537
  const empty2 = summarizeAudit([]);
12466
12538
  process.stdout.write(opts.json ? JSON.stringify(empty2) + "\n" : renderAuditStats(empty2));
@@ -12499,7 +12571,7 @@ var init_audit = __esm({
12499
12571
  });
12500
12572
 
12501
12573
  // src/cli/hook.ts
12502
- import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
12574
+ import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "node:fs";
12503
12575
  import { createHash as createHash7 } from "node:crypto";
12504
12576
  function setSnapshotCache(cache3) {
12505
12577
  snapshotCache = cache3;
@@ -12796,9 +12868,9 @@ function turnTransientBlocks(cwd, sessionId, policy, changes) {
12796
12868
  recordObserverHealth(cwd, sessionId, telemetry.state, telemetry.reason);
12797
12869
  }
12798
12870
  const cp = cursorPath(cwd, sessionId);
12799
- if (!existsSync10(log)) return none;
12871
+ if (!existsSync9(log)) return none;
12800
12872
  let offset = 0;
12801
- if (cp && existsSync10(cp)) {
12873
+ if (cp && existsSync9(cp)) {
12802
12874
  const n2 = Number(readFileSync10(cp, "utf8"));
12803
12875
  offset = Number.isFinite(n2) ? n2 : 0;
12804
12876
  }
@@ -12979,7 +13051,7 @@ var init_hook = __esm({
12979
13051
  });
12980
13052
 
12981
13053
  // src/ptree-cache.ts
12982
- import { lstatSync as lstatSync5 } from "node:fs";
13054
+ import { lstatSync as lstatSync6 } from "node:fs";
12983
13055
  import { join as join14 } from "node:path";
12984
13056
  function keyOf(st) {
12985
13057
  return `${st.dev}:${st.ino}:${st.size}:${st.mode}:${st.mtimeNs}:${st.ctimeNs}`;
@@ -13033,7 +13105,7 @@ var init_ptree_cache = __esm({
13033
13105
  const abs = join14(cwd, rel);
13034
13106
  let st;
13035
13107
  try {
13036
- st = lstatSync5(abs, { bigint: true });
13108
+ st = lstatSync6(abs, { bigint: true });
13037
13109
  } catch {
13038
13110
  this.map.delete(abs);
13039
13111
  this.stats.misses++;
@@ -13055,7 +13127,7 @@ var init_ptree_cache = __esm({
13055
13127
  const entry = compute();
13056
13128
  let after;
13057
13129
  try {
13058
- after = lstatSync5(abs, { bigint: true });
13130
+ after = lstatSync6(abs, { bigint: true });
13059
13131
  } catch {
13060
13132
  this.map.delete(abs);
13061
13133
  return entry;
@@ -13073,7 +13145,7 @@ var init_ptree_cache = __esm({
13073
13145
  });
13074
13146
 
13075
13147
  // src/cli/hook-service.ts
13076
- import { chmodSync, existsSync as existsSync11, lstatSync as lstatSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
13148
+ import { chmodSync, existsSync as existsSync10, lstatSync as lstatSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
13077
13149
  import { createConnection as createConnection2, createServer } from "node:net";
13078
13150
  import { realpathSync as realpathSync4 } from "node:fs";
13079
13151
  import { sep } from "node:path";
@@ -13161,8 +13233,8 @@ function removeQuietly(p) {
13161
13233
  }
13162
13234
  }
13163
13235
  function ensurePrivateDir(dir, uid) {
13164
- if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
13165
- const st = lstatSync6(dir);
13236
+ if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
13237
+ const st = lstatSync7(dir);
13166
13238
  if (!st.isDirectory()) throw new Error(`${dir} is not a directory`);
13167
13239
  if (st.uid !== uid) throw new Error(`${dir} is owned by uid ${st.uid}, not ${uid}; refusing to serve from it`);
13168
13240
  if ((st.mode & 63) !== 0) chmodSync(dir, 448);
@@ -13358,7 +13430,7 @@ async function stopHookService(paths, expectedRoot) {
13358
13430
  process.kill(st.pid, "SIGTERM");
13359
13431
  } catch {
13360
13432
  }
13361
- const gone = () => !pidAlive2(st.pid) || !existsSync11(paths.socket);
13433
+ const gone = () => !pidAlive2(st.pid) || !existsSync10(paths.socket);
13362
13434
  const until = Date.now() + STOP_WAIT_MS;
13363
13435
  while (!gone() && Date.now() < until) sleepSync(50);
13364
13436
  if (!gone()) throw new Error(`hook service pid ${st.pid} did not exit within ${STOP_WAIT_MS / 1e3}s`);
@@ -13594,11 +13666,11 @@ var init_verifier_limits = __esm({
13594
13666
 
13595
13667
  // src/safe-write.ts
13596
13668
  import { randomBytes as randomBytes2 } from "node:crypto";
13597
- import { lstatSync as lstatSync7, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
13669
+ import { lstatSync as lstatSync8, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
13598
13670
  function writeTargetKind(path) {
13599
13671
  let st;
13600
13672
  try {
13601
- st = lstatSync7(path, { throwIfNoEntry: false });
13673
+ st = lstatSync8(path, { throwIfNoEntry: false });
13602
13674
  } catch (e) {
13603
13675
  if (errnoCode(e) === "ENOTDIR") return "absent";
13604
13676
  throw e;
@@ -13619,7 +13691,7 @@ function refuseNonRegular(path) {
13619
13691
  }
13620
13692
  function existingMode(path, fallback) {
13621
13693
  if (writeTargetKind(path) !== "file") return fallback;
13622
- return lstatSync7(path).mode & 511;
13694
+ return lstatSync8(path).mode & 511;
13623
13695
  }
13624
13696
  function atomicReplaceFile(path, content, mode) {
13625
13697
  const tmp = `${path}.${process.pid}.${randomBytes2(8).toString("hex")}.tmp`;
@@ -13640,7 +13712,7 @@ var init_safe_write = __esm({
13640
13712
  // src/cli/init.ts
13641
13713
  import { execFileSync as execFileSync6 } from "node:child_process";
13642
13714
  import { createHash as createHash8 } from "node:crypto";
13643
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync5 } from "node:fs";
13715
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync5 } from "node:fs";
13644
13716
  import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute9, join as join15, relative as relative4, resolve as resolve6 } from "node:path";
13645
13717
  function gitConfig(cwd, key2) {
13646
13718
  try {
@@ -13744,7 +13816,7 @@ function verifierCandidates(cwd) {
13744
13816
  if (/^\s*\[tool\.pytest(?:\.ini_options)?\]\s*$/m.test(pyproject)) add("pytest");
13745
13817
  } catch {
13746
13818
  }
13747
- if (existsSync12(join15(cwd, "pytest.ini"))) add("pytest");
13819
+ if (existsSync11(join15(cwd, "pytest.ini"))) add("pytest");
13748
13820
  try {
13749
13821
  const setupCfg = readFileSync12(join15(cwd, "setup.cfg"), "utf8");
13750
13822
  if (/^\s*\[tool:pytest\]\s*$/m.test(setupCfg)) add("pytest");
@@ -13804,7 +13876,7 @@ function planPolicy(cwd) {
13804
13876
  const path = join15(cwd, POLICY_FILE);
13805
13877
  const refused = refuseNonRegular(path);
13806
13878
  if (refused) return { item: "policy", path: POLICY_FILE, status: "error", detail: refused };
13807
- if (existsSync12(path)) {
13879
+ if (existsSync11(path)) {
13808
13880
  try {
13809
13881
  loadPolicy(cwd);
13810
13882
  } catch (e) {
@@ -13823,7 +13895,7 @@ function planPolicy(cwd) {
13823
13895
  function planGitignore(cwd) {
13824
13896
  const rel = ".gitignore";
13825
13897
  const path = join15(cwd, rel);
13826
- if (!existsSync12(join15(cwd, "node_modules"))) return null;
13898
+ if (!existsSync11(join15(cwd, "node_modules"))) return null;
13827
13899
  let existing = "";
13828
13900
  let kind;
13829
13901
  try {
@@ -13888,7 +13960,7 @@ function planClaudeHooks(cwd) {
13888
13960
  const refused = refuseNonRegular(path);
13889
13961
  if (refused) return { item: "agent", path: rel, status: "error", detail: refused };
13890
13962
  let settings = {};
13891
- if (existsSync12(path)) {
13963
+ if (existsSync11(path)) {
13892
13964
  let parsed;
13893
13965
  try {
13894
13966
  parsed = JSON.parse(readFileSync12(path, "utf8"));
@@ -13940,7 +14012,7 @@ function planClaudeHooks(cwd) {
13940
14012
  return {
13941
14013
  item: "agent",
13942
14014
  path: rel,
13943
- status: existsSync12(path) ? "update" : "create",
14015
+ status: existsSync11(path) ? "update" : "create",
13944
14016
  detail: [
13945
14017
  needPre && "wire PreToolUse deny",
13946
14018
  needStop && "wire Stop sweep",
@@ -13984,7 +14056,7 @@ function hooksDir(cwd) {
13984
14056
  if (out3) return resolve6(cwd, out3);
13985
14057
  } catch {
13986
14058
  }
13987
- return existsSync12(join15(cwd, ".git")) ? join15(cwd, ".git", "hooks") : null;
14059
+ return existsSync11(join15(cwd, ".git")) ? join15(cwd, ".git", "hooks") : null;
13988
14060
  }
13989
14061
  function display(cwd, path) {
13990
14062
  const rel = relative4(cwd, path);
@@ -14011,11 +14083,11 @@ function planPreCommit(cwd) {
14011
14083
  const skip = (detail) => ({ item: "pre-commit", path: "(none)", status: "skip", detail });
14012
14084
  let path;
14013
14085
  let note;
14014
- if (existsSync12(join15(cwd, ".husky"))) {
14086
+ if (existsSync11(join15(cwd, ".husky"))) {
14015
14087
  path = join15(cwd, ".husky", "pre-commit");
14016
14088
  note = "husky";
14017
14089
  } else {
14018
- const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) => existsSync12(join15(cwd, c))));
14090
+ const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) => existsSync11(join15(cwd, c))));
14019
14091
  if (managed) {
14020
14092
  return skip(`${managed.name} manages this repository's hooks and regenerates them on install, so a line in the hooks directory would not last \u2014 ${managed.hint}`);
14021
14093
  }
@@ -14033,7 +14105,7 @@ function planPreCommit(cwd) {
14033
14105
  const rel = display(cwd, path);
14034
14106
  const refused = refuseNonRegular(path);
14035
14107
  if (refused) return { item: "pre-commit", path: rel, status: "error", detail: refused };
14036
- const existing = existsSync12(path) ? readFileSync12(path, "utf8") : null;
14108
+ const existing = existsSync11(path) ? readFileSync12(path, "utf8") : null;
14037
14109
  const hookMode = () => existingMode(path, 493) | 73;
14038
14110
  if (existing === null) {
14039
14111
  return {
@@ -14164,7 +14236,7 @@ function planWorkflow(cwd, force) {
14164
14236
  };
14165
14237
  const refused = refuseNonRegular(path);
14166
14238
  if (refused) return { item: "ci", path: rel, status: "error", detail: refused };
14167
- if (!existsSync12(path)) {
14239
+ if (!existsSync11(path)) {
14168
14240
  return {
14169
14241
  item: "ci",
14170
14242
  path: rel,
@@ -14522,8 +14594,8 @@ var init_fingerprint = __esm({
14522
14594
  // src/dependency-env.ts
14523
14595
  import { createHash as createHash10 } from "node:crypto";
14524
14596
  import {
14525
- existsSync as existsSync13,
14526
- lstatSync as lstatSync8,
14597
+ existsSync as existsSync12,
14598
+ lstatSync as lstatSync9,
14527
14599
  readdirSync as readdirSync3,
14528
14600
  readFileSync as readFileSync13,
14529
14601
  readlinkSync as readlinkSync2,
@@ -14548,7 +14620,7 @@ function inside(root, candidate) {
14548
14620
  return rel === "" || rel !== ".." && !rel.startsWith(".." + sep3) && !isAbsolute10(rel);
14549
14621
  }
14550
14622
  function modeKind(path) {
14551
- const st = lstatSync8(path);
14623
+ const st = lstatSync9(path);
14552
14624
  if (st.isFile()) return { kind: "file", mode: st.mode };
14553
14625
  if (st.isDirectory()) return { kind: "dir", mode: st.mode };
14554
14626
  if (st.isSymbolicLink()) return { kind: "symlink", mode: st.mode };
@@ -14558,7 +14630,7 @@ function fingerprintRoot(root, cwd, h) {
14558
14630
  let rootStat;
14559
14631
  let currentReal;
14560
14632
  try {
14561
- rootStat = lstatSync8(root.path);
14633
+ rootStat = lstatSync9(root.path);
14562
14634
  currentReal = realpathSync6(root.path);
14563
14635
  } catch (e) {
14564
14636
  throw new Unattestable(
@@ -14676,7 +14748,7 @@ function snapshot(roots, probes, cwd) {
14676
14748
  const h = createHash10("sha256");
14677
14749
  for (const probe of probes) {
14678
14750
  h.update(
14679
- "probe\0" + probe.kind + "\0" + probe.path + "\0" + (existsSync13(probe.path) ? "present" : "absent") + "\0"
14751
+ "probe\0" + probe.kind + "\0" + probe.path + "\0" + (existsSync12(probe.path) ? "present" : "absent") + "\0"
14680
14752
  );
14681
14753
  }
14682
14754
  for (const root of roots) fingerprintRoot(root, cwd, h);
@@ -14735,7 +14807,7 @@ function resolveExecutable(token, cwd, env) {
14735
14807
  if (token.includes("/") || token.includes("\\")) {
14736
14808
  const path = isAbsolute10(token) ? token : resolve7(cwd, token);
14737
14809
  try {
14738
- return existsSync13(path) ? realpathSync6(path) : null;
14810
+ return existsSync12(path) ? realpathSync6(path) : null;
14739
14811
  } catch {
14740
14812
  return null;
14741
14813
  }
@@ -14743,7 +14815,7 @@ function resolveExecutable(token, cwd, env) {
14743
14815
  for (const entry of (env.PATH ?? "").split(delimiter).filter(Boolean)) {
14744
14816
  const candidate = resolve7(entry, token);
14745
14817
  try {
14746
- if (existsSync13(candidate) && statSync3(candidate).isFile()) return realpathSync6(candidate);
14818
+ if (existsSync12(candidate) && statSync3(candidate).isFile()) return realpathSync6(candidate);
14747
14819
  } catch {
14748
14820
  }
14749
14821
  }
@@ -14766,7 +14838,7 @@ function inferredVenvFromToken(token, cwd) {
14766
14838
  const parentName = basename4(parent).toLowerCase();
14767
14839
  if (parentName !== "bin" && parentName !== "scripts") return null;
14768
14840
  const root = dirname6(parent);
14769
- return existsSync13(join16(root, "pyvenv.cfg")) ? root : null;
14841
+ return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
14770
14842
  }
14771
14843
  function unsupportedEcosystem(command, token) {
14772
14844
  const name = token ? basename4(token).toLowerCase() : "";
@@ -14782,11 +14854,11 @@ function inferredVenv(executable) {
14782
14854
  const parentName = basename4(parent).toLowerCase();
14783
14855
  if (parentName !== "bin" && parentName !== "scripts") return null;
14784
14856
  const root = dirname6(parent);
14785
- return existsSync13(join16(root, "pyvenv.cfg")) ? root : null;
14857
+ return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
14786
14858
  }
14787
14859
  function venvProblem(root) {
14788
14860
  const cfg = join16(root, "pyvenv.cfg");
14789
- if (!existsSync13(cfg)) return "VIRTUAL_ENV " + JSON.stringify(root) + " has no pyvenv.cfg";
14861
+ if (!existsSync12(cfg)) return "VIRTUAL_ENV " + JSON.stringify(root) + " has no pyvenv.cfg";
14790
14862
  try {
14791
14863
  const body = readFileSync13(cfg, "utf8");
14792
14864
  if (/^\s*include-system-site-packages\s*=\s*true\s*$/im.test(body)) {
@@ -14813,7 +14885,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
14813
14885
  };
14814
14886
  try {
14815
14887
  const nodeModules = join16(cwd, "node_modules");
14816
- if (existsSync13(nodeModules)) addRoot("node_modules", nodeModules);
14888
+ if (existsSync12(nodeModules)) addRoot("node_modules", nodeModules);
14817
14889
  else probes.push({ kind: "node_modules", path: nodeModules });
14818
14890
  const token = firstExecutable(command);
14819
14891
  const executable = resolveExecutable(token, cwd, env);
@@ -14825,7 +14897,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
14825
14897
  venv = resolve7(env.VIRTUAL_ENV);
14826
14898
  } else {
14827
14899
  venv = inferredVenv(executable) ?? inferredVenvFromToken(token, cwd);
14828
- if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) && existsSync13(join16(cwd, ".venv", "pyvenv.cfg"))) {
14900
+ if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) && existsSync12(join16(cwd, ".venv", "pyvenv.cfg"))) {
14829
14901
  venv = join16(cwd, ".venv");
14830
14902
  }
14831
14903
  }
@@ -15304,7 +15376,7 @@ if (child) {
15304
15376
  // src/verifier-backend.ts
15305
15377
  import { createHash as createHash11, randomUUID } from "node:crypto";
15306
15378
  import { spawnSync as spawnSync2 } from "node:child_process";
15307
- import { accessSync as accessSync2, constants as constants3, readFileSync as readFileSync14, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
15379
+ import { accessSync as accessSync2, constants as constants4, readFileSync as readFileSync14, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
15308
15380
  import { delimiter as delimiter2, dirname as dirname7, join as join18, resolve as resolve8 } from "node:path";
15309
15381
  function identity() {
15310
15382
  const uid = typeof process.getuid === "function" ? process.getuid() : null;
@@ -15341,7 +15413,7 @@ function findExecutable(name) {
15341
15413
  if (!raw) continue;
15342
15414
  const candidate = join18(raw, name);
15343
15415
  try {
15344
- accessSync2(candidate, constants3.X_OK);
15416
+ accessSync2(candidate, constants4.X_OK);
15345
15417
  return realpathSync7(candidate);
15346
15418
  } catch {
15347
15419
  }
@@ -16405,7 +16477,7 @@ var init_verification_receipt = __esm({
16405
16477
  // src/cli/verify.ts
16406
16478
  import { execFileSync as execFileSync9, spawnSync as spawnSync3 } from "node:child_process";
16407
16479
  import { createHash as createHash14 } from "node:crypto";
16408
- import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync11, existsSync as existsSync14 } from "node:fs";
16480
+ import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync11, existsSync as existsSync13 } from "node:fs";
16409
16481
  import { tmpdir as tmpdir4 } from "node:os";
16410
16482
  import { dirname as dirname10, isAbsolute as isAbsolute11, join as join21, relative as relative6, resolve as resolve9, sep as sep4 } from "node:path";
16411
16483
  function oracleAssuranceReport() {
@@ -16499,7 +16571,7 @@ function validateSymlinkGraph(target, out3, root, dependencyRoot, label) {
16499
16571
  const current = join21(base, ...stack);
16500
16572
  let st;
16501
16573
  try {
16502
- st = lstatSync9(current);
16574
+ st = lstatSync10(current);
16503
16575
  } catch {
16504
16576
  continue;
16505
16577
  }
@@ -16541,7 +16613,7 @@ function rejectLinkedParent(cwd, rel) {
16541
16613
  current = join21(current, part);
16542
16614
  let st;
16543
16615
  try {
16544
- st = lstatSync9(current);
16616
+ st = lstatSync10(current);
16545
16617
  } catch {
16546
16618
  continue;
16547
16619
  }
@@ -16567,7 +16639,7 @@ function materialize(cwd, dest, dependencyRoot) {
16567
16639
  rejectLinkedParent(cwd, rel);
16568
16640
  let st;
16569
16641
  try {
16570
- st = lstatSync9(src);
16642
+ st = lstatSync10(src);
16571
16643
  } catch {
16572
16644
  continue;
16573
16645
  }
@@ -16601,7 +16673,7 @@ function probeFilesystemCaseSensitivity(dir) {
16601
16673
  const lower = join21(dir, ".tw-case-probe-a");
16602
16674
  try {
16603
16675
  writeFileSync11(upper, "", { flag: "wx" });
16604
- return !existsSync14(lower);
16676
+ return !existsSync13(lower);
16605
16677
  } finally {
16606
16678
  rmSync9(upper, { force: true });
16607
16679
  }
@@ -16621,7 +16693,7 @@ function caseFoldCollision(paths) {
16621
16693
  }
16622
16694
  function dropSymlink(p) {
16623
16695
  try {
16624
- if (lstatSync9(p).isSymbolicLink()) rmSync9(p, { force: true });
16696
+ if (lstatSync10(p).isSymbolicLink()) rmSync9(p, { force: true });
16625
16697
  } catch {
16626
16698
  }
16627
16699
  }
@@ -16663,7 +16735,7 @@ function overlayDigest(dest, paths) {
16663
16735
  h.update("\0");
16664
16736
  const p = join21(dest, rel);
16665
16737
  try {
16666
- const st = lstatSync9(p);
16738
+ const st = lstatSync10(p);
16667
16739
  h.update(String(st.mode));
16668
16740
  h.update(st.isSymbolicLink() ? readlinkSync3(p) : readFileSync16(p));
16669
16741
  } catch {
@@ -17015,7 +17087,7 @@ function runVerifyImpl(opts) {
17015
17087
  if (!filesystemCaseSensitive) {
17016
17088
  const present = (rel) => {
17017
17089
  try {
17018
- lstatSync9(join21(cwd, rel));
17090
+ lstatSync10(join21(cwd, rel));
17019
17091
  return true;
17020
17092
  } catch {
17021
17093
  return false;
@@ -18390,7 +18462,7 @@ raise SystemExit(0)
18390
18462
 
18391
18463
  // src/cli/doctor.ts
18392
18464
  import { execFileSync as execFileSync11 } from "node:child_process";
18393
- import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync5 } from "node:fs";
18465
+ import { existsSync as existsSync14, readFileSync as readFileSync18, readdirSync as readdirSync5 } from "node:fs";
18394
18466
  import { join as join23, resolve as resolve11 } from "node:path";
18395
18467
  function lifecyclePlatformCheck(platform = process.platform, linuxPython = platform === "linux" ? trustedLinuxPython() : null) {
18396
18468
  if (platform === "linux") {
@@ -18446,7 +18518,7 @@ function wiringState(status, authority) {
18446
18518
  return authority ? "BROKEN" : "WARN";
18447
18519
  }
18448
18520
  function pinsInFile(path) {
18449
- if (!existsSync15(path)) return [];
18521
+ if (!existsSync14(path)) return [];
18450
18522
  let src = "";
18451
18523
  try {
18452
18524
  src = readFileSync18(path, "utf8");
@@ -18470,7 +18542,7 @@ function workflowPermissionCheck(cwd, workflowRels = [".github/workflows/tamperw
18470
18542
  const warnings = [];
18471
18543
  for (const rel of workflowRels) {
18472
18544
  const path = resolve11(cwd, rel);
18473
- if (!existsSync15(path)) {
18545
+ if (!existsSync14(path)) {
18474
18546
  broken.push(`${rel} is missing`);
18475
18547
  continue;
18476
18548
  }
@@ -18875,7 +18947,7 @@ function diagnose(opts = {}) {
18875
18947
  } else {
18876
18948
  const workflowDirRel = ".github/workflows";
18877
18949
  const workflowDir = resolve11(cwd, workflowDirRel);
18878
- if (!existsSync15(workflowDir)) {
18950
+ if (!existsSync14(workflowDir)) {
18879
18951
  return fail("ci-verifier", `${workflowDirRel}: workflow directory does not exist`);
18880
18952
  }
18881
18953
  let entries;
@@ -18895,7 +18967,7 @@ function diagnose(opts = {}) {
18895
18967
  const authorityWorkflows = [];
18896
18968
  for (const workflowRel of workflowRels) {
18897
18969
  const workflowPath = resolve11(cwd, workflowRel);
18898
- if (!existsSync15(workflowPath)) {
18970
+ if (!existsSync14(workflowPath)) {
18899
18971
  return fail("ci-verifier", `${workflowRel}: workflow does not exist`);
18900
18972
  }
18901
18973
  let doc;
@@ -19211,7 +19283,7 @@ var init_status2 = __esm({
19211
19283
  // src/cli/trace-verify.ts
19212
19284
  import { execFileSync as execFileSync12, spawnSync as spawnSync5 } from "node:child_process";
19213
19285
  import {
19214
- existsSync as existsSync16,
19286
+ existsSync as existsSync15,
19215
19287
  mkdtempSync as mkdtempSync5,
19216
19288
  readFileSync as readFileSync19,
19217
19289
  readdirSync as readdirSync6,
@@ -19470,7 +19542,7 @@ function materializeBase(base, cwd, dest) {
19470
19542
  }
19471
19543
  const hostModules = join24(cwd, "node_modules");
19472
19544
  const tracedModules = join24(dest, "node_modules");
19473
- if (existsSync16(hostModules) && !existsSync16(tracedModules)) {
19545
+ if (existsSync15(hostModules) && !existsSync15(tracedModules)) {
19474
19546
  symlinkSync2(resolve12(hostModules), tracedModules, "dir");
19475
19547
  }
19476
19548
  }
@@ -19782,7 +19854,7 @@ var init_immutable = __esm({
19782
19854
  });
19783
19855
 
19784
19856
  // src/runtimes.ts
19785
- import { existsSync as existsSync17, readFileSync as readFileSync20 } from "node:fs";
19857
+ import { existsSync as existsSync16, readFileSync as readFileSync20 } from "node:fs";
19786
19858
  import { join as join25 } from "node:path";
19787
19859
  function isRecord6(x) {
19788
19860
  return typeof x === "object" && x !== null && !Array.isArray(x);
@@ -19812,7 +19884,7 @@ function claudeSettingsBeyondTamperward(cwd) {
19812
19884
  const path = join25(cwd, ".claude", "settings.json");
19813
19885
  let raw;
19814
19886
  try {
19815
- if (!existsSync17(path)) return false;
19887
+ if (!existsSync16(path)) return false;
19816
19888
  raw = readFileSync20(path, "utf8");
19817
19889
  } catch {
19818
19890
  return false;
@@ -19839,7 +19911,7 @@ function detectRuntimes(cwd) {
19839
19911
  for (const rt of KNOWN_RUNTIMES) {
19840
19912
  const marker = rt.markers.find((m) => {
19841
19913
  try {
19842
- return existsSync17(join25(cwd, m));
19914
+ return existsSync16(join25(cwd, m));
19843
19915
  } catch {
19844
19916
  return false;
19845
19917
  }
@@ -20864,7 +20936,7 @@ var init_adapter3 = __esm({
20864
20936
 
20865
20937
  // src/adapters/copilot-sdk/changes.ts
20866
20938
  import { execFileSync as execFileSync13 } from "node:child_process";
20867
- import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as existsSync18, realpathSync as realpathSync10 } from "node:fs";
20939
+ import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as existsSync17, realpathSync as realpathSync10 } from "node:fs";
20868
20940
  import { tmpdir as tmpdir7 } from "node:os";
20869
20941
  import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute16, relative as relative11, resolve as resolve15, join as join26 } from "node:path";
20870
20942
  function asStr4(v) {
@@ -20883,7 +20955,7 @@ function canonicalContainedTarget(abs, root) {
20883
20955
  }
20884
20956
  let dir = abs;
20885
20957
  const tail = [];
20886
- while (!existsSync18(dir)) {
20958
+ while (!existsSync17(dir)) {
20887
20959
  const parent = dirname12(dir);
20888
20960
  if (parent === dir) break;
20889
20961
  tail.unshift(basename5(dir));
@@ -21371,6 +21443,8 @@ var init_evidence = __esm({
21371
21443
  ref: "copilot-sdk-capture-2026-09-20",
21372
21444
  source: "harness/adapters/copilot-sdk/evidence/capture-2026-09-20.json",
21373
21445
  source_artifact_sha256: "c46fba989dc0e772012c5fdb1291cf099326d24da2b551788be2e1e85113e49a",
21446
+ // sha256sum of the committed capture (#619 re-grounded it on 2026-09-20; #697 pins it).
21447
+ committed_artifact_sha256: "1c2d1acdfabc927e72dfa765cdb8da6fd995e6cbcad89812496d5c34e62e7903",
21374
21448
  binding: {
21375
21449
  runtime_id: "github-copilot-sdk-hosted",
21376
21450
  runtime_version: "copilot-runtime@1.0.85",
@@ -21393,16 +21467,19 @@ var init_evidence = __esm({
21393
21467
  {
21394
21468
  id: "pre-deny:shell",
21395
21469
  result: "proven",
21470
+ capture_path: "returned-reject",
21396
21471
  detail: "returned-reject path (permission.completed result.kind denied): a rejected permission decision blocked shell tool dispatch \u2014 protected state not mutated (shell-pre-deny observation, boundary seq 2 < completion seq 3)"
21397
21472
  },
21398
21473
  {
21399
21474
  id: "hook-not-invoked",
21400
21475
  result: "proven",
21476
+ capture_path: "callback-failure",
21401
21477
  detail: "callback-failure path: a broken permission callback (sync-throw, reject and adapter-throw, independently) failed CLOSED \u2014 the tool did not dispatch and protected state stayed intact"
21402
21478
  },
21403
21479
  {
21404
21480
  id: "transport:timeout",
21405
21481
  result: "inconclusive",
21482
+ capture_path: "callback-timeout",
21406
21483
  detail: "callback-timeout path: a hung permission handler emits no permission.completed (the pinned SDK has no handler timeout), so non-dispatch is intrinsically unobservable \u2014 timeout is not proven either way"
21407
21484
  }
21408
21485
  ]
@@ -21706,7 +21783,7 @@ var init_runtime_qualification = __esm({
21706
21783
 
21707
21784
  // src/cli/runtime.ts
21708
21785
  import { execFileSync as execFileSync14 } from "node:child_process";
21709
- import { existsSync as existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
21786
+ import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
21710
21787
  import { join as join27, dirname as dirname13 } from "node:path";
21711
21788
  function storePath(cwd) {
21712
21789
  const dir = gitDir(cwd);
@@ -21714,7 +21791,7 @@ function storePath(cwd) {
21714
21791
  }
21715
21792
  function readStore(cwd) {
21716
21793
  const path = storePath(cwd);
21717
- if (!path || !existsSync19(path)) return null;
21794
+ if (!path || !existsSync18(path)) return null;
21718
21795
  try {
21719
21796
  const parsed = JSON.parse(readFileSync22(path, "utf8"));
21720
21797
  if (parsed && typeof parsed === "object" && parsed.records && typeof parsed.records === "object") return parsed;
@@ -21885,7 +21962,7 @@ function resolveHookConfigHash(canonicalId, cwd) {
21885
21962
  "github-copilot-cli": join27(cwd, ".github", "hooks", "tamperward.json")
21886
21963
  };
21887
21964
  const file = files[canonicalId];
21888
- if (!file || !existsSync19(file)) return null;
21965
+ if (!file || !existsSync18(file)) return null;
21889
21966
  try {
21890
21967
  const raw = readFileSync22(file, "utf8");
21891
21968
  let hooks = raw;
@@ -22166,7 +22243,7 @@ var init_runtime = __esm({
22166
22243
 
22167
22244
  // src/cli/onboard.ts
22168
22245
  import { execFileSync as execFileSync15 } from "node:child_process";
22169
- import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync7, readFileSync as readFileSync23, realpathSync as realpathSync11, rmSync as rmSync13 } from "node:fs";
22246
+ import { lstatSync as lstatSync11, mkdtempSync as mkdtempSync7, readFileSync as readFileSync23, realpathSync as realpathSync11, rmSync as rmSync13 } from "node:fs";
22170
22247
  import { tmpdir as tmpdir8 } from "node:os";
22171
22248
  import { join as join28, relative as relative12, resolve as resolve16, sep as sep6 } from "node:path";
22172
22249
  import { createInterface } from "node:readline";
@@ -22674,7 +22751,7 @@ function runDemo(cwd, head, runners, out3) {
22674
22751
  return;
22675
22752
  }
22676
22753
  const targetPath = join28(wt, target.path);
22677
- const targetStat = lstatSync10(targetPath, { throwIfNoEntry: false });
22754
+ const targetStat = lstatSync11(targetPath, { throwIfNoEntry: false });
22678
22755
  if (!targetStat || !targetStat.isFile() || targetStat.isSymbolicLink()) {
22679
22756
  out3("Demo skipped: the selected test is not a regular file in the disposable worktree.");
22680
22757
  return;
@@ -23347,7 +23424,7 @@ var init_record = __esm({
23347
23424
  // src/research/run.ts
23348
23425
  import { randomUUID as randomUUID2 } from "node:crypto";
23349
23426
  import { execFileSync as execFileSync16 } from "node:child_process";
23350
- import { closeSync as closeSync4, existsSync as existsSync20, linkSync, mkdirSync as mkdirSync12, openSync as openSync4, readFileSync as readFileSync25, renameSync as renameSync4, rmSync as rmSync14, unlinkSync, writeFileSync as writeFileSync15, writeSync } from "node:fs";
23427
+ import { closeSync as closeSync5, existsSync as existsSync19, linkSync, mkdirSync as mkdirSync12, openSync as openSync5, readFileSync as readFileSync25, renameSync as renameSync4, rmSync as rmSync14, unlinkSync, writeFileSync as writeFileSync15, writeSync } from "node:fs";
23351
23428
  import { hostname } from "node:os";
23352
23429
  import { join as join29, resolve as resolve19 } from "node:path";
23353
23430
  function git7(args, cwd) {
@@ -23384,7 +23461,7 @@ function lockHolder(path) {
23384
23461
  function acquireResearchLock(ledger, breakStaleLock = false) {
23385
23462
  mkdirSync12(ledger, { recursive: true });
23386
23463
  const path = researchLockPath(ledger);
23387
- if (breakStaleLock && existsSync20(path)) {
23464
+ if (breakStaleLock && existsSync19(path)) {
23388
23465
  const owner2 = readLockOwner(path);
23389
23466
  if (!owner2) {
23390
23467
  throw new ResearchError(`research output ${ledger} has an unreadable lock at ${path}; verify no run is active, then remove it deliberately`);
@@ -23427,12 +23504,12 @@ function acquireResearchLock(ledger, breakStaleLock = false) {
23427
23504
  const text = JSON.stringify(owner) + "\n";
23428
23505
  let fd = -1;
23429
23506
  try {
23430
- fd = openSync4(path, "wx", 384);
23507
+ fd = openSync5(path, "wx", 384);
23431
23508
  writeSync(fd, text);
23432
- closeSync4(fd);
23509
+ closeSync5(fd);
23433
23510
  fd = -1;
23434
23511
  } catch (e) {
23435
- if (fd !== -1) closeSync4(fd);
23512
+ if (fd !== -1) closeSync5(fd);
23436
23513
  if (e.code === "EEXIST") {
23437
23514
  throw new ResearchError(
23438
23515
  `research output ${ledger} is already locked by ${lockHolder(path)}; refusing concurrent writers. Verify the owner is not running, then remove ${path} deliberately or rerun with --break-lock`
@@ -23757,7 +23834,7 @@ function runResearch(opts) {
23757
23834
  try {
23758
23835
  for (let pair = 1; pair <= pairs; pair++) {
23759
23836
  const path = pairRecordPath(ledger, task.id, pair);
23760
- if (!existsSync20(path)) continue;
23837
+ if (!existsSync19(path)) continue;
23761
23838
  const existing = resumableRecord(path, {
23762
23839
  task: task.id,
23763
23840
  pair,
@@ -23877,16 +23954,16 @@ var init_run2 = __esm({
23877
23954
  });
23878
23955
 
23879
23956
  // src/research/ledger-files.ts
23880
- import { closeSync as closeSync5, constants as constants4, fstatSync as fstatSync2, lstatSync as lstatSync11, openSync as openSync5, readFileSync as readFileSync26, readdirSync as readdirSync7, realpathSync as realpathSync12 } from "node:fs";
23957
+ import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as openSync6, readFileSync as readFileSync26, readdirSync as readdirSync7, realpathSync as realpathSync12 } from "node:fs";
23881
23958
  import { join as join30, resolve as resolve20 } from "node:path";
23882
23959
  function lstatOrNull(path) {
23883
23960
  try {
23884
- return lstatSync11(path);
23961
+ return lstatSync12(path);
23885
23962
  } catch {
23886
23963
  return null;
23887
23964
  }
23888
23965
  }
23889
- function kindOf(st) {
23966
+ function kindOf2(st) {
23890
23967
  if (st.isSymbolicLink()) return "a symlink";
23891
23968
  if (st.isDirectory()) return "a directory";
23892
23969
  if (st.isFIFO()) return "a FIFO";
@@ -23898,7 +23975,7 @@ function readRegularFile(path, realPairsDir, name) {
23898
23975
  const listed = lstatOrNull(path);
23899
23976
  if (listed === null) throw new ResearchError(`ledger record ${path} vanished while the ledger was being read`);
23900
23977
  if (!listed.isFile()) {
23901
- throw new ResearchError(`ledger record ${path} is ${kindOf(listed)}; only a regular file placed directly in pairs/ is read`);
23978
+ throw new ResearchError(`ledger record ${path} is ${kindOf2(listed)}; only a regular file placed directly in pairs/ is read`);
23902
23979
  }
23903
23980
  if (listed.nlink !== 1) {
23904
23981
  throw new ResearchError(`ledger record ${path} has ${listed.nlink} links; a hard link can name a file outside pairs/, so only a singly linked regular file is read`);
@@ -23907,22 +23984,22 @@ function readRegularFile(path, realPairsDir, name) {
23907
23984
  if (real !== join30(realPairsDir, name)) {
23908
23985
  throw new ResearchError(`ledger record ${path} resolves outside the pairs directory (${real}); refusing to read it`);
23909
23986
  }
23910
- const flags = constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0);
23987
+ const flags = constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0);
23911
23988
  let fd;
23912
23989
  try {
23913
- fd = openSync5(path, flags);
23990
+ fd = openSync6(path, flags);
23914
23991
  } catch (e) {
23915
23992
  throw new ResearchError(`cannot open ledger record ${path}: ${errorMessage(e)}`);
23916
23993
  }
23917
23994
  try {
23918
- const opened = fstatSync2(fd);
23995
+ const opened = fstatSync3(fd);
23919
23996
  const sameInode = process.platform === "win32" || opened.dev === listed.dev && opened.ino === listed.ino;
23920
23997
  if (!opened.isFile() || !sameInode || opened.nlink !== 1) {
23921
23998
  throw new ResearchError(`ledger record ${path} changed between listing and reading; refusing to read it`);
23922
23999
  }
23923
24000
  return readFileSync26(fd);
23924
24001
  } finally {
23925
- closeSync5(fd);
24002
+ closeSync6(fd);
23926
24003
  }
23927
24004
  }
23928
24005
  function readPairFiles(ledger) {
@@ -24093,7 +24170,7 @@ var init_summarize = __esm({
24093
24170
 
24094
24171
  // src/research/init.ts
24095
24172
  import { createHash as createHash17 } from "node:crypto";
24096
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
24173
+ import { existsSync as existsSync20, mkdirSync as mkdirSync13, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
24097
24174
  import { basename as basename6, dirname as dirname15, resolve as resolve21 } from "node:path";
24098
24175
  function idFrom(repo) {
24099
24176
  const clean = repo.replace(/[\\/]$/, "").split(/[\\/]/).pop() || "task";
@@ -24105,7 +24182,7 @@ function createResearchManifest(opts) {
24105
24182
  if (!opts.prompt) throw new ResearchError("research init requires --prompt");
24106
24183
  if (!opts.verifyCommand) throw new ResearchError("research init requires --verify-command");
24107
24184
  const out3 = resolve21(opts.out);
24108
- if (existsSync21(out3)) throw new ResearchError(`research init refuses to overwrite ${out3}; choose a new path`);
24185
+ if (existsSync20(out3)) throw new ResearchError(`research init refuses to overwrite ${out3}; choose a new path`);
24109
24186
  const id = opts.id ?? idFrom(opts.repo);
24110
24187
  if (!/^[A-Za-z0-9._-]+$/.test(id)) throw new ResearchError(`research init id must match [A-Za-z0-9._-] (got "${id}")`);
24111
24188
  if (opts.verifyBudget !== void 0 && (!Number.isFinite(opts.verifyBudget) || opts.verifyBudget <= 0)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.39.3",
3
+ "version": "2.39.5",
4
4
  "description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "hexrift",