protect-mcp 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6319,6 +6319,101 @@ var init_hook_patterns = __esm({
6319
6319
  }
6320
6320
  });
6321
6321
 
6322
+ // src/sample.ts
6323
+ var sample_exports = {};
6324
+ __export(sample_exports, {
6325
+ SAMPLE_KID: () => SAMPLE_KID,
6326
+ buildSampleKit: () => buildSampleKit
6327
+ });
6328
+ function signEnvelope(unsigned, privHex) {
6329
+ const msg = new TextEncoder().encode(canonicalJson(unsigned));
6330
+ const signature = bytesToHex(ed25519.sign(msg, hexToBytes(privHex)));
6331
+ return { ...unsigned, signature };
6332
+ }
6333
+ function buildSampleKit(dir, opts) {
6334
+ const receiptsPath = (0, import_node_path7.join)(dir, ".protect-mcp-receipts.jsonl");
6335
+ const keyPath = (0, import_node_path7.join)(dir, "keys", "gateway.json");
6336
+ if (!opts?.force && ((0, import_node_fs10.existsSync)(receiptsPath) || (0, import_node_fs10.existsSync)(keyPath))) {
6337
+ throw Object.assign(
6338
+ new Error(`refusing to overwrite an existing record or signing key in ${dir}`),
6339
+ { code: "SAMPLE_EXISTS" }
6340
+ );
6341
+ }
6342
+ (0, import_node_fs10.mkdirSync)((0, import_node_path7.join)(dir, "keys"), { recursive: true });
6343
+ const priv = ed25519.utils.randomPrivateKey();
6344
+ const privHex = bytesToHex(priv);
6345
+ const pub = bytesToHex(ed25519.getPublicKey(priv));
6346
+ (0, import_node_fs10.writeFileSync)(keyPath, JSON.stringify({ privateKey: privHex, publicKey: pub, kid: SAMPLE_KID }, null, 2));
6347
+ (0, import_node_fs10.writeFileSync)((0, import_node_path7.join)(dir, "keys", ".gitignore"), "# Never commit signing keys\n*.json\n");
6348
+ const now = opts?.now ?? /* @__PURE__ */ new Date();
6349
+ const stamp = (i) => new Date(now.getTime() - (7 - i) * 5 * 6e4).toISOString();
6350
+ const receipt = (i, tool, decision, caps, extra) => {
6351
+ const ts = stamp(i);
6352
+ const payload = {
6353
+ tool,
6354
+ decision,
6355
+ reason_code: decision === "deny" ? "policy_deny" : "policy_ok",
6356
+ policy_digest: SAMPLE_KID,
6357
+ scope: `${tool}-${ts}`,
6358
+ mode: "enforce",
6359
+ request_id: `${tool}-${ts}`,
6360
+ spec: "draft-farley-acta-signed-receipts-01",
6361
+ issuer_certification: "self-signed",
6362
+ public_key: pub,
6363
+ hook_event: "PreToolUse",
6364
+ enrichment: { v: 2, input_digest: sha256Hex4(tool + ts), capabilities: caps, ...extra || {} }
6365
+ };
6366
+ return signEnvelope({
6367
+ v: 2,
6368
+ type: decision === "deny" ? "gateway_restraint" : "decision_receipt",
6369
+ algorithm: "ed25519",
6370
+ kid: SAMPLE_KID,
6371
+ issuer: "protect-mcp",
6372
+ issued_at: ts,
6373
+ payload
6374
+ }, privHex);
6375
+ };
6376
+ const pay = (amount) => ({
6377
+ payment: { amount, asset: "USDC", recipient_digest: sha256Hex4("sample-merchant"), scheme: "exact" }
6378
+ });
6379
+ const rows = [
6380
+ receipt(0, "Read", "allow", ["fs.read"]),
6381
+ receipt(1, "Bash", "allow", ["exec.shell"]),
6382
+ receipt(2, "Write", "allow", ["fs.write"]),
6383
+ receipt(3, "WebFetch", "deny", ["net.egress"]),
6384
+ receipt(4, "x402_pay", "allow", ["financial", "payment"], pay(0.02)),
6385
+ receipt(5, "Read", "allow", ["fs.read", "secret.adjacent"]),
6386
+ receipt(6, "wallet_send_payment", "allow", ["financial", "payment"], pay(12.5)),
6387
+ receipt(7, "Bash", "allow", ["exec.shell", "vcs"])
6388
+ ];
6389
+ (0, import_node_fs10.writeFileSync)(receiptsPath, rows.map((r) => JSON.stringify(r)).join("\n") + "\n");
6390
+ const tampered = rows.map((r) => JSON.parse(JSON.stringify(r)));
6391
+ tampered[3].payload.decision = "allow";
6392
+ (0, import_node_fs10.writeFileSync)((0, import_node_path7.join)(dir, "demo-tampered.jsonl"), tampered.map((r) => JSON.stringify(r)).join("\n") + "\n");
6393
+ return {
6394
+ dir,
6395
+ publicKey: pub,
6396
+ kid: SAMPLE_KID,
6397
+ receipts: rows,
6398
+ paymentsUsd: [0.02, 12.5],
6399
+ files: [".protect-mcp-receipts.jsonl", "demo-tampered.jsonl", "keys/gateway.json"]
6400
+ };
6401
+ }
6402
+ var import_node_fs10, import_node_path7, SAMPLE_KID, sha256Hex4;
6403
+ var init_sample = __esm({
6404
+ "src/sample.ts"() {
6405
+ "use strict";
6406
+ import_node_fs10 = require("fs");
6407
+ import_node_path7 = require("path");
6408
+ init_sha256();
6409
+ init_utils();
6410
+ init_ed25519();
6411
+ init_receipt_enrichment();
6412
+ SAMPLE_KID = "sample-demo";
6413
+ sha256Hex4 = (s) => bytesToHex(sha2562(new TextEncoder().encode(s)));
6414
+ }
6415
+ });
6416
+
6322
6417
  // src/scopeblind-bridge.ts
