tamperward 2.29.12 → 2.29.13

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 +77 -17
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -18237,18 +18237,69 @@ var init_trace_verify = __esm({
18237
18237
  });
18238
18238
 
18239
18239
  // src/runtimes.ts
18240
- import { existsSync as existsSync17 } from "node:fs";
18240
+ import { existsSync as existsSync17, readFileSync as readFileSync21 } from "node:fs";
18241
18241
  import { join as join23 } from "node:path";
18242
+ function isRecord4(x) {
18243
+ return typeof x === "object" && x !== null && !Array.isArray(x);
18244
+ }
18245
+ function hooksBeyondTamperward(hooks) {
18246
+ if (!isRecord4(hooks)) return hooks != null;
18247
+ for (const entries of Object.values(hooks)) {
18248
+ if (!Array.isArray(entries)) {
18249
+ if (entries != null) return true;
18250
+ continue;
18251
+ }
18252
+ for (const entry of entries) {
18253
+ const hs = isRecord4(entry) ? entry.hooks : null;
18254
+ if (!Array.isArray(hs)) {
18255
+ if (hs != null) return true;
18256
+ continue;
18257
+ }
18258
+ for (const h of hs) {
18259
+ const cmd = isRecord4(h) ? String(h.command ?? "") : "";
18260
+ if (!/tamperward/.test(cmd)) return true;
18261
+ }
18262
+ }
18263
+ }
18264
+ return false;
18265
+ }
18266
+ function claudeSettingsBeyondTamperward(cwd) {
18267
+ const path = join23(cwd, ".claude", "settings.json");
18268
+ let raw;
18269
+ try {
18270
+ if (!existsSync17(path)) return false;
18271
+ raw = readFileSync21(path, "utf8");
18272
+ } catch {
18273
+ return false;
18274
+ }
18275
+ let parsed;
18276
+ try {
18277
+ parsed = JSON.parse(raw);
18278
+ } catch {
18279
+ return raw.trim().length > 0;
18280
+ }
18281
+ if (!isRecord4(parsed)) return raw.trim().length > 0;
18282
+ for (const [key2, value] of Object.entries(parsed)) {
18283
+ if (key2 === "disableAllHooks") continue;
18284
+ if (key2 === "hooks") {
18285
+ if (hooksBeyondTamperward(value)) return true;
18286
+ continue;
18287
+ }
18288
+ return true;
18289
+ }
18290
+ return false;
18291
+ }
18242
18292
  function detectRuntimes(cwd) {
18243
18293
  const found = [];
18244
18294
  for (const rt of KNOWN_RUNTIMES) {
18245
- const matchedMarker = rt.markers.find((m) => {
18295
+ const marker = rt.markers.find((m) => {
18246
18296
  try {
18247
18297
  return existsSync17(join23(cwd, m));
18248
18298
  } catch {
18249
18299
  return false;
18250
18300
  }
18251
18301
  });
18302
+ const matchedMarker = marker ?? rt.detectExtra?.(cwd) ?? void 0;
18252
18303
  if (matchedMarker !== void 0) found.push({ ...rt, matchedMarker });
18253
18304
  }
18254
18305
  return found;
@@ -18268,10 +18319,14 @@ function detectionHeadline(detected) {
18268
18319
  return `Detected ${detected.length} agent runtimes: ${parts.join(", ")}.`;
18269
18320
  }
18270
18321
  function neutralOnlyCaveat(detected) {
18271
- if (detected.length === 0 || hasInLoopRuntime(detected)) return null;
18272
- const names = detected.map((r) => r.label).join(", ");
18273
- const tracking = [...new Set(detected.map((r) => r.adapterTracking).filter(Boolean))].join(", ");
18274
- return `In-loop steering (deny-before-execute) ships for Claude Code only today, so on ${names} your live protection is the agent-neutral layers: pre-commit and CI. The Claude hook wiring is still written and is inert unless Claude Code runs in this repository.${tracking ? ` A native in-loop adapter is tracked in ${tracking}.` : ""}`;
18322
+ const neutral = detected.filter((r) => r.steering === "neutral");
18323
+ if (neutral.length === 0) return null;
18324
+ const names = neutral.map((r) => r.label).join(", ");
18325
+ const tracking = [...new Set(neutral.map((r) => r.adapterTracking).filter(Boolean))].join(", ");
18326
+ const claudeAlso = hasInLoopRuntime(detected);
18327
+ const lead = claudeAlso ? `In-loop steering (deny-before-execute) ships for Claude Code only today: Claude Code here gets it, but on ${names} your live protection is ` : `In-loop steering (deny-before-execute) ships for Claude Code only today, so on ${names} your live protection is `;
18328
+ const tail = claudeAlso ? "" : " The Claude hook wiring is still written and is inert unless Claude Code runs in this repository.";
18329
+ return `${lead}the agent-neutral layers: pre-commit and CI.${tail}${tracking ? ` A native in-loop adapter is tracked in ${tracking}.` : ""}`;
18275
18330
  }
18276
18331
  var KNOWN_RUNTIMES;
18277
18332
  var init_runtimes = __esm({
@@ -18280,8 +18335,13 @@ var init_runtimes = __esm({
18280
18335
  KNOWN_RUNTIMES = [
18281
18336
  {
18282
18337
  id: "claude-code",
18338
+ // Markers are Claude Code files `init` never writes, so detection never mistakes
18339
+ // TamperWard's own generated `.claude/settings.json` for evidence a human runs
18340
+ // Claude here (#526). `detectExtra` looks at that generated file's CONTENT for
18341
+ // real use (configuration beyond the two hooks init merges in).
18283
18342
  label: "Claude Code",
18284
- markers: [".claude/settings.json", ".claude"],
18343
+ markers: ["CLAUDE.md", ".claude/settings.local.json", ".claude/commands", ".claude/agents"],
18344
+ detectExtra: (cwd) => claudeSettingsBeyondTamperward(cwd) ? ".claude/settings.json" : null,
18285
18345
  steering: "in-loop",
18286
18346
  note: "native in-loop steering (PreToolUse deny + Stop sweep) plus the agent-neutral layers."
18287
18347
  },
@@ -18315,7 +18375,7 @@ var init_runtimes = __esm({
18315
18375
 
18316
18376
  // src/cli/onboard.ts
18317
18377
  import { execFileSync as execFileSync12 } from "node:child_process";
18318
- import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync6, readFileSync as readFileSync21, realpathSync as realpathSync11, rmSync as rmSync10 } from "node:fs";
18378
+ import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync6, readFileSync as readFileSync22, realpathSync as realpathSync11, rmSync as rmSync10 } from "node:fs";
18319
18379
  import { tmpdir as tmpdir7 } from "node:os";
18320
18380
  import { join as join24, relative as relative7, resolve as resolve12, sep as sep5 } from "node:path";
18321
18381
  import { createInterface } from "node:readline";
@@ -18391,7 +18451,7 @@ function writeVerifyCommand(cwd, command) {
18391
18451
  return `${POLICY_FILE} is not a regular file; refusing to follow or replace a symlink or special file`;
18392
18452
  }
18393
18453
  const mode = existingMode(path, 420);
18394
- const original = kind === "file" ? readFileSync21(path, "utf8") : null;
18454
+ const original = kind === "file" ? readFileSync22(path, "utf8") : null;
18395
18455
  let next;
18396
18456
  try {
18397
18457
  const doc = parseDocument(original && original.trim() ? original : "version: 1\n");
@@ -18992,7 +19052,7 @@ var init_capture = __esm({
18992
19052
 
18993
19053
  // src/research/manifest.ts
18994
19054
  import { createHash as createHash13 } from "node:crypto";
18995
- import { readFileSync as readFileSync22 } from "node:fs";
19055
+ import { readFileSync as readFileSync23 } from "node:fs";
18996
19056
  import { dirname as dirname10, resolve as resolve14 } from "node:path";
18997
19057
  function taskFrom(raw, index, manifestDir) {
18998
19058
  const where = `task #${index + 1}`;
@@ -19026,7 +19086,7 @@ function readManifest(path) {
19026
19086
  const abs = resolve14(path);
19027
19087
  let bytes;
19028
19088
  try {
19029
- bytes = readFileSync22(abs);
19089
+ bytes = readFileSync23(abs);
19030
19090
  } catch (e) {
19031
19091
  throw new ResearchError(`cannot read task manifest ${abs}: ${e instanceof Error ? e.message : String(e)}`);
19032
19092
  }
@@ -19238,7 +19298,7 @@ var init_record = __esm({
19238
19298
 
19239
19299
  // src/research/run.ts
19240
19300
  import { execFileSync as execFileSync13 } from "node:child_process";
19241
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
19301
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync24, renameSync as renameSync4, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
19242
19302
  import { join as join25, resolve as resolve15 } from "node:path";
19243
19303
  function git6(args, cwd) {
19244
19304
  return execFileSync13("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
@@ -19249,7 +19309,7 @@ function pairRecordPath(ledger, task, pair) {
19249
19309
  function resumableRecord(path, expected) {
19250
19310
  let raw;
19251
19311
  try {
19252
- raw = JSON.parse(readFileSync23(path, "utf8"));
19312
+ raw = JSON.parse(readFileSync24(path, "utf8"));
19253
19313
  } catch (e) {
19254
19314
  throw new ResearchError(`ledger record ${path} is malformed (${errorMessage(e).split("\n")[0]}); remove it to regenerate the pair, or use a new --out`);
19255
19315
  }
@@ -19672,7 +19732,7 @@ var init_run2 = __esm({
19672
19732
  });
19673
19733
 
19674
19734
  // src/research/summarize.ts
19675
- import { readdirSync as readdirSync7, readFileSync as readFileSync24 } from "node:fs";
19735
+ import { readdirSync as readdirSync7, readFileSync as readFileSync25 } from "node:fs";
19676
19736
  import { join as join26, resolve as resolve16 } from "node:path";
19677
19737
  function readLedger2(dir) {
19678
19738
  const pairsDir = join26(resolve16(dir), "pairs");
@@ -19687,7 +19747,7 @@ function readLedger2(dir) {
19687
19747
  const path = join26(pairsDir, n);
19688
19748
  let raw;
19689
19749
  try {
19690
- raw = JSON.parse(readFileSync24(path, "utf8"));
19750
+ raw = JSON.parse(readFileSync25(path, "utf8"));
19691
19751
  } catch (e) {
19692
19752
  throw new ResearchError(`ledger record ${path} is not valid JSON: ${errorMessage(e)}`);
19693
19753
  }
@@ -20394,7 +20454,7 @@ var init_main = __esm({
20394
20454
  // src/cli/index.ts
20395
20455
  init_hook_client();
20396
20456
  init_exit();
20397
- import { readFileSync as readFileSync25 } from "node:fs";
20457
+ import { readFileSync as readFileSync26 } from "node:fs";
20398
20458
  function loadMain() {
20399
20459
  return Promise.resolve().then(() => (init_main(), main_exports));
20400
20460
  }
@@ -20407,7 +20467,7 @@ async function launch(argv) {
20407
20467
  if (kind && hookServiceEnabled()) {
20408
20468
  let raw = null;
20409
20469
  try {
20410
- raw = readFileSync25(0, "utf8");
20470
+ raw = readFileSync26(0, "utf8");
20411
20471
  } catch {
20412
20472
  raw = null;
20413
20473
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.29.12",
3
+ "version": "2.29.13",
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",