tamperward 2.28.0 → 2.29.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/dist/cli/index.js +97 -15
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -17956,11 +17956,88 @@ var init_trace_verify = __esm({
|
|
|
17956
17956
|
}
|
|
17957
17957
|
});
|
|
17958
17958
|
|
|
17959
|
+
// src/runtimes.ts
|
|
17960
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
17961
|
+
import { join as join23 } from "node:path";
|
|
17962
|
+
function detectRuntimes(cwd) {
|
|
17963
|
+
const found = [];
|
|
17964
|
+
for (const rt of KNOWN_RUNTIMES) {
|
|
17965
|
+
const matchedMarker = rt.markers.find((m) => {
|
|
17966
|
+
try {
|
|
17967
|
+
return existsSync17(join23(cwd, m));
|
|
17968
|
+
} catch {
|
|
17969
|
+
return false;
|
|
17970
|
+
}
|
|
17971
|
+
});
|
|
17972
|
+
if (matchedMarker !== void 0) found.push({ ...rt, matchedMarker });
|
|
17973
|
+
}
|
|
17974
|
+
return found;
|
|
17975
|
+
}
|
|
17976
|
+
function hasInLoopRuntime(detected) {
|
|
17977
|
+
return detected.some((r) => r.steering === "in-loop");
|
|
17978
|
+
}
|
|
17979
|
+
function detectionHeadline(detected) {
|
|
17980
|
+
if (detected.length === 0) {
|
|
17981
|
+
return "No agent runtime detected. Wiring Claude Code in-loop steering plus the agent-neutral layers (pre-commit + CI) that protect any agent or human.";
|
|
17982
|
+
}
|
|
17983
|
+
if (detected.length === 1) {
|
|
17984
|
+
const r = detected[0];
|
|
17985
|
+
return `Detected ${r.label} \u2014 ${r.note}`;
|
|
17986
|
+
}
|
|
17987
|
+
const parts = detected.map((r) => `${r.label} (${r.steering === "in-loop" ? "in-loop" : "neutral layers"})`);
|
|
17988
|
+
return `Detected ${detected.length} agent runtimes: ${parts.join(", ")}.`;
|
|
17989
|
+
}
|
|
17990
|
+
function neutralOnlyCaveat(detected) {
|
|
17991
|
+
if (detected.length === 0 || hasInLoopRuntime(detected)) return null;
|
|
17992
|
+
const names = detected.map((r) => r.label).join(", ");
|
|
17993
|
+
const tracking = [...new Set(detected.map((r) => r.adapterTracking).filter(Boolean))].join(", ");
|
|
17994
|
+
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}.` : ""}`;
|
|
17995
|
+
}
|
|
17996
|
+
var KNOWN_RUNTIMES;
|
|
17997
|
+
var init_runtimes = __esm({
|
|
17998
|
+
"src/runtimes.ts"() {
|
|
17999
|
+
"use strict";
|
|
18000
|
+
KNOWN_RUNTIMES = [
|
|
18001
|
+
{
|
|
18002
|
+
id: "claude-code",
|
|
18003
|
+
label: "Claude Code",
|
|
18004
|
+
markers: [".claude/settings.json", ".claude"],
|
|
18005
|
+
steering: "in-loop",
|
|
18006
|
+
note: "native in-loop steering (PreToolUse deny + Stop sweep) plus the agent-neutral layers."
|
|
18007
|
+
},
|
|
18008
|
+
{
|
|
18009
|
+
id: "cursor",
|
|
18010
|
+
label: "Cursor",
|
|
18011
|
+
markers: [".cursor", ".cursorrules"],
|
|
18012
|
+
steering: "neutral",
|
|
18013
|
+
adapterTracking: "#482",
|
|
18014
|
+
note: "agent-neutral layers (pre-commit + CI) today; a native in-loop adapter is tracked in #482."
|
|
18015
|
+
},
|
|
18016
|
+
{
|
|
18017
|
+
id: "copilot",
|
|
18018
|
+
label: "GitHub Copilot",
|
|
18019
|
+
markers: [".github/copilot-instructions.md", ".github/copilot"],
|
|
18020
|
+
steering: "neutral",
|
|
18021
|
+
adapterTracking: "#482",
|
|
18022
|
+
note: "agent-neutral layers (pre-commit + CI) today; a native in-loop adapter is tracked in #482."
|
|
18023
|
+
},
|
|
18024
|
+
{
|
|
18025
|
+
id: "codex",
|
|
18026
|
+
label: "an AGENTS.md-aware agent (e.g. Codex)",
|
|
18027
|
+
markers: [".codex", "AGENTS.md"],
|
|
18028
|
+
steering: "neutral",
|
|
18029
|
+
adapterTracking: "#482",
|
|
18030
|
+
note: "agent-neutral layers (pre-commit + CI) today; a native in-loop adapter is tracked in #482."
|
|
18031
|
+
}
|
|
18032
|
+
];
|
|
18033
|
+
}
|
|
18034
|
+
});
|
|
18035
|
+
|
|
17959
18036
|
// src/cli/onboard.ts
|
|
17960
18037
|
import { execFileSync as execFileSync12 } from "node:child_process";
|
|
17961
18038
|
import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync6, readFileSync as readFileSync21, realpathSync as realpathSync11, rmSync as rmSync10 } from "node:fs";
|
|
17962
18039
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
17963
|
-
import { join as
|
|
18040
|
+
import { join as join24, relative as relative7, resolve as resolve12, sep as sep5 } from "node:path";
|
|
17964
18041
|
import { createInterface } from "node:readline";
|
|
17965
18042
|
import { parseDocument } from "yaml";
|
|
17966
18043
|
function readlineAsker(input, output) {
|
|
@@ -18028,7 +18105,7 @@ function explainVerdict(v, code2) {
|
|
|
18028
18105
|
}
|
|
18029
18106
|
}
|
|
18030
18107
|
function writeVerifyCommand(cwd, command) {
|
|
18031
|
-
const path =
|
|
18108
|
+
const path = join24(cwd, POLICY_FILE);
|
|
18032
18109
|
const kind = writeTargetKind(path);
|
|
18033
18110
|
if (kind === "symlink" || kind === "irregular") {
|
|
18034
18111
|
return `${POLICY_FILE} is not a regular file; refusing to follow or replace a symlink or special file`;
|
|
@@ -18182,11 +18259,15 @@ async function runOnboard(opts, io = {}) {
|
|
|
18182
18259
|
}
|
|
18183
18260
|
}
|
|
18184
18261
|
section(2);
|
|
18262
|
+
const detected = detectRuntimes(cwd);
|
|
18263
|
+
status("RUNTIME", detectionHeadline(detected), "info");
|
|
18264
|
+
const caveat = neutralOnlyCaveat(detected);
|
|
18265
|
+
if (caveat) status("NOTE", caveat, "warn");
|
|
18185
18266
|
const plan = planInit(cwd);
|
|
18186
18267
|
const names = {
|
|
18187
18268
|
policy: "Policy",
|
|
18188
18269
|
gitignore: "Git ignore",
|
|
18189
|
-
agent: "Claude
|
|
18270
|
+
agent: "In-loop (Claude)",
|
|
18190
18271
|
"pre-commit": "Pre-commit",
|
|
18191
18272
|
ci: "CI workflow",
|
|
18192
18273
|
codeowners: "CODEOWNERS"
|
|
@@ -18423,13 +18504,13 @@ function runDemo(cwd, head, runners, out3) {
|
|
|
18423
18504
|
}
|
|
18424
18505
|
const before = treeFingerprint(cwd);
|
|
18425
18506
|
out3(`working tree fingerprint before: ${before.slice(0, 16)}`);
|
|
18426
|
-
const wt = mkdtempSync6(
|
|
18507
|
+
const wt = mkdtempSync6(join24(tmpdir7(), "tw-onboard-demo-"));
|
|
18427
18508
|
try {
|
|
18428
18509
|
if (git5(cwd, ["worktree", "add", "--detach", wt, head]) === null) {
|
|
18429
18510
|
out3("Demo skipped: could not create a temporary worktree (git worktree add failed).");
|
|
18430
18511
|
return;
|
|
18431
18512
|
}
|
|
18432
|
-
const targetPath =
|
|
18513
|
+
const targetPath = join24(wt, target.path);
|
|
18433
18514
|
const targetStat = lstatSync10(targetPath, { throwIfNoEntry: false });
|
|
18434
18515
|
if (!targetStat || !targetStat.isFile() || targetStat.isSymbolicLink()) {
|
|
18435
18516
|
out3("Demo skipped: the selected test is not a regular file in the disposable worktree.");
|
|
@@ -18484,6 +18565,7 @@ var init_onboard = __esm({
|
|
|
18484
18565
|
init_policy();
|
|
18485
18566
|
init_policy_load();
|
|
18486
18567
|
init_narrow();
|
|
18568
|
+
init_runtimes();
|
|
18487
18569
|
init_wiring();
|
|
18488
18570
|
init_safe_write();
|
|
18489
18571
|
Aborted = class extends Error {
|
|
@@ -18876,13 +18958,13 @@ var init_record = __esm({
|
|
|
18876
18958
|
|
|
18877
18959
|
// src/research/run.ts
|
|
18878
18960
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
18879
|
-
import { existsSync as
|
|
18880
|
-
import { join as
|
|
18961
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
|
|
18962
|
+
import { join as join25, resolve as resolve15 } from "node:path";
|
|
18881
18963
|
function git6(args, cwd) {
|
|
18882
18964
|
return execFileSync13("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
18883
18965
|
}
|
|
18884
18966
|
function pairRecordPath(ledger, task, pair) {
|
|
18885
|
-
return
|
|
18967
|
+
return join25(ledger, "pairs", `${task}--${pair}.json`);
|
|
18886
18968
|
}
|
|
18887
18969
|
function resumableRecord(path, expected) {
|
|
18888
18970
|
let raw;
|
|
@@ -18928,9 +19010,9 @@ function writeRecordAtomically(path, text) {
|
|
|
18928
19010
|
renameSync4(tmp, path);
|
|
18929
19011
|
}
|
|
18930
19012
|
function freshWorkspace(ledger, task, pair, arm, sourceBase) {
|
|
18931
|
-
const ws3 =
|
|
19013
|
+
const ws3 = join25(ledger, "workspaces", `${task.id}--${pair}--${arm}`);
|
|
18932
19014
|
rmSync11(ws3, { recursive: true, force: true });
|
|
18933
|
-
mkdirSync9(
|
|
19015
|
+
mkdirSync9(join25(ledger, "workspaces"), { recursive: true });
|
|
18934
19016
|
try {
|
|
18935
19017
|
execFileSync13("git", ["clone", "-q", "--no-hardlinks", task.repo, ws3], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
18936
19018
|
} catch (e) {
|
|
@@ -19178,14 +19260,14 @@ function runResearch(opts) {
|
|
|
19178
19260
|
}
|
|
19179
19261
|
const ledger = resolve15(opts.out);
|
|
19180
19262
|
const pairs = opts.pairs ?? 1;
|
|
19181
|
-
mkdirSync9(
|
|
19263
|
+
mkdirSync9(join25(ledger, "pairs"), { recursive: true });
|
|
19182
19264
|
for (const task of tasks) {
|
|
19183
19265
|
const existingRecords = /* @__PURE__ */ new Map();
|
|
19184
19266
|
let sourceBase = null;
|
|
19185
19267
|
try {
|
|
19186
19268
|
for (let pair = 1; pair <= pairs; pair++) {
|
|
19187
19269
|
const path = pairRecordPath(ledger, task.id, pair);
|
|
19188
|
-
if (!
|
|
19270
|
+
if (!existsSync18(path)) continue;
|
|
19189
19271
|
const existing = resumableRecord(path, {
|
|
19190
19272
|
task: task.id,
|
|
19191
19273
|
pair,
|
|
@@ -19311,9 +19393,9 @@ var init_run2 = __esm({
|
|
|
19311
19393
|
|
|
19312
19394
|
// src/research/summarize.ts
|
|
19313
19395
|
import { readdirSync as readdirSync7, readFileSync as readFileSync24 } from "node:fs";
|
|
19314
|
-
import { join as
|
|
19396
|
+
import { join as join26, resolve as resolve16 } from "node:path";
|
|
19315
19397
|
function readLedger2(dir) {
|
|
19316
|
-
const pairsDir =
|
|
19398
|
+
const pairsDir = join26(resolve16(dir), "pairs");
|
|
19317
19399
|
let names;
|
|
19318
19400
|
try {
|
|
19319
19401
|
names = readdirSync7(pairsDir).filter((n) => n.endsWith(".json")).sort();
|
|
@@ -19322,7 +19404,7 @@ function readLedger2(dir) {
|
|
|
19322
19404
|
}
|
|
19323
19405
|
if (names.length === 0) throw new ResearchError(`ledger ${pairsDir} holds no pair records`);
|
|
19324
19406
|
return names.map((n) => {
|
|
19325
|
-
const path =
|
|
19407
|
+
const path = join26(pairsDir, n);
|
|
19326
19408
|
let raw;
|
|
19327
19409
|
try {
|
|
19328
19410
|
raw = JSON.parse(readFileSync24(path, "utf8"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.29.0",
|
|
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",
|