6323
6418
  function getScopeBlindBridge() {
6324
6419
  if (!singleton) singleton = new ScopeBlindBridge();
@@ -6527,7 +6622,7 @@ function detectSandboxState() {
6527
6622
  }
6528
6623
  if (process.platform === "linux") {
6529
6624
  try {
6530
- const procStatus = (0, import_node_fs10.readFileSync)("/proc/self/status", "utf-8");
6625
+ const procStatus = (0, import_node_fs11.readFileSync)("/proc/self/status", "utf-8");
6531
6626
  if (procStatus.includes("Seccomp: 2")) return "enabled";
6532
6627
  } catch {
6533
6628
  }
@@ -6972,14 +7067,14 @@ function emitDecisionLog(state, entry) {
6972
7067
  process.stderr.write(`[PROTECT_MCP] ${JSON.stringify(log)}
6973
7068
  `);
6974
7069
  try {
6975
- (0, import_node_fs10.appendFileSync)(state.logFilePath, JSON.stringify(log) + "\n");
7070
+ (0, import_node_fs11.appendFileSync)(state.logFilePath, JSON.stringify(log) + "\n");
6976
7071
  } catch {
6977
7072
  }
6978
7073
  if (isSigningEnabled()) {
6979
7074
  const signed = signDecision(log);
6980
7075
  if (signed.signed) {
6981
7076
  try {
6982
- (0, import_node_fs10.appendFileSync)(state.receiptFilePath, signed.signed + "\n");
7077
+ (0, import_node_fs11.appendFileSync)(state.receiptFilePath, signed.signed + "\n");
6983
7078
  } catch {
6984
7079
  }
6985
7080
  state.receiptBuffer.add(log.request_id, signed.signed);
@@ -7003,7 +7098,7 @@ function emitDecisionLog(state, entry) {
7003
7098
  at: new Date(log.timestamp).toISOString()
7004
7099
  });
7005
7100
  try {
7006
- (0, import_node_fs10.appendFileSync)(state.receiptFilePath, tombstone + "\n");
7101
+ (0, import_node_fs11.appendFileSync)(state.receiptFilePath, tombstone + "\n");
7007
7102
  } catch {
7008
7103
  }
7009
7104
  process.stderr.write(`[PROTECT_MCP_SIGNING_FAILURE] ${tombstone}
@@ -7091,8 +7186,8 @@ async function startHookServer(options = {}) {
7091
7186
  }
7092
7187
  }
7093
7188
  if (!jsonPolicy?.signing) {
7094
- const keyPath = (0, import_node_path7.join)(process.cwd(), "keys", "gateway.json");
7095
- if ((0, import_node_fs10.existsSync)(keyPath)) {
7189
+ const keyPath = (0, import_node_path8.join)(process.cwd(), "keys", "gateway.json");
7190
+ if ((0, import_node_fs11.existsSync)(keyPath)) {
7096
7191
  const warnings = await initSigning({ key_path: keyPath, issuer: "protect-mcp", enabled: true });
7097
7192
  for (const w of warnings) {
7098
7193
  process.stderr.write(`[PROTECT_MCP] Warning: ${w}
@@ -7114,8 +7209,8 @@ async function startHookServer(options = {}) {
7114
7209
  verbose,
7115
7210
  enforce,
7116
7211
  policyDigest,
7117
- logFilePath: (0, import_node_path7.join)(process.cwd(), LOG_FILE3),
7118
- receiptFilePath: (0, import_node_path7.join)(process.cwd(), RECEIPTS_FILE2),
7212
+ logFilePath: (0, import_node_path8.join)(process.cwd(), LOG_FILE3),
7213
+ receiptFilePath: (0, import_node_path8.join)(process.cwd(), RECEIPTS_FILE2),
7119
7214
  permissionSuggestions: /* @__PURE__ */ new Map(),
7120
7215
  configAlerts: []
7121
7216
  };
@@ -7264,7 +7359,7 @@ async function startHookServer(options = {}) {
7264
7359
  `);
7265
7360
  w(`
7266
7361
  `);
7267
- const hasSlug = process.env.SCOPEBLIND_SLUG || (0, import_node_fs10.existsSync)((0, import_node_path7.join)(process.cwd(), ".scopeblind"));
7362
+ const hasSlug = process.env.SCOPEBLIND_SLUG || (0, import_node_fs11.existsSync)((0, import_node_path8.join)(process.cwd(), ".scopeblind"));
7268
7363
  if (!hasSlug) {
7269
7364
  w(` Dashboard npx protect-mcp connect
7270
7365
  `);
@@ -7295,8 +7390,8 @@ async function startHookServer(options = {}) {
7295
7390
  function findCedarDir() {
7296
7391
  for (const candidate of ["cedar", "policies", "."]) {
7297
7392
  try {
7298
- if ((0, import_node_fs10.existsSync)(candidate)) {
7299
- const files = (0, import_node_fs10.readdirSync)(candidate, { encoding: "utf-8" });
7393
+ if ((0, import_node_fs11.existsSync)(candidate)) {
7394
+ const files = (0, import_node_fs11.readdirSync)(candidate, { encoding: "utf-8" });
7300
7395
  if (files.some((f) => f.endsWith(".cedar"))) {
7301
7396
  return candidate;
7302
7397
  }
@@ -7317,14 +7412,14 @@ function normalizeHookInput(raw) {
7317
7412
  }
7318
7413
  return result;
7319
7414
  }
7320
- var import_node_http2, import_node_crypto6, import_node_fs10, import_node_path7, DEFAULT_PORT, LOG_FILE3, RECEIPTS_FILE2, PAYLOAD_HASH_THRESHOLD, SNAKE_TO_CAMEL_MAP;
7415
+ var import_node_http2, import_node_crypto6, import_node_fs11, import_node_path8, DEFAULT_PORT, LOG_FILE3, RECEIPTS_FILE2, PAYLOAD_HASH_THRESHOLD, SNAKE_TO_CAMEL_MAP;
7321
7416
  var init_hook_server = __esm({
7322
7417
  "src/hook-server.ts"() {
7323
7418
  "use strict";
7324
7419
  import_node_http2 = require("http");
7325
7420
  import_node_crypto6 = require("crypto");
7326
- import_node_fs10 = require("fs");
7327
- import_node_path7 = require("path");
7421
+ import_node_fs11 = require("fs");
7422
+ import_node_path8 = require("path");
7328
7423
  init_cedar_evaluator();
7329
7424
  init_signing();
7330
7425
  init_policy();
@@ -7550,8 +7645,8 @@ function generateReport(logPath, receiptPath, periodDays) {
7550
7645
  const now = /* @__PURE__ */ new Date();
7551
7646
  const from = new Date(now.getTime() - periodDays * 864e5);
7552
7647
  const entries = [];
7553
- if ((0, import_node_fs11.existsSync)(logPath)) {
7554
- const raw = (0, import_node_fs11.readFileSync)(logPath, "utf-8");
7648
+ if ((0, import_node_fs12.existsSync)(logPath)) {
7649
+ const raw = (0, import_node_fs12.readFileSync)(logPath, "utf-8");
7555
7650
  for (const line of raw.split("\n")) {
7556
7651
  const trimmed = line.trim();
7557
7652
  if (!trimmed) continue;
@@ -7571,8 +7666,8 @@ function generateReport(logPath, receiptPath, periodDays) {
7571
7666
  let receiptsSigned = 0;
7572
7667
  let signerKid = "";
7573
7668
  let signerIssuer = "";
7574
- if ((0, import_node_fs11.existsSync)(receiptPath)) {
7575
- const raw = (0, import_node_fs11.readFileSync)(receiptPath, "utf-8");
7669
+ if ((0, import_node_fs12.existsSync)(receiptPath)) {
7670
+ const raw = (0, import_node_fs12.readFileSync)(receiptPath, "utf-8");
7576
7671
  for (const line of raw.split("\n")) {
7577
7672
  const trimmed = line.trim();
7578
7673
  if (!trimmed) continue;
@@ -7704,11 +7799,11 @@ function formatReportMarkdown(report) {
7704
7799
  lines.push("*Generated by protect-mcp \xB7 scopeblind.com*");
7705
7800
  return lines.join("\n");
7706
7801
  }
7707
- var import_node_fs11;
7802
+ var import_node_fs12;
7708
7803
  var init_report = __esm({
7709
7804
  "src/report.ts"() {
7710
7805
  "use strict";
7711
- import_node_fs11 = require("fs");
7806
+ import_node_fs12 = require("fs");
7712
7807
  }
7713
7808
  });
7714
7809
 
@@ -8752,8 +8847,8 @@ Next: run \`npx protect-mcp dashboard --open\` and review tool inventory, policy
8752
8847
 
8753
8848
  // src/cli.ts
8754
8849
  var import_node_crypto7 = require("crypto");
8755
- var import_node_fs12 = require("fs");
8756
- var import_node_path8 = require("path");
8850
+ var import_node_fs13 = require("fs");
8851
+ var import_node_path9 = require("path");
8757
8852
  var import_node_os = require("os");
8758
8853
  function printHelp() {
8759
8854
  process.stderr.write(`
@@ -8775,14 +8870,16 @@ Usage:
8775
8870
  protect-mcp policy-packs list|show|install [pack] [--dir ./cedar] [--force]
8776
8871
  protect-mcp connect
8777
8872
  protect-mcp init [--dir <path>]
8873
+ protect-mcp sample [--dir <path>] [--force]
8778
8874
  protect-mcp demo
8779
8875
  protect-mcp trace <receipt_id> [--endpoint <url>] [--depth <n>]
8780
8876
  protect-mcp status [--dir <path>]
8781
8877
  protect-mcp digest [--today] [--dir <path>]
8782
8878
  protect-mcp receipts [--last <n>] [--dir <path>]
8783
8879
  protect-mcp record [--dir <path>] [--live] [--no-open]
8784
- protect-mcp claim [--no <cap>] [--only <c,c>] [--count <verdict>] [--dir <path>] [--output <path>]
8785
- protect-mcp verify-claim <claim.json> [--key <public-hex>]
8880
+ protect-mcp claim [--no <cap>] [--only <c,c>] [--count <verdict>] [--payment-under <amount>] [--anchor] [--dir <path>] [--output <path>]
8881
+ protect-mcp verify-claim <claim.json> [--key <public-hex>] [--check-anchor] [--offline]
8882
+ protect-mcp anchor-record [--dir <path>] [--force]
8786
8883
  protect-mcp bundle [--output <path>] [--dir <path>]
8787
8884
  protect-mcp simulate --policy <path> [--log <path>] [--tier <tier>] [--json]
8788
8885
  protect-mcp report [--period <days>d] [--format md|json] [--output <path>] [--dir <path>]
@@ -8796,6 +8893,7 @@ Options:
8796
8893
  --port <port> HTTP server port (default: 3000 for --http, 9377 for serve)
8797
8894
  --verbose Enable debug logging to stderr
8798
8895
  --help Show this help
8896
+ --version Print the installed version
8799
8897
 
8800
8898
  Commands:
8801
8899
  serve Start HTTP hook server for Claude Code integration (port 9377)
@@ -8906,17 +9004,17 @@ function parseArgs(argv) {
8906
9004
  return { policyPath, cedarDir, slug, enforce, verbose, childCommand };
8907
9005
  }
8908
9006
  async function handleInit(argv) {
8909
- const { writeFileSync: writeFileSync4, existsSync: existsSync9, mkdirSync: mkdirSync3 } = await import("fs");
8910
- const { join: join8 } = await import("path");
9007
+ const { writeFileSync: writeFileSync5, existsSync: existsSync10, mkdirSync: mkdirSync4 } = await import("fs");
9008
+ const { join: join9 } = await import("path");
8911
9009
  let dir = process.cwd();
8912
9010
  const dirIdx = argv.indexOf("--dir");
8913
9011
  if (dirIdx !== -1 && argv[dirIdx + 1]) {
8914
9012
  dir = argv[dirIdx + 1];
8915
9013
  }
8916
- const configPath = join8(dir, "protect-mcp.json");
8917
- const keysDir = join8(dir, "keys");
8918
- const keyPath = join8(keysDir, "gateway.json");
8919
- if (existsSync9(configPath)) {
9014
+ const configPath = join9(dir, "protect-mcp.json");
9015
+ const keysDir = join9(dir, "keys");
9016
+ const keyPath = join9(keysDir, "gateway.json");
9017
+ if (existsSync10(configPath)) {
8920
9018
  process.stderr.write(`[PROTECT_MCP] Config already exists at ${configPath}
8921
9019
  `);
8922
9020
  process.stderr.write("[PROTECT_MCP] Delete it first if you want to regenerate.\n");
@@ -8935,19 +9033,19 @@ async function handleInit(argv) {
8935
9033
  kid: "generated"
8936
9034
  };
8937
9035
  }
8938
- if (!existsSync9(keysDir)) {
8939
- mkdirSync3(keysDir, { recursive: true });
9036
+ if (!existsSync10(keysDir)) {
9037
+ mkdirSync4(keysDir, { recursive: true });
8940
9038
  }
8941
- writeFileSync4(keyPath, JSON.stringify({
9039
+ writeFileSync5(keyPath, JSON.stringify({
8942
9040
  privateKey: keypair.privateKey,
8943
9041
  publicKey: keypair.publicKey,
8944
9042
  kid: keypair.kid,
8945
9043
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
8946
9044
  warning: "KEEP THIS FILE SECRET. Never commit to version control."
8947
9045
  }, null, 2) + "\n");
8948
- const gitignorePath = join8(keysDir, ".gitignore");
8949
- if (!existsSync9(gitignorePath)) {
8950
- writeFileSync4(gitignorePath, "# Never commit signing keys\n*.json\n");
9046
+ const gitignorePath = join9(keysDir, ".gitignore");
9047
+ if (!existsSync10(gitignorePath)) {
9048
+ writeFileSync5(gitignorePath, "# Never commit signing keys\n*.json\n");
8951
9049
  }
8952
9050
  const config = {
8953
9051
  tools: {
@@ -8981,7 +9079,7 @@ async function handleInit(argv) {
8981
9079
  }
8982
9080
  }
8983
9081
  };
8984
- writeFileSync4(configPath, JSON.stringify(config, null, 2) + "\n");
9082
+ writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
8985
9083
  const claudeConfig = {
8986
9084
  "mcpServers": {
8987
9085
  "my-server": {
@@ -9019,8 +9117,8 @@ Add --enforce when ready to block policy violations.
9019
9117
  `);
9020
9118
  }
9021
9119
  async function handleDemo() {
9022
- const { existsSync: existsSync9 } = await import("fs");
9023
- const { join: join8, dirname: dirname3, resolve } = await import("path");
9120
+ const { existsSync: existsSync10 } = await import("fs");
9121
+ const { join: join9, dirname: dirname3, resolve } = await import("path");
9024
9122
  const { realpathSync } = await import("fs");
9025
9123
  const cliPath = resolve(process.argv[1] || "dist/cli.js");
9026
9124
  let cliDir;
@@ -9029,9 +9127,9 @@ async function handleDemo() {
9029
9127
  } catch {
9030
9128
  cliDir = dirname3(cliPath);
9031
9129
  }
9032
- const demoServerPath = join8(cliDir, "demo-server.js");
9033
- const configPath = join8(process.cwd(), "protect-mcp.json");
9034
- const hasConfig = existsSync9(configPath);
9130
+ const demoServerPath = join9(cliDir, "demo-server.js");
9131
+ const configPath = join9(process.cwd(), "protect-mcp.json");
9132
+ const hasConfig = existsSync10(configPath);
9035
9133
  if (!hasConfig) {
9036
9134
  process.stderr.write(`
9037
9135
  ${bold("protect-mcp demo")}
@@ -9105,15 +9203,15 @@ Starting demo server with 5 tools...
9105
9203
  await gateway.start();
9106
9204
  }
9107
9205
  async function handleStatus2(argv) {
9108
- const { readFileSync: readFileSync11, existsSync: existsSync9 } = await import("fs");
9109
- const { join: join8 } = await import("path");
9206
+ const { readFileSync: readFileSync11, existsSync: existsSync10 } = await import("fs");
9207
+ const { join: join9 } = await import("path");
9110
9208
  let dir = process.cwd();
9111
9209
  const dirIdx = argv.indexOf("--dir");
9112
9210
  if (dirIdx !== -1 && argv[dirIdx + 1]) {
9113
9211
  dir = argv[dirIdx + 1];
9114
9212
  }
9115
- const logPath = join8(dir, ".protect-mcp-log.jsonl");
9116
- if (!existsSync9(logPath)) {
9213
+ const logPath = join9(dir, ".protect-mcp-log.jsonl");
9214
+ if (!existsSync10(logPath)) {
9117
9215
  process.stderr.write(`${bold("protect-mcp status")}
9118
9216
 
9119
9217
  `);
@@ -9202,8 +9300,8 @@ ${bold("protect-mcp status")}
9202
9300
  process.stdout.write(` ${reason.padEnd(25)} ${count}
9203
9301
  `);
9204
9302
  }
9205
- const evidencePath = join8(dir, ".protect-mcp-evidence.json");
9206
- if (existsSync9(evidencePath)) {
9303
+ const evidencePath = join9(dir, ".protect-mcp-evidence.json");
9304
+ if (existsSync10(evidencePath)) {
9207
9305
  try {
9208
9306
  const evidenceRaw = readFileSync11(evidencePath, "utf-8");
9209
9307
  const evidence = JSON.parse(evidenceRaw);
@@ -9214,8 +9312,8 @@ ${bold("protect-mcp status")}
9214
9312
  } catch {
9215
9313
  }
9216
9314
  }
9217
- const keyPath = join8(dir, "keys", "gateway.json");
9218
- if (existsSync9(keyPath)) {
9315
+ const keyPath = join9(dir, "keys", "gateway.json");
9316
+ if (existsSync10(keyPath)) {
9219
9317
  try {
9220
9318
  const keyData = JSON.parse(readFileSync11(keyPath, "utf-8"));
9221
9319
  if (keyData.publicKey) {
@@ -9245,7 +9343,7 @@ function commandNeedsValue(argv, flag) {
9245
9343
  return Boolean(value && !value.startsWith("--"));
9246
9344
  }
9247
9345
  function absoluteOrCwd(pathValue) {
9248
- return (0, import_node_path8.resolve)(process.cwd(), pathValue);
9346
+ return (0, import_node_path9.resolve)(process.cwd(), pathValue);
9249
9347
  }
9250
9348
  function shellQuoteArg(arg) {
9251
9349
  if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(arg)) return arg;
@@ -9264,18 +9362,18 @@ function wrapperArgsFor(command, opts) {
9264
9362
  }
9265
9363
  function claudeDesktopConfigPath() {
9266
9364
  if (process.platform === "darwin") {
9267
- return (0, import_node_path8.join)((0, import_node_os.homedir)(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
9365
+ return (0, import_node_path9.join)((0, import_node_os.homedir)(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
9268
9366
  }
9269
9367
  if (process.platform === "win32") {
9270
- return (0, import_node_path8.join)(process.env.APPDATA || (0, import_node_path8.join)((0, import_node_os.homedir)(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
9368
+ return (0, import_node_path9.join)(process.env.APPDATA || (0, import_node_path9.join)((0, import_node_os.homedir)(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
9271
9369
  }
9272
- return (0, import_node_path8.join)((0, import_node_os.homedir)(), ".config", "Claude", "claude_desktop_config.json");
9370
+ return (0, import_node_path9.join)((0, import_node_os.homedir)(), ".config", "Claude", "claude_desktop_config.json");
9273
9371
  }
9274
9372
  async function ensureLocalConfig(dir = process.cwd()) {
9275
- const { existsSync: existsSync9 } = await import("fs");
9276
- const { join: join8, resolve } = await import("path");
9277
- const configPath = join8(dir, "protect-mcp.json");
9278
- if (!existsSync9(configPath)) {
9373
+ const { existsSync: existsSync10 } = await import("fs");
9374
+ const { join: join9, resolve } = await import("path");
9375
+ const configPath = join9(dir, "protect-mcp.json");
9376
+ if (!existsSync10(configPath)) {
9279
9377
  process.stderr.write(`${bold("protect-mcp wrap")}
9280
9378
 
9281
9379
  No protect-mcp.json found; creating local shadow-mode config first.
@@ -9287,7 +9385,7 @@ No protect-mcp.json found; creating local shadow-mode config first.
9287
9385
  }
9288
9386
  function parseJsonlFile(pathValue) {
9289
9387
  try {
9290
- const raw = (0, import_node_fs12.readFileSync)(pathValue, "utf-8");
9388
+ const raw = (0, import_node_fs13.readFileSync)(pathValue, "utf-8");
9291
9389
  return raw.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
9292
9390
  try {
9293
9391
  return [JSON.parse(line)];
@@ -9301,7 +9399,7 @@ function parseJsonlFile(pathValue) {
9301
9399
  }
9302
9400
  function parseJsonlRecords(pathValue) {
9303
9401
  try {
9304
- const raw = (0, import_node_fs12.readFileSync)(pathValue, "utf-8");
9402
+ const raw = (0, import_node_fs13.readFileSync)(pathValue, "utf-8");
9305
9403
  return raw.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
9306
9404
  try {
9307
9405
  return [{
@@ -9319,8 +9417,8 @@ function parseJsonlRecords(pathValue) {
9319
9417
  }
9320
9418
  function loadPolicyJson(policyPath) {
9321
9419
  try {
9322
- if (!(0, import_node_fs12.existsSync)(policyPath)) return null;
9323
- return JSON.parse((0, import_node_fs12.readFileSync)(policyPath, "utf-8"));
9420
+ if (!(0, import_node_fs13.existsSync)(policyPath)) return null;
9421
+ return JSON.parse((0, import_node_fs13.readFileSync)(policyPath, "utf-8"));
9324
9422
  } catch {
9325
9423
  return null;
9326
9424
  }
@@ -9465,10 +9563,10 @@ function suggestedGuardrailFor(_tool, risk, reasons) {
9465
9563
  policy: { rate_limit: "100/hour" }
9466
9564
  };
9467
9565
  }
9468
- function buildDashboardSummary(dir, policyPath = (0, import_node_path8.join)(dir, "protect-mcp.json")) {
9469
- const logPath = (0, import_node_path8.join)(dir, ".protect-mcp-log.jsonl");
9470
- const receiptPath = (0, import_node_path8.join)(dir, ".protect-mcp-receipts.jsonl");
9471
- const keyPath = (0, import_node_path8.join)(dir, "keys", "gateway.json");
9566
+ function buildDashboardSummary(dir, policyPath = (0, import_node_path9.join)(dir, "protect-mcp.json")) {
9567
+ const logPath = (0, import_node_path9.join)(dir, ".protect-mcp-log.jsonl");
9568
+ const receiptPath = (0, import_node_path9.join)(dir, ".protect-mcp-receipts.jsonl");
9569
+ const keyPath = (0, import_node_path9.join)(dir, "keys", "gateway.json");
9472
9570
  const entries = parseJsonlFile(logPath);
9473
9571
  const receiptRecords = parseJsonlRecords(receiptPath);
9474
9572
  const receipts = receiptRecords.map((record) => record.value);
@@ -9513,9 +9611,9 @@ function buildDashboardSummary(dir, policyPath = (0, import_node_path8.join)(dir
9513
9611
  const pendingApprovals = entries.filter((e) => e.decision === "require_approval").slice(-25).reverse();
9514
9612
  const chains = buildReceiptChains(entries, receiptRecords);
9515
9613
  let key = null;
9516
- if ((0, import_node_fs12.existsSync)(keyPath)) {
9614
+ if ((0, import_node_fs13.existsSync)(keyPath)) {
9517
9615
  try {
9518
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(keyPath, "utf-8"));
9616
+ const parsed = JSON.parse((0, import_node_fs13.readFileSync)(keyPath, "utf-8"));
9519
9617
  key = {
9520
9618
  kid: parsed.kid || null,
9521
9619
  issuer: parsed.issuer || "protect-mcp",
@@ -9532,10 +9630,10 @@ function buildDashboardSummary(dir, policyPath = (0, import_node_path8.join)(dir
9532
9630
  receipts: receiptPath,
9533
9631
  key: keyPath,
9534
9632
  policy: policyPath,
9535
- log_exists: (0, import_node_fs12.existsSync)(logPath),
9536
- receipts_exist: (0, import_node_fs12.existsSync)(receiptPath),
9537
- key_exists: (0, import_node_fs12.existsSync)(keyPath),
9538
- policy_exists: (0, import_node_fs12.existsSync)(policyPath)
9633
+ log_exists: (0, import_node_fs13.existsSync)(logPath),
9634
+ receipts_exist: (0, import_node_fs13.existsSync)(receiptPath),
9635
+ key_exists: (0, import_node_fs13.existsSync)(keyPath),
9636
+ policy_exists: (0, import_node_fs13.existsSync)(policyPath)
9539
9637
  },
9540
9638
  totals: {
9541
9639
  decisions: entries.length,
@@ -9572,7 +9670,7 @@ function buildDashboardSummary(dir, policyPath = (0, import_node_path8.join)(dir
9572
9670
  }))
9573
9671
  },
9574
9672
  connector_pilots: {
9575
- directory: (0, import_node_path8.join)(dir, ".protect-mcp", "connectors"),
9673
+ directory: (0, import_node_path9.join)(dir, ".protect-mcp", "connectors"),
9576
9674
  installed: readInstalledConnectorPilots(dir),
9577
9675
  doctor: connectorDoctor(dir),
9578
9676
  available: CONNECTOR_PILOTS.map((pilot) => ({
@@ -9950,7 +10048,7 @@ async function handleDashboard(argv) {
9950
10048
  const { resolve } = await import("path");
9951
10049
  const port = commandNeedsValue(argv, "--port") ? parseInt(flagValue(argv, "--port") || "9877", 10) : 9877;
9952
10050
  const dir = resolve(commandNeedsValue(argv, "--dir") ? flagValue(argv, "--dir") || process.cwd() : process.cwd());
9953
- const policyPath = resolve(flagValue(argv, "--policy") || (0, import_node_path8.join)(dir, "protect-mcp.json"));
10051
+ const policyPath = resolve(flagValue(argv, "--policy") || (0, import_node_path9.join)(dir, "protect-mcp.json"));
9954
10052
  const approvalEndpoint = flagValue(argv, "--approval-endpoint");
9955
10053
  const approvalNonce = flagValue(argv, "--approval-nonce");
9956
10054
  const open = argv.includes("--open");
@@ -10155,32 +10253,32 @@ function writeToolPolicy(policyPath, tool, action) {
10155
10253
  tools,
10156
10254
  default_tier: existing.default_tier || "unknown"
10157
10255
  };
10158
- (0, import_node_fs12.writeFileSync)(policyPath, JSON.stringify(next, null, 2) + "\n");
10256
+ (0, import_node_fs13.writeFileSync)(policyPath, JSON.stringify(next, null, 2) + "\n");
10159
10257
  return next;
10160
10258
  }
10161
10259
  function policyPackDirectory(dir) {
10162
- return (0, import_node_path8.join)(dir, "cedar");
10260
+ return (0, import_node_path9.join)(dir, "cedar");
10163
10261
  }
10164
10262
  function installedPolicyPackIds(dir) {
10165
10263
  const cedarDir = policyPackDirectory(dir);
10166
10264
  return POLICY_PACKS.filter(
10167
- (pack) => pack.files.every((file) => (0, import_node_fs12.existsSync)((0, import_node_path8.join)(cedarDir, file.path)))
10265
+ (pack) => pack.files.every((file) => (0, import_node_fs13.existsSync)((0, import_node_path9.join)(cedarDir, file.path)))
10168
10266
  ).map((pack) => pack.id);
10169
10267
  }
10170
10268
  function installPolicyPackToDir(dir, packId, force = false) {
10171
10269
  const packs = packId === "all" ? POLICY_PACKS : [getPolicyPack(packId)].filter(Boolean);
10172
10270
  if (packs.length === 0) throw new Error(`Unknown policy pack: ${packId}`);
10173
10271
  const outDir = policyPackDirectory(dir);
10174
- (0, import_node_fs12.mkdirSync)(outDir, { recursive: true });
10272
+ (0, import_node_fs13.mkdirSync)(outDir, { recursive: true });
10175
10273
  const written = [];
10176
10274
  for (const pack of packs) {
10177
10275
  for (const file of pack.files) {
10178
- const outPath = (0, import_node_path8.join)(outDir, file.path);
10179
- if ((0, import_node_fs12.existsSync)(outPath) && !force) {
10276
+ const outPath = (0, import_node_path9.join)(outDir, file.path);
10277
+ if ((0, import_node_fs13.existsSync)(outPath) && !force) {
10180
10278
  throw new Error(`Refusing to overwrite ${outPath}. Pass force=true if intentional.`);
10181
10279
  }
10182
- (0, import_node_fs12.mkdirSync)((0, import_node_path8.dirname)(outPath), { recursive: true });
10183
- (0, import_node_fs12.writeFileSync)(outPath, file.contents.endsWith("\n") ? file.contents : `${file.contents}
10280
+ (0, import_node_fs13.mkdirSync)((0, import_node_path9.dirname)(outPath), { recursive: true });
10281
+ (0, import_node_fs13.writeFileSync)(outPath, file.contents.endsWith("\n") ? file.contents : `${file.contents}
10184
10282
  `);
10185
10283
  written.push(outPath);
10186
10284
  }
@@ -10188,19 +10286,19 @@ function installPolicyPackToDir(dir, packId, force = false) {
10188
10286
  return { dir: outDir, written, packs: packs.map((pack) => pack.id) };
10189
10287
  }
10190
10288
  function dashboardRegistryStatus(dir) {
10191
- const identityPath = (0, import_node_path8.join)(dir, ".protect-mcp-org.json");
10192
- const registryPath = (0, import_node_path8.join)(dir, ".protect-mcp-registry.json");
10193
- const verifierPath = (0, import_node_path8.join)(dir, "scopeblind-verifier.html");
10194
- const identity = (0, import_node_fs12.existsSync)(identityPath) ? (() => {
10289
+ const identityPath = (0, import_node_path9.join)(dir, ".protect-mcp-org.json");
10290
+ const registryPath = (0, import_node_path9.join)(dir, ".protect-mcp-registry.json");
10291
+ const verifierPath = (0, import_node_path9.join)(dir, "scopeblind-verifier.html");
10292
+ const identity = (0, import_node_fs13.existsSync)(identityPath) ? (() => {
10195
10293
  try {
10196
- return JSON.parse((0, import_node_fs12.readFileSync)(identityPath, "utf-8"));
10294
+ return JSON.parse((0, import_node_fs13.readFileSync)(identityPath, "utf-8"));
10197
10295
  } catch {
10198
10296
  return null;
10199
10297
  }
10200
10298
  })() : null;
10201
- const registry = (0, import_node_fs12.existsSync)(registryPath) ? (() => {
10299
+ const registry = (0, import_node_fs13.existsSync)(registryPath) ? (() => {
10202
10300
  try {
10203
- return JSON.parse((0, import_node_fs12.readFileSync)(registryPath, "utf-8"));
10301
+ return JSON.parse((0, import_node_fs13.readFileSync)(registryPath, "utf-8"));
10204
10302
  } catch {
10205
10303
  return null;
10206
10304
  }
@@ -10208,9 +10306,9 @@ function dashboardRegistryStatus(dir) {
10208
10306
  const anchors = Array.isArray(registry?.anchors) ? registry.anchors : [];
10209
10307
  const hosted = anchors.some((anchor) => anchor.timestamp_source === "scopeblind-hosted");
10210
10308
  return {
10211
- identity_exists: (0, import_node_fs12.existsSync)(identityPath),
10212
- registry_exists: (0, import_node_fs12.existsSync)(registryPath),
10213
- verifier_exists: (0, import_node_fs12.existsSync)(verifierPath),
10309
+ identity_exists: (0, import_node_fs13.existsSync)(identityPath),
10310
+ registry_exists: (0, import_node_fs13.existsSync)(registryPath),
10311
+ verifier_exists: (0, import_node_fs13.existsSync)(verifierPath),
10214
10312
  identity_path: identityPath,
10215
10313
  registry_path: registryPath,
10216
10314
  verifier_path: verifierPath,
@@ -10231,13 +10329,13 @@ async function readJsonBody(req) {
10231
10329
  }
10232
10330
  async function buildAuditBundleForDir(dir) {
10233
10331
  const { createAuditBundle: createAuditBundle2 } = await Promise.resolve().then(() => (init_bundle(), bundle_exports));
10234
- const receiptPath = (0, import_node_path8.join)(dir, ".protect-mcp-receipts.jsonl");
10235
- const keyPath = (0, import_node_path8.join)(dir, "keys", "gateway.json");
10236
- if (!(0, import_node_fs12.existsSync)(receiptPath)) throw new Error("No receipt file found.");
10237
- if (!(0, import_node_fs12.existsSync)(keyPath)) throw new Error("No signing key found.");
10332
+ const receiptPath = (0, import_node_path9.join)(dir, ".protect-mcp-receipts.jsonl");
10333
+ const keyPath = (0, import_node_path9.join)(dir, "keys", "gateway.json");
10334
+ if (!(0, import_node_fs13.existsSync)(receiptPath)) throw new Error("No receipt file found.");
10335
+ if (!(0, import_node_fs13.existsSync)(keyPath)) throw new Error("No signing key found.");
10238
10336
  const receipts = parseJsonlFile(receiptPath);
10239
10337
  if (receipts.length === 0) throw new Error("No signed receipts found.");
10240
- const keyData = JSON.parse((0, import_node_fs12.readFileSync)(keyPath, "utf-8"));
10338
+ const keyData = JSON.parse((0, import_node_fs13.readFileSync)(keyPath, "utf-8"));
10241
10339
  return createAuditBundle2({
10242
10340
  tenant: keyData.issuer || "protect-mcp",
10243
10341
  receipts,
@@ -10255,17 +10353,17 @@ function collectSelectiveDisclosurePackages(dir) {
10255
10353
  const out = [];
10256
10354
  const seen = /* @__PURE__ */ new Set();
10257
10355
  const candidates = [];
10258
- const receiptsDir = (0, import_node_path8.join)(dir, "receipts");
10259
- if ((0, import_node_fs12.existsSync)(receiptsDir)) {
10260
- for (const name of (0, import_node_fs12.readdirSync)(receiptsDir)) {
10356
+ const receiptsDir = (0, import_node_path9.join)(dir, "receipts");
10357
+ if ((0, import_node_fs13.existsSync)(receiptsDir)) {
10358
+ for (const name of (0, import_node_fs13.readdirSync)(receiptsDir)) {
10261
10359
  if (name.includes("selective-disclosure") && name.endsWith(".json")) {
10262
- candidates.push((0, import_node_path8.join)(receiptsDir, name));
10360
+ candidates.push((0, import_node_path9.join)(receiptsDir, name));
10263
10361
  }
10264
10362
  }
10265
10363
  }
10266
- const jsonlPath = (0, import_node_path8.join)(dir, ".protect-mcp-selective-disclosures.jsonl");
10267
- if ((0, import_node_fs12.existsSync)(jsonlPath)) {
10268
- for (const line of (0, import_node_fs12.readFileSync)(jsonlPath, "utf-8").split("\n").map((s) => s.trim()).filter(Boolean)) {
10364
+ const jsonlPath = (0, import_node_path9.join)(dir, ".protect-mcp-selective-disclosures.jsonl");
10365
+ if ((0, import_node_fs13.existsSync)(jsonlPath)) {
10366
+ for (const line of (0, import_node_fs13.readFileSync)(jsonlPath, "utf-8").split("\n").map((s) => s.trim()).filter(Boolean)) {
10269
10367
  try {
10270
10368
  const parsed = JSON.parse(line);
10271
10369
  addSelectiveDisclosure(out, seen, parsed);
@@ -10275,7 +10373,7 @@ function collectSelectiveDisclosurePackages(dir) {
10275
10373
  }
10276
10374
  for (const path of candidates) {
10277
10375
  try {
10278
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf-8"));
10376
+ const parsed = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf-8"));
10279
10377
  addSelectiveDisclosure(out, seen, parsed);
10280
10378
  } catch {
10281
10379
  }
@@ -10308,7 +10406,7 @@ async function recordApprovalResolution(opts) {
10308
10406
  takeover_note: opts.body.takeover_note || void 0,
10309
10407
  payload_hash: opts.body.payload_hash || void 0
10310
10408
  };
10311
- (0, import_node_fs12.appendFileSync)((0, import_node_path8.join)(opts.dir, ".protect-mcp-approval-resolutions.jsonl"), JSON.stringify(record) + "\n");
10409
+ (0, import_node_fs13.appendFileSync)((0, import_node_path9.join)(opts.dir, ".protect-mcp-approval-resolutions.jsonl"), JSON.stringify(record) + "\n");
10312
10410
  let forwarded = null;
10313
10411
  if (resolution === "approve" && opts.approvalEndpoint && opts.approvalNonce) {
10314
10412
  const endpoint = opts.approvalEndpoint.replace(/\/$/, "") + "/approve";
@@ -10331,7 +10429,7 @@ async function recordApprovalResolution(opts) {
10331
10429
  return { recorded: true, resolution: record, forwarded };
10332
10430
  }
10333
10431
  async function handleRecommend(argv) {
10334
- const { writeFileSync: writeFileSync4 } = await import("fs");
10432
+ const { writeFileSync: writeFileSync5 } = await import("fs");
10335
10433
  const { resolve } = await import("path");
10336
10434
  const dir = resolve(commandNeedsValue(argv, "--dir") ? flagValue(argv, "--dir") || process.cwd() : process.cwd());
10337
10435
  const outputPath = resolve(flagValue(argv, "--output") || "protect-mcp.recommended.json");
@@ -10380,7 +10478,7 @@ Dry run only. Write the policy with:
10380
10478
  process.stdout.write(dim(body));
10381
10479
  return;
10382
10480
  }
10383
- writeFileSync4(outputPath, body);
10481
+ writeFileSync5(outputPath, body);
10384
10482
  process.stdout.write(`
10385
10483
  ${green("\u2713 Wrote recommended policy")}
10386
10484
  `);
@@ -10393,7 +10491,7 @@ ${green("\u2713 Wrote recommended policy")}
10393
10491
  `);
10394
10492
  }
10395
10493
  async function handleWrap(argv) {
10396
- const { existsSync: existsSync9, readFileSync: readFileSync11, writeFileSync: writeFileSync4 } = await import("fs");
10494
+ const { existsSync: existsSync10, readFileSync: readFileSync11, writeFileSync: writeFileSync5 } = await import("fs");
10397
10495
  const { resolve } = await import("path");
10398
10496
  const configFlag = flagValue(argv, "--config");
10399
10497
  const cedarFlag = flagValue(argv, "--cedar");
@@ -10430,7 +10528,7 @@ ${bold("protect-mcp wrap")}
10430
10528
  return;
10431
10529
  }
10432
10530
  const claudePath = resolve(flagValue(argv, "--path") || claudeDesktopConfigPath());
10433
- if (!claudeDesktop && !existsSync9(claudePath)) {
10531
+ if (!claudeDesktop && !existsSync10(claudePath)) {
10434
10532
  process.stdout.write(`
10435
10533
  ${bold("protect-mcp wrap")}
10436
10534
 
@@ -10447,7 +10545,7 @@ ${bold("protect-mcp wrap")}
10447
10545
  `);
10448
10546
  return;
10449
10547
  }
10450
- if (!existsSync9(claudePath)) {
10548
+ if (!existsSync10(claudePath)) {
10451
10549
  process.stderr.write(`protect-mcp wrap: Claude Desktop config not found at ${claudePath}
10452
10550
  `);
10453
10551
  process.exit(1);
@@ -10518,8 +10616,8 @@ Dry run only. Apply with:
10518
10616
  return;
10519
10617
  }
10520
10618
  const backupPath = `${claudePath}.bak.${Date.now()}`;
10521
- writeFileSync4(backupPath, readFileSync11(claudePath, "utf-8"));
10522
- writeFileSync4(claudePath, JSON.stringify(next, null, 2) + "\n");
10619
+ writeFileSync5(backupPath, readFileSync11(claudePath, "utf-8"));
10620
+ writeFileSync5(claudePath, JSON.stringify(next, null, 2) + "\n");
10523
10621
  process.stdout.write(`
10524
10622
  ${green("\u2713 Claude Desktop config updated")}
10525
10623
  `);
@@ -10545,14 +10643,14 @@ function yellow(s) {
10545
10643
  return process.env.NO_COLOR ? s : `\x1B[33m${s}\x1B[0m`;
10546
10644
  }
10547
10645
  async function handleDigest(argv) {
10548
- const { readFileSync: readFileSync11, existsSync: existsSync9 } = await import("fs");
10549
- const { join: join8 } = await import("path");
10646
+ const { readFileSync: readFileSync11, existsSync: existsSync10 } = await import("fs");
10647
+ const { join: join9 } = await import("path");
10550
10648
  let dir = process.cwd();
10551
10649
  const dirIdx = argv.indexOf("--dir");
10552
10650
  if (dirIdx !== -1 && argv[dirIdx + 1]) dir = argv[dirIdx + 1];
10553
10651
  const today = argv.includes("--today");
10554
- const logPath = join8(dir, ".protect-mcp-log.jsonl");
10555
- if (!existsSync9(logPath)) {
10652
+ const logPath = join9(dir, ".protect-mcp-log.jsonl");
10653
+ if (!existsSync10(logPath)) {
10556
10654
  process.stderr.write(`${bold("protect-mcp digest")}
10557
10655
 
10558
10656
  No log file found. Run protect-mcp first.
@@ -10636,15 +10734,15 @@ ${bold("\u{1F6E1}\uFE0F Agent Daily Digest")}
10636
10734
  `);
10637
10735
  }
10638
10736
  async function handleReceipts2(argv) {
10639
- const { readFileSync: readFileSync11, existsSync: existsSync9 } = await import("fs");
10640
- const { join: join8 } = await import("path");
10737
+ const { readFileSync: readFileSync11, existsSync: existsSync10 } = await import("fs");
10738
+ const { join: join9 } = await import("path");
10641
10739
  let dir = process.cwd();
10642
10740
  const dirIdx = argv.indexOf("--dir");
10643
10741
  if (dirIdx !== -1 && argv[dirIdx + 1]) dir = argv[dirIdx + 1];
10644
10742
  const lastIdx = argv.indexOf("--last");
10645
10743
  const count = lastIdx !== -1 && argv[lastIdx + 1] ? parseInt(argv[lastIdx + 1], 10) : 20;
10646
- const receiptsPath = join8(dir, ".protect-mcp-receipts.jsonl");
10647
- if (!existsSync9(receiptsPath)) {
10744
+ const receiptsPath = join9(dir, ".protect-mcp-receipts.jsonl");
10745
+ if (!existsSync10(receiptsPath)) {
10648
10746
  process.stderr.write(`${bold("protect-mcp receipts")}
10649
10747
 
10650
10748
  No signed receipt file found. Run protect-mcp with signing enabled first.
@@ -10678,19 +10776,19 @@ async function pkgVersion() {
10678
10776
  if (_pkgV) return _pkgV;
10679
10777
  let v = "0.0.0";
10680
10778
  try {
10681
- const { readFileSync: readFileSync11, existsSync: existsSync9, realpathSync } = await import("fs");
10682
- const { dirname: dirname3, join: join8, resolve } = await import("path");
10779
+ const { readFileSync: readFileSync11, existsSync: existsSync10, realpathSync } = await import("fs");
10780
+ const { dirname: dirname3, join: join9, resolve } = await import("path");
10683
10781
  let base = "";
10684
10782
  try {
10685
10783
  base = dirname3(realpathSync(resolve(process.argv[1] || "")));
10686
10784
  } catch {
10687
10785
  }
10688
10786
  const candidates = [
10689
- base ? join8(base, "..", "package.json") : "",
10690
- base ? join8(base, "package.json") : ""
10787
+ base ? join9(base, "..", "package.json") : "",
10788
+ base ? join9(base, "package.json") : ""
10691
10789
  ].filter(Boolean);
10692
10790
  for (const p of candidates) {
10693
- if (existsSync9(p)) {
10791
+ if (existsSync10(p)) {
10694
10792
  const parsed = JSON.parse(readFileSync11(p, "utf-8"));
10695
10793
  if (parsed && parsed.name === "protect-mcp" && parsed.version) {
10696
10794
  v = parsed.version;
@@ -10727,16 +10825,16 @@ function mapRecordEntry(e) {
10727
10825
  return { ts, tool, verdict, reason, hook, signed, caps, agent, dur, id: String(e.request_id || p.request_id || ""), digest, raw: e };
10728
10826
  }
10729
10827
  async function handleRecord(argv) {
10730
- const { readFileSync: readFileSync11, existsSync: existsSync9, writeFileSync: writeFileSync4 } = await import("fs");
10731
- const { join: join8 } = await import("path");
10828
+ const { readFileSync: readFileSync11, existsSync: existsSync10, writeFileSync: writeFileSync5 } = await import("fs");
10829
+ const { join: join9 } = await import("path");
10732
10830
  const osMod = await import("os");
10733
10831
  const cp = await import("child_process");
10734
10832
  let dir = process.cwd();
10735
10833
  const di = argv.indexOf("--dir");
10736
10834
  if (di !== -1 && argv[di + 1]) dir = argv[di + 1];
10737
- const recPath = join8(dir, ".protect-mcp-receipts.jsonl");
10738
- const logPath = join8(dir, ".protect-mcp-log.jsonl");
10739
- const pick = () => existsSync9(recPath) ? recPath : existsSync9(logPath) ? logPath : null;
10835
+ const recPath = join9(dir, ".protect-mcp-receipts.jsonl");
10836
+ const logPath = join9(dir, ".protect-mcp-log.jsonl");
10837
+ const pick = () => existsSync10(recPath) ? recPath : existsSync10(logPath) ? logPath : null;
10740
10838
  const chosen = pick();
10741
10839
  if (!chosen) {
10742
10840
  process.stderr.write(`
@@ -10761,7 +10859,7 @@ Start the gate with ${bold("npx protect-mcp serve")}, use your agent, then run t
10761
10859
  let pinnedKey = "";
10762
10860
  let pinnedKid = "";
10763
10861
  try {
10764
- const kd = JSON.parse(readFileSync11(join8(dir, "keys", "gateway.json"), "utf-8"));
10862
+ const kd = JSON.parse(readFileSync11(join9(dir, "keys", "gateway.json"), "utf-8"));
10765
10863
  if (kd && typeof kd.publicKey === "string" && /^[0-9a-f]{64}$/i.test(kd.publicKey)) {
10766
10864
  pinnedKey = kd.publicKey;
10767
10865
  pinnedKid = typeof kd.kid === "string" ? kd.kid : "";
@@ -10822,8 +10920,8 @@ ${bold("\u{1F6E1}\uFE0F Your record")} ${dim("\xB7")} live at ${url}
10822
10920
  const recs = readRecs(chosen);
10823
10921
  const meta = { file: chosen, signed: chosen === recPath, count: recs.length, live: false, pinned_key: pinnedKey, pinned_kid: pinnedKid };
10824
10922
  const html = RECORD_HTML.replace("__DATA__", () => JSON.stringify(recs)).replace("__META__", () => JSON.stringify(meta));
10825
- const out = join8(osMod.tmpdir(), "protect-mcp-record-" + Date.now() + ".html");
10826
- writeFileSync4(out, html);
10923
+ const out = join9(osMod.tmpdir(), "protect-mcp-record-" + Date.now() + ".html");
10924
+ writeFileSync5(out, html);
10827
10925
  openTarget(out);
10828
10926
  process.stdout.write(`
10829
10927
  ${bold("\u{1F6E1}\uFE0F Your record")} ${dim("\xB7")} ${recs.length} decision${recs.length === 1 ? "" : "s"}, all on this machine
@@ -10996,8 +11094,8 @@ render();kickVerify();
10996
11094
  if(META.live){var poll=function(){fetch('/data',{cache:'no-store'}).then(function(r){return r.json()}).then(function(d){var nr=d.recs||[];var changed=nr.length!==RECORDS.length;RECORDS=nr;META.count=RECORDS.length;if(typeof d.signed==='boolean')META.signed=d.signed;if(changed){render();kickVerify()}}).catch(function(){})};poll();setInterval(poll,2000);}
10997
11095
  </script></body></html>`;
10998
11096
  async function handleClaim(argv) {
10999
- const { readFileSync: readFileSync11, existsSync: existsSync9, writeFileSync: writeFileSync4 } = await import("fs");
11000
- const { join: join8 } = await import("path");
11097
+ const { readFileSync: readFileSync11, existsSync: existsSync10, writeFileSync: writeFileSync5 } = await import("fs");
11098
+ const { join: join9 } = await import("path");
11001
11099
  const { buildClaim: buildClaim2 } = await Promise.resolve().then(() => (init_claim(), claim_exports));
11002
11100
  let dir = process.cwd();
11003
11101
  const di = argv.indexOf("--dir");
@@ -11030,8 +11128,8 @@ Example: ${bold("npx protect-mcp claim --no net.egress --anchor")}
11030
11128
  process.exit(0);
11031
11129
  return;
11032
11130
  }
11033
- const keyPath = join8(dir, "keys", "gateway.json");
11034
- if (!existsSync9(keyPath)) {
11131
+ const keyPath = join9(dir, "keys", "gateway.json");
11132
+ if (!existsSync10(keyPath)) {
11035
11133
  process.stderr.write(`
11036
11134
  ${bold("protect-mcp claim")}
11037
11135
 
@@ -11060,8 +11158,8 @@ protect-mcp claim: ${keyPath} is missing privateKey/publicKey.
11060
11158
  process.exit(1);
11061
11159
  return;
11062
11160
  }
11063
- const recPath = join8(dir, ".protect-mcp-receipts.jsonl");
11064
- if (!existsSync9(recPath)) {
11161
+ const recPath = join9(dir, ".protect-mcp-receipts.jsonl");
11162
+ if (!existsSync10(recPath)) {
11065
11163
  process.stderr.write(`
11066
11164
  ${bold("protect-mcp claim")}
11067
11165
 
@@ -11088,8 +11186,8 @@ protect-mcp claim: no readable receipts in ${recPath}.
11088
11186
  }
11089
11187
  const pack = buildClaim2(receipts, predicate, { privateKey: key.privateKey, publicKey: key.publicKey, kid: key.kid || "gateway", issuer: "protect-mcp" }, (/* @__PURE__ */ new Date()).toISOString());
11090
11188
  const oi = argv.indexOf("--output");
11091
- const out = oi !== -1 && argv[oi + 1] ? argv[oi + 1] : join8(dir, "claim-" + Date.now() + ".json");
11092
- writeFileSync4(out, JSON.stringify(pack, null, 2) + "\n");
11189
+ const out = oi !== -1 && argv[oi + 1] ? argv[oi + 1] : join9(dir, "claim-" + Date.now() + ".json");
11190
+ writeFileSync5(out, JSON.stringify(pack, null, 2) + "\n");
11093
11191
  process.stdout.write(`
11094
11192
  ${bold("\u{1F6E1}\uFE0F Signed claim")}
11095
11193
  `);
@@ -11115,7 +11213,7 @@ ${bold("\u{1F6E1}\uFE0F Signed claim")}
11115
11213
  );
11116
11214
  if (res.ok) {
11117
11215
  const sidecar = out.replace(/\.json$/, "") + ".anchor.json";
11118
- writeFileSync4(sidecar, JSON.stringify({ log: logBase || "https://scopeblind.com", seq: res.seq, entry_url: res.entry_url, anchored_at: res.anchored_at, claim_digest: res.claim_digest, envelope: res.envelope }, null, 2) + "\n");
11216
+ writeFileSync5(sidecar, JSON.stringify({ log: logBase || "https://scopeblind.com", seq: res.seq, entry_url: res.entry_url, anchored_at: res.anchored_at, claim_digest: res.claim_digest, envelope: res.envelope }, null, 2) + "\n");
11119
11217
  process.stdout.write(` ${green("Anchored")} as log entry ${bold("#" + res.seq)}${res.already_anchored ? dim(" (already present)") : ""} ${dim(res.entry_url || "")}
11120
11218
  `);
11121
11219
  process.stdout.write(` ${dim("A counterparty can now confirm this exact claim existed at " + (res.anchored_at || "this time") + " and cannot be quietly re-cut.")}
@@ -11144,16 +11242,16 @@ ${bold("\u{1F6E1}\uFE0F Signed claim")}
11144
11242
  process.exit(0);
11145
11243
  }
11146
11244
  async function handleAnchorRecord(argv) {
11147
- const { readFileSync: readFileSync11, existsSync: existsSync9, appendFileSync: appendFileSync3 } = await import("fs");
11148
- const { join: join8 } = await import("path");
11245
+ const { readFileSync: readFileSync11, existsSync: existsSync10, appendFileSync: appendFileSync3 } = await import("fs");
11246
+ const { join: join9 } = await import("path");
11149
11247
  const { anchorRecordCheckpoint: anchorRecordCheckpoint2, buildRecordCheckpoint: buildRecordCheckpoint2, lookupPinnedIdentity: lookupPinnedIdentity2 } = await Promise.resolve().then(() => (init_claim(), claim_exports));
11150
11248
  let dir = process.cwd();
11151
11249
  const di = argv.indexOf("--dir");
11152
11250
  if (di !== -1 && argv[di + 1]) dir = argv[di + 1];
11153
11251
  const li = argv.indexOf("--log");
11154
11252
  const logBase = li !== -1 && argv[li + 1] ? argv[li + 1] : void 0;
11155
- const keyPath = join8(dir, "keys", "gateway.json");
11156
- if (!existsSync9(keyPath)) {
11253
+ const keyPath = join9(dir, "keys", "gateway.json");
11254
+ if (!existsSync10(keyPath)) {
11157
11255
  process.stderr.write(`
11158
11256
  ${bold("protect-mcp anchor-record")}
11159
11257
 
@@ -11182,8 +11280,8 @@ protect-mcp anchor-record: ${keyPath} is missing privateKey/publicKey.
11182
11280
  process.exit(1);
11183
11281
  return;
11184
11282
  }
11185
- const recPath = join8(dir, ".protect-mcp-receipts.jsonl");
11186
- if (!existsSync9(recPath)) {
11283
+ const recPath = join9(dir, ".protect-mcp-receipts.jsonl");
11284
+ if (!existsSync10(recPath)) {
11187
11285
  process.stderr.write(`
11188
11286
  ${bold("protect-mcp anchor-record")}
11189
11287
 
@@ -11209,9 +11307,9 @@ protect-mcp anchor-record: no readable receipts in ${recPath}.
11209
11307
  return;
11210
11308
  }
11211
11309
  const claimKey = { privateKey: key.privateKey, publicKey: key.publicKey, kid: key.kid || "gateway", issuer: "protect-mcp" };
11212
- const historyPath = join8(dir, ".protect-mcp-anchors.jsonl");
11310
+ const historyPath = join9(dir, ".protect-mcp-anchors.jsonl");
11213
11311
  const preview = buildRecordCheckpoint2(receipts, claimKey, "preview");
11214
- if (!argv.includes("--force") && existsSync9(historyPath)) {
11312
+ if (!argv.includes("--force") && existsSync10(historyPath)) {
11215
11313
  const lines = readFileSync11(historyPath, "utf-8").split(/\r?\n/).filter(Boolean);
11216
11314
  const last = lines.length ? (() => {
11217
11315
  try {
@@ -11270,10 +11368,10 @@ ${bold("\u{1F6E1}\uFE0F Record checkpoint")}
11270
11368
  process.exit(0);
11271
11369
  }
11272
11370
  async function handleVerifyClaim(argv) {
11273
- const { readFileSync: readFileSync11, existsSync: existsSync9 } = await import("fs");
11371
+ const { readFileSync: readFileSync11, existsSync: existsSync10 } = await import("fs");
11274
11372
  const { verifyClaim: verifyClaim2 } = await Promise.resolve().then(() => (init_claim(), claim_exports));
11275
11373
  const file = argv.find((a) => !a.startsWith("--"));
11276
- if (!file || !existsSync9(file)) {
11374
+ if (!file || !existsSync10(file)) {
11277
11375
  process.stderr.write(`
11278
11376
  ${bold("protect-mcp verify-claim")} <claim.json> [--key <public-hex>]
11279
11377
 
@@ -11322,7 +11420,7 @@ ${bold("protect-mcp verify-claim")}
11322
11420
  const sidecarPath = ai !== -1 && argv[ai + 1] ? argv[ai + 1] : file.replace(/\.json$/, "") + ".anchor.json";
11323
11421
  const requireAnchor = argv.includes("--check-anchor");
11324
11422
  let anchorOk = true;
11325
- if (existsSync9(sidecarPath)) {
11423
+ if (existsSync10(sidecarPath)) {
11326
11424
  const { checkClaimAnchor: checkClaimAnchor2 } = await Promise.resolve().then(() => (init_claim(), claim_exports));
11327
11425
  let sidecar = null;
11328
11426
  try {
@@ -11393,24 +11491,24 @@ ${bold("protect-mcp verify-claim")}
11393
11491
  process.exit(finalValid ? 0 : 1);
11394
11492
  }
11395
11493
  async function handleBundle(argv) {
11396
- const { readFileSync: readFileSync11, writeFileSync: writeFileSync4, existsSync: existsSync9 } = await import("fs");
11397
- const { join: join8 } = await import("path");
11494
+ const { readFileSync: readFileSync11, writeFileSync: writeFileSync5, existsSync: existsSync10 } = await import("fs");
11495
+ const { join: join9 } = await import("path");
11398
11496
  const { createAuditBundle: createAuditBundle2 } = await Promise.resolve().then(() => (init_bundle(), bundle_exports));
11399
11497
  let dir = process.cwd();
11400
11498
  const dirIdx = argv.indexOf("--dir");
11401
11499
  if (dirIdx !== -1 && argv[dirIdx + 1]) dir = argv[dirIdx + 1];
11402
11500
  const outputIdx = argv.indexOf("--output");
11403
- const outputPath = outputIdx !== -1 && argv[outputIdx + 1] ? argv[outputIdx + 1] : join8(dir, "audit-bundle.json");
11404
- const receiptsPath = join8(dir, ".protect-mcp-receipts.jsonl");
11405
- const keyPath = join8(dir, "keys", "gateway.json");
11406
- if (!existsSync9(receiptsPath)) {
11501
+ const outputPath = outputIdx !== -1 && argv[outputIdx + 1] ? argv[outputIdx + 1] : join9(dir, "audit-bundle.json");
11502
+ const receiptsPath = join9(dir, ".protect-mcp-receipts.jsonl");
11503
+ const keyPath = join9(dir, "keys", "gateway.json");
11504
+ if (!existsSync10(receiptsPath)) {
11407
11505
  process.stderr.write(`${bold("protect-mcp bundle")}
11408
11506
 
11409
11507
  No signed receipt file found. Run protect-mcp with signing enabled first.
11410
11508
  `);
11411
11509
  process.exit(0);
11412
11510
  }
11413
- if (!existsSync9(keyPath)) {
11511
+ if (!existsSync10(keyPath)) {
11414
11512
  process.stderr.write(`${bold("protect-mcp bundle")}
11415
11513
 
11416
11514
  No key file found at ${keyPath}
@@ -11431,7 +11529,7 @@ No key file found at ${keyPath}
11431
11529
  use: "sig"
11432
11530
  }]
11433
11531
  });
11434
- writeFileSync4(outputPath, JSON.stringify(bundle, null, 2) + "\n");
11532
+ writeFileSync5(outputPath, JSON.stringify(bundle, null, 2) + "\n");
11435
11533
  process.stdout.write(`
11436
11534
  ${bold("protect-mcp bundle")}
11437
11535
 
@@ -11447,8 +11545,8 @@ ${bold("protect-mcp bundle")}
11447
11545
  `);
11448
11546
  }
11449
11547
  async function createSandbox() {
11450
- const { mkdirSync: mkdirSync3, writeFileSync: writeFileSync4, existsSync: existsSync9, readFileSync: readFileSync11 } = await import("fs");
11451
- const { join: join8 } = await import("path");
11548
+ const { mkdirSync: mkdirSync4, writeFileSync: writeFileSync5, existsSync: existsSync10, readFileSync: readFileSync11 } = await import("fs");
11549
+ const { join: join9 } = await import("path");
11452
11550
  const { homedir } = await import("os");
11453
11551
  let response;
11454
11552
  try {
@@ -11478,19 +11576,19 @@ async function createSandbox() {
11478
11576
  return null;
11479
11577
  }
11480
11578
  const dashboardUrl = `https://scopeblind.com/t/${data.slug}`;
11481
- const configDir = join8(homedir(), ".protect-mcp");
11482
- if (!existsSync9(configDir)) {
11483
- mkdirSync3(configDir, { recursive: true });
11579
+ const configDir = join9(homedir(), ".protect-mcp");
11580
+ if (!existsSync10(configDir)) {
11581
+ mkdirSync4(configDir, { recursive: true });
11484
11582
  }
11485
- const configPath = join8(configDir, "config.json");
11583
+ const configPath = join9(configDir, "config.json");
11486
11584
  let existing = {};
11487
- if (existsSync9(configPath)) {
11585
+ if (existsSync10(configPath)) {
11488
11586
  try {
11489
11587
  existing = JSON.parse(readFileSync11(configPath, "utf-8"));
11490
11588
  } catch {
11491
11589
  }
11492
11590
  }
11493
- writeFileSync4(configPath, JSON.stringify({
11591
+ writeFileSync5(configPath, JSON.stringify({
11494
11592
  ...existing,
11495
11593
  sandbox_slug: data.slug,
11496
11594
  dashboard_url: dashboardUrl
@@ -11523,10 +11621,10 @@ ${"\u2500".repeat(50)}
11523
11621
  }
11524
11622
  async function handleQuickstart(argv) {
11525
11623
  const connectFlag = argv.includes("--connect");
11526
- const { mkdtempSync, writeFileSync: writeFileSync4, existsSync: existsSync9, mkdirSync: mkdirSync3, readFileSync: readFileSync11 } = await import("fs");
11527
- const { join: join8 } = await import("path");
11624
+ const { mkdtempSync, writeFileSync: writeFileSync5, existsSync: existsSync10, mkdirSync: mkdirSync4, readFileSync: readFileSync11 } = await import("fs");
11625
+ const { join: join9 } = await import("path");
11528
11626
  const { tmpdir } = await import("os");
11529
- const dir = mkdtempSync(join8(tmpdir(), "protect-mcp-quickstart-"));
11627
+ const dir = mkdtempSync(join9(tmpdir(), "protect-mcp-quickstart-"));
11530
11628
  process.stdout.write(`
11531
11629
  ${bold("protect-mcp quickstart")}
11532
11630
  `);
@@ -11551,8 +11649,8 @@ ${bold("protect-mcp quickstart")}
11551
11649
  Working dir: ${dir}
11552
11650
 
11553
11651
  `);
11554
- const keysDir = join8(dir, "keys");
11555
- mkdirSync3(keysDir, { recursive: true });
11652
+ const keysDir = join9(dir, "keys");
11653
+ mkdirSync4(keysDir, { recursive: true });
11556
11654
  const { randomBytes: randomBytes4 } = await import("crypto");
11557
11655
  let keypair;
11558
11656
  try {
@@ -11572,13 +11670,13 @@ ${bold("protect-mcp quickstart")}
11572
11670
  kid: `quickstart-${Date.now()}`
11573
11671
  };
11574
11672
  }
11575
- writeFileSync4(join8(keysDir, "gateway.json"), JSON.stringify({
11673
+ writeFileSync5(join9(keysDir, "gateway.json"), JSON.stringify({
11576
11674
  privateKey: keypair.privateKey,
11577
11675
  publicKey: keypair.publicKey,
11578
11676
  kid: keypair.kid,
11579
11677
  generated_at: (/* @__PURE__ */ new Date()).toISOString()
11580
11678
  }, null, 2) + "\n");
11581
- const configPath = join8(dir, "protect-mcp.json");
11679
+ const configPath = join9(dir, "protect-mcp.json");
11582
11680
  const config = {
11583
11681
  tools: {
11584
11682
  "*": { rate_limit: "100/hour" },
@@ -11586,12 +11684,12 @@ ${bold("protect-mcp quickstart")}
11586
11684
  },
11587
11685
  default_tier: "unknown",
11588
11686
  signing: {
11589
- key_path: join8(keysDir, "gateway.json"),
11687
+ key_path: join9(keysDir, "gateway.json"),
11590
11688
  issuer: "protect-mcp-quickstart",
11591
11689
  enabled: true
11592
11690
  }
11593
11691
  };
11594
- writeFileSync4(configPath, JSON.stringify(config, null, 2) + "\n");
11692
+ writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
11595
11693
  process.stdout.write(` \u2713 Keypair generated (kid: ${keypair.kid})
11596
11694
  `);
11597
11695
  process.stdout.write(` \u2713 Policy created (shadow mode, all tools logged)
@@ -11606,7 +11704,7 @@ ${bold("protect-mcp quickstart")}
11606
11704
  const dashboardUrl = await createSandbox();
11607
11705
  if (dashboardUrl) {
11608
11706
  const updatedConfig = { ...config, dashboard_url: dashboardUrl };
11609
- writeFileSync4(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
11707
+ writeFileSync5(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
11610
11708
  process.stdout.write(green(` \u2713 Dashboard created: ${dashboardUrl}
11611
11709
  `));
11612
11710
  process.stdout.write(` Receipts will be uploaded automatically.
@@ -11642,7 +11740,7 @@ ${bold("protect-mcp quickstart")}
11642
11740
  }
11643
11741
  async function handleRegistry(argv) {
11644
11742
  const subcommand = argv[0] || "status";
11645
- const dir = (0, import_node_path8.resolve)(flagValue(argv, "--dir") || process.cwd());
11743
+ const dir = (0, import_node_path9.resolve)(flagValue(argv, "--dir") || process.cwd());
11646
11744
  const orgName = flagValue(argv, "--org") || process.env.SCOPEBLIND_ORG;
11647
11745
  const orgId = flagValue(argv, "--org-id") || process.env.SCOPEBLIND_ORG_ID;
11648
11746
  const billingAccountId = flagValue(argv, "--billing-account") || process.env.SCOPEBLIND_BILLING_ACCOUNT;
@@ -11724,14 +11822,14 @@ ${bold("protect-mcp registry anchor")}
11724
11822
  return;
11725
11823
  }
11726
11824
  if (subcommand === "status") {
11727
- const registryPath = (0, import_node_path8.join)(dir, registryMod.REGISTRY_FILE);
11728
- const identityPath = (0, import_node_path8.join)(dir, registryMod.ORG_IDENTITY_FILE);
11825
+ const registryPath = (0, import_node_path9.join)(dir, registryMod.REGISTRY_FILE);
11826
+ const identityPath = (0, import_node_path9.join)(dir, registryMod.ORG_IDENTITY_FILE);
11729
11827
  process.stdout.write(`
11730
11828
  ${bold("protect-mcp registry status")}
11731
11829
 
11732
11830
  `);
11733
- if ((0, import_node_fs12.existsSync)(identityPath)) {
11734
- const identity = JSON.parse((0, import_node_fs12.readFileSync)(identityPath, "utf-8"));
11831
+ if ((0, import_node_fs13.existsSync)(identityPath)) {
11832
+ const identity = JSON.parse((0, import_node_fs13.readFileSync)(identityPath, "utf-8"));
11735
11833
  process.stdout.write(` Org: ${identity.org_name || "unknown"}
11736
11834
  `);
11737
11835
  process.stdout.write(` Org ID: ${identity.org_id || "unknown"}
@@ -11742,8 +11840,8 @@ ${bold("protect-mcp registry status")}
11742
11840
  process.stdout.write(` Org identity: ${yellow("missing")} (${identityPath})
11743
11841
  `);
11744
11842
  }
11745
- if ((0, import_node_fs12.existsSync)(registryPath)) {
11746
- const registry = JSON.parse((0, import_node_fs12.readFileSync)(registryPath, "utf-8"));
11843
+ if ((0, import_node_fs13.existsSync)(registryPath)) {
11844
+ const registry = JSON.parse((0, import_node_fs13.readFileSync)(registryPath, "utf-8"));
11747
11845
  const hosted = Array.isArray(registry.anchors) && registry.anchors.some((a) => a.timestamp_source === "scopeblind-hosted");
11748
11846
  process.stdout.write(` Registry: ${registryPath}
11749
11847
  `);
@@ -11753,7 +11851,7 @@ ${bold("protect-mcp registry status")}
11753
11851
  `);
11754
11852
  process.stdout.write(` Boundary: ${hosted ? green("hosted digest anchor") : yellow("local preview only")}
11755
11853
  `);
11756
- process.stdout.write(` Verifier page: ${(0, import_node_path8.join)(dir, registryMod.VERIFIER_PAGE_FILE)}
11854
+ process.stdout.write(` Verifier page: ${(0, import_node_path9.join)(dir, registryMod.VERIFIER_PAGE_FILE)}
11757
11855
  `);
11758
11856
  } else {
11759
11857
  process.stdout.write(` Registry: ${yellow("missing")} (${registryPath})
@@ -11781,10 +11879,10 @@ async function handleKillerDemo(argv) {
11781
11879
  verifySelectiveDisclosurePackage: verifySelectiveDisclosurePackage2
11782
11880
  } = await Promise.resolve().then(() => (init_signing_committed(), signing_committed_exports));
11783
11881
  const registryMod = await Promise.resolve().then(() => (init_receipt_registry(), receipt_registry_exports));
11784
- const dir = (0, import_node_path8.resolve)(flagValue(argv, "--dir") || mkdtempSync((0, import_node_path8.join)(tmpdir(), "scopeblind-killer-demo-")));
11785
- (0, import_node_fs12.mkdirSync)(dir, { recursive: true });
11786
- (0, import_node_fs12.mkdirSync)((0, import_node_path8.join)(dir, "keys"), { recursive: true });
11787
- (0, import_node_fs12.mkdirSync)((0, import_node_path8.join)(dir, "receipts"), { recursive: true });
11882
+ const dir = (0, import_node_path9.resolve)(flagValue(argv, "--dir") || mkdtempSync((0, import_node_path9.join)(tmpdir(), "scopeblind-killer-demo-")));
11883
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
11884
+ (0, import_node_fs13.mkdirSync)((0, import_node_path9.join)(dir, "keys"), { recursive: true });
11885
+ (0, import_node_fs13.mkdirSync)((0, import_node_path9.join)(dir, "receipts"), { recursive: true });
11788
11886
  const privateKeyBytes = randomBytes4(32);
11789
11887
  const publicKeyBytes = ed255192.getPublicKey(privateKeyBytes);
11790
11888
  const keypair = {
@@ -11793,14 +11891,14 @@ async function handleKillerDemo(argv) {
11793
11891
  kid: `killer-demo-${Date.now()}`,
11794
11892
  issuer: "scopeblind-killer-demo"
11795
11893
  };
11796
- const keyPath = (0, import_node_path8.join)(dir, "keys", "gateway.json");
11797
- (0, import_node_fs12.writeFileSync)(keyPath, JSON.stringify({
11894
+ const keyPath = (0, import_node_path9.join)(dir, "keys", "gateway.json");
11895
+ (0, import_node_fs13.writeFileSync)(keyPath, JSON.stringify({
11798
11896
  ...keypair,
11799
11897
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
11800
11898
  warning: "Demo key only. Do not use for production."
11801
11899
  }, null, 2) + "\n");
11802
- const shadowConfigPath = (0, import_node_path8.join)(dir, "protect-mcp.shadow.json");
11803
- const policyPackPath = (0, import_node_path8.join)(dir, "protect-mcp.policy-pack.json");
11900
+ const shadowConfigPath = (0, import_node_path9.join)(dir, "protect-mcp.shadow.json");
11901
+ const policyPackPath = (0, import_node_path9.join)(dir, "protect-mcp.policy-pack.json");
11804
11902
  const config = {
11805
11903
  tools: { "*": { rate_limit: "100/hour" } },
11806
11904
  default_tier: "signed-known",
@@ -11819,11 +11917,11 @@ async function handleKillerDemo(argv) {
11819
11917
  signing: { key_path: keyPath, issuer: keypair.issuer, enabled: true },
11820
11918
  notes: ["Demo policy pack: approvals for GitHub, email, and PMS booking; destructive tools blocked."]
11821
11919
  };
11822
- (0, import_node_fs12.writeFileSync)(shadowConfigPath, JSON.stringify(config, null, 2) + "\n");
11823
- (0, import_node_fs12.writeFileSync)(policyPackPath, JSON.stringify(policyPack, null, 2) + "\n");
11920
+ (0, import_node_fs13.writeFileSync)(shadowConfigPath, JSON.stringify(config, null, 2) + "\n");
11921
+ (0, import_node_fs13.writeFileSync)(policyPackPath, JSON.stringify(policyPack, null, 2) + "\n");
11824
11922
  await initSigning({ enabled: true, key_path: keyPath, issuer: keypair.issuer });
11825
- const logPath = (0, import_node_path8.join)(dir, ".protect-mcp-log.jsonl");
11826
- const receiptPath = (0, import_node_path8.join)(dir, ".protect-mcp-receipts.jsonl");
11923
+ const logPath = (0, import_node_path9.join)(dir, ".protect-mcp-log.jsonl");
11924
+ const receiptPath = (0, import_node_path9.join)(dir, ".protect-mcp-receipts.jsonl");
11827
11925
  const shadowCalls = [
11828
11926
  { tool: "read_file", input: { path: "/research/macro-notes.md" }, reason: "observe_mode" },
11829
11927
  { tool: "github_create_pr", input: { repo: "scopeblind/legate", branch: "agent/pms-adapter", title: "Wire mock PMS adapter" }, reason: "observe_mode" },
@@ -11832,7 +11930,7 @@ async function handleKillerDemo(argv) {
11832
11930
  ];
11833
11931
  for (const [idx, call] of shadowCalls.entries()) {
11834
11932
  const requestId2 = `demo-shadow-${idx + 1}`;
11835
- (0, import_node_fs12.appendFileSync)(logPath, JSON.stringify({
11933
+ (0, import_node_fs13.appendFileSync)(logPath, JSON.stringify({
11836
11934
  v: 2,
11837
11935
  tool: call.tool,
11838
11936
  decision: "allow",
@@ -11867,8 +11965,8 @@ async function handleKillerDemo(argv) {
11867
11965
  policy_digest: (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(policyPack)).digest("hex").slice(0, 16),
11868
11966
  action_readback: readback
11869
11967
  };
11870
- (0, import_node_fs12.appendFileSync)(logPath, JSON.stringify(requireApprovalEntry) + "\n");
11871
- (0, import_node_fs12.appendFileSync)((0, import_node_path8.join)(dir, ".protect-mcp-approval-resolutions.jsonl"), JSON.stringify({
11968
+ (0, import_node_fs13.appendFileSync)(logPath, JSON.stringify(requireApprovalEntry) + "\n");
11969
+ (0, import_node_fs13.appendFileSync)((0, import_node_path9.join)(dir, ".protect-mcp-approval-resolutions.jsonl"), JSON.stringify({
11872
11970
  type: "scopeblind.approval_resolution.v1",
11873
11971
  at: (/* @__PURE__ */ new Date()).toISOString(),
11874
11972
  request_id: requestId,
@@ -11888,11 +11986,11 @@ async function handleKillerDemo(argv) {
11888
11986
  truncated: false
11889
11987
  }
11890
11988
  };
11891
- (0, import_node_fs12.appendFileSync)(logPath, JSON.stringify(executedEntry) + "\n");
11989
+ (0, import_node_fs13.appendFileSync)(logPath, JSON.stringify(executedEntry) + "\n");
11892
11990
  const signed = signDecision(executedEntry);
11893
11991
  if (!signed.signed) throw new Error(`demo signing failed: ${signed.warning || signed.error || "unknown"}`);
11894
- (0, import_node_fs12.appendFileSync)(receiptPath, signed.signed + "\n");
11895
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "receipts", "approved-pms-booking.receipt.json"), JSON.stringify(JSON.parse(signed.signed), null, 2) + "\n");
11992
+ (0, import_node_fs13.appendFileSync)(receiptPath, signed.signed + "\n");
11993
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "receipts", "approved-pms-booking.receipt.json"), JSON.stringify(JSON.parse(signed.signed), null, 2) + "\n");
11896
11994
  const receiptArtifact = JSON.parse(signed.signed);
11897
11995
  const tamperedArtifact = JSON.parse(signed.signed);
11898
11996
  if (tamperedArtifact.payload && typeof tamperedArtifact.payload === "object") {
@@ -11903,7 +12001,7 @@ async function handleKillerDemo(argv) {
11903
12001
  }
11904
12002
  const validOriginal = artifacts.verifyArtifact(receiptArtifact, keypair.publicKey);
11905
12003
  const validTampered = artifacts.verifyArtifact(tamperedArtifact, keypair.publicKey);
11906
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "receipts", "tampered.receipt.json"), JSON.stringify(tamperedArtifact, null, 2) + "\n");
12004
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "receipts", "tampered.receipt.json"), JSON.stringify(tamperedArtifact, null, 2) + "\n");
11907
12005
  const committed = signCommittedDecision2(
11908
12006
  executedEntry,
11909
12007
  ["tool", "payload_digest", "swarm"],
@@ -11915,11 +12013,11 @@ async function handleKillerDemo(argv) {
11915
12013
  const committedReceipt = JSON.parse(committed.signed);
11916
12014
  const disclosurePackage = createSelectiveDisclosurePackage2(committedReceipt, ["tool"], committed.openings);
11917
12015
  const disclosureVerification = verifySelectiveDisclosurePackage2(committedReceipt, disclosurePackage);
11918
- (0, import_node_fs12.appendFileSync)(receiptPath, committed.signed + "\n");
11919
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "receipts", "selective-disclosure.receipt.json"), JSON.stringify(committedReceipt, null, 2) + "\n");
11920
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "receipts", "selective-disclosure.package.json"), JSON.stringify(disclosurePackage, null, 2) + "\n");
11921
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "receipts", "selective-disclosure.tool-only.json"), JSON.stringify(disclosurePackage, null, 2) + "\n");
11922
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "verification-results.json"), JSON.stringify({
12016
+ (0, import_node_fs13.appendFileSync)(receiptPath, committed.signed + "\n");
12017
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "receipts", "selective-disclosure.receipt.json"), JSON.stringify(committedReceipt, null, 2) + "\n");
12018
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "receipts", "selective-disclosure.package.json"), JSON.stringify(disclosurePackage, null, 2) + "\n");
12019
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "receipts", "selective-disclosure.tool-only.json"), JSON.stringify(disclosurePackage, null, 2) + "\n");
12020
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "verification-results.json"), JSON.stringify({
11923
12021
  original_receipt_valid: validOriginal,
11924
12022
  tampered_receipt_valid: validTampered,
11925
12023
  selective_disclosure_valid: disclosureVerification.valid,
@@ -12002,19 +12100,19 @@ async function handleKillerDemo(argv) {
12002
12100
  "No raw prompt, payload, output, private key, or raw receipt is uploaded by the registry flow. Hosted mode submits receipt digests, request ids, org public keys, and billing account metadata only.",
12003
12101
  ""
12004
12102
  ].join("\n");
12005
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "DEMO-RUNBOOK.md"), runbook);
12006
- (0, import_node_fs12.writeFileSync)((0, import_node_path8.join)(dir, "demo-summary.json"), JSON.stringify({
12103
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "DEMO-RUNBOOK.md"), runbook);
12104
+ (0, import_node_fs13.writeFileSync)((0, import_node_path9.join)(dir, "demo-summary.json"), JSON.stringify({
12007
12105
  dir,
12008
12106
  dashboard_command: `npx protect-mcp dashboard --dir ${dir} --policy ${policyPackPath} --open`,
12009
12107
  policy_pack: policyPackPath,
12010
- receipt: (0, import_node_path8.join)(dir, "receipts", "approved-pms-booking.receipt.json"),
12011
- tampered_receipt: (0, import_node_path8.join)(dir, "receipts", "tampered.receipt.json"),
12012
- selective_disclosure_receipt: (0, import_node_path8.join)(dir, "receipts", "selective-disclosure.receipt.json"),
12013
- selective_disclosure_package: (0, import_node_path8.join)(dir, "receipts", "selective-disclosure.tool-only.json"),
12014
- verification_results: (0, import_node_path8.join)(dir, "verification-results.json"),
12108
+ receipt: (0, import_node_path9.join)(dir, "receipts", "approved-pms-booking.receipt.json"),
12109
+ tampered_receipt: (0, import_node_path9.join)(dir, "receipts", "tampered.receipt.json"),
12110
+ selective_disclosure_receipt: (0, import_node_path9.join)(dir, "receipts", "selective-disclosure.receipt.json"),
12111
+ selective_disclosure_package: (0, import_node_path9.join)(dir, "receipts", "selective-disclosure.tool-only.json"),
12112
+ verification_results: (0, import_node_path9.join)(dir, "verification-results.json"),
12015
12113
  registry: registry.registryPath,
12016
12114
  verifier_page: registry.verifierPath,
12017
- runbook: (0, import_node_path8.join)(dir, "DEMO-RUNBOOK.md"),
12115
+ runbook: (0, import_node_path9.join)(dir, "DEMO-RUNBOOK.md"),
12018
12116
  original_valid: validOriginal.valid,
12019
12117
  tampered_valid: validTampered.valid,
12020
12118
  selective_disclosure_valid: disclosureVerification.valid
@@ -12027,9 +12125,9 @@ ${bold("protect-mcp killer-demo")}
12027
12125
  `);
12028
12126
  process.stdout.write(` Dashboard: ${dim(`npx protect-mcp dashboard --dir ${dir} --policy ${policyPackPath} --open`)}
12029
12127
  `);
12030
- process.stdout.write(` Runbook: ${(0, import_node_path8.join)(dir, "DEMO-RUNBOOK.md")}
12128
+ process.stdout.write(` Runbook: ${(0, import_node_path9.join)(dir, "DEMO-RUNBOOK.md")}
12031
12129
  `);
12032
- process.stdout.write(` Signed receipt: ${(0, import_node_path8.join)(dir, "receipts", "approved-pms-booking.receipt.json")}
12130
+ process.stdout.write(` Signed receipt: ${(0, import_node_path9.join)(dir, "receipts", "approved-pms-booking.receipt.json")}
12033
12131
  `);
12034
12132
  process.stdout.write(` Tamper check: original=${validOriginal.valid ? green("valid") : red("invalid")} tampered=${validTampered.valid ? red("valid") : green("invalid")}
12035
12133
  `);
@@ -12049,8 +12147,8 @@ async function handleVerifyDisclosure(argv) {
12049
12147
  process.exit(1);
12050
12148
  }
12051
12149
  const { verifySelectiveDisclosurePackage: verifySelectiveDisclosurePackage2 } = await Promise.resolve().then(() => (init_signing_committed(), signing_committed_exports));
12052
- const receipt = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path8.resolve)(receiptPath), "utf-8"));
12053
- const disclosure = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path8.resolve)(disclosurePath), "utf-8"));
12150
+ const receipt = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path9.resolve)(receiptPath), "utf-8"));
12151
+ const disclosure = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path9.resolve)(disclosurePath), "utf-8"));
12054
12152
  const result = verifySelectiveDisclosurePackage2(receipt, disclosure);
12055
12153
  process.stdout.write(`
12056
12154
  ${bold("protect-mcp verify-disclosure")}
@@ -12086,7 +12184,7 @@ ${red("Errors:")}
12086
12184
  async function handlePolicyPacks(argv) {
12087
12185
  const subcommand = argv[0] || "list";
12088
12186
  const packArg = argv[1];
12089
- const dir = (0, import_node_path8.resolve)(flagValue(argv, "--dir") || "./cedar");
12187
+ const dir = (0, import_node_path9.resolve)(flagValue(argv, "--dir") || "./cedar");
12090
12188
  const force = argv.includes("--force");
12091
12189
  if (subcommand === "list") {
12092
12190
  process.stdout.write(`
@@ -12141,17 +12239,17 @@ ${bold(pack.name)} (${pack.id})
12141
12239
  `);
12142
12240
  process.exit(1);
12143
12241
  }
12144
- (0, import_node_fs12.mkdirSync)(dir, { recursive: true });
12242
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
12145
12243
  const written = [];
12146
12244
  for (const pack of packs) {
12147
12245
  for (const file of pack.files) {
12148
- const outPath = (0, import_node_path8.join)(dir, file.path);
12149
- if ((0, import_node_fs12.existsSync)(outPath) && !force) {
12246
+ const outPath = (0, import_node_path9.join)(dir, file.path);
12247
+ if ((0, import_node_fs13.existsSync)(outPath) && !force) {
12150
12248
  process.stderr.write(`Refusing to overwrite ${outPath}. Re-run with --force if intentional.
12151
12249
  `);
12152
12250
  process.exit(1);
12153
12251
  }
12154
- (0, import_node_fs12.writeFileSync)(outPath, file.contents.endsWith("\n") ? file.contents : `${file.contents}
12252
+ (0, import_node_fs13.writeFileSync)(outPath, file.contents.endsWith("\n") ? file.contents : `${file.contents}
12155
12253
  `);
12156
12254
  written.push(outPath);
12157
12255
  }
@@ -12176,7 +12274,7 @@ Next: ${dim(`protect-mcp serve --cedar ${dir}`)} for shadow mode, then add ${dim
12176
12274
  async function handleConnectors(argv) {
12177
12275
  const subcommand = argv[0] || "list";
12178
12276
  const pilotArg = argv[1];
12179
- const dir = (0, import_node_path8.resolve)(flagValue(argv, "--dir") || process.cwd());
12277
+ const dir = (0, import_node_path9.resolve)(flagValue(argv, "--dir") || process.cwd());
12180
12278
  const force = argv.includes("--force");
12181
12279
  if (subcommand === "list") {
12182
12280
  process.stdout.write(`
@@ -12418,11 +12516,11 @@ ${"\u2500".repeat(60)}
12418
12516
  `);
12419
12517
  }
12420
12518
  async function traceLocal(receiptId) {
12421
- const { readFileSync: readFileSync11, existsSync: existsSync9 } = await import("fs");
12422
- const { join: join8 } = await import("path");
12519
+ const { readFileSync: readFileSync11, existsSync: existsSync10 } = await import("fs");
12520
+ const { join: join9 } = await import("path");
12423
12521
  const dir = process.cwd();
12424
- const receiptsDir = join8(dir, ".protect-mcp", "receipts");
12425
- if (!existsSync9(receiptsDir)) {
12522
+ const receiptsDir = join9(dir, ".protect-mcp", "receipts");
12523
+ if (!existsSync10(receiptsDir)) {
12426
12524
  process.stdout.write(` No local receipts found in ${receiptsDir}
12427
12525
 
12428
12526
  `);
@@ -12436,7 +12534,7 @@ async function traceLocal(receiptId) {
12436
12534
  const receipts = [];
12437
12535
  for (const file of files) {
12438
12536
  try {
12439
- const content = readFileSync11(join8(receiptsDir, file), "utf-8");
12537
+ const content = readFileSync11(join9(receiptsDir, file), "utf-8");
12440
12538
  const receipt = JSON.parse(content);
12441
12539
  receipts.push(receipt);
12442
12540
  } catch {
@@ -12493,8 +12591,8 @@ function getTypeEmoji(type) {
12493
12591
  }
12494
12592
  }
12495
12593
  async function handleInitHooks(argv) {
12496
- const { writeFileSync: writeFileSync4, existsSync: existsSync9, mkdirSync: mkdirSync3, readFileSync: readFileSync11 } = await import("fs");
12497
- const { join: join8 } = await import("path");
12594
+ const { writeFileSync: writeFileSync5, existsSync: existsSync10, mkdirSync: mkdirSync4, readFileSync: readFileSync11 } = await import("fs");
12595
+ const { join: join9 } = await import("path");
12498
12596
  const { generateHookSettings: generateHookSettings2, generateSampleCedarPolicy: generateSampleCedarPolicy2, generateVerifyReceiptSkill: generateVerifyReceiptSkill2 } = await Promise.resolve().then(() => (init_hook_patterns(), hook_patterns_exports));
12499
12597
  let dir = process.cwd();
12500
12598
  const dirIdx = argv.indexOf("--dir");
@@ -12508,13 +12606,13 @@ ${bold("protect-mcp init-hooks")}
12508
12606
  process.stdout.write(`${"\u2500".repeat(55)}
12509
12607
 
12510
12608
  `);
12511
- const claudeDir = join8(dir, ".claude");
12512
- const settingsPath = join8(claudeDir, "settings.json");
12609
+ const claudeDir = join9(dir, ".claude");
12610
+ const settingsPath = join9(claudeDir, "settings.json");
12513
12611
  let existingSettings = {};
12514
- if (!existsSync9(claudeDir)) {
12515
- mkdirSync3(claudeDir, { recursive: true });
12612
+ if (!existsSync10(claudeDir)) {
12613
+ mkdirSync4(claudeDir, { recursive: true });
12516
12614
  }
12517
- if (existsSync9(settingsPath)) {
12615
+ if (existsSync10(settingsPath)) {
12518
12616
  try {
12519
12617
  existingSettings = JSON.parse(readFileSync11(settingsPath, "utf-8"));
12520
12618
  } catch {
@@ -12530,7 +12628,7 @@ ${bold("protect-mcp init-hooks")}
12530
12628
  ...hookSettings.hooks
12531
12629
  }
12532
12630
  };
12533
- writeFileSync4(settingsPath, JSON.stringify(mergedSettings, null, 2) + "\n");
12631
+ writeFileSync5(settingsPath, JSON.stringify(mergedSettings, null, 2) + "\n");
12534
12632
  process.stdout.write(` ${green("\u2713")} ${settingsPath}
12535
12633
  `);
12536
12634
  process.stdout.write(` Hook URL: ${dim(hookUrl)}
@@ -12538,26 +12636,26 @@ ${bold("protect-mcp init-hooks")}
12538
12636
  process.stdout.write(` Events: PreToolUse, PostToolUse, SubagentStart/Stop, Task, Session, Config, Stop
12539
12637
 
12540
12638
  `);
12541
- const keysDir = join8(dir, "keys");
12542
- const keyPath = join8(keysDir, "gateway.json");
12543
- if (!existsSync9(keyPath)) {
12544
- if (!existsSync9(keysDir)) mkdirSync3(keysDir, { recursive: true });
12639
+ const keysDir = join9(dir, "keys");
12640
+ const keyPath = join9(keysDir, "gateway.json");
12641
+ if (!existsSync10(keyPath)) {
12642
+ if (!existsSync10(keysDir)) mkdirSync4(keysDir, { recursive: true });
12545
12643
  const { randomBytes: rb } = await import("crypto");
12546
12644
  try {
12547
12645
  const { ed25519: ed255192 } = await Promise.resolve().then(() => (init_ed25519(), ed25519_exports));
12548
12646
  const { bytesToHex: bytesToHex2 } = await Promise.resolve().then(() => (init_utils(), utils_exports));
12549
12647
  const privateKey = rb(32);
12550
12648
  const publicKey = ed255192.getPublicKey(privateKey);
12551
- writeFileSync4(keyPath, JSON.stringify({
12649
+ writeFileSync5(keyPath, JSON.stringify({
12552
12650
  privateKey: bytesToHex2(privateKey),
12553
12651
  publicKey: bytesToHex2(publicKey),
12554
12652
  kid: `hook-${Date.now()}`,
12555
12653
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
12556
12654
  warning: "KEEP THIS FILE SECRET. Never commit to version control."
12557
12655
  }, null, 2) + "\n");
12558
- const gitignorePath = join8(keysDir, ".gitignore");
12559
- if (!existsSync9(gitignorePath)) {
12560
- writeFileSync4(gitignorePath, "# Never commit signing keys\n*.json\n");
12656
+ const gitignorePath = join9(keysDir, ".gitignore");
12657
+ if (!existsSync10(gitignorePath)) {
12658
+ writeFileSync5(gitignorePath, "# Never commit signing keys\n*.json\n");
12561
12659
  }
12562
12660
  process.stdout.write(` ${green("\u2713")} ${keyPath} (Ed25519 keypair)
12563
12661
 
@@ -12572,11 +12670,11 @@ ${bold("protect-mcp init-hooks")}
12572
12670
 
12573
12671
  `);
12574
12672
  }
12575
- const policiesDir = join8(dir, "policies");
12576
- const cedarPath = join8(policiesDir, "agent.cedar");
12577
- if (!existsSync9(cedarPath)) {
12578
- if (!existsSync9(policiesDir)) mkdirSync3(policiesDir, { recursive: true });
12579
- writeFileSync4(cedarPath, generateSampleCedarPolicy2());
12673
+ const policiesDir = join9(dir, "policies");
12674
+ const cedarPath = join9(policiesDir, "agent.cedar");
12675
+ if (!existsSync10(cedarPath)) {
12676
+ if (!existsSync10(policiesDir)) mkdirSync4(policiesDir, { recursive: true });
12677
+ writeFileSync5(cedarPath, generateSampleCedarPolicy2());
12580
12678
  process.stdout.write(` ${green("\u2713")} ${cedarPath}
12581
12679
  `);
12582
12680
  process.stdout.write(` Edit to customize tool permissions. Cedar deny is AUTHORITATIVE.
@@ -12587,8 +12685,8 @@ ${bold("protect-mcp init-hooks")}
12587
12685
 
12588
12686
  `);
12589
12687
  }
12590
- const configPath = join8(dir, "protect-mcp.json");
12591
- if (!existsSync9(configPath)) {
12688
+ const configPath = join9(dir, "protect-mcp.json");
12689
+ if (!existsSync10(configPath)) {
12592
12690
  const config = {
12593
12691
  tools: { "*": { rate_limit: "100/hour" } },
12594
12692
  default_tier: "unknown",
@@ -12598,16 +12696,16 @@ ${bold("protect-mcp init-hooks")}
12598
12696
  enabled: true
12599
12697
  }
12600
12698
  };
12601
- writeFileSync4(configPath, JSON.stringify(config, null, 2) + "\n");
12699
+ writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
12602
12700
  process.stdout.write(` ${green("\u2713")} ${configPath}
12603
12701
 
12604
12702
  `);
12605
12703
  }
12606
- const skillsDir = join8(dir, ".claude", "skills", "verify-receipt");
12607
- const skillPath = join8(skillsDir, "SKILL.md");
12608
- if (!existsSync9(skillPath)) {
12609
- mkdirSync3(skillsDir, { recursive: true });
12610
- writeFileSync4(skillPath, generateVerifyReceiptSkill2());
12704
+ const skillsDir = join9(dir, ".claude", "skills", "verify-receipt");
12705
+ const skillPath = join9(skillsDir, "SKILL.md");
12706
+ if (!existsSync10(skillPath)) {
12707
+ mkdirSync4(skillsDir, { recursive: true });
12708
+ writeFileSync5(skillPath, generateVerifyReceiptSkill2());
12611
12709
  process.stdout.write(` ${green("\u2713")} ${skillPath}
12612
12710
  `);
12613
12711
  process.stdout.write(` Use ${dim("/verify-receipt")} in Claude Code to check audit trails.
@@ -12663,13 +12761,13 @@ ${bold("protect-mcp init-hooks")}
12663
12761
  }
12664
12762
  async function sendInstallTelemetry() {
12665
12763
  try {
12666
- const { existsSync: existsSync9, mkdirSync: mkdirSync3, writeFileSync: writeFileSync4, readFileSync: readFileSync11 } = await import("fs");
12667
- const { join: join8, dirname: dirname3 } = await import("path");
12764
+ const { existsSync: existsSync10, mkdirSync: mkdirSync4, writeFileSync: writeFileSync5, readFileSync: readFileSync11 } = await import("fs");
12765
+ const { join: join9, dirname: dirname3 } = await import("path");
12668
12766
  const { homedir } = await import("os");
12669
12767
  const { fileURLToPath } = await import("url");
12670
- const markerDir = join8(homedir(), ".protect-mcp");
12671
- const markerFile = join8(markerDir, ".telemetry-sent");
12672
- if (existsSync9(markerFile) || process.env.PROTECT_MCP_TELEMETRY === "off") {
12768
+ const markerDir = join9(homedir(), ".protect-mcp");
12769
+ const markerFile = join9(markerDir, ".telemetry-sent");
12770
+ if (existsSync10(markerFile) || process.env.PROTECT_MCP_TELEMETRY === "off") {
12673
12771
  return;
12674
12772
  }
12675
12773
  const version = await pkgVersion();
@@ -12689,10 +12787,10 @@ async function sendInstallTelemetry() {
12689
12787
  signal: controller.signal
12690
12788
  }).catch(() => {
12691
12789
  }).finally(() => clearTimeout(timeout));
12692
- if (!existsSync9(markerDir)) {
12693
- mkdirSync3(markerDir, { recursive: true });
12790
+ if (!existsSync10(markerDir)) {
12791
+ mkdirSync4(markerDir, { recursive: true });
12694
12792
  }
12695
- writeFileSync4(markerFile, String(Date.now()), "utf-8");
12793
+ writeFileSync5(markerFile, String(Date.now()), "utf-8");
12696
12794
  process.stderr.write(
12697
12795
  "[protect-mcp] Thanks for installing! Anonymous telemetry sent (disable: PROTECT_MCP_TELEMETRY=off)\n[protect-mcp] Free dashboard: npx protect-mcp connect | https://scopeblind.com\n"
12698
12796
  );
@@ -12708,8 +12806,8 @@ function loadPolicyArg(argv) {
12708
12806
  const policyFile = flagValue(argv, "--policy");
12709
12807
  try {
12710
12808
  if (cedarDir) return loadCedarPolicies(cedarDir);
12711
- if (policyFile && (0, import_node_fs12.existsSync)(policyFile)) {
12712
- return policySetFromSource((0, import_node_fs12.readFileSync)(policyFile, "utf-8"), (0, import_node_path8.basename)(policyFile));
12809
+ if (policyFile && (0, import_node_fs13.existsSync)(policyFile)) {
12810
+ return policySetFromSource((0, import_node_fs13.readFileSync)(policyFile, "utf-8"), (0, import_node_path9.basename)(policyFile));
12713
12811
  }
12714
12812
  } catch {
12715
12813
  }
@@ -12810,7 +12908,7 @@ async function handleSign(argv) {
12810
12908
  if (m.tool) tool = m.tool;
12811
12909
  }
12812
12910
  }
12813
- if (keyPath && (0, import_node_fs12.existsSync)(keyPath)) {
12911
+ if (keyPath && (0, import_node_fs13.existsSync)(keyPath)) {
12814
12912
  try {
12815
12913
  await initSigning({ enabled: true, key_path: keyPath });
12816
12914
  } catch {
@@ -12827,12 +12925,12 @@ async function handleSign(argv) {
12827
12925
  timestamp: Date.now()
12828
12926
  });
12829
12927
  try {
12830
- (0, import_node_fs12.mkdirSync)(receiptsDir, { recursive: true });
12928
+ (0, import_node_fs13.mkdirSync)(receiptsDir, { recursive: true });
12831
12929
  } catch {
12832
12930
  }
12833
12931
  const line = signed.signed ?? JSON.stringify({ tool, request_id: requestId, signed: false, note: signed.warning || "no signer configured" });
12834
12932
  try {
12835
- (0, import_node_fs12.appendFileSync)((0, import_node_path8.join)(receiptsDir, "receipts.jsonl"), line + "\n");
12933
+ (0, import_node_fs13.appendFileSync)((0, import_node_path9.join)(receiptsDir, "receipts.jsonl"), line + "\n");
12836
12934
  } catch {
12837
12935
  }
12838
12936
  if (format === "hermes") {
@@ -12842,12 +12940,55 @@ async function handleSign(argv) {
12842
12940
  process.stdout.write(JSON.stringify({ signed: Boolean(signed.signed), artifact_type: signed.artifact_type, request_id: requestId }) + "\n");
12843
12941
  process.exit(0);
12844
12942
  }
12943
+ async function handleSample(argv) {
12944
+ const dir = flagValue(argv, "--dir") || process.cwd();
12945
+ const { buildSampleKit: buildSampleKit2 } = await Promise.resolve().then(() => (init_sample(), sample_exports));
12946
+ let kit;
12947
+ try {
12948
+ kit = buildSampleKit2(dir, { force: argv.includes("--force") });
12949
+ } catch (err) {
12950
+ if (err?.code === "SAMPLE_EXISTS") {
12951
+ process.stderr.write(
12952
+ "\nprotect-mcp sample: this folder already has a record or signing key.\nThis command seeds a LABELED SAMPLE record and will not touch a real one.\nRun it in an empty folder, or pass --force to overwrite.\n\n"
12953
+ );
12954
+ process.exit(1);
12955
+ }
12956
+ throw err;
12957
+ }
12958
+ process.stdout.write(`
12959
+ ${bold("\u{1F6E1} Sample record seeded")} \xB7 8 decisions (1 blocked, 2 payments), signed with a fresh key ${dim(`(kid ${kit.kid})`)}
12960
+
12961
+ `);
12962
+ process.stdout.write(" .protect-mcp-receipts.jsonl the signed sample record\n");
12963
+ process.stdout.write(" demo-tampered.jsonl the same record with ONE decision edited after signing\n");
12964
+ process.stdout.write(` keys/gateway.json sample keypair ${dim("(never commit)")}
12965
+
12966
+ `);
12967
+ process.stdout.write(`${bold("Replay the demo")} ${dim("(the film: legate.scopeblind.com/record)")}
12968
+ `);
12969
+ process.stdout.write(" npx protect-mcp record\n");
12970
+ process.stdout.write(" npx protect-mcp claim --payment-under 100 --anchor --output payments-under-100.json\n");
12971
+ process.stdout.write(" npx protect-mcp verify-claim payments-under-100.json\n");
12972
+ process.stdout.write(" npx protect-mcp anchor-record\n\n");
12973
+ process.stdout.write(`${dim("Drop demo-tampered.jsonl into the record page to watch tampering get caught.")}
12974
+ `);
12975
+ process.stdout.write(`${dim("Everything runs locally; --anchor publishes only a digest to the public log.")}
12976
+
12977
+ `);
12978
+ process.exit(0);
12979
+ }
12845
12980
  async function main() {
12846
12981
  sendInstallTelemetry().catch(() => {
12847
12982
  });
12848
12983
  const args = process.argv.slice(2);
12849
12984
  process.env.PROTECT_MCP_VERSION = process.env.PROTECT_MCP_VERSION || await pkgVersion();
12850
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
12985
+ const preSep = args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
12986
+ if (args[0] === "version" || preSep.includes("--version") || preSep.includes("-V")) {
12987
+ process.stdout.write(`${process.env.PROTECT_MCP_VERSION || "unknown"}
12988
+ `);
12989
+ process.exit(0);
12990
+ }
12991
+ if (args.length === 0 || args[0] === "help" || preSep.includes("--help") || preSep.includes("-h")) {
12851
12992
  printHelp();
12852
12993
  process.exit(0);
12853
12994
  }
@@ -12901,6 +13042,10 @@ async function main() {
12901
13042
  await handleAnchorRecord(args.slice(1));
12902
13043
  return;
12903
13044
  }
13045
+ if (args[0] === "sample") {
13046
+ await handleSample(args.slice(1));
13047
+ return;
13048
+ }
12904
13049
  if (args[0] === "init-hooks") {
12905
13050
  await handleInitHooks(args.slice(1));
12906
13051
  process.exit(0);
@@ -13005,10 +13150,10 @@ async function main() {
13005
13150
  let cedarPolicySet = null;
13006
13151
  let effectiveCedarDir = cedarDir;
13007
13152
  if (!effectiveCedarDir && !policyPath) {
13008
- const { existsSync: existsSync9, readdirSync: readdirSync4 } = await import("fs");
13153
+ const { existsSync: existsSync10, readdirSync: readdirSync4 } = await import("fs");
13009
13154
  for (const candidate of ["cedar", "policies", "."]) {
13010
13155
  try {
13011
- if (existsSync9(candidate) && readdirSync4(candidate).some((f) => f.endsWith(".cedar"))) {
13156
+ if (existsSync10(candidate) && readdirSync4(candidate).some((f) => f.endsWith(".cedar"))) {
13012
13157
  effectiveCedarDir = candidate;
13013
13158
  process.stderr.write(`[PROTECT_MCP] Auto-detected Cedar policies in ./${candidate}/
13014
13159
  `);
@@ -13119,8 +13264,8 @@ async function handleSimulate(args) {
13119
13264
  process.stderr.write("Usage: protect-mcp simulate --policy <path> [--log <path>] [--tier <tier>] [--json]\n");
13120
13265
  process.exit(1);
13121
13266
  }
13122
- const { existsSync: existsSync9 } = await import("fs");
13123
- if (!existsSync9(logPath)) {
13267
+ const { existsSync: existsSync10 } = await import("fs");
13268
+ if (!existsSync10(logPath)) {
13124
13269
  process.stderr.write(`Log file not found: ${logPath}
13125
13270
  `);
13126
13271
  process.stderr.write("Run protect-mcp in shadow mode first to generate a log file.\n");
@@ -13142,8 +13287,8 @@ async function handleSimulate(args) {
13142
13287
  }
13143
13288
  }
13144
13289
  async function handleDoctor() {
13145
- const { existsSync: existsSync9, readFileSync: readFileSync11, readdirSync: readdirSync4 } = await import("fs");
13146
- const { join: join8 } = await import("path");
13290
+ const { existsSync: existsSync10, readFileSync: readFileSync11, readdirSync: readdirSync4 } = await import("fs");
13291
+ const { join: join9 } = await import("path");
13147
13292
  const { execSync } = await import("child_process");
13148
13293
  const green2 = (s) => `\x1B[32m\u2713\x1B[0m ${s}`;
13149
13294
  const red2 = (s) => `\x1B[31m\u2717\x1B[0m ${s}`;
@@ -13162,8 +13307,8 @@ async function handleDoctor() {
13162
13307
  `));
13163
13308
  issues++;
13164
13309
  }
13165
- const configPath = join8(process.cwd(), "scopeblind.config.json");
13166
- if (existsSync9(configPath)) {
13310
+ const configPath = join9(process.cwd(), "scopeblind.config.json");
13311
+ if (existsSync10(configPath)) {
13167
13312
  try {
13168
13313
  const config = JSON.parse(readFileSync11(configPath, "utf-8"));
13169
13314
  if (config.signing?.private_key || config.signing?.key_file) {
@@ -13182,7 +13327,7 @@ async function handleDoctor() {
13182
13327
  let policyFound = false;
13183
13328
  for (const dir of ["cedar", "policies", "."]) {
13184
13329
  try {
13185
- if (existsSync9(dir) && readdirSync4(dir).some((f) => f.endsWith(".cedar"))) {
13330
+ if (existsSync10(dir) && readdirSync4(dir).some((f) => f.endsWith(".cedar"))) {
13186
13331
  process.stdout.write(green2(`Cedar policies found in ./${dir}/
13187
13332
  `));
13188
13333
  policyFound = true;
@@ -13193,7 +13338,7 @@ async function handleDoctor() {
13193
13338
  }
13194
13339
  if (!policyFound) {
13195
13340
  for (const name of ["policy.json", "protect-mcp.policy.json", "scopeblind-policy.json"]) {
13196
- if (existsSync9(name)) {
13341
+ if (existsSync10(name)) {
13197
13342
  process.stdout.write(green2(`JSON policy found: ${name}
13198
13343
  `));
13199
13344
  policyFound = true;
@@ -13214,9 +13359,9 @@ async function handleDoctor() {
13214
13359
  } catch {
13215
13360
  process.stdout.write(dim2(" Cedar WASM not installed\n"));
13216
13361
  }
13217
- const logFile = join8(process.cwd(), "protect-mcp-decisions.jsonl");
13218
- const receiptFile = join8(process.cwd(), "protect-mcp-receipts.jsonl");
13219
- if (existsSync9(logFile)) {
13362
+ const logFile = join9(process.cwd(), "protect-mcp-decisions.jsonl");
13363
+ const receiptFile = join9(process.cwd(), "protect-mcp-receipts.jsonl");
13364
+ if (existsSync10(logFile)) {
13220
13365
  try {
13221
13366
  const lines = readFileSync11(logFile, "utf-8").trim().split("\n").length;
13222
13367
  process.stdout.write(green2(`Decision log: ${lines} entries
@@ -13227,7 +13372,7 @@ async function handleDoctor() {
13227
13372
  } else {
13228
13373
  process.stdout.write(dim2(" No decision log yet, will be created on first tool call\n"));
13229
13374
  }
13230
- if (existsSync9(receiptFile)) {
13375
+ if (existsSync10(receiptFile)) {
13231
13376
  try {
13232
13377
  const lines = readFileSync11(receiptFile, "utf-8").trim().split("\n").length;
13233
13378
  process.stdout.write(green2(`Receipt file: ${lines} signed receipts
@@ -13298,9 +13443,9 @@ async function handleReport(args) {
13298
13443
  }
13299
13444
  }
13300
13445
  const { generateReport: generateReport2, formatReportMarkdown: formatReportMarkdown2 } = await Promise.resolve().then(() => (init_report(), report_exports));
13301
- const { join: join8 } = await import("path");
13302
- const logPath = join8(dir, ".protect-mcp-log.jsonl");
13303
- const receiptPath = join8(dir, ".protect-mcp-receipts.jsonl");
13446
+ const { join: join9 } = await import("path");
13447
+ const logPath = join9(dir, ".protect-mcp-log.jsonl");
13448
+ const receiptPath = join9(dir, ".protect-mcp-receipts.jsonl");
13304
13449
  const report = generateReport2(logPath, receiptPath, period);
13305
13450
  let output;
13306
13451
  if (format === "md") {
@@ -13309,8 +13454,8 @@ async function handleReport(args) {
13309
13454
  output = JSON.stringify(report, null, 2);
13310
13455
  }
13311
13456
  if (outputPath) {
13312
- const { writeFileSync: writeFileSync4 } = await import("fs");
13313
- writeFileSync4(outputPath, output, "utf-8");
13457
+ const { writeFileSync: writeFileSync5 } = await import("fs");
13458
+ writeFileSync5(outputPath, output, "utf-8");
13314
13459
  process.stderr.write(`Report written to ${outputPath}
13315
13460
  `);
13316
13461
  } else {