calllint 0.9.3 → 1.0.1

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 +1130 -87
  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,611 @@ 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
+ // ../../packages/signature/src/ed25519.ts
4413
+ import { createHash as createHash2 } from "node:crypto";
4414
+
4415
+ // ../../node_modules/.pnpm/@noble+ed25519@2.3.0/node_modules/@noble/ed25519/index.js
4416
+ var ed25519_CURVE = {
4417
+ p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
4418
+ n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
4419
+ h: 8n,
4420
+ a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
4421
+ d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
4422
+ Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
4423
+ Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n
4424
+ };
4425
+ var { p: P, n: N, Gx, Gy, a: _a, d: _d } = ed25519_CURVE;
4426
+ var h = 8n;
4427
+ var L = 32;
4428
+ var L2 = 64;
4429
+ var err = (m = "") => {
4430
+ throw new Error(m);
4431
+ };
4432
+ var isBig = (n) => typeof n === "bigint";
4433
+ var isStr = (s) => typeof s === "string";
4434
+ var isBytes = (a) => a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
4435
+ var abytes = (a, l) => !isBytes(a) || typeof l === "number" && l > 0 && a.length !== l ? err("Uint8Array expected") : a;
4436
+ var u8n = (len) => new Uint8Array(len);
4437
+ var u8fr = (buf) => Uint8Array.from(buf);
4438
+ var padh = (n, pad) => n.toString(16).padStart(pad, "0");
4439
+ var bytesToHex = (b) => Array.from(abytes(b)).map((e) => padh(e, 2)).join("");
4440
+ var C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
4441
+ var _ch = (ch) => {
4442
+ if (ch >= C._0 && ch <= C._9)
4443
+ return ch - C._0;
4444
+ if (ch >= C.A && ch <= C.F)
4445
+ return ch - (C.A - 10);
4446
+ if (ch >= C.a && ch <= C.f)
4447
+ return ch - (C.a - 10);
4448
+ return;
4449
+ };
4450
+ var hexToBytes = (hex) => {
4451
+ const e = "hex invalid";
4452
+ if (!isStr(hex))
4453
+ return err(e);
4454
+ const hl = hex.length;
4455
+ const al = hl / 2;
4456
+ if (hl % 2)
4457
+ return err(e);
4458
+ const array = u8n(al);
4459
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
4460
+ const n1 = _ch(hex.charCodeAt(hi));
4461
+ const n2 = _ch(hex.charCodeAt(hi + 1));
4462
+ if (n1 === void 0 || n2 === void 0)
4463
+ return err(e);
4464
+ array[ai] = n1 * 16 + n2;
4465
+ }
4466
+ return array;
4467
+ };
4468
+ var toU8 = (a, len) => abytes(isStr(a) ? hexToBytes(a) : u8fr(abytes(a)), len);
4469
+ var cr = () => globalThis?.crypto;
4470
+ var subtle = () => cr()?.subtle ?? err("crypto.subtle must be defined");
4471
+ var concatBytes = (...arrs) => {
4472
+ const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0));
4473
+ let pad = 0;
4474
+ arrs.forEach((a) => {
4475
+ r.set(a, pad);
4476
+ pad += a.length;
4477
+ });
4478
+ return r;
4479
+ };
4480
+ var randomBytes2 = (len = L) => {
4481
+ const c = cr();
4482
+ return c.getRandomValues(u8n(len));
4483
+ };
4484
+ var big = BigInt;
4485
+ var arange = (n, min, max, msg = "bad number: out of range") => isBig(n) && min <= n && n < max ? n : err(msg);
4486
+ var M = (a, b = P) => {
4487
+ const r = a % b;
4488
+ return r >= 0n ? r : b + r;
4489
+ };
4490
+ var modN = (a) => M(a, N);
4491
+ var invert = (num, md) => {
4492
+ if (num === 0n || md <= 0n)
4493
+ err("no inverse n=" + num + " mod=" + md);
4494
+ let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
4495
+ while (a !== 0n) {
4496
+ const q = b / a, r = b % a;
4497
+ const m = x - u * q, n = y - v * q;
4498
+ b = a, a = r, x = u, y = v, u = m, v = n;
4499
+ }
4500
+ return b === 1n ? M(x, md) : err("no inverse");
4501
+ };
4502
+ var callHash = (name) => {
4503
+ const fn = etc[name];
4504
+ if (typeof fn !== "function")
4505
+ err("hashes." + name + " not set");
4506
+ return fn;
4507
+ };
4508
+ var apoint = (p) => p instanceof Point ? p : err("Point expected");
4509
+ var B256 = 2n ** 256n;
4510
+ var Point = class _Point {
4511
+ static BASE;
4512
+ static ZERO;
4513
+ ex;
4514
+ ey;
4515
+ ez;
4516
+ et;
4517
+ constructor(ex, ey, ez, et) {
4518
+ const max = B256;
4519
+ this.ex = arange(ex, 0n, max);
4520
+ this.ey = arange(ey, 0n, max);
4521
+ this.ez = arange(ez, 1n, max);
4522
+ this.et = arange(et, 0n, max);
4523
+ Object.freeze(this);
4524
+ }
4525
+ static fromAffine(p) {
4526
+ return new _Point(p.x, p.y, 1n, M(p.x * p.y));
4527
+ }
4528
+ /** RFC8032 5.1.3: Uint8Array to Point. */
4529
+ static fromBytes(hex, zip215 = false) {
4530
+ const d = _d;
4531
+ const normed = u8fr(abytes(hex, L));
4532
+ const lastByte = hex[31];
4533
+ normed[31] = lastByte & ~128;
4534
+ const y = bytesToNumLE(normed);
4535
+ const max = zip215 ? B256 : P;
4536
+ arange(y, 0n, max);
4537
+ const y2 = M(y * y);
4538
+ const u = M(y2 - 1n);
4539
+ const v = M(d * y2 + 1n);
4540
+ let { isValid, value: x } = uvRatio(u, v);
4541
+ if (!isValid)
4542
+ err("bad point: y not sqrt");
4543
+ const isXOdd = (x & 1n) === 1n;
4544
+ const isLastByteOdd = (lastByte & 128) !== 0;
4545
+ if (!zip215 && x === 0n && isLastByteOdd)
4546
+ err("bad point: x==0, isLastByteOdd");
4547
+ if (isLastByteOdd !== isXOdd)
4548
+ x = M(-x);
4549
+ return new _Point(x, y, 1n, M(x * y));
4550
+ }
4551
+ /** Checks if the point is valid and on-curve. */
4552
+ assertValidity() {
4553
+ const a = _a;
4554
+ const d = _d;
4555
+ const p = this;
4556
+ if (p.is0())
4557
+ throw new Error("bad point: ZERO");
4558
+ const { ex: X, ey: Y, ez: Z, et: T } = p;
4559
+ const X2 = M(X * X);
4560
+ const Y2 = M(Y * Y);
4561
+ const Z2 = M(Z * Z);
4562
+ const Z4 = M(Z2 * Z2);
4563
+ const aX2 = M(X2 * a);
4564
+ const left = M(Z2 * M(aX2 + Y2));
4565
+ const right = M(Z4 + M(d * M(X2 * Y2)));
4566
+ if (left !== right)
4567
+ throw new Error("bad point: equation left != right (1)");
4568
+ const XY = M(X * Y);
4569
+ const ZT = M(Z * T);
4570
+ if (XY !== ZT)
4571
+ throw new Error("bad point: equation left != right (2)");
4572
+ return this;
4573
+ }
4574
+ /** Equality check: compare points P&Q. */
4575
+ equals(other) {
4576
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
4577
+ const { ex: X2, ey: Y2, ez: Z2 } = apoint(other);
4578
+ const X1Z2 = M(X1 * Z2);
4579
+ const X2Z1 = M(X2 * Z1);
4580
+ const Y1Z2 = M(Y1 * Z2);
4581
+ const Y2Z1 = M(Y2 * Z1);
4582
+ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
4583
+ }
4584
+ is0() {
4585
+ return this.equals(I);
4586
+ }
4587
+ /** Flip point over y coordinate. */
4588
+ negate() {
4589
+ return new _Point(M(-this.ex), this.ey, this.ez, M(-this.et));
4590
+ }
4591
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
4592
+ double() {
4593
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
4594
+ const a = _a;
4595
+ const A = M(X1 * X1);
4596
+ const B = M(Y1 * Y1);
4597
+ const C2 = M(2n * M(Z1 * Z1));
4598
+ const D = M(a * A);
4599
+ const x1y1 = X1 + Y1;
4600
+ const E = M(M(x1y1 * x1y1) - A - B);
4601
+ const G2 = D + B;
4602
+ const F = G2 - C2;
4603
+ const H = D - B;
4604
+ const X3 = M(E * F);
4605
+ const Y3 = M(G2 * H);
4606
+ const T3 = M(E * H);
4607
+ const Z3 = M(F * G2);
4608
+ return new _Point(X3, Y3, Z3, T3);
4609
+ }
4610
+ /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
4611
+ add(other) {
4612
+ const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
4613
+ const { ex: X2, ey: Y2, ez: Z2, et: T2 } = apoint(other);
4614
+ const a = _a;
4615
+ const d = _d;
4616
+ const A = M(X1 * X2);
4617
+ const B = M(Y1 * Y2);
4618
+ const C2 = M(T1 * d * T2);
4619
+ const D = M(Z1 * Z2);
4620
+ const E = M((X1 + Y1) * (X2 + Y2) - A - B);
4621
+ const F = M(D - C2);
4622
+ const G2 = M(D + C2);
4623
+ const H = M(B - a * A);
4624
+ const X3 = M(E * F);
4625
+ const Y3 = M(G2 * H);
4626
+ const T3 = M(E * H);
4627
+ const Z3 = M(F * G2);
4628
+ return new _Point(X3, Y3, Z3, T3);
4629
+ }
4630
+ /**
4631
+ * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
4632
+ * Uses {@link wNAF} for base point.
4633
+ * Uses fake point to mitigate side-channel leakage.
4634
+ * @param n scalar by which point is multiplied
4635
+ * @param safe safe mode guards against timing attacks; unsafe mode is faster
4636
+ */
4637
+ multiply(n, safe = true) {
4638
+ if (!safe && (n === 0n || this.is0()))
4639
+ return I;
4640
+ arange(n, 1n, N);
4641
+ if (n === 1n)
4642
+ return this;
4643
+ if (this.equals(G))
4644
+ return wNAF(n).p;
4645
+ let p = I;
4646
+ let f = G;
4647
+ for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
4648
+ if (n & 1n)
4649
+ p = p.add(d);
4650
+ else if (safe)
4651
+ f = f.add(d);
4652
+ }
4653
+ return p;
4654
+ }
4655
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
4656
+ toAffine() {
4657
+ const { ex: x, ey: y, ez: z } = this;
4658
+ if (this.equals(I))
4659
+ return { x: 0n, y: 1n };
4660
+ const iz = invert(z, P);
4661
+ if (M(z * iz) !== 1n)
4662
+ err("invalid inverse");
4663
+ return { x: M(x * iz), y: M(y * iz) };
4664
+ }
4665
+ toBytes() {
4666
+ const { x, y } = this.assertValidity().toAffine();
4667
+ const b = numTo32bLE(y);
4668
+ b[31] |= x & 1n ? 128 : 0;
4669
+ return b;
4670
+ }
4671
+ toHex() {
4672
+ return bytesToHex(this.toBytes());
4673
+ }
4674
+ // encode to hex string
4675
+ clearCofactor() {
4676
+ return this.multiply(big(h), false);
4677
+ }
4678
+ isSmallOrder() {
4679
+ return this.clearCofactor().is0();
4680
+ }
4681
+ isTorsionFree() {
4682
+ let p = this.multiply(N / 2n, false).double();
4683
+ if (N % 2n)
4684
+ p = p.add(this);
4685
+ return p.is0();
4686
+ }
4687
+ static fromHex(hex, zip215) {
4688
+ return _Point.fromBytes(toU8(hex), zip215);
4689
+ }
4690
+ get x() {
4691
+ return this.toAffine().x;
4692
+ }
4693
+ get y() {
4694
+ return this.toAffine().y;
4695
+ }
4696
+ toRawBytes() {
4697
+ return this.toBytes();
4698
+ }
4699
+ };
4700
+ var G = new Point(Gx, Gy, 1n, M(Gx * Gy));
4701
+ var I = new Point(0n, 1n, 1n, 0n);
4702
+ Point.BASE = G;
4703
+ Point.ZERO = I;
4704
+ var numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), L2)).reverse();
4705
+ var bytesToNumLE = (b) => big("0x" + bytesToHex(u8fr(abytes(b)).reverse()));
4706
+ var pow2 = (x, power) => {
4707
+ let r = x;
4708
+ while (power-- > 0n) {
4709
+ r *= r;
4710
+ r %= P;
4711
+ }
4712
+ return r;
4713
+ };
4714
+ var pow_2_252_3 = (x) => {
4715
+ const x2 = x * x % P;
4716
+ const b2 = x2 * x % P;
4717
+ const b4 = pow2(b2, 2n) * b2 % P;
4718
+ const b5 = pow2(b4, 1n) * x % P;
4719
+ const b10 = pow2(b5, 5n) * b5 % P;
4720
+ const b20 = pow2(b10, 10n) * b10 % P;
4721
+ const b40 = pow2(b20, 20n) * b20 % P;
4722
+ const b80 = pow2(b40, 40n) * b40 % P;
4723
+ const b160 = pow2(b80, 80n) * b80 % P;
4724
+ const b240 = pow2(b160, 80n) * b80 % P;
4725
+ const b250 = pow2(b240, 10n) * b10 % P;
4726
+ const pow_p_5_8 = pow2(b250, 2n) * x % P;
4727
+ return { pow_p_5_8, b2 };
4728
+ };
4729
+ var RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n;
4730
+ var uvRatio = (u, v) => {
4731
+ const v3 = M(v * v * v);
4732
+ const v7 = M(v3 * v3 * v);
4733
+ const pow = pow_2_252_3(u * v7).pow_p_5_8;
4734
+ let x = M(u * v3 * pow);
4735
+ const vx2 = M(v * x * x);
4736
+ const root1 = x;
4737
+ const root2 = M(x * RM1);
4738
+ const useRoot1 = vx2 === u;
4739
+ const useRoot2 = vx2 === M(-u);
4740
+ const noRoot = vx2 === M(-u * RM1);
4741
+ if (useRoot1)
4742
+ x = root1;
4743
+ if (useRoot2 || noRoot)
4744
+ x = root2;
4745
+ if ((M(x) & 1n) === 1n)
4746
+ x = M(-x);
4747
+ return { isValid: useRoot1 || useRoot2, value: x };
4748
+ };
4749
+ var modL_LE = (hash) => modN(bytesToNumLE(hash));
4750
+ var sha512a = (...m) => etc.sha512Async(...m);
4751
+ var sha512s = (...m) => callHash("sha512Sync")(...m);
4752
+ var hash2extK = (hashed) => {
4753
+ const head = hashed.slice(0, L);
4754
+ head[0] &= 248;
4755
+ head[31] &= 127;
4756
+ head[31] |= 64;
4757
+ const prefix = hashed.slice(L, L2);
4758
+ const scalar = modL_LE(head);
4759
+ const point = G.multiply(scalar);
4760
+ const pointBytes = point.toBytes();
4761
+ return { head, prefix, scalar, point, pointBytes };
4762
+ };
4763
+ var getExtendedPublicKeyAsync = (priv) => sha512a(toU8(priv, L)).then(hash2extK);
4764
+ var getExtendedPublicKey = (priv) => hash2extK(sha512s(toU8(priv, L)));
4765
+ var getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;
4766
+ var hashFinishS = (res) => res.finish(sha512s(res.hashable));
4767
+ var _sign = (e, rBytes, msg) => {
4768
+ const { pointBytes: P2, scalar: s } = e;
4769
+ const r = modL_LE(rBytes);
4770
+ const R = G.multiply(r).toBytes();
4771
+ const hashable = concatBytes(R, P2, msg);
4772
+ const finish = (hashed) => {
4773
+ const S = modN(r + modL_LE(hashed) * s);
4774
+ return abytes(concatBytes(R, numTo32bLE(S)), L2);
4775
+ };
4776
+ return { hashable, finish };
4777
+ };
4778
+ var sign = (msg, privKey) => {
4779
+ const m = toU8(msg);
4780
+ const e = getExtendedPublicKey(privKey);
4781
+ const rBytes = sha512s(e.prefix, m);
4782
+ return hashFinishS(_sign(e, rBytes, m));
4783
+ };
4784
+ var veriOpts = { zip215: true };
4785
+ var _verify = (sig, msg, pub, opts = veriOpts) => {
4786
+ sig = toU8(sig, L2);
4787
+ msg = toU8(msg);
4788
+ pub = toU8(pub, L);
4789
+ const { zip215 } = opts;
4790
+ let A;
4791
+ let R;
4792
+ let s;
4793
+ let SB;
4794
+ let hashable = Uint8Array.of();
4795
+ try {
4796
+ A = Point.fromHex(pub, zip215);
4797
+ R = Point.fromHex(sig.slice(0, L), zip215);
4798
+ s = bytesToNumLE(sig.slice(L, L2));
4799
+ SB = G.multiply(s, false);
4800
+ hashable = concatBytes(R.toBytes(), A.toBytes(), msg);
4801
+ } catch (error) {
4802
+ }
4803
+ const finish = (hashed) => {
4804
+ if (SB == null)
4805
+ return false;
4806
+ if (!zip215 && A.isSmallOrder())
4807
+ return false;
4808
+ const k = modL_LE(hashed);
4809
+ const RkA = R.add(A.multiply(k, false));
4810
+ return RkA.add(SB.negate()).clearCofactor().is0();
4811
+ };
4812
+ return { hashable, finish };
4813
+ };
4814
+ var verify = (s, m, p, opts = veriOpts) => hashFinishS(_verify(s, m, p, opts));
4815
+ var etc = {
4816
+ sha512Async: async (...messages) => {
4817
+ const s = subtle();
4818
+ const m = concatBytes(...messages);
4819
+ return u8n(await s.digest("SHA-512", m.buffer));
4820
+ },
4821
+ sha512Sync: void 0,
4822
+ bytesToHex,
4823
+ hexToBytes,
4824
+ concatBytes,
4825
+ mod: M,
4826
+ invert,
4827
+ randomBytes: randomBytes2
4828
+ };
4829
+ var utils = {
4830
+ getExtendedPublicKeyAsync,
4831
+ getExtendedPublicKey,
4832
+ randomPrivateKey: () => randomBytes2(L),
4833
+ precompute: (w = 8, p = G) => {
4834
+ p.multiply(3n);
4835
+ w;
4836
+ return p;
4837
+ }
4838
+ // no-op
4839
+ };
4840
+ var W = 8;
4841
+ var scalarBits = 256;
4842
+ var pwindows = Math.ceil(scalarBits / W) + 1;
4843
+ var pwindowSize = 2 ** (W - 1);
4844
+ var precompute = () => {
4845
+ const points = [];
4846
+ let p = G;
4847
+ let b = p;
4848
+ for (let w = 0; w < pwindows; w++) {
4849
+ b = p;
4850
+ points.push(b);
4851
+ for (let i = 1; i < pwindowSize; i++) {
4852
+ b = b.add(p);
4853
+ points.push(b);
4854
+ }
4855
+ p = b.double();
4856
+ }
4857
+ return points;
4858
+ };
4859
+ var Gpows = void 0;
4860
+ var ctneg = (cnd, p) => {
4861
+ const n = p.negate();
4862
+ return cnd ? n : p;
4863
+ };
4864
+ var wNAF = (n) => {
4865
+ const comp = Gpows || (Gpows = precompute());
4866
+ let p = I;
4867
+ let f = G;
4868
+ const pow_2_w = 2 ** W;
4869
+ const maxNum = pow_2_w;
4870
+ const mask = big(pow_2_w - 1);
4871
+ const shiftBy = big(W);
4872
+ for (let w = 0; w < pwindows; w++) {
4873
+ let wbits = Number(n & mask);
4874
+ n >>= shiftBy;
4875
+ if (wbits > pwindowSize) {
4876
+ wbits -= maxNum;
4877
+ n += 1n;
4878
+ }
4879
+ const off = w * pwindowSize;
4880
+ const offF = off;
4881
+ const offP = off + Math.abs(wbits) - 1;
4882
+ const isEven = w % 2 !== 0;
4883
+ const isNeg = wbits < 0;
4884
+ if (wbits === 0) {
4885
+ f = f.add(ctneg(isEven, comp[offF]));
4886
+ } else {
4887
+ p = p.add(ctneg(isNeg, comp[offP]));
4888
+ }
4889
+ }
4890
+ return { p, f };
4891
+ };
4892
+
4893
+ // ../../packages/signature/src/base64url.ts
4894
+ function base64urlEncode(bytes) {
4895
+ const base64 = Buffer.from(bytes).toString("base64");
4896
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
4897
+ }
4898
+ function base64urlDecode(str) {
4899
+ const padded = str + "===".slice((str.length + 3) % 4);
4900
+ const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
4901
+ return new Uint8Array(Buffer.from(base64, "base64"));
4902
+ }
4903
+
4904
+ // ../../packages/signature/src/ed25519.ts
4905
+ etc.sha512Sync = (...messages) => {
4906
+ const hash = createHash2("sha512");
4907
+ hash.update(etc.concatBytes(...messages));
4908
+ return new Uint8Array(hash.digest());
4909
+ };
4910
+ function generateKeypair(keyId) {
4911
+ const privateKey = utils.randomPrivateKey();
4912
+ const publicKey = getPublicKey(privateKey);
4913
+ return {
4914
+ privateKey,
4915
+ publicKey,
4916
+ keyId
4917
+ };
4918
+ }
4919
+ function signReceipt(unsignedReceipt, keypair) {
4920
+ const canonical = stableStringify(unsignedReceipt);
4921
+ const hash = sha256(canonical);
4922
+ const hashHex = hash.slice(7);
4923
+ const hashBytes = Buffer.from(hashHex, "hex");
4924
+ const signatureBytes = sign(hashBytes, keypair.privateKey);
4925
+ const signatureBase64url = base64urlEncode(signatureBytes);
4926
+ return {
4927
+ algorithm: "ed25519",
4928
+ key_id: keypair.keyId,
4929
+ value: signatureBase64url,
4930
+ signed_at: (/* @__PURE__ */ new Date()).toISOString()
4931
+ };
4932
+ }
4933
+ function verifyReceipt2(signedReceipt, publicKey) {
4934
+ try {
4935
+ const sig = signedReceipt.signature;
4936
+ if (!sig) {
4937
+ return { valid: false, error: "No signature field in receipt" };
4938
+ }
4939
+ if (sig.algorithm !== "ed25519") {
4940
+ return { valid: false, error: `Unsupported algorithm: ${sig.algorithm}` };
4941
+ }
4942
+ const publicKeyBytes = typeof publicKey === "string" ? base64urlDecode(publicKey) : publicKey;
4943
+ if (publicKeyBytes.length !== 32) {
4944
+ return { valid: false, error: "Invalid public key length (expected 32 bytes)" };
4945
+ }
4946
+ const signatureBytes = base64urlDecode(sig.value);
4947
+ if (signatureBytes.length !== 64) {
4948
+ return { valid: false, error: "Invalid signature length (expected 64 bytes)" };
4949
+ }
4950
+ const { signature, ...unsignedReceipt } = signedReceipt;
4951
+ const canonical = stableStringify(unsignedReceipt);
4952
+ const hash = sha256(canonical);
4953
+ const hashHex = hash.slice(7);
4954
+ const hashBytes = Buffer.from(hashHex, "hex");
4955
+ const valid = verify(signatureBytes, hashBytes, publicKeyBytes);
4956
+ return { valid, key_id: sig.key_id };
4957
+ } catch (error) {
4414
4958
  return {
4415
- stdout: "",
4416
- stderr: "Usage: calllint receipt verify <receipt.json>",
4417
- exitCode: EXIT.USAGE
4959
+ valid: false,
4960
+ error: error instanceof Error ? error.message : "Unknown verification error"
4418
4961
  };
4419
4962
  }
4963
+ }
4964
+ function exportKeypair(keypair) {
4965
+ return {
4966
+ key_id: keypair.keyId,
4967
+ algorithm: "ed25519",
4968
+ private_key: base64urlEncode(keypair.privateKey),
4969
+ public_key: base64urlEncode(keypair.publicKey)
4970
+ };
4971
+ }
4972
+ function importKeypair(json) {
4973
+ if (json.algorithm !== "ed25519") {
4974
+ throw new Error(`Unsupported algorithm: ${json.algorithm}`);
4975
+ }
4976
+ return {
4977
+ keyId: json.key_id,
4978
+ privateKey: base64urlDecode(json.private_key),
4979
+ publicKey: base64urlDecode(json.public_key)
4980
+ };
4981
+ }
4982
+
4983
+ // src/commands/receipt.ts
4984
+ function receiptCommand(args, deps) {
4985
+ const sub = args.positionals[0];
4986
+ switch (sub) {
4987
+ case "verify":
4988
+ return receiptVerify(args, deps);
4989
+ case "sign":
4990
+ return receiptSign(args, deps);
4991
+ case "keygen":
4992
+ return receiptKeygen(args, deps);
4993
+ default:
4994
+ return {
4995
+ stdout: "",
4996
+ stderr: [
4997
+ "Usage: calllint receipt <subcommand>",
4998
+ "",
4999
+ "Subcommands:",
5000
+ " verify <receipt.json> Validate receipt structure and signature",
5001
+ " sign <receipt.json> --key <file> Sign receipt locally (development only)",
5002
+ " keygen --out <file> Generate test keypair (development only)"
5003
+ ].join("\n"),
5004
+ exitCode: EXIT.USAGE
5005
+ };
5006
+ }
5007
+ }
5008
+ function receiptVerify(args, deps) {
4420
5009
  const file = args.positionals[1];
4421
5010
  if (!file) {
4422
5011
  return {
4423
5012
  stdout: "",
4424
- stderr: "Usage: calllint receipt verify <receipt.json>",
5013
+ stderr: "Usage: calllint receipt verify <receipt.json> [--public-key <keyfile>]",
4425
5014
  exitCode: EXIT.USAGE
4426
5015
  };
4427
5016
  }
@@ -4449,31 +5038,224 @@ function receiptCommand(args, deps) {
4449
5038
  return { stdout: "", stderr: `CallLint receipt: invalid
4450
5039
  - ${msg}`, exitCode: 1 };
4451
5040
  }
4452
- const result = verifyReceipt(parsed);
5041
+ const structResult = verifyReceipt(parsed);
5042
+ if (!structResult.valid) {
5043
+ if (flagBool(args.flags, "json")) {
5044
+ return {
5045
+ stdout: JSON.stringify(structResult, null, 2),
5046
+ exitCode: 1
5047
+ };
5048
+ }
5049
+ const lines = ["CallLint receipt: invalid", ...structResult.errors.map((e) => ` - ${e}`)];
5050
+ return { stdout: "", stderr: lines.join("\n"), exitCode: 1 };
5051
+ }
5052
+ const receipt = parsed;
5053
+ if (receipt.signature) {
5054
+ return verifySignature(receipt, args, deps);
5055
+ }
5056
+ if (flagBool(args.flags, "json")) {
5057
+ return {
5058
+ stdout: JSON.stringify(
5059
+ {
5060
+ valid: true,
5061
+ receipt_id: receipt.receipt_id,
5062
+ schema_version: receipt.schema_version,
5063
+ verdict: receipt.verdict,
5064
+ signed: false
5065
+ },
5066
+ null,
5067
+ 2
5068
+ ),
5069
+ exitCode: EXIT.OK
5070
+ };
5071
+ }
5072
+ const stdout = [
5073
+ "\u2713 CallLint receipt: valid",
5074
+ ` Receipt ID: ${receipt.receipt_id}`,
5075
+ ` Schema: ${receipt.schema_version}`,
5076
+ ` Verdict: ${receipt.verdict}`,
5077
+ ` Signature: unsigned local receipt`
5078
+ ].join("\n");
5079
+ return { stdout, exitCode: EXIT.OK };
5080
+ }
5081
+ function verifySignature(receipt, args, deps) {
5082
+ const sig = receipt.signature;
5083
+ const publicKeyUrl = sig.public_key_url || "https://calllint.com/.well-known/receipt-keys.json";
5084
+ const publicKeyFlag = args.flags["public-key"];
5085
+ if (!publicKeyFlag || typeof publicKeyFlag !== "string") {
5086
+ return {
5087
+ stdout: "",
5088
+ stderr: [
5089
+ "Receipt has a signature but no public key was provided.",
5090
+ ` Signature key_id: ${sig.key_id}`,
5091
+ ` Public key URL: ${publicKeyUrl}`,
5092
+ "",
5093
+ "Verify offline by passing the public key:",
5094
+ " calllint receipt verify <receipt.json> --public-key <keyfile>"
5095
+ ].join("\n"),
5096
+ exitCode: EXIT.ERROR
5097
+ };
5098
+ }
5099
+ let publicKey;
5100
+ try {
5101
+ const keyJson = JSON.parse(readFileSync8(resolve4(deps.cwd, publicKeyFlag), "utf8"));
5102
+ publicKey = keyJson.public_key;
5103
+ if (typeof publicKey !== "string") {
5104
+ throw new Error("key file has no string 'public_key' field");
5105
+ }
5106
+ } catch (e) {
5107
+ return {
5108
+ stdout: "",
5109
+ stderr: `Could not read public key from ${publicKeyFlag}: ${e instanceof Error ? e.message : String(e)}`,
5110
+ exitCode: EXIT.ERROR
5111
+ };
5112
+ }
5113
+ const cryptoResult = verifyReceipt2(receipt, publicKey);
4453
5114
  if (flagBool(args.flags, "json")) {
4454
5115
  return {
4455
- stdout: JSON.stringify(result, null, 2),
4456
- exitCode: result.valid ? EXIT.OK : 1
5116
+ stdout: JSON.stringify(
5117
+ {
5118
+ valid: cryptoResult.valid,
5119
+ receipt_id: receipt.receipt_id,
5120
+ schema_version: receipt.schema_version,
5121
+ verdict: receipt.verdict,
5122
+ signed: true,
5123
+ signature: {
5124
+ valid: cryptoResult.valid,
5125
+ key_id: sig.key_id,
5126
+ algorithm: sig.algorithm,
5127
+ signed_at: sig.signed_at,
5128
+ error: cryptoResult.error
5129
+ }
5130
+ },
5131
+ null,
5132
+ 2
5133
+ ),
5134
+ exitCode: cryptoResult.valid ? EXIT.OK : 1
4457
5135
  };
4458
5136
  }
4459
- if (!result.valid) {
4460
- const lines = ["CallLint receipt: invalid", ...result.errors.map((e) => ` - ${e}`)];
5137
+ if (!cryptoResult.valid) {
5138
+ const lines = [
5139
+ "\u2717 CallLint receipt: signature INVALID",
5140
+ ` Receipt ID: ${receipt.receipt_id}`,
5141
+ ` Signature key: ${sig.key_id}`,
5142
+ ` Error: ${cryptoResult.error || "signature verification failed"}`
5143
+ ];
4461
5144
  return { stdout: "", stderr: lines.join("\n"), exitCode: 1 };
4462
5145
  }
4463
- const r = parsed;
4464
- const signature = r.signature ? "present (shape-only, not cryptographically verified)" : "unsigned local receipt";
4465
5146
  const stdout = [
4466
- "CallLint receipt: valid",
4467
- `receipt_id: ${r.receipt_id}`,
4468
- `schema: ${r.schema_version}`,
4469
- `verdict: ${r.verdict}`,
4470
- `signature: ${signature}`
5147
+ "\u2713 CallLint receipt: valid",
5148
+ ` Receipt ID: ${receipt.receipt_id}`,
5149
+ ` Schema: ${receipt.schema_version}`,
5150
+ ` Verdict: ${receipt.verdict}`,
5151
+ ` Signature: valid (key: ${sig.key_id})`,
5152
+ ` Signed at: ${sig.signed_at}`
4471
5153
  ].join("\n");
4472
5154
  return { stdout, exitCode: EXIT.OK };
4473
5155
  }
5156
+ function receiptSign(args, deps) {
5157
+ const receiptFile = args.positionals[1];
5158
+ const keyFile = args.flags["key"];
5159
+ const outFile = args.flags["out"] || receiptFile;
5160
+ if (!receiptFile || !keyFile || typeof keyFile !== "string") {
5161
+ return {
5162
+ stdout: "",
5163
+ stderr: [
5164
+ "Usage: calllint receipt sign <receipt.json> --key <keyfile> [--out <output>]",
5165
+ "",
5166
+ "Sign a receipt locally (development/testing only).",
5167
+ "Production signing requires cloud service: calllint scan --sign"
5168
+ ].join("\n"),
5169
+ exitCode: EXIT.USAGE
5170
+ };
5171
+ }
5172
+ let unsignedReceipt;
5173
+ try {
5174
+ unsignedReceipt = JSON.parse(readFileSync8(resolve4(deps.cwd, receiptFile), "utf8"));
5175
+ } catch (e) {
5176
+ return {
5177
+ stdout: "",
5178
+ stderr: `Could not read receipt ${receiptFile}: ${e instanceof Error ? e.message : String(e)}`,
5179
+ exitCode: EXIT.ERROR
5180
+ };
5181
+ }
5182
+ if (unsignedReceipt.signature) {
5183
+ return {
5184
+ stdout: "",
5185
+ stderr: "Receipt already has a signature field. Cannot sign again.",
5186
+ exitCode: EXIT.ERROR
5187
+ };
5188
+ }
5189
+ let keypair;
5190
+ try {
5191
+ const keyJson = JSON.parse(readFileSync8(resolve4(deps.cwd, keyFile), "utf8"));
5192
+ keypair = importKeypair(keyJson);
5193
+ } catch (e) {
5194
+ return {
5195
+ stdout: "",
5196
+ stderr: `Could not read key file ${keyFile}: ${e instanceof Error ? e.message : String(e)}`,
5197
+ exitCode: EXIT.ERROR
5198
+ };
5199
+ }
5200
+ try {
5201
+ const signature = signReceipt(unsignedReceipt, keypair);
5202
+ const signedReceipt = { ...unsignedReceipt, signature };
5203
+ writeFileSync6(resolve4(deps.cwd, outFile), JSON.stringify(signedReceipt, null, 2) + "\n", "utf8");
5204
+ const stdout = [
5205
+ "\u2713 Receipt signed successfully",
5206
+ ` Key ID: ${signature.key_id}`,
5207
+ ` Algorithm: ${signature.algorithm}`,
5208
+ ` Signed at: ${signature.signed_at}`,
5209
+ ` Output: ${outFile}`
5210
+ ].join("\n");
5211
+ return { stdout, exitCode: EXIT.OK };
5212
+ } catch (e) {
5213
+ return {
5214
+ stdout: "",
5215
+ stderr: `Signing failed: ${e instanceof Error ? e.message : String(e)}`,
5216
+ exitCode: EXIT.ERROR
5217
+ };
5218
+ }
5219
+ }
5220
+ function receiptKeygen(args, deps) {
5221
+ const outFile = args.flags["out"];
5222
+ if (!outFile || typeof outFile !== "string") {
5223
+ return {
5224
+ stdout: "",
5225
+ stderr: [
5226
+ "Usage: calllint receipt keygen --out <file>",
5227
+ "",
5228
+ "Generate a test ed25519 keypair (development/testing only).",
5229
+ "Production keys are managed by cloud service."
5230
+ ].join("\n"),
5231
+ exitCode: EXIT.USAGE
5232
+ };
5233
+ }
5234
+ const keyId = args.flags["key-id"] || "calllint-dev-2026-h2";
5235
+ try {
5236
+ const keypair = generateKeypair(keyId);
5237
+ const exported = exportKeypair(keypair);
5238
+ writeFileSync6(resolve4(deps.cwd, outFile), JSON.stringify(exported, null, 2) + "\n", "utf8");
5239
+ const stdout = [
5240
+ "\u2713 Keypair generated successfully",
5241
+ ` Key ID: ${keyId}`,
5242
+ ` Algorithm: ed25519`,
5243
+ ` Output: ${outFile}`,
5244
+ "",
5245
+ "\u26A0\uFE0F Development/testing only. Do NOT use for production."
5246
+ ].join("\n");
5247
+ return { stdout, exitCode: EXIT.OK };
5248
+ } catch (e) {
5249
+ return {
5250
+ stdout: "",
5251
+ stderr: `Keygen failed: ${e instanceof Error ? e.message : String(e)}`,
5252
+ exitCode: EXIT.ERROR
5253
+ };
5254
+ }
5255
+ }
4474
5256
 
4475
5257
  // src/commands/action.ts
4476
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
5258
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
4477
5259
  import { resolve as resolve5 } from "node:path";
4478
5260
 
4479
5261
  // ../../packages/action-analyzer/src/types.ts
@@ -5016,15 +5798,15 @@ Expected: calllint.action.v0`,
5016
5798
  exitCode: verdict === "SAFE" ? 0 : 1
5017
5799
  };
5018
5800
  } catch (error) {
5019
- const err = error;
5801
+ const err2 = error;
5020
5802
  let stderr = "";
5021
- if (err.code === "ENOENT") {
5803
+ if (err2.code === "ENOENT") {
5022
5804
  stderr = `Error: File not found: ${actionFile}`;
5023
5805
  } else if (error instanceof SyntaxError) {
5024
5806
  stderr = `Error: Invalid JSON in ${actionFile}
5025
5807
  ${error.message}`;
5026
5808
  } else {
5027
- stderr = `Error: ${err.message}`;
5809
+ stderr = `Error: ${err2.message}`;
5028
5810
  }
5029
5811
  return {
5030
5812
  stdout: "",
@@ -5092,13 +5874,267 @@ function writeActionReceipt(descriptor, rawContent, actionReport, policy, args,
5092
5874
  args.flags["receipt-out"] ?? "calllint-action-receipt.json"
5093
5875
  );
5094
5876
  try {
5095
- writeFileSync6(outPath, JSON.stringify(receipt, null, 2) + "\n", "utf8");
5877
+ writeFileSync7(outPath, JSON.stringify(receipt, null, 2) + "\n", "utf8");
5096
5878
  } catch (e) {
5097
5879
  return `Could not write action receipt to ${outPath}: ${e instanceof Error ? e.message : String(e)}`;
5098
5880
  }
5099
5881
  return void 0;
5100
5882
  }
5101
5883
 
5884
+ // src/commands/inbox.ts
5885
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "node:fs";
5886
+ import { resolve as resolve6 } from "node:path";
5887
+ function inboxCommand(args, deps) {
5888
+ const subcommand = args.positionals[0];
5889
+ if (!subcommand || subcommand === "help") {
5890
+ return {
5891
+ stdout: inboxHelp(),
5892
+ stderr: "",
5893
+ exitCode: 0
5894
+ };
5895
+ }
5896
+ if (subcommand === "inspect") {
5897
+ return inboxInspect(args, deps);
5898
+ }
5899
+ return {
5900
+ stdout: "",
5901
+ stderr: `Unknown inbox subcommand: ${subcommand}
5902
+ Run \`calllint inbox help\`.`,
5903
+ exitCode: 2
5904
+ };
5905
+ }
5906
+ function inboxInspect(args, deps) {
5907
+ const eventFile = args.positionals[1];
5908
+ if (!eventFile) {
5909
+ return {
5910
+ stdout: "",
5911
+ stderr: "Error: Missing event file\nUsage: calllint inbox inspect <normalized-event.json>",
5912
+ exitCode: 2
5913
+ };
5914
+ }
5915
+ try {
5916
+ const absolutePath = resolve6(deps.cwd, eventFile);
5917
+ const content = readFileSync10(absolutePath, "utf-8");
5918
+ const event = JSON.parse(content);
5919
+ if (event.schema_version !== "calllint.agent-inbox-event.v0") {
5920
+ return {
5921
+ stdout: "",
5922
+ stderr: `Error: Unsupported schema version: ${event.schema_version}
5923
+ Expected: calllint.agent-inbox-event.v0`,
5924
+ exitCode: 2
5925
+ };
5926
+ }
5927
+ if (!event.event_type || !event.timestamp || !event.source || !event.normalized_content) {
5928
+ return {
5929
+ stdout: "",
5930
+ stderr: "Error: Invalid inbox event - missing required fields (event_type, timestamp, source, normalized_content)",
5931
+ exitCode: 2
5932
+ };
5933
+ }
5934
+ const policyPath = args.flags["policy"];
5935
+ const policy = loadPolicyOrDefault(policyPath ? resolve6(deps.cwd, policyPath) : void 0);
5936
+ const actionCandidate = event.action_candidate;
5937
+ let verdict;
5938
+ let findings;
5939
+ let stdout = "";
5940
+ if (!actionCandidate) {
5941
+ verdict = "SAFE";
5942
+ findings = [];
5943
+ if (args.flags["json"]) {
5944
+ const report = {
5945
+ schema_version: "calllint.inbox-report.v0",
5946
+ verdict,
5947
+ findings: [],
5948
+ event: {
5949
+ event_type: event.event_type,
5950
+ provider: event.source.provider,
5951
+ account_id: event.source.account_id,
5952
+ timestamp: event.timestamp
5953
+ },
5954
+ action_candidate: null,
5955
+ scan_timestamp: deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
5956
+ };
5957
+ stdout = JSON.stringify(report, null, 2);
5958
+ } else {
5959
+ stdout = `
5960
+ \u{1F4EC} Inbox Event: ${event.event_type} (${event.source.provider})
5961
+ Verdict: \u2705 SAFE
5962
+ Action Candidate: None (informational only)
5963
+ `;
5964
+ }
5965
+ } else {
5966
+ if (actionCandidate.schema_version !== "calllint.action.v0") {
5967
+ return {
5968
+ stdout: "",
5969
+ stderr: `Error: Unsupported action_candidate schema: ${actionCandidate.schema_version}
5970
+ Expected: calllint.action.v0`,
5971
+ exitCode: 2
5972
+ };
5973
+ }
5974
+ findings = analyzeAction(actionCandidate);
5975
+ verdict = computeActionVerdict2(findings, policy);
5976
+ if (args.flags["json"]) {
5977
+ const report = {
5978
+ schema_version: "calllint.inbox-report.v0",
5979
+ verdict,
5980
+ findings,
5981
+ event: {
5982
+ event_type: event.event_type,
5983
+ provider: event.source.provider,
5984
+ account_id: event.source.account_id,
5985
+ timestamp: event.timestamp
5986
+ },
5987
+ action_candidate: {
5988
+ kind: actionCandidate.kind,
5989
+ schema_version: actionCandidate.schema_version
5990
+ },
5991
+ scan_timestamp: deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
5992
+ };
5993
+ stdout = JSON.stringify(report, null, 2);
5994
+ } else {
5995
+ const verdictEmoji = verdict === "SAFE" ? "\u2705" : verdict === "BLOCK" ? "\u26D4" : verdict === "REVIEW" ? "\u26A0\uFE0F" : "\u25C7";
5996
+ stdout = `
5997
+ \u{1F4EC} Inbox Event: ${event.event_type} (${event.source.provider})
5998
+ \u{1F50D} Action Candidate: ${actionCandidate.kind}
5999
+ Verdict: ${verdictEmoji} ${verdict}
6000
+ Findings: ${findings.length}
6001
+ `;
6002
+ if (findings.length > 0) {
6003
+ stdout += "\n";
6004
+ for (const f of findings) {
6005
+ stdout += ` \u2022 ${f.id}: ${f.impact}
6006
+ `;
6007
+ }
6008
+ }
6009
+ }
6010
+ }
6011
+ if (args.flags["receipt"]) {
6012
+ const receiptError = writeInboxReceipt(event, content, verdict, findings, policy, args, deps);
6013
+ if (receiptError) {
6014
+ return { stdout: "", stderr: receiptError, exitCode: 2 };
6015
+ }
6016
+ }
6017
+ return {
6018
+ stdout,
6019
+ stderr: "",
6020
+ exitCode: verdict === "SAFE" ? 0 : 1
6021
+ };
6022
+ } catch (error) {
6023
+ const err2 = error;
6024
+ let stderr = "";
6025
+ if (err2.code === "ENOENT") {
6026
+ stderr = `Error: File not found: ${eventFile}`;
6027
+ } else if (error instanceof SyntaxError) {
6028
+ stderr = `Error: Invalid JSON in ${eventFile}
6029
+ ${error.message}`;
6030
+ } else {
6031
+ stderr = `Error: ${err2.message}`;
6032
+ }
6033
+ return {
6034
+ stdout: "",
6035
+ stderr,
6036
+ exitCode: 2
6037
+ };
6038
+ }
6039
+ }
6040
+ function computeActionVerdict2(findings, policy) {
6041
+ if (findings.length === 0) {
6042
+ return "SAFE";
6043
+ }
6044
+ const hasBlocker = findings.some((f) => f.blocker || f.severity === "critical");
6045
+ if (hasBlocker) {
6046
+ return "BLOCK";
6047
+ }
6048
+ const hasHigh = findings.some((f) => f.severity === "high");
6049
+ if (hasHigh) {
6050
+ return "REVIEW";
6051
+ }
6052
+ return "REVIEW";
6053
+ }
6054
+ function writeInboxReceipt(event, rawContent, verdict, findings, policy, args, deps) {
6055
+ try {
6056
+ const target = event.source.account_id ? `${event.source.provider}.${event.source.account_id}` : event.source.provider;
6057
+ const inboxReport = {
6058
+ schema_version: "calllint.inbox-report.v0",
6059
+ verdict,
6060
+ counts: {
6061
+ SAFE: verdict === "SAFE" ? 1 : 0,
6062
+ REVIEW: verdict === "REVIEW" ? 1 : 0,
6063
+ BLOCK: verdict === "BLOCK" ? 1 : 0,
6064
+ UNKNOWN: verdict === "UNKNOWN" ? 1 : 0
6065
+ },
6066
+ reports: [{ findings }]
6067
+ };
6068
+ const toolVersion = deps.toolVersion || "0.0.0-dev";
6069
+ const receipt = createReceipt(
6070
+ {
6071
+ toolVersion,
6072
+ subject: { type: "action", target },
6073
+ // Use 'action' type (inbox extends action)
6074
+ inputForHash: rawContent,
6075
+ effectivePolicyForHash: policy || { policy: "default" },
6076
+ scanReport: inboxReport,
6077
+ rulesetForHash: { tool: "calllint", version: toolVersion },
6078
+ networkUsed: false
6079
+ },
6080
+ deps.generatedAt || (/* @__PURE__ */ new Date()).toISOString()
6081
+ );
6082
+ const receiptOutPath = args.flags["receipt-out"] || "calllint-inbox-receipt.json";
6083
+ const absoluteReceiptPath = resolve6(deps.cwd, receiptOutPath);
6084
+ writeFileSync8(absoluteReceiptPath, JSON.stringify(receipt, null, 2) + "\n", "utf-8");
6085
+ return null;
6086
+ } catch (error) {
6087
+ const err2 = error;
6088
+ return `Error writing receipt: ${err2.message}`;
6089
+ }
6090
+ }
6091
+ function inboxHelp() {
6092
+ return `
6093
+ calllint inbox \u2014 Inspect normalized agent inbox events
6094
+
6095
+ USAGE
6096
+ calllint inbox inspect <normalized-event.json> [options]
6097
+
6098
+ DESCRIPTION
6099
+ Read a normalized agent inbox event (calllint.agent-inbox-event.v0),
6100
+ extract the optional action_candidate field, and analyze it using the
6101
+ R4 action analyzer. Returns SAFE/REVIEW/BLOCK/UNKNOWN verdict with
6102
+ evidence-backed findings.
6103
+
6104
+ This command is a composition layer: it does NOT fetch messages, poll
6105
+ providers, or implement OAuth. Caller provides pre-normalized events.
6106
+
6107
+ OPTIONS
6108
+ --receipt Write a receipt (calllint.receipt.v0) with subject.type="inbox"
6109
+ --receipt-out <path> Receipt output path (default: calllint-receipt.json)
6110
+ --policy <path> Custom policy file
6111
+ --json JSON output
6112
+
6113
+ EXIT CODES
6114
+ 0 SAFE (no blockers observed)
6115
+ 1 REVIEW / BLOCK / UNKNOWN
6116
+ 2 Invalid input or schema violation
6117
+
6118
+ EXAMPLES
6119
+ # Inspect a normalized Gmail event with action candidate
6120
+ calllint inbox inspect gmail-reply.normalized.json
6121
+
6122
+ # Generate receipt for audit trail
6123
+ calllint inbox inspect resend-invoice.json --receipt
6124
+
6125
+ # JSON output for programmatic use
6126
+ calllint inbox inspect slack-mention.json --json
6127
+
6128
+ SEE ALSO
6129
+ docs/AGENT_INBOX_PREFLIGHT.md \u2014 Usage guide + worked examples
6130
+ docs/AGENT_INBOX_ADAPTER_CONTRACT.md \u2014 Provider \u2192 normalized transformation
6131
+ packages/fixtures/agent-inbox/ \u2014 6 providers \xD7 2 examples (reference)
6132
+ ADR 0031 \u2014 Agent Inbox Runtime design
6133
+ ADR 0030 \u2014 Agent Inbox Spec (v0.10.0 design)
6134
+ ADR 0029 \u2014 Unified External Action Preflight (R4)
6135
+ `;
6136
+ }
6137
+
5102
6138
  // src/run.ts
