altimate-receipts 0.6.2 → 0.8.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/{chunk-OQJHGUIN.js → chunk-6QULLAVH.js} +2 -2
- package/dist/chunk-NPYC3NGR.js +859 -0
- package/dist/chunk-NPYC3NGR.js.map +1 -0
- package/dist/{chunk-72Y2GS7I.js → chunk-SGVU3CGP.js} +330 -23
- package/dist/chunk-SGVU3CGP.js.map +1 -0
- package/dist/cli.js +98 -114
- package/dist/cli.js.map +1 -1
- package/dist/index.js +4 -222
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/package.json +1 -1
- package/schema/agent-execution-receipt-v1.json +303 -58
- package/dist/chunk-5R6W4W4R.js +0 -607
- package/dist/chunk-5R6W4W4R.js.map +0 -1
- package/dist/chunk-72Y2GS7I.js.map +0 -1
- /package/dist/{chunk-OQJHGUIN.js.map → chunk-6QULLAVH.js.map} +0 -0
package/dist/chunk-5R6W4W4R.js
DELETED
|
@@ -1,607 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
agentIds,
|
|
4
|
-
buildReceipt,
|
|
5
|
-
commandOf,
|
|
6
|
-
cwdAtFirstGit,
|
|
7
|
-
deriveEvidence,
|
|
8
|
-
deriveFindings,
|
|
9
|
-
deriveSpans,
|
|
10
|
-
destroysGitData,
|
|
11
|
-
destructiveMatch,
|
|
12
|
-
estimateCost,
|
|
13
|
-
filePathOf,
|
|
14
|
-
gradeLetter,
|
|
15
|
-
isEditTool,
|
|
16
|
-
isNoVerify,
|
|
17
|
-
loadById,
|
|
18
|
-
parseGitInvocations,
|
|
19
|
-
redact,
|
|
20
|
-
redactReceipt,
|
|
21
|
-
rewritesHistory,
|
|
22
|
-
touchedPaths
|
|
23
|
-
} from "./chunk-72Y2GS7I.js";
|
|
24
|
-
|
|
25
|
-
// src/receipt/canonical.ts
|
|
26
|
-
function canonicalize(value) {
|
|
27
|
-
return serialize(value);
|
|
28
|
-
}
|
|
29
|
-
function serialize(value) {
|
|
30
|
-
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
31
|
-
return JSON.stringify(value);
|
|
32
|
-
}
|
|
33
|
-
if (typeof value === "string") {
|
|
34
|
-
return JSON.stringify(value);
|
|
35
|
-
}
|
|
36
|
-
if (Array.isArray(value)) {
|
|
37
|
-
return `[${value.map(serialize).join(",")}]`;
|
|
38
|
-
}
|
|
39
|
-
if (typeof value === "object") {
|
|
40
|
-
const obj = value;
|
|
41
|
-
const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
42
|
-
const body = keys.map((k) => `${JSON.stringify(k)}:${serialize(obj[k])}`).join(",");
|
|
43
|
-
return `{${body}}`;
|
|
44
|
-
}
|
|
45
|
-
return "null";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// src/share/clipboard.ts
|
|
49
|
-
import { spawnSync } from "child_process";
|
|
50
|
-
function candidates() {
|
|
51
|
-
if (process.platform === "darwin") {
|
|
52
|
-
return [{ cmd: "pbcopy", args: [] }];
|
|
53
|
-
}
|
|
54
|
-
if (process.platform === "win32") {
|
|
55
|
-
return [{ cmd: "clip", args: [] }];
|
|
56
|
-
}
|
|
57
|
-
return [
|
|
58
|
-
{ cmd: "wl-copy", args: [] },
|
|
59
|
-
{ cmd: "xclip", args: ["-selection", "clipboard"] },
|
|
60
|
-
{ cmd: "xsel", args: ["--clipboard", "--input"] }
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
function copyToClipboard(text) {
|
|
64
|
-
for (const { cmd, args } of candidates()) {
|
|
65
|
-
try {
|
|
66
|
-
const res = spawnSync(cmd, args, { input: text, stdio: ["pipe", "ignore", "ignore"] });
|
|
67
|
-
if (!res.error && res.status === 0) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
} catch {
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/share/markdown.ts
|
|
77
|
-
var VERDICT = {
|
|
78
|
-
F: "DO NOT MERGE WITHOUT REVIEW",
|
|
79
|
-
C: "NEEDS A CLOSE REVIEW",
|
|
80
|
-
B: "MINOR THINGS TO CHECK",
|
|
81
|
-
A: "LOOKS CLEAN"
|
|
82
|
-
};
|
|
83
|
-
var ICON = {
|
|
84
|
-
critical: "\u26D4",
|
|
85
|
-
high: "\u26A0\uFE0F",
|
|
86
|
-
medium: "\u{1F50D}",
|
|
87
|
-
low: "\xB7"
|
|
88
|
-
};
|
|
89
|
-
var base = (p) => p.split("/").pop() ?? p;
|
|
90
|
-
function renderShareMarkdown(args) {
|
|
91
|
-
const { summary, session, derived, findings } = args;
|
|
92
|
-
const { main, minor } = findings;
|
|
93
|
-
const g = gradeLetter(main);
|
|
94
|
-
const ev = deriveEvidence(session, derived);
|
|
95
|
-
const counts = ["critical", "high", "medium"].map((s) => {
|
|
96
|
-
const n = main.filter((f) => f.severity === s).length;
|
|
97
|
-
return n ? `${n} ${s}` : null;
|
|
98
|
-
}).filter(Boolean).join(" \xB7 ") || "no findings";
|
|
99
|
-
const title = redact(summary.title || "untitled session");
|
|
100
|
-
const out = [];
|
|
101
|
-
out.push(`## \u{1F9FE} Receipt \u2014 ${title} \xB7 Grade ${g}`);
|
|
102
|
-
out.push("");
|
|
103
|
-
out.push(`**${VERDICT[g]}** \xB7 ${counts} \xB7 _${summary.source}_`);
|
|
104
|
-
out.push("");
|
|
105
|
-
if (main.length) {
|
|
106
|
-
out.push("### Findings");
|
|
107
|
-
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
108
|
-
const sorted = [...main].sort(
|
|
109
|
-
(a, b) => order[a.severity] - order[b.severity] || b.score - a.score
|
|
110
|
-
);
|
|
111
|
-
for (const f of sorted.slice(0, 12)) {
|
|
112
|
-
const tag = f.impactLabel ? ` \u2014 ${redact(f.impactLabel)}` : "";
|
|
113
|
-
const loc = f.filePath ? ` (\`${redact(base(f.filePath))}\`)` : "";
|
|
114
|
-
out.push(`- ${ICON[f.severity]} **${redact(f.title)}**${tag}${loc}`);
|
|
115
|
-
}
|
|
116
|
-
if (minor.length) {
|
|
117
|
-
out.push(`- _+${minor.length} minor (collapsed)_`);
|
|
118
|
-
}
|
|
119
|
-
out.push("");
|
|
120
|
-
}
|
|
121
|
-
out.push("### Evidence");
|
|
122
|
-
out.push(
|
|
123
|
-
`${ev.filesChanged} files \xB7 ${ev.edits} edits \xB7 ${ev.commands} commands \xB7 ${ev.testsRan ? "tests ran \u2713" : "no test run detected"} \xB7 ${ev.destructiveOps} destructive ops`
|
|
124
|
-
);
|
|
125
|
-
out.push("");
|
|
126
|
-
out.push("_Verified by Receipts \xB7 deterministic \xB7 0 model calls \xB7 evidence, not judgement_");
|
|
127
|
-
return `${out.join("\n")}
|
|
128
|
-
`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/sign/envelope.ts
|
|
132
|
-
var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json";
|
|
133
|
-
function pae(payloadType, payload) {
|
|
134
|
-
const typeBytes = Buffer.from(payloadType, "utf8");
|
|
135
|
-
const bodyBytes = Buffer.from(payload, "utf8");
|
|
136
|
-
const header = `DSSEv1 ${typeBytes.length} ${payloadType} ${bodyBytes.length} `;
|
|
137
|
-
return Buffer.concat([Buffer.from(header, "utf8"), bodyBytes]);
|
|
138
|
-
}
|
|
139
|
-
function toDsseEnvelope(receipt) {
|
|
140
|
-
const canonical = canonicalize(receipt);
|
|
141
|
-
return {
|
|
142
|
-
payloadType: DSSE_PAYLOAD_TYPE,
|
|
143
|
-
payload: Buffer.from(canonical, "utf8").toString("base64"),
|
|
144
|
-
signatures: []
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
function envelopePae(env) {
|
|
148
|
-
const raw = Buffer.from(env.payload, "base64").toString("utf8");
|
|
149
|
-
return pae(env.payloadType, raw);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// src/trace/diffScope.ts
|
|
153
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
154
|
-
|
|
155
|
-
// src/findings/surface.ts
|
|
156
|
-
var OPERATOR_KINDS = /* @__PURE__ */ new Set([
|
|
157
|
-
"loop",
|
|
158
|
-
"bottleneck",
|
|
159
|
-
"cost-concentration",
|
|
160
|
-
"cache-opportunity",
|
|
161
|
-
"model-downgrade"
|
|
162
|
-
]);
|
|
163
|
-
function findingSurface(id) {
|
|
164
|
-
if (OPERATOR_KINDS.has(id) || id.startsWith("errcluster-")) {
|
|
165
|
-
return "operator";
|
|
166
|
-
}
|
|
167
|
-
return "merge";
|
|
168
|
-
}
|
|
169
|
-
function destructiveOutsideRepo(title) {
|
|
170
|
-
const clause = title.replace(/^Destructive op:\s*/i, "").replace(/\s*×\d+\s*$/, "");
|
|
171
|
-
const m = clause.match(/^\s*(rm|rmdir)\b(.*)$/i);
|
|
172
|
-
if (!m) {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
const operands = m[2].split(/\s+/).filter((t) => t && !t.startsWith("-"));
|
|
176
|
-
if (operands.length === 0) {
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
const scratch = (t) => {
|
|
180
|
-
const p = t.replace(/^["']|["']$/g, "");
|
|
181
|
-
return /\$/.test(p) || p.startsWith("/tmp") || p.startsWith("/var/folders") || p.startsWith("/private/var/folders") || p.startsWith("~");
|
|
182
|
-
};
|
|
183
|
-
return operands.every(scratch);
|
|
184
|
-
}
|
|
185
|
-
function regenerableReceiptRm(title) {
|
|
186
|
-
const clause = title.replace(/^Destructive op:\s*/i, "").replace(/\s*×\d+\s*$/, "");
|
|
187
|
-
const m = clause.match(/^\s*(rm|rmdir)\b(.*)$/i);
|
|
188
|
-
if (!m) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
const operands = m[2].split(/\s+/).filter((t) => t && !t.startsWith("-"));
|
|
192
|
-
if (operands.length === 0) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
const receiptJson = (t) => /(?:^|\/)\.receipts\/[^/]+\.json$/.test(t.replace(/^["']|["']$/g, ""));
|
|
196
|
-
return operands.every(receiptJson);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// src/trace/diffScope.ts
|
|
200
|
-
function git(args, cwd) {
|
|
201
|
-
const r = spawnSync2("git", args, { encoding: "utf8", cwd });
|
|
202
|
-
return r.status === 0 ? r.stdout : null;
|
|
203
|
-
}
|
|
204
|
-
var RECEIPTS_DIR_RE = /(?:^|\/)\.receipts\//;
|
|
205
|
-
function changedFiles(baseOverride, opts) {
|
|
206
|
-
const root = git(["rev-parse", "--show-toplevel"])?.trim();
|
|
207
|
-
if (!root) {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
let base2 = baseOverride;
|
|
211
|
-
if (!base2) {
|
|
212
|
-
const sym = git(["symbolic-ref", "refs/remotes/origin/HEAD"], root)?.trim();
|
|
213
|
-
if (sym) {
|
|
214
|
-
base2 = sym.replace("refs/remotes/", "");
|
|
215
|
-
} else if (git(["rev-parse", "--verify", "--quiet", "origin/main"], root) !== null) {
|
|
216
|
-
base2 = "origin/main";
|
|
217
|
-
} else {
|
|
218
|
-
base2 = "main";
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
let out = git(["diff", "--name-only", `${base2}...HEAD`], root);
|
|
222
|
-
if (out === null && !baseOverride) {
|
|
223
|
-
out = git(["diff", "--name-only", "main...HEAD"], root);
|
|
224
|
-
if (out !== null) {
|
|
225
|
-
base2 = "main";
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const pending = opts?.includeWorkingTree ? workingTreeFiles(root) : [];
|
|
229
|
-
if (out === null && pending.length === 0) {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
const files = [.../* @__PURE__ */ new Set([...(out ?? "").split("\n").map((s) => s.trim()), ...pending])].filter(Boolean).filter((f) => !RECEIPTS_DIR_RE.test(f)).sort();
|
|
233
|
-
if (files.length === 0) {
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
return { base: base2, files, repoRoot: root };
|
|
237
|
-
}
|
|
238
|
-
function workingTreeFiles(root) {
|
|
239
|
-
const out = git(["status", "--porcelain", "-z", "--untracked-files=all"], root);
|
|
240
|
-
if (!out) {
|
|
241
|
-
return [];
|
|
242
|
-
}
|
|
243
|
-
const toks = out.split("\0");
|
|
244
|
-
const files = [];
|
|
245
|
-
for (let i = 0; i < toks.length; i++) {
|
|
246
|
-
const t = toks[i];
|
|
247
|
-
if (!t || t.length < 4 || t[2] !== " ") {
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
files.push(t.slice(3));
|
|
251
|
-
if (t[0] === "R" || t[0] === "C") {
|
|
252
|
-
i++;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return files;
|
|
256
|
-
}
|
|
257
|
-
function inDiff(filePath, files) {
|
|
258
|
-
const base2 = filePath.split("/").pop();
|
|
259
|
-
for (const d of files) {
|
|
260
|
-
if (d === filePath || d.endsWith(`/${filePath}`) || filePath.endsWith(`/${d}`)) {
|
|
261
|
-
return true;
|
|
262
|
-
}
|
|
263
|
-
if (base2 && d.split("/").pop() === base2) {
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
269
|
-
var PROCESS_PREFIXES = ["pipe-sh", "tool-fabricated", "tool-malformed-args"];
|
|
270
|
-
var isProcessFinding = (id) => PROCESS_PREFIXES.some((p) => id === p || id.startsWith(`${p}-`));
|
|
271
|
-
var isDestructive = (id) => id.startsWith("destructive-");
|
|
272
|
-
var isGitProcess = (id) => id.startsWith("force-push") || id.startsWith("destructive-git");
|
|
273
|
-
function hookBypassIsPushOnly(command) {
|
|
274
|
-
const noVerify = parseGitInvocations(command).filter(isNoVerify);
|
|
275
|
-
return noVerify.length > 0 && noVerify.every((inv) => inv.subcommand === "push");
|
|
276
|
-
}
|
|
277
|
-
function gitTouchesDiff(command, files) {
|
|
278
|
-
for (const inv of parseGitInvocations(command)) {
|
|
279
|
-
if (!destroysGitData(inv) && !rewritesHistory(inv)) {
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
if (touchedPaths(inv).some((p) => inDiff(p, files))) {
|
|
283
|
-
return true;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
function keepUnderDiff(f, files, commandFor, locusFor) {
|
|
289
|
-
if (locusFor?.(f) === "elsewhere") {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
if (isProcessFinding(f.id)) {
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
if (f.id === "hook-bypass" || f.id.startsWith("hook-bypass-")) {
|
|
296
|
-
const cmd = commandFor?.(f);
|
|
297
|
-
return cmd ? !hookBypassIsPushOnly(cmd) : true;
|
|
298
|
-
}
|
|
299
|
-
if (isGitProcess(f.id)) {
|
|
300
|
-
const cmd = commandFor?.(f);
|
|
301
|
-
return cmd ? gitTouchesDiff(cmd, files) : false;
|
|
302
|
-
}
|
|
303
|
-
if (isDestructive(f.id)) {
|
|
304
|
-
if (destructiveOutsideRepo(f.title) || regenerableReceiptRm(f.title)) {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
const cmd = commandFor?.(f) ?? f.title.replace(/^Destructive op:\s*/i, "").replace(/\s*×\d+\s*$/, "");
|
|
308
|
-
if (/(^|[\s;&|])git\s/.test(cmd)) {
|
|
309
|
-
return gitTouchesDiff(cmd, files);
|
|
310
|
-
}
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
return f.filePath ? inDiff(f.filePath, files) : false;
|
|
314
|
-
}
|
|
315
|
-
function diffEffort(derived, files) {
|
|
316
|
-
const editedGens = /* @__PURE__ */ new Set();
|
|
317
|
-
for (const s of derived.spans) {
|
|
318
|
-
if (s.kind !== "tool" || !s.parentSpanId || !isEditTool(s.name)) {
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
const fp = filePathOf(s.input);
|
|
322
|
-
if (fp && inDiff(fp, files)) {
|
|
323
|
-
editedGens.add(s.parentSpanId);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
let cost = 0;
|
|
327
|
-
let tokens = 0;
|
|
328
|
-
for (const s of derived.spans) {
|
|
329
|
-
if (s.kind === "generation" && editedGens.has(s.spanId)) {
|
|
330
|
-
cost += s.cost || estimateCost(s.tokens, s.name);
|
|
331
|
-
tokens += s.tokens?.total ?? 0;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return { cost, tokens, turns: editedGens.size };
|
|
335
|
-
}
|
|
336
|
-
function narrowEffort(sliceDerived, files) {
|
|
337
|
-
if (!sliceDerived) {
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
const eff = diffEffort(sliceDerived, files);
|
|
341
|
-
return eff.turns > 0 ? eff : null;
|
|
342
|
-
}
|
|
343
|
-
function applyDiffScope(derived, findings, files, projectPath) {
|
|
344
|
-
const spanCmd = /* @__PURE__ */ new Map();
|
|
345
|
-
const spanCwd = /* @__PURE__ */ new Map();
|
|
346
|
-
for (const s of derived.spans) {
|
|
347
|
-
if (s.spanId) {
|
|
348
|
-
spanCmd.set(s.spanId, commandOf(s.input));
|
|
349
|
-
if (s.cwd) {
|
|
350
|
-
spanCwd.set(s.spanId, s.cwd);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
const cmdOf = (f) => f.evidenceSpanId ? spanCmd.get(f.evidenceSpanId) : void 0;
|
|
355
|
-
const locusOf = (f) => {
|
|
356
|
-
if (!projectPath || !f.evidenceSpanId) {
|
|
357
|
-
return void 0;
|
|
358
|
-
}
|
|
359
|
-
const base2 = spanCwd.get(f.evidenceSpanId);
|
|
360
|
-
const state = cwdAtFirstGit(spanCmd.get(f.evidenceSpanId) ?? "", base2);
|
|
361
|
-
if (state.kind === "unknown") {
|
|
362
|
-
return "elsewhere";
|
|
363
|
-
}
|
|
364
|
-
const at = state.kind === "known" ? state.path : base2;
|
|
365
|
-
if (!at) {
|
|
366
|
-
return void 0;
|
|
367
|
-
}
|
|
368
|
-
return at === projectPath || at.startsWith(`${projectPath}/`) ? "here" : "elsewhere";
|
|
369
|
-
};
|
|
370
|
-
const keep = (f) => keepUnderDiff(f, files, cmdOf, locusOf);
|
|
371
|
-
const scopedFindings = {
|
|
372
|
-
main: findings.main.filter(keep),
|
|
373
|
-
minor: findings.minor.filter(keep)
|
|
374
|
-
};
|
|
375
|
-
const filesChanged = derived.filesChanged.filter((fc) => inDiff(fc.path, files));
|
|
376
|
-
const destructiveCount = derived.spans.filter((s) => s.destructive).filter((s) => {
|
|
377
|
-
const cmd = commandOf(s.input);
|
|
378
|
-
const clause = destructiveMatch(cmd) ?? cmd;
|
|
379
|
-
if (destructiveOutsideRepo(clause) || regenerableReceiptRm(clause)) {
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
if (/(^|[\s;&|])git\s/.test(cmd)) {
|
|
383
|
-
return gitTouchesDiff(cmd, files);
|
|
384
|
-
}
|
|
385
|
-
return true;
|
|
386
|
-
}).length;
|
|
387
|
-
const eff = diffEffort(derived, files);
|
|
388
|
-
return {
|
|
389
|
-
derived: {
|
|
390
|
-
...derived,
|
|
391
|
-
filesChanged,
|
|
392
|
-
destructiveCount,
|
|
393
|
-
diffCostUsd: eff.cost,
|
|
394
|
-
diffTokens: eff.tokens,
|
|
395
|
-
diffTurns: eff.turns
|
|
396
|
-
},
|
|
397
|
-
findings: scopedFindings
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/trace/slice.ts
|
|
402
|
-
function branchesIn(session) {
|
|
403
|
-
const seen = [];
|
|
404
|
-
for (const m of session.messages) {
|
|
405
|
-
if (m.gitBranch && !seen.includes(m.gitBranch)) {
|
|
406
|
-
seen.push(m.gitBranch);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return seen;
|
|
410
|
-
}
|
|
411
|
-
function effectiveBranches(messages) {
|
|
412
|
-
const firstTagged = messages.find((m) => m.gitBranch)?.gitBranch;
|
|
413
|
-
let current = firstTagged;
|
|
414
|
-
return messages.map((m) => {
|
|
415
|
-
if (m.gitBranch) {
|
|
416
|
-
current = m.gitBranch;
|
|
417
|
-
}
|
|
418
|
-
return current;
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
function sliceByBranch(session, branch) {
|
|
422
|
-
if (!branchesIn(session).includes(branch)) {
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
const eff = effectiveBranches(session.messages);
|
|
426
|
-
const messages = session.messages.filter((_, i) => eff[i] === branch);
|
|
427
|
-
if (messages.length === 0) {
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
|
-
const timestamps = messages.map((m) => m.timestamp).filter((t) => typeof t === "number");
|
|
431
|
-
const startedAt = timestamps.length ? Math.min(...timestamps) : session.startedAt;
|
|
432
|
-
const endedAt = timestamps.length ? Math.max(...timestamps) : session.endedAt;
|
|
433
|
-
return {
|
|
434
|
-
...session,
|
|
435
|
-
id: `${session.id}#${branch}`,
|
|
436
|
-
gitBranch: branch,
|
|
437
|
-
startedAt,
|
|
438
|
-
endedAt,
|
|
439
|
-
messages,
|
|
440
|
-
// Scope the subject digest to this branch's slice (reproducible by re-slicing).
|
|
441
|
-
digestSource: JSON.stringify({ id: session.id, branch, messages })
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// src/sign/rederive.ts
|
|
446
|
-
function sourceFromReceipt(receipt) {
|
|
447
|
-
const prefix = receipt.subject?.[0]?.name?.split("/")[0];
|
|
448
|
-
return agentIds().find((id) => id === prefix);
|
|
449
|
-
}
|
|
450
|
-
async function rederiveFromTranscript(path, opts = {}) {
|
|
451
|
-
const loaded = await loadById(opts.source ?? "claude-code", path);
|
|
452
|
-
if (!loaded) {
|
|
453
|
-
return null;
|
|
454
|
-
}
|
|
455
|
-
const scope = opts.scope;
|
|
456
|
-
const branch = scope?.kind === "branch" ? scope.branch : opts.branch;
|
|
457
|
-
const session = branch ? sliceByBranch(loaded, branch) ?? loaded : loaded;
|
|
458
|
-
let derived = deriveSpans(session);
|
|
459
|
-
let findings = deriveFindings(derived);
|
|
460
|
-
if (scope?.kind === "diff" && scope.files) {
|
|
461
|
-
const scoped = applyDiffScope(derived, findings, scope.files, session.projectPath);
|
|
462
|
-
derived = scoped.derived;
|
|
463
|
-
findings = scoped.findings;
|
|
464
|
-
if (scope.branch) {
|
|
465
|
-
const slice = sliceByBranch(loaded, scope.branch);
|
|
466
|
-
const eff = narrowEffort(slice ? deriveSpans(slice) : null, scope.files);
|
|
467
|
-
if (eff) {
|
|
468
|
-
derived = {
|
|
469
|
-
...derived,
|
|
470
|
-
diffCostUsd: eff.cost,
|
|
471
|
-
diffTokens: eff.tokens,
|
|
472
|
-
diffTurns: eff.turns
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
const receipt = await buildReceipt(session, derived, findings, { scope });
|
|
478
|
-
return opts.redact ? redactReceipt(receipt) : receipt;
|
|
479
|
-
}
|
|
480
|
-
async function compareToTranscript(committed, transcriptPath, opts = {}) {
|
|
481
|
-
const fresh = await rederiveFromTranscript(transcriptPath, {
|
|
482
|
-
redact: true,
|
|
483
|
-
...opts,
|
|
484
|
-
// Re-derive through the adapter the receipt names (its subject prefix), so a
|
|
485
|
-
// codex/cursor receipt isn't re-run through the Claude adapter. An explicit
|
|
486
|
-
// opts.source still wins.
|
|
487
|
-
source: opts.source ?? sourceFromReceipt(committed),
|
|
488
|
-
scope: committed.predicate.scope
|
|
489
|
-
});
|
|
490
|
-
if (!fresh) {
|
|
491
|
-
return { rederived: false, matches: false };
|
|
492
|
-
}
|
|
493
|
-
return { rederived: true, matches: canonicalize(committed) === canonicalize(fresh) };
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// src/report/checks.ts
|
|
497
|
-
var CHECK_CATALOG = [
|
|
498
|
-
{
|
|
499
|
-
key: "destructive",
|
|
500
|
-
icon: "\u{1F6E1}\uFE0F",
|
|
501
|
-
label: "destructive ops",
|
|
502
|
-
prefixes: ["destructive", "file-shrink"]
|
|
503
|
-
},
|
|
504
|
-
{
|
|
505
|
-
key: "git-history",
|
|
506
|
-
icon: "\u{1F33F}",
|
|
507
|
-
label: "git-history safety",
|
|
508
|
-
prefixes: ["force-push", "history-rewrite"]
|
|
509
|
-
},
|
|
510
|
-
{ key: "secrets", icon: "\u{1F511}", label: "secret leaks", prefixes: ["secret"] },
|
|
511
|
-
{ key: "cicd", icon: "\u2699\uFE0F", label: "CI/CD tampering", prefixes: ["ci-cd-touch"] },
|
|
512
|
-
{ key: "lockfile", icon: "\u{1F4E6}", label: "lockfile integrity", prefixes: ["lockfile-edit"] },
|
|
513
|
-
{
|
|
514
|
-
key: "tests",
|
|
515
|
-
icon: "\u{1F9EA}",
|
|
516
|
-
label: "test integrity",
|
|
517
|
-
prefixes: [
|
|
518
|
-
"fake-green",
|
|
519
|
-
"test-focus",
|
|
520
|
-
"test-skipped",
|
|
521
|
-
"test-trivialised",
|
|
522
|
-
"grader-edit",
|
|
523
|
-
"eval-override"
|
|
524
|
-
]
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
key: "weakening",
|
|
528
|
-
icon: "\u{1F513}",
|
|
529
|
-
label: "config/safety weakening",
|
|
530
|
-
prefixes: ["config-weaken", "hook-bypass", "pipe-sh"]
|
|
531
|
-
},
|
|
532
|
-
{
|
|
533
|
-
key: "blind-edits",
|
|
534
|
-
icon: "\u{1F441}\uFE0F",
|
|
535
|
-
label: "blind / unverified edits",
|
|
536
|
-
prefixes: ["blind-edit", "unverified-change", "edit-reversion"]
|
|
537
|
-
},
|
|
538
|
-
{ key: "injection", icon: "\u{1F489}", label: "prompt-injection", prefixes: ["prompt-injection"] },
|
|
539
|
-
{ key: "trojan", icon: "\u{1F575}\uFE0F", label: "hidden unicode", prefixes: ["trojan-source"] },
|
|
540
|
-
{
|
|
541
|
-
key: "duplication",
|
|
542
|
-
icon: "\u{1F4CB}",
|
|
543
|
-
label: "duplicated code",
|
|
544
|
-
prefixes: ["dup-file", "duplicated-code"]
|
|
545
|
-
},
|
|
546
|
-
{ key: "swallowed", icon: "\u{1F92B}", label: "swallowed errors", prefixes: ["error-swallowed"] },
|
|
547
|
-
{ key: "stubbed", icon: "\u{1F6A7}", label: "stubbed implementation", prefixes: ["impl-stubbed"] },
|
|
548
|
-
{ key: "malformed", icon: "\u{1F9F1}", label: "malformed artifacts", prefixes: ["malformed-artifact"] },
|
|
549
|
-
{ key: "truncated", icon: "\u2702\uFE0F", label: "truncated turns", prefixes: ["truncated-turn"] },
|
|
550
|
-
{
|
|
551
|
-
key: "promises",
|
|
552
|
-
icon: "\u{1F91D}",
|
|
553
|
-
label: "unfulfilled claims",
|
|
554
|
-
prefixes: ["claimed-commit-none", "unfulfilled-promise"]
|
|
555
|
-
},
|
|
556
|
-
{
|
|
557
|
-
key: "tool-calls",
|
|
558
|
-
icon: "\u{1F9EC}",
|
|
559
|
-
label: "tool-call integrity",
|
|
560
|
-
prefixes: ["tool-fabricated", "tool-malformed-args"]
|
|
561
|
-
}
|
|
562
|
-
];
|
|
563
|
-
function matches(id, check) {
|
|
564
|
-
return check.prefixes.some((p) => id === p || id.startsWith(`${p}-`));
|
|
565
|
-
}
|
|
566
|
-
function checkForId(id) {
|
|
567
|
-
return CHECK_CATALOG.find((c) => matches(id, c));
|
|
568
|
-
}
|
|
569
|
-
var SEV_RANK = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
570
|
-
function categorize(findings) {
|
|
571
|
-
const flagged = [];
|
|
572
|
-
const cleared = [];
|
|
573
|
-
for (const check of CHECK_CATALOG) {
|
|
574
|
-
const hits = findings.filter((f) => matches(f.id, check));
|
|
575
|
-
if (hits.length > 0) {
|
|
576
|
-
const severity = hits.map((f) => f.severity ?? "high").sort((a, b) => SEV_RANK[a] - SEV_RANK[b])[0];
|
|
577
|
-
flagged.push({ check, count: hits.length, severity });
|
|
578
|
-
} else {
|
|
579
|
-
cleared.push(check);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return { flagged, cleared, total: CHECK_CATALOG.length };
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
export {
|
|
586
|
-
canonicalize,
|
|
587
|
-
CHECK_CATALOG,
|
|
588
|
-
checkForId,
|
|
589
|
-
categorize,
|
|
590
|
-
copyToClipboard,
|
|
591
|
-
renderShareMarkdown,
|
|
592
|
-
DSSE_PAYLOAD_TYPE,
|
|
593
|
-
pae,
|
|
594
|
-
toDsseEnvelope,
|
|
595
|
-
envelopePae,
|
|
596
|
-
findingSurface,
|
|
597
|
-
destructiveOutsideRepo,
|
|
598
|
-
changedFiles,
|
|
599
|
-
inDiff,
|
|
600
|
-
narrowEffort,
|
|
601
|
-
applyDiffScope,
|
|
602
|
-
branchesIn,
|
|
603
|
-
sliceByBranch,
|
|
604
|
-
rederiveFromTranscript,
|
|
605
|
-
compareToTranscript
|
|
606
|
-
};
|
|
607
|
-
//# sourceMappingURL=chunk-5R6W4W4R.js.map
|