@peac/cli 0.10.9 → 0.10.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.cjs +2257 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.mjs +2236 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +21 -16
  7. package/dist/cli.js +0 -90
  8. package/dist/cli.js.map +0 -1
  9. package/dist/commands/bridge/index.js +0 -20
  10. package/dist/commands/bridge/index.js.map +0 -1
  11. package/dist/commands/bridge/install.js +0 -27
  12. package/dist/commands/bridge/install.js.map +0 -1
  13. package/dist/commands/bridge/start.js +0 -123
  14. package/dist/commands/bridge/start.js.map +0 -1
  15. package/dist/commands/bridge/status.js +0 -192
  16. package/dist/commands/bridge/status.js.map +0 -1
  17. package/dist/commands/bridge/stop.js +0 -130
  18. package/dist/commands/bridge/stop.js.map +0 -1
  19. package/dist/commands/bundle.js +0 -363
  20. package/dist/commands/bundle.js.map +0 -1
  21. package/dist/commands/conformance.js +0 -301
  22. package/dist/commands/conformance.js.map +0 -1
  23. package/dist/commands/discover.js +0 -39
  24. package/dist/commands/discover.js.map +0 -1
  25. package/dist/commands/hash.js +0 -106
  26. package/dist/commands/hash.js.map +0 -1
  27. package/dist/commands/policy.js +0 -712
  28. package/dist/commands/policy.js.map +0 -1
  29. package/dist/commands/samples.js +0 -360
  30. package/dist/commands/samples.js.map +0 -1
  31. package/dist/commands/verify.js +0 -50
  32. package/dist/commands/verify.js.map +0 -1
  33. package/dist/commands/workflow.d.ts +0 -11
  34. package/dist/commands/workflow.d.ts.map +0 -1
  35. package/dist/commands/workflow.js +0 -214
  36. package/dist/commands/workflow.js.map +0 -1
  37. package/dist/index.js +0 -240
  38. package/dist/index.js.map +0 -1
  39. package/dist/lib/conformance/digest.js +0 -202
  40. package/dist/lib/conformance/digest.js.map +0 -1
  41. package/dist/lib/conformance/index.js +0 -30
  42. package/dist/lib/conformance/index.js.map +0 -1
  43. package/dist/lib/conformance/manifest.js +0 -66
  44. package/dist/lib/conformance/manifest.js.map +0 -1
  45. package/dist/lib/conformance/profiles.js +0 -138
  46. package/dist/lib/conformance/profiles.js.map +0 -1
  47. package/dist/lib/conformance/types.js +0 -8
  48. package/dist/lib/conformance/types.js.map +0 -1
  49. package/dist/lib/conformance/validators.js +0 -415
  50. package/dist/lib/conformance/validators.js.map +0 -1
  51. package/dist/lib/conformance-runner.js +0 -433
  52. package/dist/lib/conformance-runner.js.map +0 -1
  53. package/dist/lib/samples-loader.js +0 -311
  54. package/dist/lib/samples-loader.js.map +0 -1
  55. package/dist/lib/version.js +0 -61
  56. package/dist/lib/version.js.map +0 -1
  57. package/dist/types.js +0 -6
  58. package/dist/types.js.map +0 -1
  59. package/dist/utils.js +0 -101
  60. package/dist/utils.js.map +0 -1