5103
6139
  function run(argv, deps) {
5104
6140
  const args = parseArgs(argv);
@@ -5168,7 +6204,9 @@ function run(argv, deps) {
5168
6204
  case "receipt":
5169
6205
  return receiptCommand(args, { cwd: deps.cwd });
5170
6206
  case "action":
5171
- return actionCommand(args, { cwd: deps.cwd });
6207
+ return actionCommand(args, { cwd: deps.cwd, toolVersion: deps.toolVersion, generatedAt: deps.generatedAt });
6208
+ case "inbox":
6209
+ return inboxCommand(args, { cwd: deps.cwd, toolVersion: deps.toolVersion, generatedAt: deps.generatedAt });
5172
6210
  case "gen-rule":
5173
6211
  return genRuleCommand(args, { cwd: deps.cwd });
5174
6212
  case "policy":
@@ -5442,13 +6480,13 @@ async function breathe(argv, deps = {}) {
5442
6480
  }
5443
6481
 
5444
6482
  // src/version.ts
5445
- import { readFileSync as readFileSync10 } from "node:fs";
6483
+ import { readFileSync as readFileSync11 } from "node:fs";
5446
6484
  import { fileURLToPath } from "node:url";
5447
6485
  import { dirname as dirname4, join as join11 } from "node:path";
5448
6486
  function resolveToolVersion() {
5449
6487
  try {
5450
6488
  const pkgPath = join11(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
5451
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
6489
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
5452
6490
  return typeof pkg.version === "string" && pkg.version.length > 0 ? pkg.version : "unknown";
5453
6491
  } catch {
5454
6492
  return "unknown";
@@ -5458,7 +6496,7 @@ function resolveToolVersion() {
5458
6496
  // src/index.ts
5459
6497
  function readStdin() {
5460
6498
  try {
5461
- return readFileSync11(0, "utf8");
6499
+ return readFileSync12(0, "utf8");
5462
6500
  } catch {
5463
6501
  return "";
5464
6502
  }
@@ -5479,8 +6517,8 @@ async function main() {
5479
6517
  let clock;
5480
6518
  try {
5481
6519
  clock = resolveClock(argv, () => /* @__PURE__ */ new Date());
5482
- } catch (err) {
5483
- process.stderr.write(`${err instanceof Error ? err.message : String(err)}
6520
+ } catch (err2) {
6521
+ process.stderr.write(`${err2 instanceof Error ? err2.message : String(err2)}
5484
6522
  `);
5485
6523
  process.exitCode = 2;
5486
6524
  return;
@@ -5489,8 +6527,8 @@ async function main() {
5489
6527
  let online;
5490
6528
  try {
5491
6529
  online = await computeOnlineEnrichment(argv, { fetchedAt: generatedAt });
5492
- } catch (err) {
5493
- process.stderr.write(`--online failed: ${err instanceof Error ? err.message : String(err)}
6530
+ } catch (err2) {
6531
+ process.stderr.write(`--online failed: ${err2 instanceof Error ? err2.message : String(err2)}
5494
6532
  `);
5495
6533
  process.exitCode = 3;
5496
6534
  return;
@@ -5515,3 +6553,8 @@ async function main() {
5515
6553
  process.exitCode = result.exitCode;
5516
6554
  }
5517
6555
  void main();
6556
+ /*! Bundled license information:
6557
+
6558
+ @noble/ed25519/index.js:
6559
+ (*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) *)
6560
+ */