calllint 0.9.2 → 1.0.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.
Files changed (2) hide show
  1. package/dist/index.js +1312 -99
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { readFileSync as readFileSync11 } from "node:fs";
4
+ import { readFileSync as readFileSync12 } from "node:fs";
5
5
  import { execFileSync } from "node:child_process";
6
6
 
7
7
  // src/args.ts
@@ -247,17 +247,17 @@ function loadPolicyFile(path) {
247
247
  let text;
248
248
  try {
249
249
  text = readFileSync(path, "utf8");
250
- } catch (err) {
250
+ } catch (err2) {
251
251
  throw new PolicyLoadError(
252
- `Could not read policy file ${path}: ${err instanceof Error ? err.message : String(err)}`
252
+ `Could not read policy file ${path}: ${err2 instanceof Error ? err2.message : String(err2)}`
253
253
  );
254
254
  }
255
255
  let parsed;
256
256
  try {
257
257
  parsed = JSON.parse(text);
258
- } catch (err) {
258
+ } catch (err2) {
259
259
  throw new PolicyLoadError(
260
- `Policy file ${path} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
260
+ `Policy file ${path} is not valid JSON: ${err2 instanceof Error ? err2.message : String(err2)}`
261
261
  );
262
262
  }
263
263
  return validatePolicy(parsed);
@@ -771,7 +771,7 @@ var SECRET_HINTS = [
771
771
  ];
772
772
  function looksSecret(key) {
773
773
  const upper = key.toUpperCase();
774
- return SECRET_HINTS.some((h) => upper.includes(h));
774
+ return SECRET_HINTS.some((h2) => upper.includes(h2));
775
775
  }
776
776
  function extractDockerEnvKeys(args) {
777
777
  const keys = [];
@@ -1095,14 +1095,14 @@ var MUTATION_HINTS = [
1095
1095
  function collectHints(text) {
1096
1096
  if (!text) return [];
1097
1097
  const lower = text.toLowerCase();
1098
- return MUTATION_HINTS.filter((h) => lower.includes(h));
1098
+ return MUTATION_HINTS.filter((h2) => lower.includes(h2));
1099
1099
  }
1100
1100
  function detectExternalMutation(ctx) {
1101
1101
  const { server, binding } = ctx;
1102
1102
  const hints = /* @__PURE__ */ new Set();
1103
1103
  const evidence = [];
1104
- for (const h of collectHints(binding.packageName)) {
1105
- hints.add(h);
1104
+ for (const h2 of collectHints(binding.packageName)) {
1105
+ hints.add(h2);
1106
1106
  evidence.push({
1107
1107
  type: "runtime-binding",
1108
1108
  key: "package",
@@ -1110,8 +1110,8 @@ function detectExternalMutation(ctx) {
1110
1110
  });
1111
1111
  }
1112
1112
  for (const tool of server.providedTools) {
1113
- for (const h of collectHints(tool.name)) {
1114
- hints.add(h);
1113
+ for (const h2 of collectHints(tool.name)) {
1114
+ hints.add(h2);
1115
1115
  evidence.push({ type: "tool-metadata", key: "tool", value: tool.name });
1116
1116
  }
1117
1117
  }
@@ -1189,7 +1189,7 @@ var PAYMENT_ACTION_VERBS = [
1189
1189
  function collectHints2(text) {
1190
1190
  if (!text) return [];
1191
1191
  const lower = text.toLowerCase();
1192
- return FINANCIAL_HINTS.filter((h) => lower.includes(h));
1192
+ return FINANCIAL_HINTS.filter((h2) => lower.includes(h2));
1193
1193
  }
1194
1194
  function collectActionVerbs(text) {
1195
1195
  if (!text) return [];
@@ -1244,8 +1244,8 @@ function detectFinancialAction(ctx) {
1244
1244
  }
1245
1245
  const hints = /* @__PURE__ */ new Set();
1246
1246
  const evidence = [];
1247
- for (const h of collectHints2(binding.packageName)) {
1248
- hints.add(h);
1247
+ for (const h2 of collectHints2(binding.packageName)) {
1248
+ hints.add(h2);
1249
1249
  evidence.push({
1250
1250
  type: "runtime-binding",
1251
1251
  key: "package",
@@ -1253,8 +1253,8 @@ function detectFinancialAction(ctx) {
1253
1253
  });
1254
1254
  }
1255
1255
  for (const tool of server.providedTools) {
1256
- for (const h of collectHints2(tool.name)) {
1257
- hints.add(h);
1256
+ for (const h2 of collectHints2(tool.name)) {
1257
+ hints.add(h2);
1258
1258
  evidence.push({ type: "tool-metadata", key: "tool", value: tool.name });
1259
1259
  }
1260
1260
  }
@@ -1393,7 +1393,7 @@ var SEND_PATTERNS = [
1393
1393
  function packageHint(name) {
1394
1394
  if (!name) return void 0;
1395
1395
  const lower = name.toLowerCase();
1396
- return MESSAGING_PACKAGE_HINTS.find((h) => lower.includes(h));
1396
+ return MESSAGING_PACKAGE_HINTS.find((h2) => lower.includes(h2));
1397
1397
  }
1398
1398
  function textMatchesSend(text) {
1399
1399
  if (!text) return false;
@@ -1456,7 +1456,7 @@ function readOauth(raw) {
1456
1456
  function broadScope(scopes) {
1457
1457
  for (const s of scopes) {
1458
1458
  const lower = s.toLowerCase();
1459
- if (BROAD_SCOPE_HINTS.some((h) => lower === h || lower.includes(h))) return s;
1459
+ if (BROAD_SCOPE_HINTS.some((h2) => lower === h2 || lower.includes(h2))) return s;
1460
1460
  }
1461
1461
  return void 0;
1462
1462
  }
@@ -1862,8 +1862,8 @@ var ConfigParseError = class extends Error {
1862
1862
  function parseJsonText(text, path) {
1863
1863
  try {
1864
1864
  return JSON.parse(text);
1865
- } catch (err) {
1866
- const reason = err instanceof Error ? err.message : String(err);
1865
+ } catch (err2) {
1866
+ const reason = err2 instanceof Error ? err2.message : String(err2);
1867
1867
  throw new ConfigParseError(`Invalid JSON: ${reason}`, path);
1868
1868
  }
1869
1869
  }
@@ -2576,7 +2576,7 @@ function classifySurface(path, content) {
2576
2576
  if (/(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$/.test(n)) return "NOOP";
2577
2577
  const base = basename2(path);
2578
2578
  if (MCP_CONFIG_BASENAMES.has(base)) return "SCAN";
2579
- if (MCP_PATH_HINTS.some((h) => normalize(path).includes(normalize(h)))) return "SCAN";
2579
+ if (MCP_PATH_HINTS.some((h2) => normalize(path).includes(normalize(h2)))) return "SCAN";
2580
2580
  if (base === "config.toml" && content && /\[mcp_servers?\.[^\]]+\]/.test(content)) {
2581
2581
  return "SCAN";
2582
2582
  }
@@ -3892,10 +3892,10 @@ function scanCommand(args, deps) {
3892
3892
  let policy;
3893
3893
  try {
3894
3894
  policy = loadPolicyOrDefault(policyPath);
3895
- } catch (err) {
3895
+ } catch (err2) {
3896
3896
  return {
3897
3897
  stdout: "",
3898
- stderr: err instanceof Error ? err.message : String(err),
3898
+ stderr: err2 instanceof Error ? err2.message : String(err2),
3899
3899
  exitCode: EXIT.ERROR
3900
3900
  };
3901
3901
  }
@@ -3918,15 +3918,15 @@ function scanOneConfig(text, configPath, policy, args, deps, allowReceipt = true
3918
3918
  extraFindings: deps.online?.extraFindings,
3919
3919
  surfaces
3920
3920
  });
3921
- } catch (err) {
3922
- if (err instanceof ConfigParseError) {
3921
+ } catch (err2) {
3922
+ if (err2 instanceof ConfigParseError) {
3923
3923
  return {
3924
3924
  stdout: "",
3925
- stderr: `Parse error in ${configPath}: ${err.message}`,
3925
+ stderr: `Parse error in ${configPath}: ${err2.message}`,
3926
3926
  exitCode: EXIT.ERROR
3927
3927
  };
3928
3928
  }
3929
- throw err;
3929
+ throw err2;
3930
3930
  }
3931
3931
  if (deps.writeCacheFile !== false) {
3932
3932
  try {
@@ -3936,8 +3936,8 @@ function scanOneConfig(text, configPath, policy, args, deps, allowReceipt = true
3936
3936
  }
3937
3937
  const stdout = renderSummary(summary, args);
3938
3938
  if (allowReceipt && flagBool(args.flags, "receipt")) {
3939
- const err = writeReceiptFile(summary, text, configPath, policy, args, deps);
3940
- if (err) return { stdout: "", stderr: err, exitCode: EXIT.ERROR };
3939
+ const err2 = writeReceiptFile(summary, text, configPath, policy, args, deps);
3940
+ if (err2) return { stdout: "", stderr: err2, exitCode: EXIT.ERROR };
3941
3941
  }
3942
3942
  const exitCode = flagBool(args.flags, "ci") ? exitCodeFor(summary, policy) : EXIT.OK;
3943
3943
  return { stdout, exitCode };
@@ -3982,10 +3982,10 @@ function scanChangedCommand(args, deps) {
3982
3982
  let policy;
3983
3983
  try {
3984
3984
  policy = loadPolicyOrDefault(policyPath);
3985
- } catch (err) {
3985
+ } catch (err2) {
3986
3986
  return {
3987
3987
  stdout: "",
3988
- stderr: err instanceof Error ? err.message : String(err),
3988
+ stderr: err2 instanceof Error ? err2.message : String(err2),
3989
3989
  exitCode: EXIT.ERROR
3990
3990
  };
3991
3991
  }
@@ -4114,7 +4114,7 @@ function genRuleCommand(args, deps) {
4114
4114
  const host = flagStr(args.flags, "host");
4115
4115
  if (!host) {
4116
4116
  const list = RULE_HOSTS.map(
4117
- (h) => ` ${h.padEnd(10)} \u2192 ${RULE_TARGETS[h].path} (${RULE_TARGETS[h].label})`
4117
+ (h2) => ` ${h2.padEnd(10)} \u2192 ${RULE_TARGETS[h2].path} (${RULE_TARGETS[h2].label})`
4118
4118
  ).join("\n");
4119
4119
  return {
4120
4120
  stdout: `Usage: calllint gen-rule --host <host> [--write] [--out <path>]
@@ -4167,10 +4167,10 @@ function diagnosticsCommand(args, deps) {
4167
4167
  let policy;
4168
4168
  try {
4169
4169
  policy = loadPolicyOrDefault(flagStr(args.flags, "policy"));
4170
- } catch (err) {
4170
+ } catch (err2) {
4171
4171
  return {
4172
4172
  stdout: "",
4173
- stderr: err instanceof Error ? err.message : String(err),
4173
+ stderr: err2 instanceof Error ? err2.message : String(err2),
4174
4174
  exitCode: EXIT.ERROR
4175
4175
  };
4176
4176
  }
@@ -4187,15 +4187,15 @@ function diagnosticsCommand(args, deps) {
4187
4187
  generatedAt: deps.generatedAt,
4188
4188
  extraFindings: deps.online?.extraFindings
4189
4189
  });
4190
- } catch (err) {
4191
- if (err instanceof ConfigParseError) {
4190
+ } catch (err2) {
4191
+ if (err2 instanceof ConfigParseError) {
4192
4192
  return {
4193
4193
  stdout: "",
4194
- stderr: `Parse error in ${configPath}: ${err.message}`,
4194
+ stderr: `Parse error in ${configPath}: ${err2.message}`,
4195
4195
  exitCode: EXIT.ERROR
4196
4196
  };
4197
4197
  }
4198
- throw err;
4198
+ throw err2;
4199
4199
  }
4200
4200
  const stdout = renderDiagnostics(summary);
4201
4201
  const exitCode = flagBool(args.flags, "ci") ? exitCodeFor(summary, policy) : EXIT.OK;
@@ -4255,10 +4255,10 @@ function policyCommand(args, deps) {
4255
4255
  try {
4256
4256
  const policy = loadPolicyOrDefault(flagStr(args.flags, "policy"));
4257
4257
  return { stdout: JSON.stringify(policy, null, 2), exitCode: EXIT.OK };
4258
- } catch (err) {
4258
+ } catch (err2) {
4259
4259
  return {
4260
4260
  stdout: "",
4261
- stderr: err instanceof Error ? err.message : String(err),
4261
+ stderr: err2 instanceof Error ? err2.message : String(err2),
4262
4262
  exitCode: EXIT.ERROR
4263
4263
  };
4264
4264
  }
@@ -4275,8 +4275,8 @@ import { join as join10 } from "node:path";
4275
4275
  function loadPolicy(args) {
4276
4276
  try {
4277
4277
  return loadPolicyOrDefault(flagStr(args.flags, "policy"));
4278
- } catch (err) {
4279
- return { error: err instanceof Error ? err.message : String(err) };
4278
+ } catch (err2) {
4279
+ return { error: err2 instanceof Error ? err2.message : String(err2) };
4280
4280
  }
4281
4281
  }
4282
4282
  function baselinePathFor(args, cwd) {
@@ -4294,19 +4294,19 @@ function baselineCommand(args, deps) {
4294
4294
  generatedAt: deps.generatedAt,
4295
4295
  extraFindings: deps.online?.extraFindings
4296
4296
  });
4297
- } catch (err) {
4298
- if (err instanceof ConfigParseError) {
4299
- return { stdout: "", stderr: `Parse error in ${input.configPath}: ${err.message}`, exitCode: EXIT.ERROR };
4297
+ } catch (err2) {
4298
+ if (err2 instanceof ConfigParseError) {
4299
+ return { stdout: "", stderr: `Parse error in ${input.configPath}: ${err2.message}`, exitCode: EXIT.ERROR };
4300
4300
  }
4301
- throw err;
4301
+ throw err2;
4302
4302
  }
4303
4303
  const baseline = buildBaseline(summary, deps.generatedAt);
4304
4304
  const path = baselinePathFor(args, deps.cwd);
4305
4305
  if (deps.writeBaselineFile !== false) {
4306
4306
  try {
4307
4307
  writeBaseline(baseline, path);
4308
- } catch (err) {
4309
- return { stdout: "", stderr: `Could not write baseline: ${String(err)}`, exitCode: EXIT.ERROR };
4308
+ } catch (err2) {
4309
+ return { stdout: "", stderr: `Could not write baseline: ${String(err2)}`, exitCode: EXIT.ERROR };
4310
4310
  }
4311
4311
  }
4312
4312
  if (flagBool(args.flags, "json")) {
@@ -4342,11 +4342,11 @@ function verifyCommand(args, deps) {
4342
4342
  generatedAt: deps.generatedAt,
4343
4343
  extraFindings: deps.online?.extraFindings
4344
4344
  });
4345
- } catch (err) {
4346
- if (err instanceof ConfigParseError) {
4347
- return { stdout: "", stderr: `Parse error in ${input.configPath}: ${err.message}`, exitCode: EXIT.ERROR };
4345
+ } catch (err2) {
4346
+ if (err2 instanceof ConfigParseError) {
4347
+ return { stdout: "", stderr: `Parse error in ${input.configPath}: ${err2.message}`, exitCode: EXIT.ERROR };
4348
4348
  }
4349
- throw err;
4349
+ throw err2;
4350
4350
  }
4351
4351
  const drift = computeDrift(baseline, summary, deps.generatedAt);
4352
4352
  const stdout = flagBool(args.flags, "json") ? renderDriftJson(drift) : renderDrift(drift);
@@ -4391,8 +4391,8 @@ function approveCommand(args, deps) {
4391
4391
  if (deps.writeFile !== false) {
4392
4392
  try {
4393
4393
  writeApproved(state, path);
4394
- } catch (err) {
4395
- return { stdout: "", stderr: `Could not write approved state: ${String(err)}`, exitCode: EXIT.ERROR };
4394
+ } catch (err2) {
4395
+ return { stdout: "", stderr: `Could not write approved state: ${String(err2)}`, exitCode: EXIT.ERROR };
4396
4396
  }
4397
4397
  }
4398
4398
  if (flagBool(args.flags, "json")) {
@@ -4406,22 +4406,603 @@ function approveCommand(args, deps) {
4406
4406
  }
4407
4407
 
4408
4408
  // src/commands/receipt.ts
4409
- import { readFileSync as readFileSync8 } from "node:fs";
4409
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
4410
4410
  import { resolve as resolve4 } from "node:path";
4411
- function receiptCommand(args, deps) {
4412
- const sub = args.positionals[0];
4413
- if (sub !== "verify") {
4411
+
4412
+ // ../../node_modules/.pnpm/@noble+ed25519@2.3.0/node_modules/@noble/ed25519/index.js
4413
+ var ed25519_CURVE = {
4414
+ p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
4415
+ n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
4416
+ h: 8n,
4417
+ a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
4418
+ d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
4419
+ Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
4420
+ Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n
4421
+ };
4422
+ var { p: P, n: N, Gx, Gy, a: _a, d: _d } = ed25519_CURVE;
4423
+ var h = 8n;
4424
+ var L = 32;
4425
+ var L2 = 64;
4426
+ var err = (m = "") => {
4427
+ throw new Error(m);
4428
+ };
4429
+ var isBig = (n) => typeof n === "bigint";
4430
+ var isStr = (s) => typeof s === "string";
4431
+ var isBytes = (a) => a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
4432
+ var abytes = (a, l) => !isBytes(a) || typeof l === "number" && l > 0 && a.length !== l ? err("Uint8Array expected") : a;
4433
+ var u8n = (len) => new Uint8Array(len);
4434
+ var u8fr = (buf) => Uint8Array.from(buf);
4435
+ var padh = (n, pad) => n.toString(16).padStart(pad, "0");
4436
+ var bytesToHex = (b) => Array.from(abytes(b)).map((e) => padh(e, 2)).join("");
4437
+ var C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
4438
+ var _ch = (ch) => {
4439
+ if (ch >= C._0 && ch <= C._9)
4440
+ return ch - C._0;
4441
+ if (ch >= C.A && ch <= C.F)
4442
+ return ch - (C.A - 10);
4443
+ if (ch >= C.a && ch <= C.f)
4444
+ return ch - (C.a - 10);
4445
+ return;
4446
+ };
4447
+ var hexToBytes = (hex) => {
4448
+ const e = "hex invalid";
4449
+ if (!isStr(hex))
4450
+ return err(e);
4451
+ const hl = hex.length;
4452
+ const al = hl / 2;
4453
+ if (hl % 2)
4454
+ return err(e);
4455
+ const array = u8n(al);
4456
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
4457
+ const n1 = _ch(hex.charCodeAt(hi));
4458
+ const n2 = _ch(hex.charCodeAt(hi + 1));
4459
+ if (n1 === void 0 || n2 === void 0)
4460
+ return err(e);
4461
+ array[ai] = n1 * 16 + n2;
4462
+ }
4463
+ return array;
4464
+ };
4465
+ var toU8 = (a, len) => abytes(isStr(a) ? hexToBytes(a) : u8fr(abytes(a)), len);
4466
+ var cr = () => globalThis?.crypto;
4467
+ var subtle = () => cr()?.subtle ?? err("crypto.subtle must be defined");
4468
+ var concatBytes = (...arrs) => {
4469
+ const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0));
4470
+ let pad = 0;
4471
+ arrs.forEach((a) => {
4472
+ r.set(a, pad);
4473
+ pad += a.length;
4474
+ });
4475
+ return r;
4476
+ };
4477
+ var randomBytes2 = (len = L) => {
4478
+ const c = cr();
4479
+ return c.getRandomValues(u8n(len));
4480
+ };
4481
+ var big = BigInt;
4482
+ var arange = (n, min, max, msg = "bad number: out of range") => isBig(n) && min <= n && n < max ? n : err(msg);
4483
+ var M = (a, b = P) => {
4484
+ const r = a % b;
4485
+ return r >= 0n ? r : b + r;
4486
+ };
4487
+ var modN = (a) => M(a, N);
4488
+ var invert = (num, md) => {
4489
+ if (num === 0n || md <= 0n)
4490
+ err("no inverse n=" + num + " mod=" + md);
4491
+ let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
4492
+ while (a !== 0n) {
4493
+ const q = b / a, r = b % a;
4494
+ const m = x - u * q, n = y - v * q;
4495
+ b = a, a = r, x = u, y = v, u = m, v = n;
4496
+ }
4497
+ return b === 1n ? M(x, md) : err("no inverse");
4498
+ };
4499
+ var callHash = (name) => {
4500
+ const fn = etc[name];
4501
+ if (typeof fn !== "function")
4502
+ err("hashes." + name + " not set");
4503
+ return fn;
4504
+ };
4505
+ var apoint = (p) => p instanceof Point ? p : err("Point expected");
4506
+ var B256 = 2n ** 256n;
4507
+ var Point = class _Point {
4508
+ static BASE;
4509
+ static ZERO;
4510
+ ex;
4511
+ ey;
4512
+ ez;
4513
+ et;
4514
+ constructor(ex, ey, ez, et) {
4515
+ const max = B256;
4516
+ this.ex = arange(ex, 0n, max);
4517
+ this.ey = arange(ey, 0n, max);
4518
+ this.ez = arange(ez, 1n, max);
4519
+ this.et = arange(et, 0n, max);
4520
+ Object.freeze(this);
4521
+ }
4522
+ static fromAffine(p) {
4523
+ return new _Point(p.x, p.y, 1n, M(p.x * p.y));
4524
+ }
4525
+ /** RFC8032 5.1.3: Uint8Array to Point. */
4526
+ static fromBytes(hex, zip215 = false) {
4527
+ const d = _d;
4528
+ const normed = u8fr(abytes(hex, L));
4529
+ const lastByte = hex[31];
4530
+ normed[31] = lastByte & ~128;
4531
+ const y = bytesToNumLE(normed);
4532
+ const max = zip215 ? B256 : P;
4533
+ arange(y, 0n, max);
4534
+ const y2 = M(y * y);
4535
+ const u = M(y2 - 1n);
4536
+ const v = M(d * y2 + 1n);
4537
+ let { isValid, value: x } = uvRatio(u, v);
4538
+ if (!isValid)
4539
+ err("bad point: y not sqrt");
4540
+ const isXOdd = (x & 1n) === 1n;
4541
+ const isLastByteOdd = (lastByte & 128) !== 0;
4542
+ if (!zip215 && x === 0n && isLastByteOdd)
4543
+ err("bad point: x==0, isLastByteOdd");
4544
+ if (isLastByteOdd !== isXOdd)
4545
+ x = M(-x);
4546
+ return new _Point(x, y, 1n, M(x * y));
4547
+ }
4548
+ /** Checks if the point is valid and on-curve. */
4549
+ assertValidity() {
4550
+ const a = _a;
4551
+ const d = _d;
4552
+ const p = this;
4553
+ if (p.is0())
4554
+ throw new Error("bad point: ZERO");
4555
+ const { ex: X, ey: Y, ez: Z, et: T } = p;
4556
+ const X2 = M(X * X);
4557
+ const Y2 = M(Y * Y);
4558
+ const Z2 = M(Z * Z);
4559
+ const Z4 = M(Z2 * Z2);
4560
+ const aX2 = M(X2 * a);
4561
+ const left = M(Z2 * M(aX2 + Y2));
4562
+ const right = M(Z4 + M(d * M(X2 * Y2)));
4563
+ if (left !== right)
4564
+ throw new Error("bad point: equation left != right (1)");
4565
+ const XY = M(X * Y);
4566
+ const ZT = M(Z * T);
4567
+ if (XY !== ZT)
4568
+ throw new Error("bad point: equation left != right (2)");
4569
+ return this;
4570
+ }
4571
+ /** Equality check: compare points P&Q. */
4572
+ equals(other) {
4573
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
4574
+ const { ex: X2, ey: Y2, ez: Z2 } = apoint(other);
4575
+ const X1Z2 = M(X1 * Z2);
4576
+ const X2Z1 = M(X2 * Z1);
4577
+ const Y1Z2 = M(Y1 * Z2);
4578
+ const Y2Z1 = M(Y2 * Z1);
4579
+ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
4580
+ }
4581
+ is0() {
4582
+ return this.equals(I);
4583
+ }
4584
+ /** Flip point over y coordinate. */
4585
+ negate() {
4586
+ return new _Point(M(-this.ex), this.ey, this.ez, M(-this.et));
4587
+ }
4588
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
4589
+ double() {
4590
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
4591
+ const a = _a;
4592
+ const A = M(X1 * X1);
4593
+ const B = M(Y1 * Y1);
4594
+ const C2 = M(2n * M(Z1 * Z1));
4595
+ const D = M(a * A);
4596
+ const x1y1 = X1 + Y1;
4597
+ const E = M(M(x1y1 * x1y1) - A - B);
4598
+ const G2 = D + B;
4599
+ const F = G2 - C2;
4600
+ const H = D - B;
4601
+ const X3 = M(E * F);
4602
+ const Y3 = M(G2 * H);
4603
+ const T3 = M(E * H);
4604
+ const Z3 = M(F * G2);
4605
+ return new _Point(X3, Y3, Z3, T3);
4606
+ }
4607
+ /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
4608
+ add(other) {
4609
+ const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
4610
+ const { ex: X2, ey: Y2, ez: Z2, et: T2 } = apoint(other);
4611
+ const a = _a;
4612
+ const d = _d;
4613
+ const A = M(X1 * X2);
4614
+ const B = M(Y1 * Y2);
4615
+ const C2 = M(T1 * d * T2);
4616
+ const D = M(Z1 * Z2);
4617
+ const E = M((X1 + Y1) * (X2 + Y2) - A - B);
4618
+ const F = M(D - C2);
4619
+ const G2 = M(D + C2);
4620
+ const H = M(B - a * A);
4621
+ const X3 = M(E * F);
4622
+ const Y3 = M(G2 * H);
4623
+ const T3 = M(E * H);
4624
+ const Z3 = M(F * G2);
4625
+ return new _Point(X3, Y3, Z3, T3);
4626
+ }
4627
+ /**
4628
+ * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
4629
+ * Uses {@link wNAF} for base point.
4630
+ * Uses fake point to mitigate side-channel leakage.
4631
+ * @param n scalar by which point is multiplied
4632
+ * @param safe safe mode guards against timing attacks; unsafe mode is faster
4633
+ */
4634
+ multiply(n, safe = true) {
4635
+ if (!safe && (n === 0n || this.is0()))
4636
+ return I;
4637
+ arange(n, 1n, N);
4638
+ if (n === 1n)
4639
+ return this;
4640
+ if (this.equals(G))
4641
+ return wNAF(n).p;
4642
+ let p = I;
4643
+ let f = G;
4644
+ for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
4645
+ if (n & 1n)
4646
+ p = p.add(d);
4647
+ else if (safe)
4648
+ f = f.add(d);
4649
+ }
4650
+ return p;
4651
+ }
4652
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
4653
+ toAffine() {
4654
+ const { ex: x, ey: y, ez: z } = this;
4655
+ if (this.equals(I))
4656
+ return { x: 0n, y: 1n };
4657
+ const iz = invert(z, P);
4658
+ if (M(z * iz) !== 1n)
4659
+ err("invalid inverse");
4660
+ return { x: M(x * iz), y: M(y * iz) };
4661
+ }
4662
+ toBytes() {
4663
+ const { x, y } = this.assertValidity().toAffine();
4664
+ const b = numTo32bLE(y);
4665
+ b[31] |= x & 1n ? 128 : 0;
4666
+ return b;
4667
+ }
4668
+ toHex() {
4669
+ return bytesToHex(this.toBytes());
4670
+ }
4671
+ // encode to hex string
4672
+ clearCofactor() {
4673
+ return this.multiply(big(h), false);
4674
+ }
4675
+ isSmallOrder() {
4676
+ return this.clearCofactor().is0();
4677
+ }
4678
+ isTorsionFree() {
4679
+ let p = this.multiply(N / 2n, false).double();
4680
+ if (N % 2n)
4681
+ p = p.add(this);
4682
+ return p.is0();
4683
+ }
4684
+ static fromHex(hex, zip215) {
4685
+ return _Point.fromBytes(toU8(hex), zip215);
4686
+ }
4687
+ get x() {
4688
+ return this.toAffine().x;
4689
+ }
4690
+ get y() {
4691
+ return this.toAffine().y;
4692
+ }
4693
+ toRawBytes() {
4694
+ return this.toBytes();
4695
+ }
4696
+ };
4697
+ var G = new Point(Gx, Gy, 1n, M(Gx * Gy));
4698
+ var I = new Point(0n, 1n, 1n, 0n);
4699
+ Point.BASE = G;
4700
+ Point.ZERO = I;
4701
+ var numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), L2)).reverse();
4702
+ var bytesToNumLE = (b) => big("0x" + bytesToHex(u8fr(abytes(b)).reverse()));
4703
+ var pow2 = (x, power) => {
4704
+ let r = x;
4705
+ while (power-- > 0n) {
4706
+ r *= r;
4707
+ r %= P;
4708
+ }
4709
+ return r;
4710
+ };
4711
+ var pow_2_252_3 = (x) => {
4712
+ const x2 = x * x % P;
4713
+ const b2 = x2 * x % P;
4714
+ const b4 = pow2(b2, 2n) * b2 % P;
4715
+ const b5 = pow2(b4, 1n) * x % P;
4716
+ const b10 = pow2(b5, 5n) * b5 % P;
4717
+ const b20 = pow2(b10, 10n) * b10 % P;
4718
+ const b40 = pow2(b20, 20n) * b20 % P;
4719
+ const b80 = pow2(b40, 40n) * b40 % P;
4720
+ const b160 = pow2(b80, 80n) * b80 % P;
4721
+ const b240 = pow2(b160, 80n) * b80 % P;
4722
+ const b250 = pow2(b240, 10n) * b10 % P;
4723
+ const pow_p_5_8 = pow2(b250, 2n) * x % P;
4724
+ return { pow_p_5_8, b2 };
4725
+ };
4726
+ var RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n;
4727
+ var uvRatio = (u, v) => {
4728
+ const v3 = M(v * v * v);
4729
+ const v7 = M(v3 * v3 * v);
4730
+ const pow = pow_2_252_3(u * v7).pow_p_5_8;
4731
+ let x = M(u * v3 * pow);
4732
+ const vx2 = M(v * x * x);
4733
+ const root1 = x;
4734
+ const root2 = M(x * RM1);
4735
+ const useRoot1 = vx2 === u;
4736
+ const useRoot2 = vx2 === M(-u);
4737
+ const noRoot = vx2 === M(-u * RM1);
4738
+ if (useRoot1)
4739
+ x = root1;
4740
+ if (useRoot2 || noRoot)
4741
+ x = root2;
4742
+ if ((M(x) & 1n) === 1n)
4743
+ x = M(-x);
4744
+ return { isValid: useRoot1 || useRoot2, value: x };
4745
+ };
4746
+ var modL_LE = (hash) => modN(bytesToNumLE(hash));
4747
+ var sha512a = (...m) => etc.sha512Async(...m);
4748
+ var sha512s = (...m) => callHash("sha512Sync")(...m);
4749
+ var hash2extK = (hashed) => {
4750
+ const head = hashed.slice(0, L);
4751
+ head[0] &= 248;
4752
+ head[31] &= 127;
4753
+ head[31] |= 64;
4754
+ const prefix = hashed.slice(L, L2);
4755
+ const scalar = modL_LE(head);
4756
+ const point = G.multiply(scalar);
4757
+ const pointBytes = point.toBytes();
4758
+ return { head, prefix, scalar, point, pointBytes };
4759
+ };
4760
+ var getExtendedPublicKeyAsync = (priv) => sha512a(toU8(priv, L)).then(hash2extK);
4761
+ var getExtendedPublicKey = (priv) => hash2extK(sha512s(toU8(priv, L)));
4762
+ var getPublicKeyAsync = (priv) => getExtendedPublicKeyAsync(priv).then((p) => p.pointBytes);
4763
+ var hashFinishA = (res) => sha512a(res.hashable).then(res.finish);
4764
+ var _sign = (e, rBytes, msg) => {
4765
+ const { pointBytes: P2, scalar: s } = e;
4766
+ const r = modL_LE(rBytes);
4767
+ const R = G.multiply(r).toBytes();
4768
+ const hashable = concatBytes(R, P2, msg);
4769
+ const finish = (hashed) => {
4770
+ const S = modN(r + modL_LE(hashed) * s);
4771
+ return abytes(concatBytes(R, numTo32bLE(S)), L2);
4772
+ };
4773
+ return { hashable, finish };
4774
+ };
4775
+ var signAsync = async (msg, privKey) => {
4776
+ const m = toU8(msg);
4777
+ const e = await getExtendedPublicKeyAsync(privKey);
4778
+ const rBytes = await sha512a(e.prefix, m);
4779
+ return hashFinishA(_sign(e, rBytes, m));
4780
+ };
4781
+ var veriOpts = { zip215: true };
4782
+ var _verify = (sig, msg, pub, opts = veriOpts) => {
4783
+ sig = toU8(sig, L2);
4784
+ msg = toU8(msg);
4785
+ pub = toU8(pub, L);
4786
+ const { zip215 } = opts;
4787
+ let A;
4788
+ let R;
4789
+ let s;
4790
+ let SB;
4791
+ let hashable = Uint8Array.of();
4792
+ try {
4793
+ A = Point.fromHex(pub, zip215);
4794
+ R = Point.fromHex(sig.slice(0, L), zip215);
4795
+ s = bytesToNumLE(sig.slice(L, L2));
4796
+ SB = G.multiply(s, false);
4797
+ hashable = concatBytes(R.toBytes(), A.toBytes(), msg);
4798
+ } catch (error) {
4799
+ }
4800
+ const finish = (hashed) => {
4801
+ if (SB == null)
4802
+ return false;
4803
+ if (!zip215 && A.isSmallOrder())
4804
+ return false;
4805
+ const k = modL_LE(hashed);
4806
+ const RkA = R.add(A.multiply(k, false));
4807
+ return RkA.add(SB.negate()).clearCofactor().is0();
4808
+ };
4809
+ return { hashable, finish };
4810
+ };
4811
+ var verifyAsync = async (s, m, p, opts = veriOpts) => hashFinishA(_verify(s, m, p, opts));
4812
+ var etc = {
4813
+ sha512Async: async (...messages) => {
4814
+ const s = subtle();
4815
+ const m = concatBytes(...messages);
4816
+ return u8n(await s.digest("SHA-512", m.buffer));
4817
+ },
4818
+ sha512Sync: void 0,
4819
+ bytesToHex,
4820
+ hexToBytes,
4821
+ concatBytes,
4822
+ mod: M,
4823
+ invert,
4824
+ randomBytes: randomBytes2
4825
+ };
4826
+ var utils = {
4827
+ getExtendedPublicKeyAsync,
4828
+ getExtendedPublicKey,
4829
+ randomPrivateKey: () => randomBytes2(L),
4830
+ precompute: (w = 8, p = G) => {
4831
+ p.multiply(3n);
4832
+ w;
4833
+ return p;
4834
+ }
4835
+ // no-op
4836
+ };
4837
+ var W = 8;
4838
+ var scalarBits = 256;
4839
+ var pwindows = Math.ceil(scalarBits / W) + 1;
4840
+ var pwindowSize = 2 ** (W - 1);
4841
+ var precompute = () => {
4842
+ const points = [];
4843
+ let p = G;
4844
+ let b = p;
4845
+ for (let w = 0; w < pwindows; w++) {
4846
+ b = p;
4847
+ points.push(b);
4848
+ for (let i = 1; i < pwindowSize; i++) {
4849
+ b = b.add(p);
4850
+ points.push(b);
4851
+ }
4852
+ p = b.double();
4853
+ }
4854
+ return points;
4855
+ };
4856
+ var Gpows = void 0;
4857
+ var ctneg = (cnd, p) => {
4858
+ const n = p.negate();
4859
+ return cnd ? n : p;
4860
+ };
4861
+ var wNAF = (n) => {
4862
+ const comp = Gpows || (Gpows = precompute());
4863
+ let p = I;
4864
+ let f = G;
4865
+ const pow_2_w = 2 ** W;
4866
+ const maxNum = pow_2_w;
4867
+ const mask = big(pow_2_w - 1);
4868
+ const shiftBy = big(W);
4869
+ for (let w = 0; w < pwindows; w++) {
4870
+ let wbits = Number(n & mask);
4871
+ n >>= shiftBy;
4872
+ if (wbits > pwindowSize) {
4873
+ wbits -= maxNum;
4874
+ n += 1n;
4875
+ }
4876
+ const off = w * pwindowSize;
4877
+ const offF = off;
4878
+ const offP = off + Math.abs(wbits) - 1;
4879
+ const isEven = w % 2 !== 0;
4880
+ const isNeg = wbits < 0;
4881
+ if (wbits === 0) {
4882
+ f = f.add(ctneg(isEven, comp[offF]));
4883
+ } else {
4884
+ p = p.add(ctneg(isNeg, comp[offP]));
4885
+ }
4886
+ }
4887
+ return { p, f };
4888
+ };
4889
+
4890
+ // ../../packages/signature/src/base64url.ts
4891
+ function base64urlEncode(bytes) {
4892
+ const base64 = Buffer.from(bytes).toString("base64");
4893
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
4894
+ }
4895
+ function base64urlDecode(str) {
4896
+ const padded = str + "===".slice((str.length + 3) % 4);
4897
+ const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
4898
+ return new Uint8Array(Buffer.from(base64, "base64"));
4899
+ }
4900
+
4901
+ // ../../packages/signature/src/ed25519.ts
4902
+ async function generateKeypair(keyId) {
4903
+ const privateKey = utils.randomPrivateKey();
4904
+ const publicKey = await getPublicKeyAsync(privateKey);
4905
+ return {
4906
+ privateKey,
4907
+ publicKey,
4908
+ keyId
4909
+ };
4910
+ }
4911
+ async function signReceipt(unsignedReceipt, keypair) {
4912
+ const canonical = stableStringify(unsignedReceipt);
4913
+ const hash = sha256(canonical);
4914
+ const hashHex = hash.slice(7);
4915
+ const hashBytes = Buffer.from(hashHex, "hex");
4916
+ const signatureBytes = await signAsync(hashBytes, keypair.privateKey);
4917
+ const signatureBase64url = base64urlEncode(signatureBytes);
4918
+ return {
4919
+ algorithm: "ed25519",
4920
+ key_id: keypair.keyId,
4921
+ value: signatureBase64url,
4922
+ signed_at: (/* @__PURE__ */ new Date()).toISOString()
4923
+ };
4924
+ }
4925
+ async function verifyReceipt2(signedReceipt, publicKey) {
4926
+ try {
4927
+ const sig = signedReceipt.signature;
4928
+ if (!sig) {
4929
+ return { valid: false, error: "No signature field in receipt" };
4930
+ }
4931
+ if (sig.algorithm !== "ed25519") {
4932
+ return { valid: false, error: `Unsupported algorithm: ${sig.algorithm}` };
4933
+ }
4934
+ const publicKeyBytes = typeof publicKey === "string" ? base64urlDecode(publicKey) : publicKey;
4935
+ if (publicKeyBytes.length !== 32) {
4936
+ return { valid: false, error: "Invalid public key length (expected 32 bytes)" };
4937
+ }
4938
+ const signatureBytes = base64urlDecode(sig.value);
4939
+ if (signatureBytes.length !== 64) {
4940
+ return { valid: false, error: "Invalid signature length (expected 64 bytes)" };
4941
+ }
4942
+ const { signature, ...unsignedReceipt } = signedReceipt;
4943
+ const canonical = stableStringify(unsignedReceipt);
4944
+ const hash = sha256(canonical);
4945
+ const hashHex = hash.slice(7);
4946
+ const hashBytes = Buffer.from(hashHex, "hex");
4947
+ const valid = await verifyAsync(signatureBytes, hashBytes, publicKeyBytes);
4948
+ return { valid, key_id: sig.key_id };
4949
+ } catch (error) {
4414
4950
  return {
4415
- stdout: "",
4416
- stderr: "Usage: calllint receipt verify <receipt.json>",
4417
- exitCode: EXIT.USAGE
4951
+ valid: false,
4952
+ error: error instanceof Error ? error.message : "Unknown verification error"
4418
4953
  };
4419
4954
  }
4955
+ }
4956
+ function exportKeypair(keypair) {
4957
+ return {
4958
+ key_id: keypair.keyId,
4959
+ algorithm: "ed25519",
4960
+ private_key: base64urlEncode(keypair.privateKey),
4961
+ public_key: base64urlEncode(keypair.publicKey)
4962
+ };
4963
+ }
4964
+ function importKeypair(json) {
4965
+ if (json.algorithm !== "ed25519") {
4966
+ throw new Error(`Unsupported algorithm: ${json.algorithm}`);
4967
+ }
4968
+ return {
4969
+ keyId: json.key_id,
4970
+ privateKey: base64urlDecode(json.private_key),
4971
+ publicKey: base64urlDecode(json.public_key)
4972
+ };
4973
+ }
4974
+
4975
+ // src/commands/receipt.ts
4976
+ function receiptCommand(args, deps) {
4977
+ const sub = args.positionals[0];
4978
+ switch (sub) {
4979
+ case "verify":
4980
+ return receiptVerify(args, deps);
4981
+ case "sign":
4982
+ return receiptSign(args, deps);
4983
+ case "keygen":
4984
+ return receiptKeygen(args, deps);
4985
+ default:
4986
+ return {
4987
+ stdout: "",
4988
+ stderr: [
4989
+ "Usage: calllint receipt <subcommand>",
4990
+ "",
4991
+ "Subcommands:",
4992
+ " verify <receipt.json> Validate receipt structure and signature",
4993
+ " sign <receipt.json> --key <file> Sign receipt locally (development only)",
4994
+ " keygen --out <file> Generate test keypair (development only)"
4995
+ ].join("\n"),
4996
+ exitCode: EXIT.USAGE
4997
+ };
4998
+ }
4999
+ }
5000
+ function receiptVerify(args, deps) {
4420
5001
  const file = args.positionals[1];
4421
5002
  if (!file) {
4422
5003
  return {
4423
5004
  stdout: "",
4424
- stderr: "Usage: calllint receipt verify <receipt.json>",
5005
+ stderr: "Usage: calllint receipt verify <receipt.json> [--public-key <keyfile>]",
4425
5006
  exitCode: EXIT.USAGE
4426
5007
  };
4427
5008
  }
@@ -4449,31 +5030,361 @@ function receiptCommand(args, deps) {
4449
5030
  return { stdout: "", stderr: `CallLint receipt: invalid
4450
5031
  - ${msg}`, exitCode: 1 };
4451
5032
  }
4452
- const result = verifyReceipt(parsed);
5033
+ const structResult = verifyReceipt(parsed);
5034
+ if (!structResult.valid) {
5035
+ if (flagBool(args.flags, "json")) {
5036
+ return {
5037
+ stdout: JSON.stringify(structResult, null, 2),
5038
+ exitCode: 1
5039
+ };
5040
+ }
5041
+ const lines = ["CallLint receipt: invalid", ...structResult.errors.map((e) => ` - ${e}`)];
5042
+ return { stdout: "", stderr: lines.join("\n"), exitCode: 1 };
5043
+ }
5044
+ const receipt = parsed;
5045
+ if (receipt.signature) {
5046
+ let cryptoResult = null;
5047
+ let errorMsg = null;
5048
+ try {
5049
+ const promise = verifySignature(receipt, args);
5050
+ let done = false;
5051
+ promise.then(
5052
+ (r) => {
5053
+ cryptoResult = r;
5054
+ done = true;
5055
+ },
5056
+ (e) => {
5057
+ errorMsg = e instanceof Error ? e.message : String(e);
5058
+ done = true;
5059
+ }
5060
+ );
5061
+ const start = Date.now();
5062
+ while (!done && Date.now() - start < 5e3) {
5063
+ }
5064
+ if (!done) {
5065
+ return {
5066
+ stdout: "",
5067
+ stderr: "Signature verification timed out",
5068
+ exitCode: EXIT.ERROR
5069
+ };
5070
+ }
5071
+ if (errorMsg) {
5072
+ return {
5073
+ stdout: "",
5074
+ stderr: `Signature verification failed: ${errorMsg}`,
5075
+ exitCode: EXIT.ERROR
5076
+ };
5077
+ }
5078
+ if (!cryptoResult) {
5079
+ return {
5080
+ stdout: "",
5081
+ stderr: "Signature verification failed (no result)",
5082
+ exitCode: EXIT.ERROR
5083
+ };
5084
+ }
5085
+ return formatVerifyResult(receipt, cryptoResult, args);
5086
+ } catch (e) {
5087
+ return {
5088
+ stdout: "",
5089
+ stderr: `Signature verification error: ${e instanceof Error ? e.message : String(e)}`,
5090
+ exitCode: EXIT.ERROR
5091
+ };
5092
+ }
5093
+ }
4453
5094
  if (flagBool(args.flags, "json")) {
4454
5095
  return {
4455
- stdout: JSON.stringify(result, null, 2),
4456
- exitCode: result.valid ? EXIT.OK : 1
5096
+ stdout: JSON.stringify(
5097
+ {
5098
+ valid: true,
5099
+ receipt_id: receipt.receipt_id,
5100
+ schema_version: receipt.schema_version,
5101
+ verdict: receipt.verdict,
5102
+ signed: false
5103
+ },
5104
+ null,
5105
+ 2
5106
+ ),
5107
+ exitCode: EXIT.OK
5108
+ };
5109
+ }
5110
+ const stdout = [
5111
+ "\u2713 CallLint receipt: valid",
5112
+ ` Receipt ID: ${receipt.receipt_id}`,
5113
+ ` Schema: ${receipt.schema_version}`,
5114
+ ` Verdict: ${receipt.verdict}`,
5115
+ ` Signature: unsigned local receipt`
5116
+ ].join("\n");
5117
+ return { stdout, exitCode: EXIT.OK };
5118
+ }
5119
+ async function verifySignature(receipt, args) {
5120
+ const sig = receipt.signature;
5121
+ const publicKeyUrl = sig.public_key_url || "https://calllint.com/.well-known/receipt-keys.json";
5122
+ let publicKey;
5123
+ const publicKeyFlag = args.flags["public-key"];
5124
+ if (publicKeyFlag && typeof publicKeyFlag === "string") {
5125
+ try {
5126
+ const keyJson = JSON.parse(readFileSync8(publicKeyFlag, "utf8"));
5127
+ publicKey = keyJson.public_key;
5128
+ } catch (e) {
5129
+ throw new Error(
5130
+ `Could not read public key from ${publicKeyFlag}: ${e instanceof Error ? e.message : String(e)}`
5131
+ );
5132
+ }
5133
+ } else {
5134
+ throw new Error(
5135
+ `Receipt has signature but public key not available.
5136
+ Signature key_id: ${sig.key_id}
5137
+ Public key URL: ${publicKeyUrl}
5138
+
5139
+ To verify locally, provide public key with --public-key <keyfile>
5140
+ Example: calllint receipt verify receipt.json --public-key dev-key.json`
5141
+ );
5142
+ }
5143
+ return await verifyReceipt2(receipt, publicKey);
5144
+ }
5145
+ function formatVerifyResult(receipt, cryptoResult, args) {
5146
+ const sig = receipt.signature;
5147
+ if (flagBool(args.flags, "json")) {
5148
+ return {
5149
+ stdout: JSON.stringify(
5150
+ {
5151
+ valid: cryptoResult.valid,
5152
+ receipt_id: receipt.receipt_id,
5153
+ schema_version: receipt.schema_version,
5154
+ verdict: receipt.verdict,
5155
+ signed: true,
5156
+ signature: {
5157
+ valid: cryptoResult.valid,
5158
+ key_id: sig.key_id,
5159
+ algorithm: sig.algorithm,
5160
+ signed_at: sig.signed_at,
5161
+ error: cryptoResult.error
5162
+ }
5163
+ },
5164
+ null,
5165
+ 2
5166
+ ),
5167
+ exitCode: cryptoResult.valid ? EXIT.OK : 1
4457
5168
  };
4458
5169
  }
4459
- if (!result.valid) {
4460
- const lines = ["CallLint receipt: invalid", ...result.errors.map((e) => ` - ${e}`)];
5170
+ if (!cryptoResult.valid) {
5171
+ const lines = [
5172
+ "\u2717 CallLint receipt: signature INVALID",
5173
+ ` Receipt ID: ${receipt.receipt_id}`,
5174
+ ` Signature key: ${sig.key_id}`,
5175
+ ` Error: ${cryptoResult.error || "signature verification failed"}`
5176
+ ];
4461
5177
  return { stdout: "", stderr: lines.join("\n"), exitCode: 1 };
4462
5178
  }
4463
- const r = parsed;
4464
- const signature = r.signature ? "present (shape-only, not cryptographically verified)" : "unsigned local receipt";
4465
5179
  const stdout = [
4466
- "CallLint receipt: valid",
4467
- `receipt_id: ${r.receipt_id}`,
4468
- `schema: ${r.schema_version}`,
4469
- `verdict: ${r.verdict}`,
4470
- `signature: ${signature}`
5180
+ "\u2713 CallLint receipt: valid",
5181
+ ` Receipt ID: ${receipt.receipt_id}`,
5182
+ ` Schema: ${receipt.schema_version}`,
5183
+ ` Verdict: ${receipt.verdict}`,
5184
+ ` Signature: valid (key: ${sig.key_id})`,
5185
+ ` Signed at: ${sig.signed_at}`
4471
5186
  ].join("\n");
4472
5187
  return { stdout, exitCode: EXIT.OK };
4473
5188
  }
5189
+ function receiptSign(args, deps) {
5190
+ const receiptFile = args.positionals[1];
5191
+ const keyFile = args.flags["key"];
5192
+ const outFile = args.flags["out"] || receiptFile;
5193
+ if (!receiptFile || !keyFile || typeof keyFile !== "string") {
5194
+ return {
5195
+ stdout: "",
5196
+ stderr: [
5197
+ "Usage: calllint receipt sign <receipt.json> --key <keyfile> [--out <output>]",
5198
+ "",
5199
+ "Sign a receipt locally (development/testing only).",
5200
+ "Production signing requires cloud service: calllint scan --sign"
5201
+ ].join("\n"),
5202
+ exitCode: EXIT.USAGE
5203
+ };
5204
+ }
5205
+ let receiptRaw;
5206
+ try {
5207
+ receiptRaw = readFileSync8(resolve4(deps.cwd, receiptFile), "utf8");
5208
+ } catch (e) {
5209
+ return {
5210
+ stdout: "",
5211
+ stderr: `Could not read receipt ${receiptFile}: ${e instanceof Error ? e.message : String(e)}`,
5212
+ exitCode: EXIT.ERROR
5213
+ };
5214
+ }
5215
+ let unsignedReceipt;
5216
+ try {
5217
+ unsignedReceipt = JSON.parse(receiptRaw);
5218
+ } catch (e) {
5219
+ return {
5220
+ stdout: "",
5221
+ stderr: `Receipt is not valid JSON: ${e instanceof Error ? e.message : String(e)}`,
5222
+ exitCode: EXIT.ERROR
5223
+ };
5224
+ }
5225
+ if (unsignedReceipt.signature) {
5226
+ return {
5227
+ stdout: "",
5228
+ stderr: "Receipt already has a signature field. Cannot sign again.",
5229
+ exitCode: EXIT.ERROR
5230
+ };
5231
+ }
5232
+ let keyJson;
5233
+ try {
5234
+ const keyRaw = readFileSync8(resolve4(deps.cwd, keyFile), "utf8");
5235
+ keyJson = JSON.parse(keyRaw);
5236
+ } catch (e) {
5237
+ return {
5238
+ stdout: "",
5239
+ stderr: `Could not read key file ${keyFile}: ${e instanceof Error ? e.message : String(e)}`,
5240
+ exitCode: EXIT.ERROR
5241
+ };
5242
+ }
5243
+ let keypair;
5244
+ try {
5245
+ keypair = importKeypair(keyJson);
5246
+ } catch (e) {
5247
+ return {
5248
+ stdout: "",
5249
+ stderr: `Invalid keypair format: ${e instanceof Error ? e.message : String(e)}`,
5250
+ exitCode: EXIT.ERROR
5251
+ };
5252
+ }
5253
+ let signature = null;
5254
+ let errorMsg = null;
5255
+ const promise = signReceipt(unsignedReceipt, keypair);
5256
+ let done = false;
5257
+ promise.then(
5258
+ (sig) => {
5259
+ signature = sig;
5260
+ done = true;
5261
+ },
5262
+ (e) => {
5263
+ errorMsg = e instanceof Error ? e.message : String(e);
5264
+ done = true;
5265
+ }
5266
+ );
5267
+ const start = Date.now();
5268
+ while (!done && Date.now() - start < 5e3) {
5269
+ }
5270
+ if (!done) {
5271
+ return {
5272
+ stdout: "",
5273
+ stderr: "Signing timed out",
5274
+ exitCode: EXIT.ERROR
5275
+ };
5276
+ }
5277
+ if (errorMsg) {
5278
+ return {
5279
+ stdout: "",
5280
+ stderr: `Signing failed: ${errorMsg}`,
5281
+ exitCode: EXIT.ERROR
5282
+ };
5283
+ }
5284
+ if (!signature) {
5285
+ return {
5286
+ stdout: "",
5287
+ stderr: "Signing failed (no result)",
5288
+ exitCode: EXIT.ERROR
5289
+ };
5290
+ }
5291
+ try {
5292
+ const signedReceipt = { ...unsignedReceipt, signature };
5293
+ const outPath = resolve4(deps.cwd, outFile);
5294
+ writeFileSync6(outPath, JSON.stringify(signedReceipt, null, 2) + "\n", "utf8");
5295
+ const stdout = [
5296
+ "\u2713 Receipt signed successfully",
5297
+ ` Key ID: ${signature.key_id}`,
5298
+ ` Algorithm: ${signature.algorithm}`,
5299
+ ` Signed at: ${signature.signed_at}`,
5300
+ ` Output: ${outFile}`
5301
+ ].join("\n");
5302
+ return { stdout, exitCode: EXIT.OK };
5303
+ } catch (e) {
5304
+ return {
5305
+ stdout: "",
5306
+ stderr: `Failed to write signed receipt: ${e instanceof Error ? e.message : String(e)}`,
5307
+ exitCode: EXIT.ERROR
5308
+ };
5309
+ }
5310
+ }
5311
+ function receiptKeygen(args, deps) {
5312
+ const outFile = args.flags["out"];
5313
+ if (!outFile || typeof outFile !== "string") {
5314
+ return {
5315
+ stdout: "",
5316
+ stderr: [
5317
+ "Usage: calllint receipt keygen --out <file>",
5318
+ "",
5319
+ "Generate a test ed25519 keypair (development/testing only).",
5320
+ "Production keys are managed by cloud service."
5321
+ ].join("\n"),
5322
+ exitCode: EXIT.USAGE
5323
+ };
5324
+ }
5325
+ const keyId = args.flags["key-id"] || "calllint-dev-2026-h2";
5326
+ let keypair = null;
5327
+ let errorMsg = null;
5328
+ const promise = generateKeypair(keyId);
5329
+ let done = false;
5330
+ promise.then(
5331
+ (kp) => {
5332
+ keypair = kp;
5333
+ done = true;
5334
+ },
5335
+ (e) => {
5336
+ errorMsg = e instanceof Error ? e.message : String(e);
5337
+ done = true;
5338
+ }
5339
+ );
5340
+ const start = Date.now();
5341
+ while (!done && Date.now() - start < 5e3) {
5342
+ }
5343
+ if (!done) {
5344
+ return {
5345
+ stdout: "",
5346
+ stderr: "Keygen timed out",
5347
+ exitCode: EXIT.ERROR
5348
+ };
5349
+ }
5350
+ if (errorMsg) {
5351
+ return {
5352
+ stdout: "",
5353
+ stderr: `Keygen failed: ${errorMsg}`,
5354
+ exitCode: EXIT.ERROR
5355
+ };
5356
+ }
5357
+ if (!keypair) {
5358
+ return {
5359
+ stdout: "",
5360
+ stderr: "Keygen failed (no result)",
5361
+ exitCode: EXIT.ERROR
5362
+ };
5363
+ }
5364
+ try {
5365
+ const exported = exportKeypair(keypair);
5366
+ const outPath = resolve4(deps.cwd, outFile);
5367
+ writeFileSync6(outPath, JSON.stringify(exported, null, 2) + "\n", "utf8");
5368
+ const stdout = [
5369
+ "\u2713 Keypair generated successfully",
5370
+ ` Key ID: ${keyId}`,
5371
+ ` Algorithm: ed25519`,
5372
+ ` Output: ${outFile}`,
5373
+ "",
5374
+ "\u26A0\uFE0F Development/testing only. Do NOT use for production."
5375
+ ].join("\n");
5376
+ return { stdout, exitCode: EXIT.OK };
5377
+ } catch (e) {
5378
+ return {
5379
+ stdout: "",
5380
+ stderr: `Failed to write keypair: ${e instanceof Error ? e.message : String(e)}`,
5381
+ exitCode: EXIT.ERROR
5382
+ };
5383
+ }
5384
+ }
4474
5385
 
4475
5386
  // src/commands/action.ts
4476
- import { readFileSync as readFileSync9 } from "node:fs";
5387
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
4477
5388
  import { resolve as resolve5 } from "node:path";
4478
5389
 
4479
5390
  // ../../packages/action-analyzer/src/types.ts
@@ -4963,21 +5874,28 @@ Expected: calllint.action.v0`,
4963
5874
  const policy = loadPolicyOrDefault(policyPath ? resolve5(deps.cwd, policyPath) : void 0);
4964
5875
  const findings = analyzeAction(descriptor);
4965
5876
  const verdict = computeActionVerdict(findings, policy);
5877
+ const actionReport = {
5878
+ schema_version: "calllint.action-report.v0",
5879
+ verdict,
5880
+ findings,
5881
+ target: {
5882
+ type: "action",
5883
+ kind: descriptor.kind,
5884
+ schema_version: descriptor.schema_version
5885
+ },
5886
+ policy_applied: "default",
5887
+ scan_timestamp: deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString(),
5888
+ counts: {
5889
+ SAFE: findings.filter((f) => !f.blocker && f.severity !== "high").length === 0 ? 1 : 0,
5890
+ REVIEW: findings.some((f) => f.severity === "high") ? 1 : 0,
5891
+ BLOCK: findings.some((f) => f.blocker || f.severity === "critical") ? 1 : 0,
5892
+ UNKNOWN: 0
5893
+ },
5894
+ reports: [{ findings }]
5895
+ };
4966
5896
  let stdout = "";
4967
5897
  if (args.flags["json"]) {
4968
- const report = {
4969
- schema_version: "calllint.action-report.v0",
4970
- verdict,
4971
- findings,
4972
- target: {
4973
- type: "action",
4974
- kind: descriptor.kind,
4975
- schema_version: descriptor.schema_version
4976
- },
4977
- policy_applied: "default",
4978
- scan_timestamp: (/* @__PURE__ */ new Date()).toISOString()
4979
- };
4980
- stdout = JSON.stringify(report, null, 2);
5898
+ stdout = JSON.stringify(actionReport, null, 2);
4981
5899
  } else {
4982
5900
  const header = `
4983
5901
  \u{1F50D} Action: ${descriptor.kind}
@@ -4997,21 +5915,27 @@ Expected: calllint.action.v0`,
4997
5915
  }
4998
5916
  stdout = header + body;
4999
5917
  }
5918
+ if (args.flags["receipt"]) {
5919
+ const receiptError = writeActionReceipt(descriptor, content, actionReport, policy, args, deps);
5920
+ if (receiptError) {
5921
+ return { stdout: "", stderr: receiptError, exitCode: 2 };
5922
+ }
5923
+ }
5000
5924
  return {
5001
5925
  stdout,
5002
5926
  stderr: "",
5003
5927
  exitCode: verdict === "SAFE" ? 0 : 1
5004
5928
  };
5005
5929
  } catch (error) {
5006
- const err = error;
5930
+ const err2 = error;
5007
5931
  let stderr = "";
5008
- if (err.code === "ENOENT") {
5932
+ if (err2.code === "ENOENT") {
5009
5933
  stderr = `Error: File not found: ${actionFile}`;
5010
5934
  } else if (error instanceof SyntaxError) {
5011
5935
  stderr = `Error: Invalid JSON in ${actionFile}
5012
5936
  ${error.message}`;
5013
5937
  } else {
5014
- stderr = `Error: ${err.message}`;
5938
+ stderr = `Error: ${err2.message}`;
5015
5939
  }
5016
5940
  return {
5017
5941
  stdout: "",
@@ -5034,11 +5958,14 @@ COMMANDS
5034
5958
  OPTIONS
5035
5959
  --json Output JSON report
5036
5960
  --policy <file> Use custom policy file
5961
+ --receipt Generate a calllint.receipt.v0 file
5962
+ --receipt-out <file> Receipt output path (default: calllint-action-receipt.json)
5037
5963
  --no-emoji Disable emoji in output
5038
5964
 
5039
5965
  EXAMPLE
5040
5966
  calllint action inspect payment.json
5041
5967
  calllint action inspect email-reply.json --json
5968
+ calllint action inspect payment.json --receipt
5042
5969
 
5043
5970
  See: https://calllint.com/docs/action-inspect (ADR 0029)
5044
5971
  `;
@@ -5057,6 +5984,285 @@ function computeActionVerdict(findings, policy) {
5057
5984
  }
5058
5985
  return "REVIEW";
5059
5986
  }
5987
+ function writeActionReceipt(descriptor, rawContent, actionReport, policy, args, deps) {
5988
+ const toolVersion = deps.toolVersion ?? "0.0.0-dev";
5989
+ const receipt = createReceipt(
5990
+ {
5991
+ toolVersion,
5992
+ subject: { type: "action", target: descriptor.kind },
5993
+ inputForHash: rawContent,
5994
+ effectivePolicyForHash: policy ?? { policy: "default" },
5995
+ scanReport: actionReport,
5996
+ rulesetForHash: { tool: "calllint", version: toolVersion },
5997
+ networkUsed: false
5998
+ },
5999
+ deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
6000
+ );
6001
+ const outPath = resolve5(
6002
+ deps.cwd,
6003
+ args.flags["receipt-out"] ?? "calllint-action-receipt.json"
6004
+ );
6005
+ try {
6006
+ writeFileSync7(outPath, JSON.stringify(receipt, null, 2) + "\n", "utf8");
6007
+ } catch (e) {
6008
+ return `Could not write action receipt to ${outPath}: ${e instanceof Error ? e.message : String(e)}`;
6009
+ }
6010
+ return void 0;
6011
+ }
6012
+
6013
+ // src/commands/inbox.ts
6014
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "node:fs";
6015
+ import { resolve as resolve6 } from "node:path";
6016
+ function inboxCommand(args, deps) {
6017
+ const subcommand = args.positionals[0];
6018
+ if (!subcommand || subcommand === "help") {
6019
+ return {
6020
+ stdout: inboxHelp(),
6021
+ stderr: "",
6022
+ exitCode: 0
6023
+ };
6024
+ }
6025
+ if (subcommand === "inspect") {
6026
+ return inboxInspect(args, deps);
6027
+ }
6028
+ return {
6029
+ stdout: "",
6030
+ stderr: `Unknown inbox subcommand: ${subcommand}
6031
+ Run \`calllint inbox help\`.`,
6032
+ exitCode: 2
6033
+ };
6034
+ }
6035
+ function inboxInspect(args, deps) {
6036
+ const eventFile = args.positionals[1];
6037
+ if (!eventFile) {
6038
+ return {
6039
+ stdout: "",
6040
+ stderr: "Error: Missing event file\nUsage: calllint inbox inspect <normalized-event.json>",
6041
+ exitCode: 2
6042
+ };
6043
+ }
6044
+ try {
6045
+ const absolutePath = resolve6(deps.cwd, eventFile);
6046
+ const content = readFileSync10(absolutePath, "utf-8");
6047
+ const event = JSON.parse(content);
6048
+ if (event.schema_version !== "calllint.agent-inbox-event.v0") {
6049
+ return {
6050
+ stdout: "",
6051
+ stderr: `Error: Unsupported schema version: ${event.schema_version}
6052
+ Expected: calllint.agent-inbox-event.v0`,
6053
+ exitCode: 2
6054
+ };
6055
+ }
6056
+ if (!event.event_type || !event.timestamp || !event.source || !event.normalized_content) {
6057
+ return {
6058
+ stdout: "",
6059
+ stderr: "Error: Invalid inbox event - missing required fields (event_type, timestamp, source, normalized_content)",
6060
+ exitCode: 2
6061
+ };
6062
+ }
6063
+ const policyPath = args.flags["policy"];
6064
+ const policy = loadPolicyOrDefault(policyPath ? resolve6(deps.cwd, policyPath) : void 0);
6065
+ const actionCandidate = event.action_candidate;
6066
+ let verdict;
6067
+ let findings;
6068
+ let stdout = "";
6069
+ if (!actionCandidate) {
6070
+ verdict = "SAFE";
6071
+ findings = [];
6072
+ if (args.flags["json"]) {
6073
+ const report = {
6074
+ schema_version: "calllint.inbox-report.v0",
6075
+ verdict,
6076
+ findings: [],
6077
+ event: {
6078
+ event_type: event.event_type,
6079
+ provider: event.source.provider,
6080
+ account_id: event.source.account_id,
6081
+ timestamp: event.timestamp
6082
+ },
6083
+ action_candidate: null,
6084
+ scan_timestamp: deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
6085
+ };
6086
+ stdout = JSON.stringify(report, null, 2);
6087
+ } else {
6088
+ stdout = `
6089
+ \u{1F4EC} Inbox Event: ${event.event_type} (${event.source.provider})
6090
+ Verdict: \u2705 SAFE
6091
+ Action Candidate: None (informational only)
6092
+ `;
6093
+ }
6094
+ } else {
6095
+ if (actionCandidate.schema_version !== "calllint.action.v0") {
6096
+ return {
6097
+ stdout: "",
6098
+ stderr: `Error: Unsupported action_candidate schema: ${actionCandidate.schema_version}
6099
+ Expected: calllint.action.v0`,
6100
+ exitCode: 2
6101
+ };
6102
+ }
6103
+ findings = analyzeAction(actionCandidate);
6104
+ verdict = computeActionVerdict2(findings, policy);
6105
+ if (args.flags["json"]) {
6106
+ const report = {
6107
+ schema_version: "calllint.inbox-report.v0",
6108
+ verdict,
6109
+ findings,
6110
+ event: {
6111
+ event_type: event.event_type,
6112
+ provider: event.source.provider,
6113
+ account_id: event.source.account_id,
6114
+ timestamp: event.timestamp
6115
+ },
6116
+ action_candidate: {
6117
+ kind: actionCandidate.kind,
6118
+ schema_version: actionCandidate.schema_version
6119
+ },
6120
+ scan_timestamp: deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
6121
+ };
6122
+ stdout = JSON.stringify(report, null, 2);
6123
+ } else {
6124
+ const verdictEmoji = verdict === "SAFE" ? "\u2705" : verdict === "BLOCK" ? "\u26D4" : verdict === "REVIEW" ? "\u26A0\uFE0F" : "\u25C7";
6125
+ stdout = `
6126
+ \u{1F4EC} Inbox Event: ${event.event_type} (${event.source.provider})
6127
+ \u{1F50D} Action Candidate: ${actionCandidate.kind}
6128
+ Verdict: ${verdictEmoji} ${verdict}
6129
+ Findings: ${findings.length}
6130
+ `;
6131
+ if (findings.length > 0) {
6132
+ stdout += "\n";
6133
+ for (const f of findings) {
6134
+ stdout += ` \u2022 ${f.id}: ${f.impact}
6135
+ `;
6136
+ }
6137
+ }
6138
+ }
6139
+ }
6140
+ if (args.flags["receipt"]) {
6141
+ const receiptError = writeInboxReceipt(event, content, verdict, findings, policy, args, deps);
6142
+ if (receiptError) {
6143
+ return { stdout: "", stderr: receiptError, exitCode: 2 };
6144
+ }
6145
+ }
6146
+ return {
6147
+ stdout,
6148
+ stderr: "",
6149
+ exitCode: verdict === "SAFE" ? 0 : 1
6150
+ };
6151
+ } catch (error) {
6152
+ const err2 = error;
6153
+ let stderr = "";
6154
+ if (err2.code === "ENOENT") {
6155
+ stderr = `Error: File not found: ${eventFile}`;
6156
+ } else if (error instanceof SyntaxError) {
6157
+ stderr = `Error: Invalid JSON in ${eventFile}
6158
+ ${error.message}`;
6159
+ } else {
6160
+ stderr = `Error: ${err2.message}`;
6161
+ }
6162
+ return {
6163
+ stdout: "",
6164
+ stderr,
6165
+ exitCode: 2
6166
+ };
6167
+ }
6168
+ }
6169
+ function computeActionVerdict2(findings, policy) {
6170
+ if (findings.length === 0) {
6171
+ return "SAFE";
6172
+ }
6173
+ const hasBlocker = findings.some((f) => f.blocker || f.severity === "critical");
6174
+ if (hasBlocker) {
6175
+ return "BLOCK";
6176
+ }
6177
+ const hasHigh = findings.some((f) => f.severity === "high");
6178
+ if (hasHigh) {
6179
+ return "REVIEW";
6180
+ }
6181
+ return "REVIEW";
6182
+ }
6183
+ function writeInboxReceipt(event, rawContent, verdict, findings, policy, args, deps) {
6184
+ try {
6185
+ const target = event.source.account_id ? `${event.source.provider}.${event.source.account_id}` : event.source.provider;
6186
+ const inboxReport = {
6187
+ schema_version: "calllint.inbox-report.v0",
6188
+ verdict,
6189
+ counts: {
6190
+ SAFE: verdict === "SAFE" ? 1 : 0,
6191
+ REVIEW: verdict === "REVIEW" ? 1 : 0,
6192
+ BLOCK: verdict === "BLOCK" ? 1 : 0,
6193
+ UNKNOWN: verdict === "UNKNOWN" ? 1 : 0
6194
+ },
6195
+ reports: [{ findings }]
6196
+ };
6197
+ const toolVersion = deps.toolVersion || "0.0.0-dev";
6198
+ const receipt = createReceipt(
6199
+ {
6200
+ toolVersion,
6201
+ subject: { type: "action", target },
6202
+ // Use 'action' type (inbox extends action)
6203
+ inputForHash: rawContent,
6204
+ effectivePolicyForHash: policy || { policy: "default" },
6205
+ scanReport: inboxReport,
6206
+ rulesetForHash: { tool: "calllint", version: toolVersion },
6207
+ networkUsed: false
6208
+ },
6209
+ deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
6210
+ );
6211
+ const receiptOutPath = args.flags["receipt-out"] || "calllint-inbox-receipt.json";
6212
+ const absoluteReceiptPath = resolve6(deps.cwd, receiptOutPath);
6213
+ writeFileSync8(absoluteReceiptPath, JSON.stringify(receipt, null, 2) + "\n", "utf-8");
6214
+ return null;
6215
+ } catch (error) {
6216
+ const err2 = error;
6217
+ return `Error writing receipt: ${err2.message}`;
6218
+ }
6219
+ }
6220
+ function inboxHelp() {
6221
+ return `
6222
+ calllint inbox \u2014 Inspect normalized agent inbox events
6223
+
6224
+ USAGE
6225
+ calllint inbox inspect <normalized-event.json> [options]
6226
+
6227
+ DESCRIPTION
6228
+ Read a normalized agent inbox event (calllint.agent-inbox-event.v0),
6229
+ extract the optional action_candidate field, and analyze it using the
6230
+ R4 action analyzer. Returns SAFE/REVIEW/BLOCK/UNKNOWN verdict with
6231
+ evidence-backed findings.
6232
+
6233
+ This command is a composition layer: it does NOT fetch messages, poll
6234
+ providers, or implement OAuth. Caller provides pre-normalized events.
6235
+
6236
+ OPTIONS
6237
+ --receipt Write a receipt (calllint.receipt.v0) with subject.type="inbox"
6238
+ --receipt-out <path> Receipt output path (default: calllint-receipt.json)
6239
+ --policy <path> Custom policy file
6240
+ --json JSON output
6241
+
6242
+ EXIT CODES
6243
+ 0 SAFE (no blockers observed)
6244
+ 1 REVIEW / BLOCK / UNKNOWN
6245
+ 2 Invalid input or schema violation
6246
+
6247
+ EXAMPLES
6248
+ # Inspect a normalized Gmail event with action candidate
6249
+ calllint inbox inspect gmail-reply.normalized.json
6250
+
6251
+ # Generate receipt for audit trail
6252
+ calllint inbox inspect resend-invoice.json --receipt
6253
+
6254
+ # JSON output for programmatic use
6255
+ calllint inbox inspect slack-mention.json --json
6256
+
6257
+ SEE ALSO
6258
+ docs/AGENT_INBOX_PREFLIGHT.md \u2014 Usage guide + worked examples
6259
+ docs/AGENT_INBOX_ADAPTER_CONTRACT.md \u2014 Provider \u2192 normalized transformation
6260
+ packages/fixtures/agent-inbox/ \u2014 6 providers \xD7 2 examples (reference)
6261
+ ADR 0031 \u2014 Agent Inbox Runtime design
6262
+ ADR 0030 \u2014 Agent Inbox Spec (v0.10.0 design)
6263
+ ADR 0029 \u2014 Unified External Action Preflight (R4)
6264
+ `;
6265
+ }
5060
6266
 
5061
6267
  // src/run.ts
5062
6268
  function run(argv, deps) {
@@ -5127,7 +6333,9 @@ function run(argv, deps) {
5127
6333
  case "receipt":
5128
6334
  return receiptCommand(args, { cwd: deps.cwd });
5129
6335
  case "action":
5130
- return actionCommand(args, { cwd: deps.cwd });
6336
+ return actionCommand(args, { cwd: deps.cwd, toolVersion: deps.toolVersion, generatedAt: deps.generatedAt });
6337
+ case "inbox":
6338
+ return inboxCommand(args, { cwd: deps.cwd, toolVersion: deps.toolVersion, generatedAt: deps.generatedAt });
5131
6339
  case "gen-rule":
5132
6340
  return genRuleCommand(args, { cwd: deps.cwd });
5133
6341
  case "policy":
@@ -5401,13 +6609,13 @@ async function breathe(argv, deps = {}) {
5401
6609
  }
5402
6610
 
5403
6611
  // src/version.ts
5404
- import { readFileSync as readFileSync10 } from "node:fs";
6612
+ import { readFileSync as readFileSync11 } from "node:fs";
5405
6613
  import { fileURLToPath } from "node:url";
5406
6614
  import { dirname as dirname4, join as join11 } from "node:path";
5407
6615
  function resolveToolVersion() {
5408
6616
  try {
5409
6617
  const pkgPath = join11(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
5410
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
6618
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
5411
6619
  return typeof pkg.version === "string" && pkg.version.length > 0 ? pkg.version : "unknown";
5412
6620
  } catch {
5413
6621
  return "unknown";
@@ -5417,7 +6625,7 @@ function resolveToolVersion() {
5417
6625
  // src/index.ts
5418
6626
  function readStdin() {
5419
6627
  try {
5420
- return readFileSync11(0, "utf8");
6628
+ return readFileSync12(0, "utf8");
5421
6629
  } catch {
5422
6630
  return "";
5423
6631
  }
@@ -5438,8 +6646,8 @@ async function main() {
5438
6646
  let clock;
5439
6647
  try {
5440
6648
  clock = resolveClock(argv, () => /* @__PURE__ */ new Date());
5441
- } catch (err) {
5442
- process.stderr.write(`${err instanceof Error ? err.message : String(err)}
6649
+ } catch (err2) {
6650
+ process.stderr.write(`${err2 instanceof Error ? err2.message : String(err2)}
5443
6651
  `);
5444
6652
  process.exitCode = 2;
5445
6653
  return;
@@ -5448,8 +6656,8 @@ async function main() {
5448
6656
  let online;
5449
6657
  try {
5450
6658
  online = await computeOnlineEnrichment(argv, { fetchedAt: generatedAt });
5451
- } catch (err) {
5452
- process.stderr.write(`--online failed: ${err instanceof Error ? err.message : String(err)}
6659
+ } catch (err2) {
6660
+ process.stderr.write(`--online failed: ${err2 instanceof Error ? err2.message : String(err2)}
5453
6661
  `);
5454
6662
  process.exitCode = 3;
5455
6663
  return;
@@ -5474,3 +6682,8 @@ async function main() {
5474
6682
  process.exitCode = result.exitCode;
5475
6683
  }
5476
6684
  void main();
6685
+ /*! Bundled license information:
6686
+
6687
+ @noble/ed25519/index.js:
6688
+ (*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) *)
6689
+ */