package/dist/index.cjs ADDED
@@ -0,0 +1,2257 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var commander = require('commander');
5
+ var protocol = require('@peac/protocol');
6
+ var crypto = require('@peac/crypto');
7
+ var fs6 = require('fs');
8
+ var path6 = require('path');
9
+ var policyKit = require('@peac/policy-kit');
10
+ var child_process = require('child_process');
11
+ var crypto$1 = require('crypto');
12
+ var schema = require('@peac/schema');
13
+ var disc = require('@peac/disc');
14
+
15
+ function _interopNamespace(e) {
16
+ if (e && e.__esModule) return e;
17
+ var n = Object.create(null);
18
+ if (e) {
19
+ Object.keys(e).forEach(function (k) {
20
+ if (k !== 'default') {
21
+ var d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: function () { return e[k]; }
25
+ });
26
+ }
27
+ });
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var fs6__namespace = /*#__PURE__*/_interopNamespace(fs6);
34
+ var path6__namespace = /*#__PURE__*/_interopNamespace(path6);
35
+
36
+ function getGlobalOptions(cmd) {
37
+ const parent = cmd.parent;
38
+ if (!parent) return {};
39
+ return parent.opts();
40
+ }
41
+ function output(data, opts, humanMessage) {
42
+ if (opts.json) {
43
+ console.log(JSON.stringify(data, null, 2));
44
+ }
45
+ }
46
+ function outputError(error, details, opts) {
47
+ if (opts.json) {
48
+ console.log(JSON.stringify({ success: false, error, ...details }, null, 2));
49
+ } else {
50
+ console.error(`Error: ${error}`);
51
+ }
52
+ }
53
+ var policy = new commander.Command("policy").description("Policy file operations").option("--json", "Output in machine-readable JSON format").option("--yes", "Skip confirmation prompts (auto-confirm)").option("--strict", "Exit non-zero on warnings");
54
+ policy.command("init").description("Create a new PEAC policy file").option("-f, --format <format>", "Output format (yaml or json)", "yaml").option("-o, --output <file>", "Output file path").option("--force", "Overwrite existing file").option("--profile <id>", "Use a pre-built profile as template").action(
55
+ (options, cmd) => {
56
+ const globalOpts = getGlobalOptions(cmd);
57
+ try {
58
+ const format = options.format?.toLowerCase() || "yaml";
59
+ const outputPath = options.output || (format === "json" ? "peac-policy.json" : "peac-policy.yaml");
60
+ if (fs6__namespace.existsSync(outputPath) && !options.force && !globalOpts.yes) {
61
+ outputError(
62
+ `File already exists: ${outputPath}`,
63
+ { path: outputPath, hint: "Use --force or --yes to overwrite" },
64
+ globalOpts
65
+ );
66
+ process.exit(1);
67
+ }
68
+ let content;
69
+ let policyName;
70
+ if (options.profile) {
71
+ try {
72
+ const profile = policyKit.loadProfile(options.profile);
73
+ const policyDoc = profile.policy;
74
+ content = format === "json" ? policyKit.serializePolicyJson(policyDoc) : policyKit.serializePolicyYaml(policyDoc);
75
+ policyName = profile.name;
76
+ } catch (err) {
77
+ if (err instanceof policyKit.ProfileError) {
78
+ outputError(err.message, { code: err.code, profile: options.profile }, globalOpts);
79
+ process.exit(1);
80
+ }
81
+ throw err;
82
+ }
83
+ } else {
84
+ const example = policyKit.createExamplePolicy();
85
+ content = format === "json" ? policyKit.serializePolicyJson(example) : policyKit.serializePolicyYaml(example);
86
+ policyName = "Example Policy";
87
+ }
88
+ fs6__namespace.writeFileSync(outputPath, content, "utf-8");
89
+ if (globalOpts.json) {
90
+ output(
91
+ {
92
+ success: true,
93
+ file: outputPath,
94
+ format,
95
+ profile: options.profile || null,
96
+ policyName
97
+ },
98
+ globalOpts
99
+ );
100
+ } else {
101
+ console.log(`Created policy file: ${outputPath}`);
102
+ if (options.profile) {
103
+ console.log(`Based on profile: ${options.profile}`);
104
+ }
105
+ console.log("");
106
+ console.log("Next steps:");
107
+ console.log(" 1. Edit the policy file to define your access rules");
108
+ console.log(" 2. Validate with: peac policy validate " + outputPath);
109
+ console.log(" 3. Generate artifacts with: peac policy generate " + outputPath);
110
+ }
111
+ process.exit(0);
112
+ } catch (err) {
113
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
114
+ process.exit(1);
115
+ }
116
+ }
117
+ );
118
+ policy.command("validate").description("Validate a PEAC policy file (YAML or JSON)").argument("<file>", "Path to policy file").option("-v, --verbose", "Show detailed validation output").action((file, options, cmd) => {
119
+ const globalOpts = getGlobalOptions(cmd);
120
+ const warnings = [];
121
+ try {
122
+ const policyDoc = policyKit.loadPolicy(file);
123
+ const result = {
124
+ success: true,
125
+ file,
126
+ valid: true,
127
+ warnings,
128
+ policy: {
129
+ version: policyDoc.version,
130
+ name: policyDoc.name || null,
131
+ defaultDecision: policyDoc.defaults.decision,
132
+ ruleCount: policyDoc.rules.length,
133
+ rules: options.verbose ? policyDoc.rules.map((r) => ({
134
+ name: r.name,
135
+ decision: r.decision,
136
+ subject: r.subject || null,
137
+ purpose: r.purpose || null,
138
+ licensingMode: r.licensing_mode || null
139
+ })) : void 0
140
+ }
141
+ };
142
+ if (globalOpts.json) {
143
+ output(result, globalOpts);
144
+ } else {
145
+ console.log(`Validating policy file: ${file}
146
+ `);
147
+ console.log("Policy is valid!\n");
148
+ console.log("Policy Information:");
149
+ console.log(` Version: ${policyDoc.version}`);
150
+ if (policyDoc.name) {
151
+ console.log(` Name: ${policyDoc.name}`);
152
+ }
153
+ console.log(` Default: ${policyDoc.defaults.decision}`);
154
+ console.log(` Rules: ${policyDoc.rules.length}`);
155
+ if (options.verbose && policyDoc.rules.length > 0) {
156
+ console.log("\nRules:");
157
+ for (const rule of policyDoc.rules) {
158
+ console.log(` - ${rule.name}: ${rule.decision}`);
159
+ if (rule.subject) {
160
+ const parts = [];
161
+ if (rule.subject.type) {
162
+ const types = Array.isArray(rule.subject.type) ? rule.subject.type.join("|") : rule.subject.type;
163
+ parts.push(`type=${types}`);
164
+ }
165
+ if (rule.subject.labels) {
166
+ parts.push(`labels=[${rule.subject.labels.join(",")}]`);
167
+ }
168
+ if (rule.subject.id) {
169
+ parts.push(`id=${rule.subject.id}`);
170
+ }
171
+ if (parts.length > 0) {
172
+ console.log(` subject: ${parts.join(", ")}`);
173
+ }
174
+ }
175
+ if (rule.purpose) {
176
+ const purposes = Array.isArray(rule.purpose) ? rule.purpose.join("|") : rule.purpose;
177
+ console.log(` purpose: ${purposes}`);
178
+ }
179
+ if (rule.licensing_mode) {
180
+ const modes = Array.isArray(rule.licensing_mode) ? rule.licensing_mode.join("|") : rule.licensing_mode;
181
+ console.log(` licensing_mode: ${modes}`);
182
+ }
183
+ }
184
+ }
185
+ if (warnings.length > 0) {
186
+ console.log("\nWarnings:");
187
+ for (const warning of warnings) {
188
+ console.log(` - ${warning}`);
189
+ }
190
+ }
191
+ }
192
+ if (globalOpts.strict && warnings.length > 0) {
193
+ process.exit(1);
194
+ }
195
+ process.exit(0);
196
+ } catch (err) {
197
+ if (err instanceof policyKit.PolicyValidationError) {
198
+ const issues = err.issues.map((i) => ({
199
+ path: i.path.join("."),
200
+ message: i.message
201
+ }));
202
+ if (globalOpts.json) {
203
+ output(
204
+ {
205
+ success: false,
206
+ file,
207
+ valid: false,
208
+ error: "Validation failed",
209
+ issues
210
+ },
211
+ globalOpts
212
+ );
213
+ } else {
214
+ console.error("Policy validation failed:\n");
215
+ for (const issue of err.issues) {
216
+ console.error(` - ${issue.path.join(".")}: ${issue.message}`);
217
+ }
218
+ }
219
+ process.exit(1);
220
+ } else if (err instanceof policyKit.PolicyLoadError) {
221
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
222
+ process.exit(1);
223
+ } else {
224
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
225
+ process.exit(1);
226
+ }
227
+ }
228
+ });
229
+ policy.command("generate").description("Generate deployment artifacts from a policy file").argument("<file>", "Path to policy file").option("-o, --out <dir>", 'Output directory (use "-" for stdout)', "dist").option("--well-known", "Output peac.txt to .well-known/ subdirectory").option("--dry-run", "Show what would be generated without writing files").option("--peac-version <version>", "PEAC protocol version (default: 0.9)").option("--site-url <url>", "Site URL for peac.txt").option("--contact <email>", "Contact email for policy questions").option("--attribution <mode>", "Attribution requirement (required, optional, none)").option("--receipts <mode>", "Receipts requirement (required, optional, omit)").option("--rate-limit <limit>", 'Rate limit string (e.g., "100/hour", "unlimited")').option("--negotiate <url>", "Negotiate endpoint URL").option("--no-comments", "Omit comments from generated files").action(
230
+ (file, options, cmd) => {
231
+ const globalOpts = getGlobalOptions(cmd);
232
+ const isStdout = options.out === "-";
233
+ try {
234
+ if (!globalOpts.json && !isStdout) {
235
+ console.log(`Loading policy: ${file}
236
+ `);
237
+ }
238
+ const policyDoc = policyKit.loadPolicy(file);
239
+ const compileOptions = {
240
+ peacVersion: options.peacVersion,
241
+ siteUrl: options.siteUrl,
242
+ contact: options.contact,
243
+ attribution: options.attribution,
244
+ receipts: options.receipts,
245
+ rateLimit: options.rateLimit,
246
+ negotiateUrl: options.negotiate,
247
+ includeComments: options.comments !== false
248
+ };
249
+ const peacTxt = policyKit.compilePeacTxt(policyDoc, compileOptions);
250
+ const robotsTxt = policyKit.compileRobotsSnippet(policyDoc, compileOptions);
251
+ const aiprefTemplates = policyKit.compileAiprefTemplates(policyDoc, compileOptions);
252
+ const markdown = policyKit.renderPolicyMarkdown(policyDoc, compileOptions);
253
+ if (isStdout || globalOpts.json) {
254
+ const result = {
255
+ success: true,
256
+ source: file,
257
+ artifacts: {
258
+ "peac.txt": peacTxt,
259
+ "robots-ai-snippet.txt": robotsTxt,
260
+ "aipref-headers.json": aiprefTemplates,
261
+ "ai-policy.md": markdown
262
+ }
263
+ };
264
+ if (isStdout && !globalOpts.json) {
265
+ console.log(peacTxt);
266
+ } else {
267
+ output(result, { json: true });
268
+ }
269
+ process.exit(0);
270
+ }
271
+ const outDir = options.out;
272
+ let peacTxtPath;
273
+ if (options.wellKnown) {
274
+ peacTxtPath = path6__namespace.join(outDir, ".well-known", "peac.txt");
275
+ } else {
276
+ peacTxtPath = path6__namespace.join(outDir, "peac.txt");
277
+ }
278
+ const robotsPath = path6__namespace.join(outDir, "robots-ai-snippet.txt");
279
+ const aiprefPath = path6__namespace.join(outDir, "aipref-headers.json");
280
+ const mdPath = path6__namespace.join(outDir, "ai-policy.md");
281
+ if (options.dryRun) {
282
+ console.log("Dry run - files that would be generated:\n");
283
+ console.log(`--- ${peacTxtPath} ---`);
284
+ console.log(peacTxt);
285
+ console.log(`--- ${robotsPath} ---`);
286
+ console.log(robotsTxt);
287
+ console.log(`--- ${aiprefPath} ---`);
288
+ console.log(JSON.stringify(aiprefTemplates, null, 2));
289
+ console.log(`
290
+ --- ${mdPath} ---`);
291
+ console.log(markdown);
292
+ process.exit(0);
293
+ }
294
+ if (!fs6__namespace.existsSync(outDir)) {
295
+ fs6__namespace.mkdirSync(outDir, { recursive: true });
296
+ }
297
+ if (options.wellKnown) {
298
+ const wellKnownDir = path6__namespace.join(outDir, ".well-known");
299
+ if (!fs6__namespace.existsSync(wellKnownDir)) {
300
+ fs6__namespace.mkdirSync(wellKnownDir, { recursive: true });
301
+ }
302
+ }
303
+ fs6__namespace.writeFileSync(peacTxtPath, peacTxt, "utf-8");
304
+ console.log(`Generated: ${peacTxtPath}`);
305
+ fs6__namespace.writeFileSync(robotsPath, robotsTxt, "utf-8");
306
+ console.log(`Generated: ${robotsPath}`);
307
+ fs6__namespace.writeFileSync(aiprefPath, JSON.stringify(aiprefTemplates, null, 2), "utf-8");
308
+ console.log(`Generated: ${aiprefPath}`);
309
+ fs6__namespace.writeFileSync(mdPath, markdown, "utf-8");
310
+ console.log(`Generated: ${mdPath}`);
311
+ console.log("");
312
+ console.log("Deployment instructions:");
313
+ if (options.wellKnown) {
314
+ console.log(` 1. Deploy ${peacTxtPath} to serve at /.well-known/peac.txt`);
315
+ } else {
316
+ console.log(` 1. Copy ${peacTxtPath} to /.well-known/peac.txt`);
317
+ }
318
+ console.log(` 2. Append ${robotsPath} to your robots.txt`);
319
+ console.log(` 3. Add headers from ${aiprefPath} to your server config`);
320
+ console.log(` 4. Publish ${mdPath} for human reference`);
321
+ process.exit(0);
322
+ } catch (err) {
323
+ if (err instanceof policyKit.PolicyLoadError) {
324
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
325
+ process.exit(1);
326
+ } else {
327
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
328
+ process.exit(1);
329
+ }
330
+ }
331
+ }
332
+ );
333
+ policy.command("explain").description("Explain which rule would apply for a given context").argument("<file>", "Path to policy file").option("-t, --type <type>", "Subject type (human, org, agent)").option("-l, --labels <labels>", "Subject labels (comma-separated)").option("-i, --id <id>", "Subject ID").option(
334
+ "-p, --purpose <purpose>",
335
+ "Access purpose (crawl, index, train, inference, ai_input, ai_index, search)"
336
+ ).option(
337
+ "-m, --licensing-mode <mode>",
338
+ "Licensing mode (subscription, pay_per_crawl, pay_per_inference)"
339
+ ).option("--all-matches", "Show all matching rules, not just the first").action(
340
+ (file, options, cmd) => {
341
+ const globalOpts = getGlobalOptions(cmd);
342
+ try {
343
+ const policyDoc = policyKit.loadPolicy(file);
344
+ const context = {};
345
+ if (options.type || options.labels || options.id) {
346
+ context.subject = {};
347
+ if (options.type) {
348
+ context.subject.type = options.type;
349
+ }
350
+ if (options.labels) {
351
+ context.subject.labels = options.labels.split(",").map((l) => l.trim());
352
+ }
353
+ if (options.id) {
354
+ context.subject.id = options.id;
355
+ }
356
+ }
357
+ if (options.purpose) {
358
+ context.purpose = options.purpose;
359
+ }
360
+ if (options.licensingMode) {
361
+ context.licensing_mode = options.licensingMode;
362
+ }
363
+ if (options.allMatches) {
364
+ const matches = policyKit.explainMatches(policyDoc, context);
365
+ if (globalOpts.json) {
366
+ output(
367
+ {
368
+ success: true,
369
+ context,
370
+ matches: matches.map((m) => {
371
+ if (m === "[default]") {
372
+ return {
373
+ rule: "[default]",
374
+ decision: policyDoc.defaults.decision
375
+ };
376
+ }
377
+ const rule = policyDoc.rules.find((r) => r.name === m);
378
+ return rule ? { rule: rule.name, decision: rule.decision } : { rule: m, decision: null };
379
+ })
380
+ },
381
+ globalOpts
382
+ );
383
+ } else {
384
+ console.log("Evaluation Context:");
385
+ if (context.subject) {
386
+ console.log(` Subject: ${JSON.stringify(context.subject)}`);
387
+ } else {
388
+ console.log(" Subject: (any)");
389
+ }
390
+ console.log(` Purpose: ${context.purpose || "(any)"}`);
391
+ console.log(` Licensing Mode: ${context.licensing_mode || "(any)"}`);
392
+ console.log();
393
+ console.log(`Matching Rules (${matches.length}):`);
394
+ for (const match of matches) {
395
+ if (match === "[default]") {
396
+ console.log(` - [default] -> ${policyDoc.defaults.decision}`);
397
+ } else {
398
+ const rule = policyDoc.rules.find((r) => r.name === match);
399
+ if (rule) {
400
+ console.log(` - ${rule.name} -> ${rule.decision}`);
401
+ }
402
+ }
403
+ }
404
+ }
405
+ } else {
406
+ const result = policyKit.evaluate(policyDoc, context);
407
+ if (globalOpts.json) {
408
+ output(
409
+ {
410
+ success: true,
411
+ context,
412
+ result: {
413
+ decision: result.decision,
414
+ matchedRule: result.matched_rule || "[default]",
415
+ reason: result.reason || null
416
+ }
417
+ },
418
+ globalOpts
419
+ );
420
+ } else {
421
+ console.log("Evaluation Context:");
422
+ if (context.subject) {
423
+ console.log(` Subject: ${JSON.stringify(context.subject)}`);
424
+ } else {
425
+ console.log(" Subject: (any)");
426
+ }
427
+ console.log(` Purpose: ${context.purpose || "(any)"}`);
428
+ console.log(` Licensing Mode: ${context.licensing_mode || "(any)"}`);
429
+ console.log();
430
+ console.log("Result:");
431
+ console.log(` Decision: ${result.decision}`);
432
+ if (result.matched_rule) {
433
+ console.log(` Matched Rule: ${result.matched_rule}`);
434
+ } else {
435
+ console.log(" Matched Rule: (default)");
436
+ }
437
+ if (result.reason) {
438
+ console.log(` Reason: ${result.reason}`);
439
+ }
440
+ }
441
+ }
442
+ process.exit(0);
443
+ } catch (err) {
444
+ if (err instanceof policyKit.PolicyLoadError) {
445
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
446
+ process.exit(1);
447
+ } else {
448
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
449
+ process.exit(1);
450
+ }
451
+ }
452
+ }
453
+ );
454
+ policy.command("list-profiles").description("List available pre-built policy profiles").action((options, cmd) => {
455
+ const globalOpts = getGlobalOptions(cmd);
456
+ try {
457
+ const profileIds = policyKit.listProfiles();
458
+ const profiles = profileIds.map((id) => policyKit.getProfileSummary(id));
459
+ if (globalOpts.json) {
460
+ output(
461
+ {
462
+ success: true,
463
+ profiles: profiles.map((p) => ({
464
+ id: p.id,
465
+ name: p.name,
466
+ description: p.description,
467
+ defaultDecision: p.defaultDecision,
468
+ ruleCount: p.ruleCount,
469
+ requiresReceipt: p.requiresReceipt,
470
+ requiredParams: p.requiredParams,
471
+ optionalParams: p.optionalParams
472
+ }))
473
+ },
474
+ globalOpts
475
+ );
476
+ } else {
477
+ console.log("Available Policy Profiles:\n");
478
+ for (const profile of profiles) {
479
+ console.log(` ${profile.id}`);
480
+ console.log(` Name: ${profile.name}`);
481
+ console.log(` Default: ${profile.defaultDecision}`);
482
+ console.log(` Rules: ${profile.ruleCount}`);
483
+ if (profile.requiresReceipt) {
484
+ console.log(" Requires receipt: yes");
485
+ }
486
+ if (profile.requiredParams.length > 0) {
487
+ console.log(` Required params: ${profile.requiredParams.join(", ")}`);
488
+ }
489
+ console.log();
490
+ }
491
+ console.log('Use "peac policy show-profile <id>" for full details');
492
+ console.log('Use "peac policy init --profile <id>" to create a policy from a profile');
493
+ }
494
+ process.exit(0);
495
+ } catch (err) {
496
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
497
+ process.exit(1);
498
+ }
499
+ });
500
+ policy.command("show-profile").description("Show details of a specific policy profile").argument("<id>", "Profile ID").action((id, options, cmd) => {
501
+ const globalOpts = getGlobalOptions(cmd);
502
+ try {
503
+ const profile = policyKit.loadProfile(id);
504
+ const summary = policyKit.getProfileSummary(id);
505
+ if (globalOpts.json) {
506
+ output(
507
+ {
508
+ success: true,
509
+ profile: {
510
+ id: profile.id,
511
+ name: profile.name,
512
+ description: profile.description,
513
+ policy: profile.policy,
514
+ parameters: profile.parameters,
515
+ defaults: profile.defaults
516
+ }
517
+ },
518
+ globalOpts
519
+ );
520
+ } else {
521
+ console.log(`Profile: ${profile.name}`);
522
+ console.log(`ID: ${profile.id}`);
523
+ console.log();
524
+ console.log("Description:");
525
+ console.log(
526
+ profile.description.split("\n").map((l) => ` ${l}`).join("\n")
527
+ );
528
+ console.log();
529
+ console.log("Policy:");
530
+ console.log(` Version: ${profile.policy.version}`);
531
+ console.log(` Default decision: ${profile.policy.defaults.decision}`);
532
+ console.log(` Rules: ${profile.policy.rules?.length || 0}`);
533
+ if (profile.policy.rules && profile.policy.rules.length > 0) {
534
+ console.log();
535
+ console.log("Rules:");
536
+ for (const rule of profile.policy.rules) {
537
+ console.log(` - ${rule.name}: ${rule.decision}`);
538
+ if (rule.purpose) {
539
+ const purposes = Array.isArray(rule.purpose) ? rule.purpose.join(", ") : rule.purpose;
540
+ console.log(` purpose: ${purposes}`);
541
+ }
542
+ if (rule.reason) {
543
+ console.log(` reason: ${rule.reason}`);
544
+ }
545
+ }
546
+ }
547
+ if (Object.keys(profile.parameters || {}).length > 0) {
548
+ console.log();
549
+ console.log("Parameters:");
550
+ for (const [key, param] of Object.entries(profile.parameters || {})) {
551
+ const required = param.required ? " (required)" : "";
552
+ console.log(` ${key}${required}`);
553
+ console.log(` ${param.description}`);
554
+ if (param.default) {
555
+ console.log(` Default: ${param.default}`);
556
+ }
557
+ if (param.example) {
558
+ console.log(` Example: ${param.example}`);
559
+ }
560
+ }
561
+ }
562
+ if (profile.defaults) {
563
+ console.log();
564
+ console.log("Defaults:");
565
+ if (profile.defaults.requirements?.receipt) {
566
+ console.log(" Receipt required: yes");
567
+ }
568
+ if (profile.defaults.rate_limit) {
569
+ console.log(
570
+ ` Rate limit: ${profile.defaults.rate_limit.limit}/${profile.defaults.rate_limit.window_seconds}s`
571
+ );
572
+ }
573
+ }
574
+ }
575
+ process.exit(0);
576
+ } catch (err) {
577
+ if (err instanceof policyKit.ProfileError) {
578
+ outputError(err.message, { code: err.code, profile: id }, globalOpts);
579
+ process.exit(1);
580
+ }
581
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
582
+ process.exit(1);
583
+ }
584
+ });
585
+ function sha256(content) {
586
+ return crypto$1.createHash("sha256").update(content, "utf8").digest("hex");
587
+ }
588
+ function zodPathToJsonPointer(path8) {
589
+ if (path8.length === 0) return "";
590
+ return "/" + path8.map((segment) => {
591
+ const str = String(segment);
592
+ return str.replace(/~/g, "~0").replace(/\//g, "~1");
593
+ }).join("/");
594
+ }
595
+ function computeCanonicalDigest(input) {
596
+ try {
597
+ const canonical = crypto.canonicalize(input);
598
+ return { alg: "sha-256+jcs", value: sha256(canonical) };
599
+ } catch {
600
+ return { alg: "sha-256+json", value: sha256(JSON.stringify(input)) };
601
+ }
602
+ }
603
+ var VECTORS_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".txt", ".jwks", ".pem", ".zip"]);
604
+ var VECTORS_EXCLUDE_FILES = /* @__PURE__ */ new Set([".DS_Store", ".gitkeep", "Thumbs.db"]);
605
+ function collectFilesRecursive(dir, basePath = "") {
606
+ const files = [];
607
+ if (!fs6__namespace.existsSync(dir)) return files;
608
+ const entries = fs6__namespace.readdirSync(dir, { withFileTypes: true });
609
+ for (const entry of entries) {
610
+ if (VECTORS_EXCLUDE_FILES.has(entry.name)) continue;
611
+ const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
612
+ const fullPath = path6__namespace.join(dir, entry.name);
613
+ if (entry.isDirectory()) {
614
+ files.push(...collectFilesRecursive(fullPath, relativePath));
615
+ } else {
616
+ const ext = path6__namespace.extname(entry.name).toLowerCase();
617
+ if (VECTORS_FILE_EXTENSIONS.has(ext)) {
618
+ files.push({
619
+ relativePath,
620
+ content: fs6__namespace.readFileSync(fullPath, "utf8")
621
+ });
622
+ }
623
+ }
624
+ }
625
+ return files;
626
+ }
627
+ function computeVectorsDigest(fixturesDir, categories) {
628
+ const hash = crypto$1.createHash("sha256");
629
+ const allFiles = [];
630
+ const manifestPath = path6__namespace.join(fixturesDir, "manifest.json");
631
+ if (fs6__namespace.existsSync(manifestPath)) {
632
+ allFiles.push({
633
+ relativePath: "manifest.json",
634
+ content: fs6__namespace.readFileSync(manifestPath, "utf8")
635
+ });
636
+ }
637
+ const sortedCategories = [...categories].sort();
638
+ for (const cat of sortedCategories) {
639
+ const categoryPath = path6__namespace.join(fixturesDir, cat);
640
+ const categoryFiles = collectFilesRecursive(categoryPath, cat);
641
+ allFiles.push(...categoryFiles);
642
+ }
643
+ allFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
644
+ for (const file of allFiles) {
645
+ const fileHash = sha256(file.content);
646
+ hash.update(file.relativePath);
647
+ hash.update("\0");
648
+ hash.update(fileHash);
649
+ }
650
+ return hash.digest("hex");
651
+ }
652
+ function loadManifest(fixturesDir) {
653
+ const manifestPath = path6__namespace.join(fixturesDir, "manifest.json");
654
+ if (!fs6__namespace.existsSync(manifestPath)) {
655
+ return {};
656
+ }
657
+ try {
658
+ return JSON.parse(fs6__namespace.readFileSync(manifestPath, "utf8"));
659
+ } catch {
660
+ return {};
661
+ }
662
+ }
663
+ function getManifestEntry(manifest, category, filename) {
664
+ return manifest[category]?.[filename];
665
+ }
666
+
667
+ // src/lib/conformance/profiles.ts
668
+ var PROFILE_CAPABILITIES = {
669
+ valid: {
670
+ profile: "receipt.verify.claims",
671
+ level: "semantic",
672
+ validator: "@peac/schema:ReceiptClaimsSchema"
673
+ },
674
+ invalid: {
675
+ profile: "receipt.verify.claims",
676
+ level: "semantic",
677
+ validator: "@peac/schema:ReceiptClaimsSchema"
678
+ },
679
+ edge: {
680
+ profile: "receipt.verify.claims",
681
+ level: "semantic",
682
+ validator: "@peac/schema:ReceiptClaimsSchema"
683
+ },
684
+ "agent-identity": {
685
+ profile: "receipt.verify.agent-identity",
686
+ level: "semantic",
687
+ validator: "@peac/schema:validateAgentIdentityAttestation"
688
+ },
689
+ attribution: {
690
+ profile: "receipt.verify.attribution",
691
+ level: "semantic",
692
+ validator: "@peac/schema:validateAttributionAttestation"
693
+ },
694
+ bundle: {
695
+ profile: "bundle.shape",
696
+ level: "shape",
697
+ validator: "structural-check",
698
+ notes: "Structure-only; no cryptographic integrity verification"
699
+ },
700
+ discovery: {
701
+ profile: "discovery.config",
702
+ level: "semantic",
703
+ validator: "@peac/disc:parse"
704
+ },
705
+ dispute: {
706
+ profile: "receipt.verify.dispute",
707
+ level: "semantic",
708
+ validator: "@peac/schema:validateDisputeAttestation"
709
+ },
710
+ interaction: {
711
+ profile: "receipt.verify.interaction",
712
+ level: "semantic",
713
+ validator: "@peac/schema:validateInteractionOrdered"
714
+ },
715
+ issue: {
716
+ profile: "receipt.issue",
717
+ level: "semantic",
718
+ validator: "@peac/schema:ReceiptClaimsSchema"
719
+ },
720
+ obligations: {
721
+ profile: "receipt.verify.obligations",
722
+ level: "semantic",
723
+ validator: "@peac/schema:validateObligationsExtension"
724
+ },
725
+ policy: {
726
+ profile: "policy.evaluate",
727
+ level: "shape",
728
+ validator: "structural-check",
729
+ notes: "Structure-only; no policy evaluation logic"
730
+ },
731
+ purpose: {
732
+ profile: "receipt.verify.purpose",
733
+ level: "semantic",
734
+ validator: "@peac/schema:isValidPurposeToken"
735
+ },
736
+ verifier: {
737
+ profile: "receipt.verify",
738
+ level: "semantic",
739
+ validator: "@peac/schema:ReceiptClaimsSchema"
740
+ },
741
+ workflow: {
742
+ profile: "workflow.validate",
743
+ level: "semantic",
744
+ validator: "@peac/schema:validateWorkflowContextOrdered"
745
+ },
746
+ x402: {
747
+ profile: "transport.x402.shape",
748
+ level: "shape",
749
+ validator: "structural-check",
750
+ notes: "Structure-only; no offer/receipt verification or term matching"
751
+ }
752
+ };
753
+ function getCategoryCapability(category) {
754
+ return PROFILE_CAPABILITIES[category] ?? {
755
+ profile: `receipt.verify.${category}`,
756
+ level: "semantic",
757
+ validator: "@peac/schema:ReceiptClaimsSchema (heuristic)",
758
+ notes: "Unknown category - uses semantic receipt validation when input looks like claims"
759
+ };
760
+ }
761
+ function getCategoryProfile(category) {
762
+ return getCategoryCapability(category).profile;
763
+ }
764
+ function shouldRunAtLevel(fixtureVersion, level) {
765
+ if (!fixtureVersion) return true;
766
+ const [major, minor] = fixtureVersion.split(".").map(Number);
767
+ const fixtureLevel = major > 0 || minor >= 10 ? "full" : minor >= 9 ? "standard" : "basic";
768
+ const levelOrder = ["basic", "standard", "full"];
769
+ return levelOrder.indexOf(fixtureLevel) <= levelOrder.indexOf(level);
770
+ }
771
+ function zodCodeToKeyword(code) {
772
+ const mapping = {
773
+ invalid_type: "type",
774
+ invalid_literal: "const",
775
+ unrecognized_keys: "additionalProperties",
776
+ invalid_union: "anyOf",
777
+ invalid_enum_value: "enum",
778
+ invalid_string: "format",
779
+ too_small: "minLength",
780
+ too_big: "maxLength",
781
+ custom: "custom"
782
+ };
783
+ return mapping[code] ?? code;
784
+ }
785
+ function validateReceiptPayload(payload) {
786
+ const result = schema.ReceiptClaimsSchema.safeParse(payload);
787
+ if (result.success) {
788
+ return { valid: true };
789
+ }
790
+ const firstIssue = result.error.issues[0];
791
+ const zodPath = firstIssue?.path ?? [];
792
+ const errorPath = zodPathToJsonPointer(zodPath);
793
+ const errorKeyword = zodCodeToKeyword(firstIssue?.code ?? "unknown");
794
+ let errorCode = "E_INVALID_FORMAT";
795
+ const pathStr = zodPath.join(".");
796
+ if (pathStr === "iss" || pathStr.startsWith("iss.")) errorCode = "E_INVALID_ISSUER";
797
+ else if (pathStr === "aud" || pathStr.startsWith("aud.")) errorCode = "E_INVALID_AUDIENCE";
798
+ else if (pathStr === "iat") errorCode = "E_INVALID_IAT";
799
+ else if (pathStr === "exp") errorCode = "E_INVALID_EXP";
800
+ else if (pathStr === "rid") errorCode = "E_INVALID_RID";
801
+ else if (firstIssue?.code === "invalid_type" && zodPath.length > 0) {
802
+ errorCode = "E_REQUIRED";
803
+ }
804
+ return {
805
+ valid: false,
806
+ error_code: errorCode,
807
+ error_message: firstIssue?.message ?? "Unknown validation error",
808
+ error_path: errorPath,
809
+ error_keyword: errorKeyword
810
+ };
811
+ }
812
+ function validateParseReceiptClaims(payload) {
813
+ const pr = schema.parseReceiptClaims(payload);
814
+ if (pr.ok) {
815
+ return { valid: true };
816
+ }
817
+ return {
818
+ valid: false,
819
+ error_code: pr.error.code,
820
+ error_message: pr.error.message
821
+ };
822
+ }
823
+ function validateDiscoveryInput(input) {
824
+ if (typeof input === "string") {
825
+ const result = disc.parse(input);
826
+ if (result.valid) {
827
+ return { valid: true };
828
+ }
829
+ return {
830
+ valid: false,
831
+ error_code: "E_DISCOVERY_PARSE_ERROR",
832
+ error_message: result.errors?.join("; ") ?? "Discovery parse error"
833
+ };
834
+ }
835
+ if (typeof input === "object" && input !== null) {
836
+ const obj = input;
837
+ if (!obj.issuer || typeof obj.issuer !== "string") {
838
+ return {
839
+ valid: false,
840
+ error_code: "E_MISSING_ISSUER",
841
+ error_message: "Discovery document missing required issuer field"
842
+ };
843
+ }
844
+ if (!obj.jwks_uri || typeof obj.jwks_uri !== "string") {
845
+ return {
846
+ valid: false,
847
+ error_code: "E_MISSING_JWKS_URI",
848
+ error_message: "Discovery document missing required jwks_uri field"
849
+ };
850
+ }
851
+ return { valid: true };
852
+ }
853
+ return {
854
+ valid: false,
855
+ error_code: "E_INVALID_DISCOVERY",
856
+ error_message: "Discovery input must be string or object"
857
+ };
858
+ }
859
+ function validateAgentIdentityInput(input) {
860
+ const result = schema.validateAgentIdentityAttestation(input);
861
+ if (result.ok) {
862
+ return { valid: true };
863
+ }
864
+ return {
865
+ valid: false,
866
+ error_code: "E_INVALID_AGENT_IDENTITY",
867
+ error_message: result.error
868
+ };
869
+ }
870
+ function validateAttributionInput(input) {
871
+ const result = schema.validateAttributionAttestation(input);
872
+ if (result.ok) {
873
+ return { valid: true };
874
+ }
875
+ return {
876
+ valid: false,
877
+ error_code: "E_INVALID_ATTRIBUTION",
878
+ error_message: result.error
879
+ };
880
+ }
881
+ function validateDisputeInput(input) {
882
+ const result = schema.validateDisputeAttestation(input);
883
+ if (result.ok) {
884
+ return { valid: true };
885
+ }
886
+ return {
887
+ valid: false,
888
+ error_code: "E_INVALID_DISPUTE",
889
+ error_message: result.error
890
+ };
891
+ }
892
+ function validateInteractionInput(input) {
893
+ const result = schema.validateInteractionOrdered(input);
894
+ if (result.valid) {
895
+ return {
896
+ valid: true,
897
+ warnings: result.warnings.map((w) => w.message)
898
+ };
899
+ }
900
+ const firstError = result.errors[0];
901
+ return {
902
+ valid: false,
903
+ error_code: firstError?.code ?? "E_INVALID_INTERACTION",
904
+ error_message: firstError?.message ?? "Interaction validation failed"
905
+ };
906
+ }
907
+ function validateWorkflowInput(input) {
908
+ const result = schema.validateWorkflowContextOrdered(input);
909
+ if (result.valid) {
910
+ return { valid: true };
911
+ }
912
+ return {
913
+ valid: false,
914
+ error_code: result.error_code,
915
+ error_message: result.error
916
+ };
917
+ }
918
+ function validateObligationsInput(input) {
919
+ const result = schema.validateObligationsExtension(input);
920
+ if (result.ok) {
921
+ return { valid: true };
922
+ }
923
+ return {
924
+ valid: false,
925
+ error_code: "E_INVALID_OBLIGATIONS",
926
+ error_message: result.error
927
+ };
928
+ }
929
+ function validatePurposeInput(input) {
930
+ if (typeof input === "object" && input !== null) {
931
+ const obj = input;
932
+ if (obj.purpose_declared && Array.isArray(obj.purpose_declared)) {
933
+ for (const p of obj.purpose_declared) {
934
+ if (typeof p === "string" && !schema.isValidPurposeToken(p) && !schema.isCanonicalPurpose(p)) {
935
+ return {
936
+ valid: false,
937
+ error_code: "E_INVALID_PURPOSE_TOKEN",
938
+ error_message: `Invalid purpose token: ${p}`
939
+ };
940
+ }
941
+ }
942
+ }
943
+ if (obj.purpose_enforced && typeof obj.purpose_enforced === "string") {
944
+ if (!schema.isValidPurposeToken(obj.purpose_enforced) && !schema.isCanonicalPurpose(obj.purpose_enforced)) {
945
+ return {
946
+ valid: false,
947
+ error_code: "E_INVALID_PURPOSE_ENFORCED",
948
+ error_message: `Invalid enforced purpose: ${obj.purpose_enforced}`
949
+ };
950
+ }
951
+ }
952
+ return { valid: true };
953
+ }
954
+ return {
955
+ valid: false,
956
+ error_code: "E_INVALID_PURPOSE",
957
+ error_message: "Purpose input must be object with purpose_declared/purpose_enforced"
958
+ };
959
+ }
960
+ function validateBundleInput(input) {
961
+ if (typeof input !== "object" || input === null) {
962
+ return {
963
+ valid: false,
964
+ error_code: "E_INVALID_BUNDLE",
965
+ error_message: "Bundle must be an object"
966
+ };
967
+ }
968
+ const obj = input;
969
+ if (!obj.version || typeof obj.version !== "string") {
970
+ return {
971
+ valid: false,
972
+ error_code: "E_MISSING_VERSION",
973
+ error_message: "Bundle missing required version field"
974
+ };
975
+ }
976
+ if (!Array.isArray(obj.entries) && !Array.isArray(obj.receipts)) {
977
+ return {
978
+ valid: false,
979
+ error_code: "E_MISSING_ENTRIES",
980
+ error_message: "Bundle missing entries or receipts array"
981
+ };
982
+ }
983
+ return { valid: true };
984
+ }
985
+ function validateX402Input(input) {
986
+ if (typeof input !== "object" || input === null) {
987
+ return {
988
+ valid: false,
989
+ error_code: "E_INVALID_X402",
990
+ error_message: "x402 input must be an object"
991
+ };
992
+ }
993
+ const obj = input;
994
+ if (obj.accepts && Array.isArray(obj.accepts)) {
995
+ for (const accept of obj.accepts) {
996
+ if (typeof accept !== "object" || accept === null) {
997
+ return {
998
+ valid: false,
999
+ error_code: "E_INVALID_ACCEPTS",
1000
+ error_message: "x402 accepts must contain payment option objects"
1001
+ };
1002
+ }
1003
+ }
1004
+ return { valid: true };
1005
+ }
1006
+ if (obj.rail && obj.reference) {
1007
+ return { valid: true };
1008
+ }
1009
+ return {
1010
+ valid: false,
1011
+ error_code: "E_INVALID_X402_STRUCTURE",
1012
+ error_message: "x402 input missing required fields (accepts or rail+reference)"
1013
+ };
1014
+ }
1015
+ function validatePolicyInput(input) {
1016
+ if (typeof input !== "object" || input === null) {
1017
+ return {
1018
+ valid: false,
1019
+ error_code: "E_INVALID_POLICY",
1020
+ error_message: "Policy input must be an object"
1021
+ };
1022
+ }
1023
+ return { valid: true };
1024
+ }
1025
+ function validateIssueInput(input) {
1026
+ if (typeof input === "object" && input !== null) {
1027
+ const obj = input;
1028
+ if (obj.claims) {
1029
+ return validateReceiptPayload(obj.claims);
1030
+ }
1031
+ if (obj.payload) {
1032
+ return validateReceiptPayload(obj.payload);
1033
+ }
1034
+ }
1035
+ return { valid: true };
1036
+ }
1037
+ var CATEGORY_VALIDATORS = {
1038
+ // Receipt claim validation
1039
+ valid: (input) => {
1040
+ const obj = input;
1041
+ return validateReceiptPayload(obj.payload ?? obj.claims ?? input);
1042
+ },
1043
+ invalid: (input) => {
1044
+ const obj = input;
1045
+ return validateReceiptPayload(obj.payload ?? obj.claims ?? input);
1046
+ },
1047
+ edge: (input) => {
1048
+ const obj = input;
1049
+ return validateReceiptPayload(obj.payload ?? obj.claims ?? input);
1050
+ },
1051
+ // Parse-level validation (unified parser, parse-level error codes).
1052
+ // The claims/payload ambiguity guard lives in the runner (test-harness concern).
1053
+ parse: (input) => {
1054
+ const obj = input;
1055
+ return validateParseReceiptClaims(obj.claims ?? obj.payload ?? input);
1056
+ },
1057
+ // Category-specific validators
1058
+ "agent-identity": validateAgentIdentityInput,
1059
+ attribution: validateAttributionInput,
1060
+ bundle: validateBundleInput,
1061
+ discovery: validateDiscoveryInput,
1062
+ dispute: validateDisputeInput,
1063
+ interaction: validateInteractionInput,
1064
+ issue: validateIssueInput,
1065
+ obligations: validateObligationsInput,
1066
+ policy: validatePolicyInput,
1067
+ purpose: validatePurposeInput,
1068
+ verifier: (input) => {
1069
+ const obj = input;
1070
+ return validateReceiptPayload(obj.payload ?? obj.claims ?? input);
1071
+ },
1072
+ workflow: validateWorkflowInput,
1073
+ x402: validateX402Input
1074
+ };
1075
+ function getValidator(category) {
1076
+ return CATEGORY_VALIDATORS[category] ?? ((input) => {
1077
+ if (typeof input === "object" && input !== null) {
1078
+ const obj = input;
1079
+ if (obj.payload || obj.claims) {
1080
+ return validateReceiptPayload(obj.payload ?? obj.claims);
1081
+ }
1082
+ if ("iss" in obj || "aud" in obj || "iat" in obj || "rid" in obj) {
1083
+ return validateReceiptPayload(input);
1084
+ }
1085
+ }
1086
+ return { valid: true };
1087
+ });
1088
+ }
1089
+
1090
+ // src/lib/conformance-runner.ts
1091
+ function getGitSha() {
1092
+ try {
1093
+ return child_process.execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
1094
+ } catch {
1095
+ return void 0;
1096
+ }
1097
+ }
1098
+ function runConformance(options, callbacks) {
1099
+ const startTime = Date.now();
1100
+ const { fixturesDir, level, category, implementationName, implementationVersion } = options;
1101
+ const manifest = loadManifest(fixturesDir);
1102
+ const entries = fs6__namespace.readdirSync(fixturesDir, { withFileTypes: true });
1103
+ let categories = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
1104
+ if (category) {
1105
+ if (!categories.includes(category)) {
1106
+ throw new Error(`Category not found: ${category}`);
1107
+ }
1108
+ categories = [category];
1109
+ }
1110
+ const vectorsDigest = computeVectorsDigest(fixturesDir, categories);
1111
+ const profiles = /* @__PURE__ */ new Set();
1112
+ const results = [];
1113
+ let passed = 0;
1114
+ let failed = 0;
1115
+ let skipped = 0;
1116
+ for (const cat of categories) {
1117
+ const categoryPath = path6__namespace.join(fixturesDir, cat);
1118
+ const profile = getCategoryProfile(cat);
1119
+ profiles.add(profile);
1120
+ const validator = getValidator(cat);
1121
+ const files = fs6__namespace.readdirSync(categoryPath).filter((f) => f.endsWith(".json")).sort();
1122
+ for (const file of files) {
1123
+ const filePath = path6__namespace.join(categoryPath, file);
1124
+ const content = fs6__namespace.readFileSync(filePath, "utf8");
1125
+ let fixture;
1126
+ const baseTestId = `${cat}.${file.replace(".json", "")}`;
1127
+ callbacks?.onTestStart?.(baseTestId);
1128
+ try {
1129
+ fixture = JSON.parse(content);
1130
+ } catch (err) {
1131
+ failed++;
1132
+ const result = {
1133
+ id: `${baseTestId}.parse`,
1134
+ category: profile,
1135
+ status: "fail",
1136
+ observed: {
1137
+ valid: false,
1138
+ error_code: "E_INVALID_JSON",
1139
+ error_message: err.message
1140
+ },
1141
+ diagnostics: {
1142
+ error_code: "E_INVALID_JSON",
1143
+ error_message: err.message
1144
+ }
1145
+ };
1146
+ results.push(result);
1147
+ callbacks?.onTestComplete?.(result);
1148
+ continue;
1149
+ }
1150
+ const fixtureObj = fixture;
1151
+ const isFixturePack = Array.isArray(fixtureObj.fixtures);
1152
+ if (isFixturePack) {
1153
+ const pack = fixture;
1154
+ if (!shouldRunAtLevel(pack.version, level)) {
1155
+ skipped++;
1156
+ const result = {
1157
+ id: baseTestId,
1158
+ category: profile,
1159
+ status: "skip",
1160
+ diagnostics: {
1161
+ skip_reason: `Fixture version ${pack.version} exceeds level ${level}`
1162
+ }
1163
+ };
1164
+ results.push(result);
1165
+ callbacks?.onTestComplete?.(result);
1166
+ continue;
1167
+ }
1168
+ for (let i = 0; i < pack.fixtures.length; i++) {
1169
+ const f = pack.fixtures[i];
1170
+ const fixtureName = f.name ?? `fixture_${i}`;
1171
+ const testId = `${baseTestId}.${fixtureName.replace(/\s+/g, "_")}`;
1172
+ const inputDigest = computeCanonicalDigest(f.input);
1173
+ callbacks?.onTestStart?.(testId);
1174
+ if (typeof f.input === "object" && f.input !== null) {
1175
+ const inputObj = f.input;
1176
+ if (inputObj.claims !== void 0 && inputObj.payload !== void 0) {
1177
+ failed++;
1178
+ const result2 = {
1179
+ id: testId,
1180
+ category: profile,
1181
+ status: "fail",
1182
+ diagnostics: {
1183
+ error_message: 'Fixture has both "claims" and "payload" -- ambiguous; use one'
1184
+ }
1185
+ };
1186
+ results.push(result2);
1187
+ callbacks?.onTestComplete?.(result2);
1188
+ continue;
1189
+ }
1190
+ }
1191
+ const observed = validator(f.input);
1192
+ const expectedValid = f.expected.valid;
1193
+ const actualValid = observed.valid;
1194
+ const expectedError = f.expected.error_code ?? f.expected.error;
1195
+ const actualError = observed.error_code;
1196
+ let status;
1197
+ if (expectedValid && actualValid) {
1198
+ status = "pass";
1199
+ passed++;
1200
+ } else if (!expectedValid && !actualValid) {
1201
+ if (expectedError && actualError && expectedError !== actualError) {
1202
+ status = "fail";
1203
+ failed++;
1204
+ } else {
1205
+ status = "pass";
1206
+ passed++;
1207
+ }
1208
+ } else {
1209
+ status = "fail";
1210
+ failed++;
1211
+ }
1212
+ const result = {
1213
+ id: testId,
1214
+ category: profile,
1215
+ status,
1216
+ expected: {
1217
+ valid: expectedValid,
1218
+ error_code: expectedError
1219
+ },
1220
+ observed: {
1221
+ valid: actualValid,
1222
+ error_code: actualError,
1223
+ error_message: observed.error_message
1224
+ },
1225
+ diagnostics: {
1226
+ input_digest: inputDigest,
1227
+ warnings: observed.warnings
1228
+ }
1229
+ };
1230
+ results.push(result);
1231
+ callbacks?.onTestComplete?.(result);
1232
+ }
1233
+ } else {
1234
+ const singleFixture = fixture;
1235
+ const testId = baseTestId;
1236
+ const manifestEntry = getManifestEntry(manifest, cat, file);
1237
+ const inputToValidate = singleFixture.payload ?? fixture;
1238
+ const inputDigest = singleFixture.payload ? computeCanonicalDigest(inputToValidate) : { alg: "sha-256", value: sha256(content) };
1239
+ const expectedValid = singleFixture.expected_valid ?? manifestEntry?.expected_valid ?? (cat === "valid" || cat === "edge");
1240
+ const expectedError = singleFixture.expected_error ?? manifestEntry?.expected_error_code;
1241
+ const expectedPath = manifestEntry?.expected_path;
1242
+ const expectedKeyword = manifestEntry?.expected_keyword;
1243
+ const observed = validator(inputToValidate);
1244
+ let status;
1245
+ if (expectedValid && observed.valid) {
1246
+ status = "pass";
1247
+ passed++;
1248
+ } else if (!expectedValid && !observed.valid) {
1249
+ let mismatch = false;
1250
+ if (expectedError && observed.error_code && expectedError !== observed.error_code) {
1251
+ mismatch = true;
1252
+ }
1253
+ if (expectedPath && observed.error_path && expectedPath !== observed.error_path) {
1254
+ mismatch = true;
1255
+ }
1256
+ if (expectedKeyword && observed.error_keyword && expectedKeyword !== observed.error_keyword) {
1257
+ mismatch = true;
1258
+ }
1259
+ if (mismatch) {
1260
+ status = "fail";
1261
+ failed++;
1262
+ } else {
1263
+ status = "pass";
1264
+ passed++;
1265
+ }
1266
+ } else {
1267
+ status = "fail";
1268
+ failed++;
1269
+ }
1270
+ const result = {
1271
+ id: testId,
1272
+ category: profile,
1273
+ status,
1274
+ expected: {
1275
+ valid: expectedValid,
1276
+ error_code: expectedError,
1277
+ error_path: expectedPath,
1278
+ error_keyword: expectedKeyword
1279
+ },
1280
+ observed: {
1281
+ valid: observed.valid,
1282
+ error_code: observed.error_code,
1283
+ error_path: observed.error_path,
1284
+ error_keyword: observed.error_keyword,
1285
+ error_message: observed.error_message
1286
+ },
1287
+ diagnostics: {
1288
+ input_digest: inputDigest,
1289
+ warnings: observed.warnings
1290
+ }
1291
+ };
1292
+ results.push(result);
1293
+ callbacks?.onTestComplete?.(result);
1294
+ }
1295
+ }
1296
+ }
1297
+ const capabilities = [];
1298
+ for (const cat of categories) {
1299
+ const capability = getCategoryCapability(cat);
1300
+ if (!capabilities.some((c) => c.profile === capability.profile)) {
1301
+ capabilities.push(capability);
1302
+ }
1303
+ }
1304
+ capabilities.sort((a, b) => a.profile.localeCompare(b.profile));
1305
+ const endTime = Date.now();
1306
+ const report = {
1307
+ report_version: "peac-conformance-report/0.1",
1308
+ suite: {
1309
+ name: "peac-core-conformance",
1310
+ version: "0.1.0",
1311
+ vectors_digest: {
1312
+ alg: "sha-256",
1313
+ value: vectorsDigest
1314
+ },
1315
+ profiles: Array.from(profiles).sort(),
1316
+ capabilities
1317
+ },
1318
+ implementation: {
1319
+ name: implementationName ?? "@peac/cli",
1320
+ version: implementationVersion ?? "0.0.0"
1321
+ },
1322
+ summary: {
1323
+ passed,
1324
+ failed,
1325
+ skipped,
1326
+ total: passed + failed + skipped,
1327
+ status: failed === 0 ? "pass" : "fail"
1328
+ },
1329
+ results,
1330
+ meta: {
1331
+ generated_at: (/* @__PURE__ */ new Date()).toISOString(),
1332
+ duration_ms: endTime - startTime,
1333
+ runner: {
1334
+ name: "@peac/cli",
1335
+ version: implementationVersion ?? "0.0.0",
1336
+ git_sha: getGitSha()
1337
+ }
1338
+ }
1339
+ };
1340
+ return report;
1341
+ }
1342
+ function formatReportText(report) {
1343
+ const lines = [];
1344
+ lines.push("PEAC Conformance Test Results");
1345
+ lines.push("=============================");
1346
+ lines.push("");
1347
+ lines.push(`Status: ${report.summary.status.toUpperCase()}`);
1348
+ lines.push(`Profiles: ${report.suite.profiles.join(", ")}`);
1349
+ lines.push("");
1350
+ lines.push("Summary:");
1351
+ lines.push(` Passed: ${report.summary.passed}`);
1352
+ lines.push(` Failed: ${report.summary.failed}`);
1353
+ lines.push(` Skipped: ${report.summary.skipped}`);
1354
+ lines.push(` Total: ${report.summary.total}`);
1355
+ const failures = report.results.filter((r) => r.status === "fail");
1356
+ if (failures.length > 0) {
1357
+ lines.push("");
1358
+ lines.push("Failures:");
1359
+ for (const f of failures) {
1360
+ lines.push(` - ${f.id}`);
1361
+ if (f.expected) {
1362
+ lines.push(
1363
+ ` Expected: valid=${f.expected.valid}${f.expected.error_code ? `, error=${f.expected.error_code}` : ""}`
1364
+ );
1365
+ }
1366
+ if (f.observed) {
1367
+ lines.push(
1368
+ ` Observed: valid=${f.observed.valid}${f.observed.error_code ? `, error=${f.observed.error_code}` : ""}`
1369
+ );
1370
+ }
1371
+ }
1372
+ }
1373
+ return lines.join("\n");
1374
+ }
1375
+ function formatReportMarkdown(report) {
1376
+ const lines = [];
1377
+ lines.push("# PEAC Conformance Report");
1378
+ lines.push("");
1379
+ lines.push(`**Status:** ${report.summary.status.toUpperCase()}`);
1380
+ lines.push(`**Profiles:** ${report.suite.profiles.join(", ")}`);
1381
+ lines.push("");
1382
+ lines.push("## Summary");
1383
+ lines.push("");
1384
+ lines.push("| Metric | Count |");
1385
+ lines.push("|--------|-------|");
1386
+ lines.push(`| Passed | ${report.summary.passed} |`);
1387
+ lines.push(`| Failed | ${report.summary.failed} |`);
1388
+ lines.push(`| Skipped | ${report.summary.skipped} |`);
1389
+ lines.push(`| Total | ${report.summary.total} |`);
1390
+ const failures = report.results.filter((r) => r.status === "fail");
1391
+ if (failures.length > 0) {
1392
+ lines.push("");
1393
+ lines.push("## Failures");
1394
+ lines.push("");
1395
+ for (const f of failures) {
1396
+ lines.push(`### ${f.id}`);
1397
+ lines.push("");
1398
+ if (f.expected) {
1399
+ lines.push(
1400
+ `- **Expected:** valid=${f.expected.valid}${f.expected.error_code ? `, error=${f.expected.error_code}` : ""}`
1401
+ );
1402
+ }
1403
+ if (f.observed) {
1404
+ lines.push(
1405
+ `- **Observed:** valid=${f.observed.valid}${f.observed.error_code ? `, error=${f.observed.error_code}` : ""}`
1406
+ );
1407
+ }
1408
+ lines.push("");
1409
+ }
1410
+ }
1411
+ return lines.join("\n");
1412
+ }
1413
+ function getVersion() {
1414
+ try {
1415
+ const pkgPath = path6.join(__dirname, "..", "..", "package.json");
1416
+ if (fs6.existsSync(pkgPath)) {
1417
+ const pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf8"));
1418
+ if (pkg.version) return pkg.version;
1419
+ }
1420
+ } catch {
1421
+ }
1422
+ try {
1423
+ const pkgPath = path6.join(process.cwd(), "packages", "cli", "package.json");
1424
+ if (fs6.existsSync(pkgPath)) {
1425
+ const pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf8"));
1426
+ if (pkg.version) return pkg.version;
1427
+ }
1428
+ } catch {
1429
+ }
1430
+ return "0.0.0-unknown";
1431
+ }
1432
+ function getRuntime() {
1433
+ return `node-${process.version.slice(1)}`;
1434
+ }
1435
+ function getCommit() {
1436
+ return process.env.GIT_COMMIT ?? process.env.GITHUB_SHA;
1437
+ }
1438
+
1439
+ // src/commands/conformance.ts
1440
+ function getGlobalOptions2(cmd) {
1441
+ const parent = cmd.parent;
1442
+ if (!parent) return {};
1443
+ return parent.opts();
1444
+ }
1445
+ function outputError2(error, details, opts) {
1446
+ if (opts.json) {
1447
+ console.log(JSON.stringify({ success: false, error, ...details }, null, 2));
1448
+ } else {
1449
+ console.error(`Error: ${error}`);
1450
+ if (details.code) {
1451
+ console.error(`Code: ${details.code}`);
1452
+ }
1453
+ if (details.hint) {
1454
+ console.error(`Hint: ${details.hint}`);
1455
+ }
1456
+ }
1457
+ }
1458
+ function findFixturesDir(customPath) {
1459
+ if (customPath) {
1460
+ if (fs6__namespace.existsSync(customPath)) {
1461
+ return customPath;
1462
+ }
1463
+ return null;
1464
+ }
1465
+ const cliPath = path6__namespace.resolve(__dirname, "../../../../specs/conformance/fixtures");
1466
+ if (fs6__namespace.existsSync(cliPath)) {
1467
+ return cliPath;
1468
+ }
1469
+ const repoPath = path6__namespace.resolve(process.cwd(), "specs/conformance/fixtures");
1470
+ if (fs6__namespace.existsSync(repoPath)) {
1471
+ return repoPath;
1472
+ }
1473
+ const upPath = path6__namespace.resolve(process.cwd(), "../../specs/conformance/fixtures");
1474
+ if (fs6__namespace.existsSync(upPath)) {
1475
+ return upPath;
1476
+ }
1477
+ return null;
1478
+ }
1479
+ function listCategories(fixturesDir) {
1480
+ const entries = fs6__namespace.readdirSync(fixturesDir, { withFileTypes: true });
1481
+ return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
1482
+ }
1483
+ function countFixtures(categoryPath) {
1484
+ if (!fs6__namespace.existsSync(categoryPath)) return 0;
1485
+ const files = fs6__namespace.readdirSync(categoryPath);
1486
+ return files.filter((f) => f.endsWith(".json")).length;
1487
+ }
1488
+ var conformance = new commander.Command("conformance").description("PEAC conformance testing (v0.10.8+)").option("--json", "Output in JSON format");
1489
+ conformance.command("run").description("Run conformance tests").option("-l, --level <level>", "Conformance level: basic, standard, full", "standard").option("-c, --category <category>", "Test specific category only").option("-o, --output <format>", "Output format: json, text, markdown", "text").option("-v, --verbose", "Show detailed test output").option("--fixtures <path>", "Path to fixtures directory").option("--implementation <name>", "Implementation name for report", "@peac/cli").action(async (options, cmd) => {
1490
+ const globalOpts = getGlobalOptions2(cmd);
1491
+ const startTime = Date.now();
1492
+ try {
1493
+ const fixturesDir = findFixturesDir(options.fixtures);
1494
+ if (!fixturesDir) {
1495
+ outputError2(
1496
+ "Fixtures directory not found",
1497
+ {
1498
+ hint: options.fixtures ? `Specified path does not exist: ${options.fixtures}` : "Run from repo root, specify --fixtures <path>, or ensure specs/conformance/fixtures is available"
1499
+ },
1500
+ globalOpts
1501
+ );
1502
+ process.exitCode = 1;
1503
+ return;
1504
+ }
1505
+ const validLevels = ["basic", "standard", "full"];
1506
+ if (!validLevels.includes(options.level)) {
1507
+ outputError2(
1508
+ "Invalid conformance level",
1509
+ {
1510
+ level: options.level,
1511
+ valid: validLevels
1512
+ },
1513
+ globalOpts
1514
+ );
1515
+ process.exitCode = 1;
1516
+ return;
1517
+ }
1518
+ const callbacks = options.verbose ? {
1519
+ onTestStart: (testId) => {
1520
+ console.log(`Running: ${testId}`);
1521
+ },
1522
+ onTestComplete: (result) => {
1523
+ const status = result.status === "pass" ? "PASS" : result.status === "fail" ? "FAIL" : "SKIP";
1524
+ console.log(` ${status}: ${result.id}`);
1525
+ }
1526
+ } : void 0;
1527
+ const report = runConformance(
1528
+ {
1529
+ fixturesDir,
1530
+ level: options.level,
1531
+ category: options.category,
1532
+ implementationName: options.implementation,
1533
+ implementationVersion: getVersion()
1534
+ },
1535
+ callbacks
1536
+ );
1537
+ report.implementation.runtime = getRuntime();
1538
+ const commit = getCommit();
1539
+ if (commit) {
1540
+ report.implementation.commit = commit;
1541
+ }
1542
+ report.meta = {
1543
+ generated_at: (/* @__PURE__ */ new Date()).toISOString(),
1544
+ runner: {
1545
+ name: "peac-cli",
1546
+ version: getVersion()
1547
+ },
1548
+ duration_ms: Date.now() - startTime
1549
+ };
1550
+ if (options.output === "json" || globalOpts.json) {
1551
+ console.log(JSON.stringify(report, null, 2));
1552
+ } else if (options.output === "markdown") {
1553
+ console.log(formatReportMarkdown(report));
1554
+ } else {
1555
+ console.log(formatReportText(report));
1556
+ }
1557
+ process.exitCode = report.summary.failed === 0 ? 0 : 1;
1558
+ } catch (err) {
1559
+ outputError2(err.message, {}, globalOpts);
1560
+ process.exitCode = 1;
1561
+ }
1562
+ });
1563
+ conformance.command("list").description("List available conformance test fixtures").option("-c, --category <category>", "List fixtures in specific category").option("--fixtures <path>", "Path to fixtures directory").action((options, cmd) => {
1564
+ const globalOpts = getGlobalOptions2(cmd);
1565
+ try {
1566
+ const fixturesDir = findFixturesDir(options.fixtures);
1567
+ if (!fixturesDir) {
1568
+ outputError2(
1569
+ "Fixtures directory not found",
1570
+ {
1571
+ hint: options.fixtures ? `Specified path does not exist: ${options.fixtures}` : "Run from repo root, specify --fixtures <path>, or ensure specs/conformance/fixtures is available"
1572
+ },
1573
+ globalOpts
1574
+ );
1575
+ process.exitCode = 1;
1576
+ return;
1577
+ }
1578
+ const manifestPath = path6__namespace.join(fixturesDir, "manifest.json");
1579
+ const manifest = fs6__namespace.existsSync(manifestPath) ? JSON.parse(fs6__namespace.readFileSync(manifestPath, "utf8")) : {};
1580
+ const categories = listCategories(fixturesDir);
1581
+ if (options.category) {
1582
+ if (!categories.includes(options.category)) {
1583
+ outputError2(
1584
+ "Category not found",
1585
+ {
1586
+ category: options.category,
1587
+ available: categories
1588
+ },
1589
+ globalOpts
1590
+ );
1591
+ process.exitCode = 1;
1592
+ return;
1593
+ }
1594
+ const categoryPath = path6__namespace.join(fixturesDir, options.category);
1595
+ const files = fs6__namespace.readdirSync(categoryPath).filter((f) => f.endsWith(".json"));
1596
+ const categoryManifest = manifest[options.category];
1597
+ if (globalOpts.json) {
1598
+ const fixtures = files.map((f) => ({
1599
+ file: f,
1600
+ description: categoryManifest?.[f]?.description || "No description"
1601
+ }));
1602
+ console.log(JSON.stringify({ category: options.category, fixtures }, null, 2));
1603
+ } else {
1604
+ console.log(`Fixtures in ${options.category}:
1605
+ `);
1606
+ for (const file of files) {
1607
+ const info = categoryManifest?.[file] || {};
1608
+ const desc = info.description || "No description";
1609
+ console.log(` ${file}`);
1610
+ console.log(` ${desc}
1611
+ `);
1612
+ }
1613
+ }
1614
+ } else {
1615
+ if (globalOpts.json) {
1616
+ const categorySummary = categories.map((cat) => ({
1617
+ name: cat,
1618
+ fixture_count: countFixtures(path6__namespace.join(fixturesDir, cat))
1619
+ }));
1620
+ console.log(JSON.stringify({ categories: categorySummary }, null, 2));
1621
+ } else {
1622
+ console.log(`Available conformance test categories:
1623
+ `);
1624
+ for (const cat of categories) {
1625
+ const count = countFixtures(path6__namespace.join(fixturesDir, cat));
1626
+ console.log(` ${cat} (${count} fixtures)`);
1627
+ }
1628
+ console.log(`
1629
+ Use 'peac conformance list -c <category>' to see fixtures in a category.`);
1630
+ }
1631
+ }
1632
+ process.exitCode = 0;
1633
+ } catch (err) {
1634
+ outputError2(err.message, {}, globalOpts);
1635
+ process.exitCode = 1;
1636
+ }
1637
+ });
1638
+ var EMBEDDED_SAMPLES = [
1639
+ {
1640
+ id: "basic-receipt",
1641
+ name: "Basic Receipt",
1642
+ description: "Minimal valid PEAC receipt with only required fields",
1643
+ category: "valid",
1644
+ claims: {
1645
+ iss: "https://sandbox.peacprotocol.org",
1646
+ aud: "https://example.com",
1647
+ iat: 0,
1648
+ // Placeholder - will be set at generation time
1649
+ exp: 0,
1650
+ // Placeholder - will be set at generation time
1651
+ rid: "sample-basic-001"
1652
+ }
1653
+ },
1654
+ {
1655
+ id: "full-receipt",
1656
+ name: "Full Receipt",
1657
+ description: "PEAC receipt with all optional claims populated",
1658
+ category: "valid",
1659
+ claims: {
1660
+ iss: "https://sandbox.peacprotocol.org",
1661
+ aud: "https://api.example.com",
1662
+ sub: "user:demo-user",
1663
+ iat: 0,
1664
+ exp: 0,
1665
+ rid: "sample-full-001",
1666
+ purpose_declared: ["search", "index"],
1667
+ purpose_enforced: "search",
1668
+ purpose_reason: "allowed"
1669
+ }
1670
+ },
1671
+ {
1672
+ id: "interaction-evidence",
1673
+ name: "Interaction Evidence",
1674
+ description: "Receipt with InteractionEvidence extension for AI agent calls",
1675
+ category: "valid",
1676
+ claims: {
1677
+ iss: "https://sandbox.peacprotocol.org",
1678
+ aud: "https://agent.example.com",
1679
+ sub: "agent:demo-agent-v1",
1680
+ iat: 0,
1681
+ exp: 0,
1682
+ rid: "sample-ie-001",
1683
+ ext: {
1684
+ "org.peacprotocol/interaction@0.1": {
1685
+ version: "0.1",
1686
+ interaction_id: "int_sample_001",
1687
+ started_at: "2026-01-01T00:00:00.000Z",
1688
+ completed_at: "2026-01-01T00:00:01.000Z",
1689
+ outcome: { kind: "success" },
1690
+ input: { hash: "sha256:abc123...", byte_length: 1024 },
1691
+ output: { hash: "sha256:def456...", byte_length: 2048 }
1692
+ }
1693
+ }
1694
+ }
1695
+ },
1696
+ {
1697
+ id: "payment-evidence",
1698
+ name: "Payment Evidence",
1699
+ description: "Receipt with payment evidence (402 flow)",
1700
+ category: "valid",
1701
+ claims: {
1702
+ iss: "https://sandbox.peacprotocol.org",
1703
+ aud: "https://api.example.com",
1704
+ iat: 0,
1705
+ exp: 0,
1706
+ rid: "sample-payment-001",
1707
+ amt: "100",
1708
+ cur: "USD",
1709
+ payment: {
1710
+ rail: "x402",
1711
+ reference: "pay_sample_001",
1712
+ amount: "100",
1713
+ currency: "USD"
1714
+ }
1715
+ }
1716
+ },
1717
+ {
1718
+ id: "long-expiry",
1719
+ name: "Long Expiry",
1720
+ description: "Receipt with 24-hour expiration",
1721
+ category: "valid",
1722
+ claims: {
1723
+ iss: "https://sandbox.peacprotocol.org",
1724
+ aud: "https://example.com",
1725
+ iat: 0,
1726
+ exp: 0,
1727
+ // Will be set to iat + 86400 at generation time
1728
+ rid: "sample-long-expiry-001"
1729
+ }
1730
+ },
1731
+ {
1732
+ id: "expired",
1733
+ name: "Expired Receipt",
1734
+ description: "Receipt that has already expired (for testing rejection)",
1735
+ category: "invalid",
1736
+ claims: {
1737
+ iss: "https://sandbox.peacprotocol.org",
1738
+ aud: "https://example.com",
1739
+ iat: 0,
1740
+ // Will be set to now - 7200 at generation time
1741
+ exp: 0,
1742
+ // Will be set to now - 3600 at generation time
1743
+ rid: "sample-expired-001"
1744
+ },
1745
+ expectedError: "E_EXPIRED_RECEIPT"
1746
+ },
1747
+ {
1748
+ id: "future-iat",
1749
+ name: "Future IAT",
1750
+ description: "Receipt with iat in the future (should be rejected)",
1751
+ category: "invalid",
1752
+ claims: {
1753
+ iss: "https://sandbox.peacprotocol.org",
1754
+ aud: "https://example.com",
1755
+ iat: 0,
1756
+ // Will be set to now + 3600 at generation time
1757
+ exp: 0,
1758
+ // Will be set to now + 7200 at generation time
1759
+ rid: "sample-future-iat-001"
1760
+ },
1761
+ expectedError: "E_FUTURE_IAT"
1762
+ },
1763
+ {
1764
+ id: "missing-iss",
1765
+ name: "Missing Issuer",
1766
+ description: "Receipt missing required iss claim (for testing validation)",
1767
+ category: "invalid",
1768
+ claims: {
1769
+ aud: "https://example.com",
1770
+ iat: 0,
1771
+ exp: 0,
1772
+ rid: "sample-no-iss-001"
1773
+ },
1774
+ expectedError: "E_MISSING_CLAIM"
1775
+ }
1776
+ ];
1777
+ function findSamplesDir(customPath) {
1778
+ if (customPath) {
1779
+ if (fs6__namespace.existsSync(customPath)) {
1780
+ return customPath;
1781
+ }
1782
+ return null;
1783
+ }
1784
+ const cliPath = path6__namespace.resolve(__dirname, "../../../../specs/conformance/samples");
1785
+ if (fs6__namespace.existsSync(cliPath)) {
1786
+ return cliPath;
1787
+ }
1788
+ const repoPath = path6__namespace.resolve(process.cwd(), "specs/conformance/samples");
1789
+ if (fs6__namespace.existsSync(repoPath)) {
1790
+ return repoPath;
1791
+ }
1792
+ const upPath = path6__namespace.resolve(process.cwd(), "../../specs/conformance/samples");
1793
+ if (fs6__namespace.existsSync(upPath)) {
1794
+ return upPath;
1795
+ }
1796
+ return null;
1797
+ }
1798
+ function loadSampleFromFile(filePath, id, category) {
1799
+ try {
1800
+ const content = JSON.parse(fs6__namespace.readFileSync(filePath, "utf8"));
1801
+ const claims = content.payload ?? content.claims ?? content;
1802
+ const description = content.$comment ?? content.description ?? `Sample ${id}`;
1803
+ return {
1804
+ id,
1805
+ name: id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
1806
+ description,
1807
+ category,
1808
+ claims,
1809
+ header: content.header,
1810
+ expectedError: content.expected_error
1811
+ };
1812
+ } catch {
1813
+ return null;
1814
+ }
1815
+ }
1816
+ function loadSamplesFromDir(samplesDir) {
1817
+ const samples2 = [];
1818
+ const validDir = path6__namespace.join(samplesDir, "valid");
1819
+ if (fs6__namespace.existsSync(validDir)) {
1820
+ const files = fs6__namespace.readdirSync(validDir).filter((f) => f.endsWith(".json"));
1821
+ for (const file of files) {
1822
+ const id = file.replace(".json", "");
1823
+ const sample = loadSampleFromFile(path6__namespace.join(validDir, file), id, "valid");
1824
+ if (sample) samples2.push(sample);
1825
+ }
1826
+ }
1827
+ const invalidDir = path6__namespace.join(samplesDir, "invalid");
1828
+ if (fs6__namespace.existsSync(invalidDir)) {
1829
+ const files = fs6__namespace.readdirSync(invalidDir).filter((f) => f.endsWith(".json"));
1830
+ for (const file of files) {
1831
+ const id = file.replace(".json", "");
1832
+ const sample = loadSampleFromFile(path6__namespace.join(invalidDir, file), id, "invalid");
1833
+ if (sample) samples2.push(sample);
1834
+ }
1835
+ }
1836
+ const edgeDir = path6__namespace.join(samplesDir, "edge");
1837
+ if (fs6__namespace.existsSync(edgeDir)) {
1838
+ const files = fs6__namespace.readdirSync(edgeDir).filter((f) => f.endsWith(".json"));
1839
+ for (const file of files) {
1840
+ const id = file.replace(".json", "");
1841
+ const sample = loadSampleFromFile(path6__namespace.join(edgeDir, file), id, "edge");
1842
+ if (sample) samples2.push(sample);
1843
+ }
1844
+ }
1845
+ return samples2;
1846
+ }
1847
+ function getSamples(customSamplesPath) {
1848
+ const samplesDir = findSamplesDir(customSamplesPath);
1849
+ if (samplesDir) {
1850
+ const dirSamples = loadSamplesFromDir(samplesDir);
1851
+ if (dirSamples.length > 0) {
1852
+ return dirSamples;
1853
+ }
1854
+ }
1855
+ return EMBEDDED_SAMPLES;
1856
+ }
1857
+ function getSampleById(id, customSamplesPath) {
1858
+ const samples2 = getSamples(customSamplesPath);
1859
+ return samples2.find((s) => s.id === id) ?? null;
1860
+ }
1861
+
1862
+ // src/commands/samples.ts
1863
+ function getGlobalOptions3(cmd) {
1864
+ const parent = cmd.parent;
1865
+ if (!parent) return {};
1866
+ return parent.opts();
1867
+ }
1868
+ function outputError3(error, details, opts) {
1869
+ if (opts.json) {
1870
+ console.log(JSON.stringify({ success: false, error, ...details }, null, 2));
1871
+ } else {
1872
+ console.error(`Error: ${error}`);
1873
+ if (details.hint) {
1874
+ console.error(`Hint: ${details.hint}`);
1875
+ }
1876
+ }
1877
+ }
1878
+ function applyTimeAdjustments(claims, sampleId, now) {
1879
+ const adjusted = { ...claims };
1880
+ const standardExpiry = 3600;
1881
+ const longExpiry = 86400;
1882
+ switch (sampleId) {
1883
+ case "expired":
1884
+ adjusted.iat = now - 7200;
1885
+ adjusted.exp = now - 3600;
1886
+ break;
1887
+ case "future-iat":
1888
+ adjusted.iat = now + 3600;
1889
+ adjusted.exp = now + 7200;
1890
+ break;
1891
+ case "long-expiry":
1892
+ adjusted.iat = now;
1893
+ adjusted.exp = now + longExpiry;
1894
+ break;
1895
+ default:
1896
+ if (adjusted.iat === 0 || !adjusted.iat) {
1897
+ adjusted.iat = now;
1898
+ }
1899
+ if (adjusted.exp === 0 || !adjusted.exp) {
1900
+ adjusted.exp = now + standardExpiry;
1901
+ }
1902
+ }
1903
+ return adjusted;
1904
+ }
1905
+ var samples = new commander.Command("samples").description("Work with PEAC sample receipts (v0.10.8+)").option("--json", "Output in JSON format");
1906
+ samples.command("list").description("List available sample receipts").option("-c, --category <category>", "Filter by category: valid, invalid, edge").option("--samples <path>", "Path to samples directory").action((options, cmd) => {
1907
+ const globalOpts = getGlobalOptions3(cmd);
1908
+ try {
1909
+ const allSamples = getSamples(options.samples);
1910
+ let filteredSamples = allSamples;
1911
+ if (options.category) {
1912
+ filteredSamples = allSamples.filter((s) => s.category === options.category);
1913
+ if (filteredSamples.length === 0) {
1914
+ outputError3("No samples in category", { category: options.category }, globalOpts);
1915
+ process.exitCode = 1;
1916
+ return;
1917
+ }
1918
+ }
1919
+ if (globalOpts.json) {
1920
+ const data = filteredSamples.map((s) => ({
1921
+ id: s.id,
1922
+ name: s.name,
1923
+ description: s.description,
1924
+ category: s.category
1925
+ }));
1926
+ console.log(JSON.stringify({ samples: data }, null, 2));
1927
+ } else {
1928
+ console.log("Available PEAC Sample Receipts\n");
1929
+ console.log("VALID SAMPLES:");
1930
+ for (const s of filteredSamples.filter((x) => x.category === "valid")) {
1931
+ console.log(` ${s.id}`);
1932
+ console.log(` ${s.description}
1933
+ `);
1934
+ }
1935
+ const invalid = filteredSamples.filter((x) => x.category === "invalid");
1936
+ if (invalid.length > 0) {
1937
+ console.log("\nINVALID SAMPLES (for testing rejection):");
1938
+ for (const s of invalid) {
1939
+ console.log(` ${s.id}`);
1940
+ console.log(` ${s.description}
1941
+ `);
1942
+ }
1943
+ }
1944
+ const edge = filteredSamples.filter((x) => x.category === "edge");
1945
+ if (edge.length > 0) {
1946
+ console.log("\nEDGE CASE SAMPLES:");
1947
+ for (const s of edge) {
1948
+ console.log(` ${s.id}`);
1949
+ console.log(` ${s.description}
1950
+ `);
1951
+ }
1952
+ }
1953
+ console.log('\nUse "peac samples show <id>" to see sample details.');
1954
+ console.log('Use "peac samples generate -o <dir>" to generate sample files.');
1955
+ }
1956
+ process.exitCode = 0;
1957
+ } catch (err) {
1958
+ outputError3(err.message, {}, globalOpts);
1959
+ process.exitCode = 1;
1960
+ }
1961
+ });
1962
+ samples.command("show").description("Show details of a specific sample").argument("<id>", "Sample ID").option("--samples <path>", "Path to samples directory").action((id, options, cmd) => {
1963
+ const globalOpts = getGlobalOptions3(cmd);
1964
+ try {
1965
+ const sample = getSampleById(id, options.samples);
1966
+ if (!sample) {
1967
+ const allSamples = getSamples(options.samples);
1968
+ const available = allSamples.map((s) => s.id);
1969
+ outputError3("Sample not found", { id, available }, globalOpts);
1970
+ process.exitCode = 1;
1971
+ return;
1972
+ }
1973
+ if (globalOpts.json) {
1974
+ console.log(JSON.stringify(sample, null, 2));
1975
+ } else {
1976
+ console.log(`Sample: ${sample.name}
1977
+ `);
1978
+ console.log(`ID: ${sample.id}`);
1979
+ console.log(`Category: ${sample.category}`);
1980
+ console.log(`Description: ${sample.description}
1981
+ `);
1982
+ console.log("Claims:");
1983
+ console.log(JSON.stringify(sample.claims, null, 2));
1984
+ if (sample.expectedError) {
1985
+ console.log(`
1986
+ Expected Error: ${sample.expectedError}`);
1987
+ }
1988
+ }
1989
+ process.exitCode = 0;
1990
+ } catch (err) {
1991
+ outputError3(err.message, {}, globalOpts);
1992
+ process.exitCode = 1;
1993
+ }
1994
+ });
1995
+ samples.command("generate").description("Generate sample receipt files").requiredOption("-o, --output <dir>", "Output directory").option("-f, --format <format>", "Output format: jws, json, bundle", "jws").option("--category <category>", "Generate only specific category").option("--samples <path>", "Path to samples directory").option("--now <timestamp>", "Unix timestamp for iat/exp (for deterministic generation)").option("--kid <kid>", "Key ID to use").action(async (options, cmd) => {
1996
+ const globalOpts = getGlobalOptions3(cmd);
1997
+ try {
1998
+ const outputDir = options.output;
1999
+ const validDir = path6__namespace.join(outputDir, "valid");
2000
+ const invalidDir = path6__namespace.join(outputDir, "invalid");
2001
+ const edgeDir = path6__namespace.join(outputDir, "edge");
2002
+ const bundlesDir = path6__namespace.join(outputDir, "bundles");
2003
+ fs6__namespace.mkdirSync(validDir, { recursive: true });
2004
+ fs6__namespace.mkdirSync(invalidDir, { recursive: true });
2005
+ fs6__namespace.mkdirSync(edgeDir, { recursive: true });
2006
+ fs6__namespace.mkdirSync(bundlesDir, { recursive: true });
2007
+ const now = options.now ? parseInt(options.now, 10) : Math.floor(Date.now() / 1e3);
2008
+ const keyPair = await crypto.generateKeypair();
2009
+ const publicKeyBytes = keyPair.publicKey;
2010
+ const privateKeyBytes = keyPair.privateKey;
2011
+ const kid = options.kid || `sandbox-${new Date(now * 1e3).toISOString().slice(0, 7)}`;
2012
+ const publicJwk = {
2013
+ kty: "OKP",
2014
+ crv: "Ed25519",
2015
+ x: crypto.base64urlEncode(publicKeyBytes),
2016
+ kid,
2017
+ use: "sig",
2018
+ alg: "EdDSA"
2019
+ };
2020
+ const generatedFiles = [];
2021
+ let samplesToGenerate = getSamples(options.samples);
2022
+ if (options.category) {
2023
+ samplesToGenerate = samplesToGenerate.filter((s) => s.category === options.category);
2024
+ }
2025
+ for (const sample of samplesToGenerate) {
2026
+ const targetDir = sample.category === "valid" ? validDir : sample.category === "edge" ? edgeDir : invalidDir;
2027
+ const filename = `${sample.id}.${options.format === "json" ? "json" : "jws"}`;
2028
+ const filepath = path6__namespace.join(targetDir, filename);
2029
+ const adjustedClaims = applyTimeAdjustments(sample.claims, sample.id, now);
2030
+ if (options.format === "json") {
2031
+ const output2 = {
2032
+ $comment: sample.description,
2033
+ header: {
2034
+ alg: "EdDSA",
2035
+ typ: "peac-receipt/0.1",
2036
+ kid
2037
+ },
2038
+ payload: adjustedClaims,
2039
+ ...sample.expectedError ? { expected_error: sample.expectedError } : {}
2040
+ };
2041
+ fs6__namespace.writeFileSync(filepath, JSON.stringify(output2, null, 2));
2042
+ } else {
2043
+ const jws = await crypto.sign(adjustedClaims, privateKeyBytes, kid);
2044
+ fs6__namespace.writeFileSync(filepath, jws);
2045
+ }
2046
+ generatedFiles.push(filepath);
2047
+ }
2048
+ const jwksPath = path6__namespace.join(bundlesDir, "sandbox-jwks.json");
2049
+ const jwks = {
2050
+ keys: [publicJwk]
2051
+ };
2052
+ fs6__namespace.writeFileSync(jwksPath, JSON.stringify(jwks, null, 2));
2053
+ generatedFiles.push(jwksPath);
2054
+ const bundlePath = path6__namespace.join(bundlesDir, "offline-verification.json");
2055
+ const bundle = {
2056
+ $comment: "Offline verification bundle with sample receipts and JWKS",
2057
+ description: "Bundle for offline verification testing. Contains test JWKS and sample metadata.",
2058
+ generated_at: new Date(now * 1e3).toISOString(),
2059
+ generator: {
2060
+ name: "peac-cli",
2061
+ version: getVersion()
2062
+ },
2063
+ jwks,
2064
+ samples: samplesToGenerate.map((s) => ({
2065
+ id: s.id,
2066
+ description: s.description,
2067
+ category: s.category
2068
+ })),
2069
+ notes: [
2070
+ "Sample timestamps are based on --now parameter or generation time.",
2071
+ "Do NOT use sandbox samples in production."
2072
+ ]
2073
+ };
2074
+ fs6__namespace.writeFileSync(bundlePath, JSON.stringify(bundle, null, 2));
2075
+ generatedFiles.push(bundlePath);
2076
+ if (globalOpts.json) {
2077
+ console.log(
2078
+ JSON.stringify(
2079
+ {
2080
+ success: true,
2081
+ output_dir: outputDir,
2082
+ files_generated: generatedFiles.length,
2083
+ files: generatedFiles,
2084
+ timestamp: now,
2085
+ kid
2086
+ },
2087
+ null,
2088
+ 2
2089
+ )
2090
+ );
2091
+ } else {
2092
+ console.log(`Sample receipts generated successfully!
2093
+ `);
2094
+ console.log(`Output directory: ${outputDir}`);
2095
+ console.log(`Files generated: ${generatedFiles.length}`);
2096
+ console.log(`Timestamp: ${now} (${new Date(now * 1e3).toISOString()})`);
2097
+ console.log(`Key ID: ${kid}
2098
+ `);
2099
+ console.log("Generated files:");
2100
+ for (const f of generatedFiles) {
2101
+ console.log(` ${path6__namespace.relative(outputDir, f)}`);
2102
+ }
2103
+ console.log(`
2104
+ JWKS for verification: ${path6__namespace.relative(outputDir, jwksPath)}`);
2105
+ }
2106
+ process.exitCode = 0;
2107
+ } catch (err) {
2108
+ outputError3(err.message, {}, globalOpts);
2109
+ process.exitCode = 1;
2110
+ }
2111
+ });
2112
+
2113
+ // src/index.ts
2114
+ var program = new commander.Command();
2115
+ program.name("peac").description("PEAC protocol command-line tools").version(getVersion()).exitOverride();
2116
+ program.command("verify").description("Verify a PEAC receipt JWS").argument("<jws>", "JWS compact serialization or path to file containing JWS").option("-v, --verbose", "Show detailed output").action(async (jwsInput, options) => {
2117
+ try {
2118
+ let jws = jwsInput;
2119
+ if (fs6__namespace.existsSync(jwsInput)) {
2120
+ jws = fs6__namespace.readFileSync(jwsInput, "utf-8").trim();
2121
+ }
2122
+ console.log("Verifying PEAC receipt...\n");
2123
+ const { header, payload } = crypto.decode(jws);
2124
+ console.log("Receipt Information:");
2125
+ console.log(` Receipt ID: ${payload.rid}`);
2126
+ console.log(` Issuer: ${payload.iss}`);
2127
+ console.log(` Audience: ${payload.aud}`);
2128
+ console.log(` Amount: ${payload.amt} ${payload.cur}`);
2129
+ console.log(` Payment: ${payload.payment.rail} (${payload.payment.reference})`);
2130
+ console.log(` Issued: ${new Date(payload.iat * 1e3).toISOString()}`);
2131
+ if (payload.exp) {
2132
+ console.log(` Expires: ${new Date(payload.exp * 1e3).toISOString()}`);
2133
+ }
2134
+ console.log();
2135
+ console.log("Verifying signature...");
2136
+ const result = await protocol.verifyReceipt(jws);
2137
+ if (result.ok) {
2138
+ console.log("Signature valid!");
2139
+ if (result.perf) {
2140
+ console.log(` Verification time: ${result.perf.verify_ms.toFixed(2)}ms`);
2141
+ if (result.perf.jwks_fetch_ms) {
2142
+ console.log(` JWKS fetch time: ${result.perf.jwks_fetch_ms.toFixed(2)}ms`);
2143
+ }
2144
+ }
2145
+ process.exitCode = 0;
2146
+ } else {
2147
+ console.log(`Verification failed: ${result.reason}`);
2148
+ if (result.details) {
2149
+ console.log(` Details: ${result.details}`);
2150
+ }
2151
+ process.exitCode = 1;
2152
+ }
2153
+ } catch (err) {
2154
+ console.error("Error:", err instanceof Error ? err.message : String(err));
2155
+ process.exitCode = 1;
2156
+ }
2157
+ });
2158
+ program.command("validate-issuer").description("Validate a PEAC issuer configuration").argument("<input>", "Path to peac-issuer.json file or issuer URL").action(async (input) => {
2159
+ try {
2160
+ console.log("Validating issuer configuration...\n");
2161
+ let config;
2162
+ if (input.startsWith("http://") || input.startsWith("https://")) {
2163
+ console.log(`Fetching from ${input}...`);
2164
+ config = await protocol.fetchIssuerConfig(input);
2165
+ } else {
2166
+ const text = fs6__namespace.readFileSync(input, "utf-8");
2167
+ config = protocol.parseIssuerConfig(text);
2168
+ }
2169
+ console.log("Issuer configuration is valid!\n");
2170
+ console.log("Issuer Configuration:");
2171
+ console.log(` Version: ${config.version}`);
2172
+ console.log(` Issuer: ${config.issuer}`);
2173
+ console.log(` JWKS URI: ${config.jwks_uri}`);
2174
+ if (config.verify_endpoint) {
2175
+ console.log(` Verify: ${config.verify_endpoint}`);
2176
+ }
2177
+ if (config.receipt_versions && config.receipt_versions.length > 0) {
2178
+ console.log(` Receipts: ${config.receipt_versions.join(", ")}`);
2179
+ }
2180
+ if (config.algorithms && config.algorithms.length > 0) {
2181
+ console.log(` Algorithms: ${config.algorithms.join(", ")}`);
2182
+ }
2183
+ if (config.payment_rails && config.payment_rails.length > 0) {
2184
+ console.log(` Rails: ${config.payment_rails.join(", ")}`);
2185
+ }
2186
+ if (config.security_contact) {
2187
+ console.log(` Security: ${config.security_contact}`);
2188
+ }
2189
+ process.exitCode = 0;
2190
+ } catch (err) {
2191
+ console.error("Error:", err instanceof Error ? err.message : String(err));
2192
+ process.exitCode = 1;
2193
+ }
2194
+ });
2195
+ program.command("decode").description("Decode a PEAC receipt JWS (without verification)").argument("<jws>", "JWS compact serialization or path to file containing JWS").option("--json", "Output as JSON").action((jwsInput, options) => {
2196
+ try {
2197
+ let jws = jwsInput;
2198
+ if (fs6__namespace.existsSync(jwsInput)) {
2199
+ jws = fs6__namespace.readFileSync(jwsInput, "utf-8").trim();
2200
+ }
2201
+ const { header, payload } = crypto.decode(jws);
2202
+ if (options.json) {
2203
+ console.log(JSON.stringify({ header, payload }, null, 2));
2204
+ } else {
2205
+ console.log("PEAC Receipt (Decoded, Not Verified)\n");
2206
+ console.log("Header:");
2207
+ console.log(` typ: ${header.typ}`);
2208
+ console.log(` alg: ${header.alg}`);
2209
+ console.log(` kid: ${header.kid}`);
2210
+ console.log();
2211
+ console.log("Claims:");
2212
+ console.log(` iss: ${payload.iss}`);
2213
+ console.log(` aud: ${payload.aud}`);
2214
+ console.log(` iat: ${payload.iat} (${new Date(payload.iat * 1e3).toISOString()})`);
2215
+ if (payload.exp) {
2216
+ console.log(` exp: ${payload.exp} (${new Date(payload.exp * 1e3).toISOString()})`);
2217
+ }
2218
+ console.log(` rid: ${payload.rid}`);
2219
+ console.log(` amt: ${payload.amt}`);
2220
+ console.log(` cur: ${payload.cur}`);
2221
+ console.log();
2222
+ console.log("Payment:");
2223
+ console.log(` rail: ${payload.payment.rail}`);
2224
+ console.log(` reference: ${payload.payment.reference}`);
2225
+ console.log(` amount: ${payload.payment.amount}`);
2226
+ console.log(` currency: ${payload.payment.currency}`);
2227
+ if (payload.subject) {
2228
+ console.log();
2229
+ console.log("Subject:");
2230
+ console.log(` uri: ${payload.subject.uri}`);
2231
+ }
2232
+ if (payload.ext) {
2233
+ console.log();
2234
+ console.log("Extensions:");
2235
+ console.log(JSON.stringify(payload.ext, null, 2));
2236
+ }
2237
+ }
2238
+ process.exitCode = 0;
2239
+ } catch (err) {
2240
+ console.error("Error:", err instanceof Error ? err.message : String(err));
2241
+ process.exitCode = 1;
2242
+ }
2243
+ });
2244
+ program.addCommand(policy);
2245
+ program.addCommand(conformance);
2246
+ program.addCommand(samples);
2247
+ try {
2248
+ program.parse();
2249
+ } catch (err) {
2250
+ if (err instanceof commander.CommanderError) {
2251
+ process.exitCode = err.exitCode;
2252
+ } else {
2253
+ throw err;
2254
+ }
2255
+ }
2256
+ //# sourceMappingURL=index.cjs.map
2257
+ //# sourceMappingURL=index.cjs.map