@peac/cli 0.12.10 → 0.12.12

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/index.mjs CHANGED
@@ -12,6 +12,7 @@ import { createHash } from 'crypto';
12
12
  import { computeReceiptRef, validateWorkflowContextOrdered, isValidPurposeToken, isCanonicalPurpose, validateObligationsExtension, validateInteractionOrdered, validateDisputeAttestation, validateAttributionAttestation, validateAgentIdentityAttestation, ReceiptClaimsSchema, parseReceiptClaims } from '@peac/schema';
13
13
  import { parse } from '@peac/disc';
14
14
  import { readDisputeBundle } from '@peac/audit';
15
+ import { createRequire } from 'module';
15
16
 
16
17
  function getGlobalOptions(cmd) {
17
18
  const parent = cmd.parent;
@@ -565,9 +566,9 @@ policy.command("show-profile").description("Show details of a specific policy pr
565
566
  function sha256(content) {
566
567
  return createHash("sha256").update(content, "utf8").digest("hex");
567
568
  }
568
- function zodPathToJsonPointer(path8) {
569
- if (path8.length === 0) return "";
570
- return "/" + path8.map((segment) => {
569
+ function zodPathToJsonPointer(path9) {
570
+ if (path9.length === 0) return "";
571
+ return "/" + path9.map((segment) => {
571
572
  const str = String(segment);
572
573
  return str.replace(/~/g, "~0").replace(/\//g, "~1");
573
574
  }).join("/");
@@ -2368,6 +2369,209 @@ function reconcileCommand() {
2368
2369
  );
2369
2370
  return reconcile;
2370
2371
  }
2372
+ var requireFrom = createRequire(path6.join(process.cwd(), "package.json"));
2373
+ function paint(status, msg) {
2374
+ const labels = {
2375
+ green: "PASS",
2376
+ yellow: "WARN",
2377
+ red: "FAIL"
2378
+ };
2379
+ return `[${labels[status]}] ${msg}`;
2380
+ }
2381
+ function parseMajor(nodeVersion) {
2382
+ const m = /^v(\d+)\./.exec(nodeVersion);
2383
+ return m ? parseInt(m[1], 10) : 0;
2384
+ }
2385
+ function checkNodeVersion() {
2386
+ const major = parseMajor(process.version);
2387
+ if (major >= 22) {
2388
+ return {
2389
+ name: "Node version",
2390
+ status: "green",
2391
+ detail: `${process.version} (>= 22 required)`
2392
+ };
2393
+ }
2394
+ return {
2395
+ name: "Node version",
2396
+ status: "red",
2397
+ detail: `${process.version} is below the required Node >= 22`
2398
+ };
2399
+ }
2400
+ function checkPackageResolution() {
2401
+ const required = ["@peac/protocol", "@peac/crypto", "@peac/schema", "@peac/kernel"];
2402
+ const missing = [];
2403
+ for (const pkg of required) {
2404
+ try {
2405
+ requireFrom.resolve(pkg);
2406
+ } catch {
2407
+ missing.push(pkg);
2408
+ }
2409
+ }
2410
+ if (missing.length === 0) {
2411
+ return {
2412
+ name: "Package resolution",
2413
+ status: "green",
2414
+ detail: `${required.length} required packages resolvable`
2415
+ };
2416
+ }
2417
+ return {
2418
+ name: "Package resolution",
2419
+ status: "red",
2420
+ detail: `${missing.length} missing: ${missing.join(", ")}`
2421
+ };
2422
+ }
2423
+ function checkKeyMaterial(cwd) {
2424
+ const env = process.env.PEAC_ISSUER_KEY || "";
2425
+ if (env) {
2426
+ if (env.startsWith("env:") || env.startsWith("file:")) {
2427
+ return {
2428
+ name: "Issuer key material",
2429
+ status: "green",
2430
+ detail: `PEAC_ISSUER_KEY set via ${env.split(":")[0]}:... scheme`
2431
+ };
2432
+ }
2433
+ return {
2434
+ name: "Issuer key material",
2435
+ status: "yellow",
2436
+ detail: "PEAC_ISSUER_KEY set but not using env: or file: scheme"
2437
+ };
2438
+ }
2439
+ const candidatePaths = [
2440
+ path6.join(cwd, "issuer.jwk.json"),
2441
+ path6.join(cwd, ".peac/issuer.jwk.json")
2442
+ ];
2443
+ for (const p of candidatePaths) {
2444
+ if (fs6.existsSync(p)) {
2445
+ return {
2446
+ name: "Issuer key material",
2447
+ status: "yellow",
2448
+ detail: `found ${path6.relative(cwd, p)}; prefer PEAC_ISSUER_KEY env var`
2449
+ };
2450
+ }
2451
+ }
2452
+ return {
2453
+ name: "Issuer key material",
2454
+ status: "yellow",
2455
+ detail: "not found (issuance disabled; read-only tools still work)"
2456
+ };
2457
+ }
2458
+ function checkPeacTxt(cwd) {
2459
+ const p = path6.join(cwd, ".well-known/peac.txt");
2460
+ if (fs6.existsSync(p)) {
2461
+ return {
2462
+ name: "peac.txt presence",
2463
+ status: "green",
2464
+ detail: `.well-known/peac.txt present at ${p}`
2465
+ };
2466
+ }
2467
+ return {
2468
+ name: "peac.txt presence",
2469
+ status: "yellow",
2470
+ detail: "no .well-known/peac.txt (discovery-layer check; optional for tool callers)"
2471
+ };
2472
+ }
2473
+ async function checkOnlineJwks(issuerUrl, timeoutMs) {
2474
+ const ctrl = new AbortController();
2475
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
2476
+ try {
2477
+ const cfgUrl = new URL("/.well-known/peac-issuer.json", issuerUrl).toString();
2478
+ const res = await fetch(cfgUrl, { signal: ctrl.signal });
2479
+ if (res.status !== 200) {
2480
+ return {
2481
+ name: "Issuer configuration",
2482
+ status: "red",
2483
+ detail: `${cfgUrl} returned ${res.status}`
2484
+ };
2485
+ }
2486
+ const cfg = await res.json();
2487
+ const jwksUri = cfg.jwks_uri;
2488
+ if (!jwksUri) {
2489
+ return {
2490
+ name: "Issuer configuration",
2491
+ status: "red",
2492
+ detail: `${cfgUrl} missing jwks_uri`
2493
+ };
2494
+ }
2495
+ const jwksRes = await fetch(jwksUri, { signal: ctrl.signal });
2496
+ if (jwksRes.status !== 200) {
2497
+ return {
2498
+ name: "Issuer configuration",
2499
+ status: "red",
2500
+ detail: `jwks_uri ${jwksUri} returned ${jwksRes.status}`
2501
+ };
2502
+ }
2503
+ const jwks = await jwksRes.json();
2504
+ const keyCount = Array.isArray(jwks.keys) ? jwks.keys.length : 0;
2505
+ if (keyCount === 0) {
2506
+ return {
2507
+ name: "Issuer configuration",
2508
+ status: "red",
2509
+ detail: `jwks_uri ${jwksUri} returned empty keys array`
2510
+ };
2511
+ }
2512
+ return {
2513
+ name: "Issuer configuration",
2514
+ status: "green",
2515
+ detail: `${cfgUrl} + jwks_uri resolvable with ${keyCount} key(s)`
2516
+ };
2517
+ } catch (err) {
2518
+ return {
2519
+ name: "Issuer configuration",
2520
+ status: "red",
2521
+ detail: `fetch failed: ${err instanceof Error ? err.message : String(err)}`
2522
+ };
2523
+ } finally {
2524
+ clearTimeout(timer);
2525
+ }
2526
+ }
2527
+ async function runDoctor(options) {
2528
+ const results = [];
2529
+ results.push(checkNodeVersion());
2530
+ results.push(checkPackageResolution());
2531
+ results.push(checkKeyMaterial(options.cwd));
2532
+ results.push(checkPeacTxt(options.cwd));
2533
+ if (options.online) {
2534
+ if (!options.issuer) {
2535
+ results.push({
2536
+ name: "Issuer configuration",
2537
+ status: "yellow",
2538
+ detail: "--online set but --issuer <url> not provided; skipping remote check"
2539
+ });
2540
+ } else {
2541
+ results.push(await checkOnlineJwks(options.issuer, options.timeout));
2542
+ }
2543
+ } else {
2544
+ results.push({
2545
+ name: "Issuer configuration",
2546
+ status: "yellow",
2547
+ detail: "offline mode (default); pass --online --issuer <url> to enable remote check"
2548
+ });
2549
+ }
2550
+ console.log("\npeac doctor");
2551
+ console.log("-----------");
2552
+ for (const r of results) {
2553
+ console.log(paint(r.status, `${r.name}: ${r.detail}`));
2554
+ }
2555
+ const hasRed = results.some((r) => r.status === "red");
2556
+ console.log(hasRed ? "\nFAIL: one or more checks are red." : "\nOK: no red checks.");
2557
+ return hasRed ? 1 : 0;
2558
+ }
2559
+ function doctor(program2) {
2560
+ program2.command("doctor").description("Run PEAC installability diagnostics (offline by default)").option("--online", "enable remote checks (issuer configuration, JWKS)", false).option("--issuer <url>", "issuer URL for --online checks (https://...)").option(
2561
+ "--timeout <ms>",
2562
+ "timeout for remote checks in milliseconds",
2563
+ (v) => parseInt(v, 10),
2564
+ 5e3
2565
+ ).action(async (opts) => {
2566
+ const exitCode = await runDoctor({
2567
+ online: !!opts.online,
2568
+ issuer: opts.issuer,
2569
+ timeout: opts.timeout,
2570
+ cwd: process.cwd()
2571
+ });
2572
+ process.exit(exitCode);
2573
+ });
2574
+ }
2371
2575
 
2372
2576
  // src/index.ts
2373
2577
  var program = new Command();
@@ -2504,6 +2708,7 @@ program.addCommand(policy);
2504
2708
  program.addCommand(conformance);
2505
2709
  program.addCommand(samples);
2506
2710
  program.addCommand(reconcileCommand());
2711
+ doctor(program);
2507
2712
  try {
2508
2713
  program.parse();
2509
2714
  } catch (err) {