chainlesschain 0.49.0 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AppLayout-Rvi759IS.js → AppLayout-6SPt_8Y_.js} +1 -1
  4. package/src/assets/web-panel/assets/{Dashboard-DBhFxXYQ.js → Dashboard-Br7kCwKJ.js} +2 -2
  5. package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
  6. package/src/assets/web-panel/assets/{index-uL0cZ8N_.js → index-tN-8TosE.js} +2 -2
  7. package/src/assets/web-panel/index.html +2 -2
  8. package/src/commands/agent-network.js +785 -0
  9. package/src/commands/automation.js +654 -0
  10. package/src/commands/dao.js +565 -0
  11. package/src/commands/did-v2.js +620 -0
  12. package/src/commands/economy.js +578 -0
  13. package/src/commands/evolution.js +391 -0
  14. package/src/commands/hmemory.js +442 -0
  15. package/src/commands/ipfs.js +392 -0
  16. package/src/commands/multimodal.js +404 -0
  17. package/src/commands/perf.js +433 -0
  18. package/src/commands/pipeline.js +449 -0
  19. package/src/commands/plugin-ecosystem.js +517 -0
  20. package/src/commands/sandbox.js +401 -0
  21. package/src/commands/social.js +311 -0
  22. package/src/commands/sso.js +798 -0
  23. package/src/commands/workflow.js +320 -0
  24. package/src/commands/zkp.js +227 -1
  25. package/src/index.js +27 -0
  26. package/src/lib/agent-economy.js +479 -0
  27. package/src/lib/agent-network.js +1121 -0
  28. package/src/lib/automation-engine.js +948 -0
  29. package/src/lib/dao-governance.js +569 -0
  30. package/src/lib/did-v2-manager.js +1127 -0
  31. package/src/lib/evolution-system.js +453 -0
  32. package/src/lib/hierarchical-memory.js +481 -0
  33. package/src/lib/ipfs-storage.js +575 -0
  34. package/src/lib/multimodal.js +39 -12
  35. package/src/lib/perf-tuning.js +734 -0
  36. package/src/lib/pipeline-orchestrator.js +928 -0
  37. package/src/lib/plugin-ecosystem.js +1109 -0
  38. package/src/lib/sandbox-v2.js +306 -0
  39. package/src/lib/social-graph-analytics.js +707 -0
  40. package/src/lib/sso-manager.js +841 -0
  41. package/src/lib/workflow-engine.js +454 -1
  42. package/src/lib/zkp-engine.js +249 -20
  43. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
@@ -0,0 +1,620 @@
1
+ /**
2
+ * `cc did-v2` (alias `didv2`) — CLI port of Phase 55 去中心化身份2.0.
3
+ *
4
+ * W3C DID v2.0 with did:key / did:web / did:chain methods, Verifiable
5
+ * Presentations with selective disclosure, social recovery via k-of-n
6
+ * guardian shards, identity roaming, and multi-source reputation
7
+ * aggregation.
8
+ */
9
+
10
+ import { Command } from "commander";
11
+
12
+ import {
13
+ DID_METHOD,
14
+ CREDENTIAL_STATUS,
15
+ RECOVERY_STATUS,
16
+ DID_STATUS,
17
+ ensureDIDv2Tables,
18
+ createDID,
19
+ resolveDID,
20
+ listDIDs,
21
+ updateDIDStatus,
22
+ issueCredential,
23
+ getCredential,
24
+ listCredentials,
25
+ revokeCredential,
26
+ createPresentation,
27
+ getPresentation,
28
+ listPresentations,
29
+ verifyPresentation,
30
+ startRecovery,
31
+ completeRecovery,
32
+ getRecovery,
33
+ listRecoveries,
34
+ roamIdentity,
35
+ listRoamingLog,
36
+ recordReputationSource,
37
+ aggregateReputation,
38
+ exportDID,
39
+ getStats,
40
+ getConfig,
41
+ } from "../lib/did-v2-manager.js";
42
+
43
+ function _dbFromCtx(cmd) {
44
+ const root = cmd?.parent?.parent ?? cmd?.parent;
45
+ return root?._db;
46
+ }
47
+
48
+ function _json(v) {
49
+ console.log(JSON.stringify(v, null, 2));
50
+ }
51
+
52
+ function _fmtTs(ts) {
53
+ if (!ts) return "—";
54
+ return new Date(ts).toISOString();
55
+ }
56
+
57
+ function _parseJsonArg(s, fallback) {
58
+ if (s == null) return fallback;
59
+ try {
60
+ return JSON.parse(s);
61
+ } catch {
62
+ return fallback;
63
+ }
64
+ }
65
+
66
+ export function registerDIDv2Command(program) {
67
+ const didv2 = new Command("did-v2")
68
+ .alias("didv2")
69
+ .description(
70
+ "Decentralized Identity 2.0 (Phase 55) — W3C DID v2.0 + VP + social recovery + roaming",
71
+ )
72
+ .hook("preAction", (thisCmd) => {
73
+ const db = _dbFromCtx(thisCmd);
74
+ if (db) ensureDIDv2Tables(db);
75
+ });
76
+
77
+ /* ── Catalogs ────────────────────────────────────── */
78
+
79
+ didv2
80
+ .command("config")
81
+ .description("Show DID v2.0 constants and defaults")
82
+ .option("--json", "JSON output")
83
+ .action((opts) => {
84
+ const cfg = getConfig();
85
+ if (opts.json) return _json(cfg);
86
+ console.log(`Methods: ${cfg.methods.join(", ")}`);
87
+ console.log(
88
+ `Default recovery threshold: ${cfg.defaultRecoveryThreshold} of ${cfg.defaultGuardianCount}`,
89
+ );
90
+ console.log(`VP default TTL: ${cfg.vpDefaultTTLMs}ms`);
91
+ console.log("Reputation source weights:");
92
+ for (const [source, weight] of Object.entries(
93
+ cfg.reputationSourceWeights,
94
+ )) {
95
+ console.log(` ${source.padEnd(14)} ${weight}`);
96
+ }
97
+ });
98
+
99
+ didv2
100
+ .command("methods")
101
+ .description("List supported DID methods")
102
+ .option("--json", "JSON output")
103
+ .action((opts) => {
104
+ const rows = Object.values(DID_METHOD);
105
+ if (opts.json) return _json(rows);
106
+ for (const m of rows) console.log(` ${m}`);
107
+ });
108
+
109
+ didv2
110
+ .command("cred-statuses")
111
+ .description("List credential statuses")
112
+ .option("--json", "JSON output")
113
+ .action((opts) => {
114
+ const rows = Object.values(CREDENTIAL_STATUS);
115
+ if (opts.json) return _json(rows);
116
+ for (const s of rows) console.log(` ${s}`);
117
+ });
118
+
119
+ didv2
120
+ .command("recovery-statuses")
121
+ .description("List recovery lifecycle statuses")
122
+ .option("--json", "JSON output")
123
+ .action((opts) => {
124
+ const rows = Object.values(RECOVERY_STATUS);
125
+ if (opts.json) return _json(rows);
126
+ for (const s of rows) console.log(` ${s}`);
127
+ });
128
+
129
+ /* ── DID lifecycle ───────────────────────────────── */
130
+
131
+ didv2
132
+ .command("create")
133
+ .description("Create a new DID v2.0 (Ed25519 keypair + document)")
134
+ .option("-m, --method <method>", "did:key | did:web | did:chain", "key")
135
+ .option("-d, --domain <domain>", "Domain for did:web")
136
+ .option(
137
+ "-s, --services <json>",
138
+ "Service endpoints JSON array",
139
+ (v) => _parseJsonArg(v, []),
140
+ [],
141
+ )
142
+ .option(
143
+ "-g, --guardians <json>",
144
+ "Guardian DIDs JSON array for social recovery",
145
+ (v) => _parseJsonArg(v, []),
146
+ [],
147
+ )
148
+ .option(
149
+ "-t, --threshold <n>",
150
+ "Recovery threshold",
151
+ (v) => parseInt(v, 10),
152
+ 3,
153
+ )
154
+ .option("--json", "JSON output")
155
+ .action((opts) => {
156
+ const db = _dbFromCtx(didv2);
157
+ const r = createDID(db, {
158
+ method: opts.method,
159
+ domain: opts.domain,
160
+ services: opts.services,
161
+ guardians: opts.guardians,
162
+ threshold: opts.threshold,
163
+ });
164
+ if (opts.json) return _json(r);
165
+ console.log(`Created ${r.did}`);
166
+ console.log(` method: ${r.method}`);
167
+ console.log(` publicKey: ${r.publicKey}`);
168
+ });
169
+
170
+ didv2
171
+ .command("resolve")
172
+ .argument("<did>", "DID URI")
173
+ .description("Resolve DID → DID document")
174
+ .option("--json", "JSON output")
175
+ .action((did, opts) => {
176
+ const db = _dbFromCtx(didv2);
177
+ const r = resolveDID(db, did);
178
+ if (!r) {
179
+ console.error(`Unknown DID: ${did}`);
180
+ process.exit(1);
181
+ }
182
+ if (opts.json) return _json(r);
183
+ console.log(`DID: ${r.did} method=${r.method} status=${r.status}`);
184
+ console.log(` publicKey: ${r.publicKey}`);
185
+ console.log(` reputation: ${r.reputationScore.toFixed(3)}`);
186
+ console.log(
187
+ ` guardians: ${r.recoveryGuardians.length} (threshold ${r.recoveryThreshold})`,
188
+ );
189
+ console.log(` services: ${r.serviceEndpoints.length}`);
190
+ });
191
+
192
+ didv2
193
+ .command("list")
194
+ .description("List all DIDs")
195
+ .option("-m, --method <method>", "Filter by method")
196
+ .option("-s, --status <status>", "Filter by status")
197
+ .option("--json", "JSON output")
198
+ .action((opts) => {
199
+ const db = _dbFromCtx(didv2);
200
+ const rows = listDIDs(db, { method: opts.method, status: opts.status });
201
+ if (opts.json) return _json(rows);
202
+ for (const r of rows) {
203
+ console.log(
204
+ ` ${r.did} [${r.status}] method=${r.method} rep=${r.reputationScore.toFixed(2)}`,
205
+ );
206
+ }
207
+ console.log(`(${rows.length} DIDs)`);
208
+ });
209
+
210
+ didv2
211
+ .command("revoke")
212
+ .argument("<did>", "DID URI")
213
+ .description("Revoke a DID (sets status=revoked)")
214
+ .option("--json", "JSON output")
215
+ .action((did, opts) => {
216
+ const db = _dbFromCtx(didv2);
217
+ const changed = updateDIDStatus(db, did, DID_STATUS.REVOKED);
218
+ if (opts.json) return _json({ changed });
219
+ console.log(changed ? `Revoked ${did}` : `No change for ${did}`);
220
+ });
221
+
222
+ /* ── Credentials ─────────────────────────────────── */
223
+
224
+ didv2
225
+ .command("cred-issue")
226
+ .description("Issue a Verifiable Credential")
227
+ .requiredOption("-h, --holder <did>", "Holder DID")
228
+ .requiredOption("-i, --issuer <did>", "Issuer DID")
229
+ .requiredOption("-t, --type <type>", "Credential type")
230
+ .option(
231
+ "-s, --subject <json>",
232
+ "credentialSubject JSON",
233
+ (v) => _parseJsonArg(v, {}),
234
+ {},
235
+ )
236
+ .option("-e, --expires-in <ms>", "Expires in ms", (v) => parseInt(v, 10))
237
+ .option("--json", "JSON output")
238
+ .action((opts) => {
239
+ const db = _dbFromCtx(didv2);
240
+ const r = issueCredential(db, {
241
+ holderDid: opts.holder,
242
+ issuerDid: opts.issuer,
243
+ type: opts.type,
244
+ credentialSubject: opts.subject,
245
+ expiresInMs: opts.expiresIn,
246
+ });
247
+ if (opts.json) return _json(r);
248
+ console.log(`Issued ${r.id}`);
249
+ console.log(` type: ${opts.type}`);
250
+ console.log(` issuer → holder: ${opts.issuer} → ${opts.holder}`);
251
+ });
252
+
253
+ didv2
254
+ .command("cred-show")
255
+ .argument("<id>", "Credential id")
256
+ .description("Show a credential")
257
+ .option("--json", "JSON output")
258
+ .action((id, opts) => {
259
+ const db = _dbFromCtx(didv2);
260
+ const r = getCredential(db, id);
261
+ if (!r) {
262
+ console.error(`Unknown credential: ${id}`);
263
+ process.exit(1);
264
+ }
265
+ if (opts.json) return _json(r);
266
+ console.log(`${r.id} [${r.status}] ${r.type}`);
267
+ console.log(` holder: ${r.holderDid}`);
268
+ console.log(` issuer: ${r.issuerDid}`);
269
+ console.log(` issued: ${_fmtTs(r.issuanceDate)}`);
270
+ console.log(` expires: ${_fmtTs(r.expirationDate)}`);
271
+ });
272
+
273
+ didv2
274
+ .command("creds")
275
+ .description("List credentials")
276
+ .option("-h, --holder <did>", "Filter by holder")
277
+ .option("-i, --issuer <did>", "Filter by issuer")
278
+ .option("-s, --status <status>", "Filter by status")
279
+ .option("--json", "JSON output")
280
+ .action((opts) => {
281
+ const db = _dbFromCtx(didv2);
282
+ const rows = listCredentials(db, {
283
+ holderDid: opts.holder,
284
+ issuerDid: opts.issuer,
285
+ status: opts.status,
286
+ });
287
+ if (opts.json) return _json(rows);
288
+ for (const r of rows) {
289
+ console.log(
290
+ ` ${r.id} [${r.status}] ${r.type} holder=${r.holderDid}`,
291
+ );
292
+ }
293
+ console.log(`(${rows.length} credentials)`);
294
+ });
295
+
296
+ didv2
297
+ .command("cred-revoke")
298
+ .argument("<id>", "Credential id")
299
+ .description("Revoke a credential")
300
+ .option("-r, --reason <reason>", "Revocation reason")
301
+ .option("--json", "JSON output")
302
+ .action((id, opts) => {
303
+ const db = _dbFromCtx(didv2);
304
+ const changed = revokeCredential(db, id, opts.reason);
305
+ if (opts.json) return _json({ changed });
306
+ console.log(changed ? `Revoked ${id}` : `No change for ${id}`);
307
+ });
308
+
309
+ /* ── Verifiable Presentations ────────────────────── */
310
+
311
+ didv2
312
+ .command("present")
313
+ .description("Build a Verifiable Presentation from credentials")
314
+ .requiredOption("-h, --holder <did>", "Holder DID")
315
+ .requiredOption("-c, --creds <csv>", "Credential ids CSV", (v) =>
316
+ v
317
+ .split(",")
318
+ .map((s) => s.trim())
319
+ .filter(Boolean),
320
+ )
321
+ .option("-r, --recipient <did>", "Recipient DID")
322
+ .option(
323
+ "-d, --disclose <csv>",
324
+ "Fields to selectively disclose (CSV)",
325
+ (v) =>
326
+ v
327
+ .split(",")
328
+ .map((s) => s.trim())
329
+ .filter(Boolean),
330
+ [],
331
+ )
332
+ .option("--ttl <ms>", "TTL in ms", (v) => parseInt(v, 10))
333
+ .option("--zkp", "Enable ZKP proof placeholder")
334
+ .option("--json", "JSON output")
335
+ .action((opts) => {
336
+ const db = _dbFromCtx(didv2);
337
+ const r = createPresentation(db, {
338
+ holderDid: opts.holder,
339
+ credentialIds: opts.creds,
340
+ recipientDid: opts.recipient,
341
+ disclosedFields: opts.disclose,
342
+ ttlMs: opts.ttl,
343
+ zkpEnabled: !!opts.zkp,
344
+ });
345
+ if (opts.json) return _json(r);
346
+ console.log(`VP ${r.id}`);
347
+ console.log(` credentials: ${r.credentialIds.length}`);
348
+ console.log(` expiresAt: ${_fmtTs(r.expiresAt)}`);
349
+ if (r.zkpProofId) console.log(` zkpProofId: ${r.zkpProofId}`);
350
+ });
351
+
352
+ didv2
353
+ .command("verify")
354
+ .argument("<id>", "Presentation id")
355
+ .description("Verify a Verifiable Presentation")
356
+ .option("--json", "JSON output")
357
+ .action((id, opts) => {
358
+ const db = _dbFromCtx(didv2);
359
+ const r = verifyPresentation(db, id);
360
+ if (opts.json) return _json(r);
361
+ if (r.ok) {
362
+ console.log(`✓ VP ${id} valid (${r.verificationTimeMs}ms)`);
363
+ } else {
364
+ console.log(`✗ VP ${id} invalid: ${r.reason}`);
365
+ process.exitCode = 1;
366
+ }
367
+ });
368
+
369
+ didv2
370
+ .command("vp-show")
371
+ .argument("<id>", "Presentation id")
372
+ .description("Show a presentation")
373
+ .option("--json", "JSON output")
374
+ .action((id, opts) => {
375
+ const db = _dbFromCtx(didv2);
376
+ const r = getPresentation(db, id);
377
+ if (!r) {
378
+ console.error(`Unknown presentation: ${id}`);
379
+ process.exit(1);
380
+ }
381
+ if (opts.json) return _json(r);
382
+ console.log(`VP ${r.id}`);
383
+ console.log(` holder: ${r.holderDid}`);
384
+ console.log(` recipient: ${r.recipientDid || "—"}`);
385
+ console.log(` credentials: ${r.credentialIds.length}`);
386
+ console.log(` disclosed: ${r.disclosedFields.join(", ") || "(all)"}`);
387
+ console.log(
388
+ ` verified: ${r.verified} (${r.verificationTimeMs ?? 0}ms)`,
389
+ );
390
+ console.log(` expiresAt: ${_fmtTs(r.expiresAt)}`);
391
+ });
392
+
393
+ didv2
394
+ .command("presentations")
395
+ .description("List presentations")
396
+ .option("-h, --holder <did>", "Filter by holder")
397
+ .option("--json", "JSON output")
398
+ .action((opts) => {
399
+ const db = _dbFromCtx(didv2);
400
+ const rows = listPresentations(db, { holderDid: opts.holder });
401
+ if (opts.json) return _json(rows);
402
+ for (const r of rows) {
403
+ console.log(
404
+ ` ${r.id} verified=${r.verified} holder=${r.holderDid} expires=${_fmtTs(r.expiresAt)}`,
405
+ );
406
+ }
407
+ console.log(`(${rows.length} presentations)`);
408
+ });
409
+
410
+ /* ── Social recovery ─────────────────────────────── */
411
+
412
+ didv2
413
+ .command("recover-start")
414
+ .description("Start social recovery (submit guardian shares)")
415
+ .requiredOption("-d, --did <did>", "DID to recover")
416
+ .requiredOption(
417
+ "-s, --shares <json>",
418
+ "Shares JSON array of {guardian, share}",
419
+ (v) => _parseJsonArg(v, []),
420
+ )
421
+ .option("--json", "JSON output")
422
+ .action((opts) => {
423
+ const db = _dbFromCtx(didv2);
424
+ const r = startRecovery(db, { did: opts.did, shares: opts.shares });
425
+ if (opts.json) return _json(r);
426
+ console.log(`Recovery ${r.id} status=${r.status}`);
427
+ console.log(` valid shares: ${r.validShares}/${r.threshold}`);
428
+ });
429
+
430
+ didv2
431
+ .command("recover-complete")
432
+ .argument("<recoveryId>", "Recovery attempt id")
433
+ .description("Complete recovery (rotate keypair when threshold met)")
434
+ .option("--json", "JSON output")
435
+ .action((recoveryId, opts) => {
436
+ const db = _dbFromCtx(didv2);
437
+ const r = completeRecovery(db, recoveryId);
438
+ if (opts.json) return _json(r);
439
+ console.log(`Recovered ${r.did}`);
440
+ console.log(` new publicKey: ${r.newPublicKey}`);
441
+ });
442
+
443
+ didv2
444
+ .command("recoveries")
445
+ .description("List recovery attempts")
446
+ .option("-d, --did <did>", "Filter by DID")
447
+ .option("--json", "JSON output")
448
+ .action((opts) => {
449
+ const db = _dbFromCtx(didv2);
450
+ const rows = listRecoveries(db, { did: opts.did });
451
+ if (opts.json) return _json(rows);
452
+ for (const r of rows) {
453
+ console.log(
454
+ ` ${r.id} [${r.status}] did=${r.did} shares=${r.sharesSubmitted.length}/${r.threshold}`,
455
+ );
456
+ }
457
+ console.log(`(${rows.length} attempts)`);
458
+ });
459
+
460
+ didv2
461
+ .command("recovery-show")
462
+ .argument("<id>", "Recovery id")
463
+ .description("Show a recovery attempt")
464
+ .option("--json", "JSON output")
465
+ .action((id, opts) => {
466
+ const db = _dbFromCtx(didv2);
467
+ const r = getRecovery(db, id);
468
+ if (!r) {
469
+ console.error(`Unknown recovery: ${id}`);
470
+ process.exit(1);
471
+ }
472
+ if (opts.json) return _json(r);
473
+ console.log(`Recovery ${r.id} status=${r.status}`);
474
+ console.log(` did: ${r.did}`);
475
+ console.log(` threshold: ${r.threshold}`);
476
+ console.log(` shares: ${r.sharesSubmitted.length}`);
477
+ if (r.newPublicKey) console.log(` new pubkey: ${r.newPublicKey}`);
478
+ });
479
+
480
+ /* ── Identity roaming ────────────────────────────── */
481
+
482
+ didv2
483
+ .command("roam")
484
+ .description("Roam identity to a new platform (cross-platform migration)")
485
+ .requiredOption("-d, --did <did>", "DID URI")
486
+ .requiredOption("-t, --target <platform>", "Target platform identifier")
487
+ .option("-s, --source <platform>", "Source platform identifier")
488
+ .option("-p, --proof <proof>", "Migration proof (opaque)")
489
+ .option("--json", "JSON output")
490
+ .action((opts) => {
491
+ const db = _dbFromCtx(didv2);
492
+ const r = roamIdentity(db, {
493
+ did: opts.did,
494
+ targetPlatform: opts.target,
495
+ sourcePlatform: opts.source,
496
+ migrationProof: opts.proof,
497
+ });
498
+ if (opts.json) return _json(r);
499
+ console.log(`Roamed ${r.did} → ${r.targetPlatform}`);
500
+ console.log(` credentials migrated: ${r.credentialsMigrated}`);
501
+ console.log(
502
+ ` reputation transferred: ${r.reputationTransferred.toFixed(3)}`,
503
+ );
504
+ });
505
+
506
+ didv2
507
+ .command("roaming-log")
508
+ .description("List roaming log entries")
509
+ .option("-d, --did <did>", "Filter by DID")
510
+ .option("--json", "JSON output")
511
+ .action((opts) => {
512
+ const db = _dbFromCtx(didv2);
513
+ const rows = listRoamingLog(db, { did: opts.did });
514
+ if (opts.json) return _json(rows);
515
+ for (const r of rows) {
516
+ console.log(
517
+ ` ${r.id} ${r.did} ${r.sourcePlatform || "?"} → ${r.targetPlatform} creds=${r.credentialsMigrated}`,
518
+ );
519
+ }
520
+ console.log(`(${rows.length} entries)`);
521
+ });
522
+
523
+ /* ── Reputation aggregation ──────────────────────── */
524
+
525
+ didv2
526
+ .command("rep-record")
527
+ .description("Record a reputation sample from a source")
528
+ .requiredOption("-d, --did <did>", "DID")
529
+ .requiredOption(
530
+ "-s, --source <source>",
531
+ "on-chain | social | marketplace | custom",
532
+ )
533
+ .requiredOption("--score <n>", "Score", (v) => parseFloat(v))
534
+ .option(
535
+ "-e, --evidence <json>",
536
+ "Evidence JSON",
537
+ (v) => _parseJsonArg(v, null),
538
+ null,
539
+ )
540
+ .option("--json", "JSON output")
541
+ .action((opts) => {
542
+ const db = _dbFromCtx(didv2);
543
+ const r = recordReputationSource(db, {
544
+ did: opts.did,
545
+ source: opts.source,
546
+ score: opts.score,
547
+ evidence: opts.evidence,
548
+ });
549
+ if (opts.json) return _json(r);
550
+ console.log(
551
+ `Recorded ${opts.source} score=${opts.score} (weight ${r.weight})`,
552
+ );
553
+ });
554
+
555
+ didv2
556
+ .command("rep-aggregate")
557
+ .argument("<did>", "DID URI")
558
+ .description("Aggregate reputation across sources")
559
+ .option("-s, --sources <csv>", "Filter to these sources (CSV)", (v) =>
560
+ v
561
+ .split(",")
562
+ .map((s) => s.trim())
563
+ .filter(Boolean),
564
+ )
565
+ .option("--json", "JSON output")
566
+ .action((did, opts) => {
567
+ const db = _dbFromCtx(didv2);
568
+ const r = aggregateReputation(db, did, { sources: opts.sources });
569
+ if (opts.json) return _json(r);
570
+ console.log(
571
+ `Aggregated score: ${r.aggregatedScore.toFixed(3)} (${r.sourceCount} samples)`,
572
+ );
573
+ for (const s of r.sources) {
574
+ console.log(
575
+ ` ${s.source.padEnd(14)} avg=${s.avgScore.toFixed(2)} weight=${s.weight} n=${s.sampleCount}`,
576
+ );
577
+ }
578
+ });
579
+
580
+ /* ── Export ──────────────────────────────────────── */
581
+
582
+ didv2
583
+ .command("export")
584
+ .argument("<did>", "DID URI")
585
+ .description("Export DID document + credentials")
586
+ .option("-f, --format <format>", "json-ld | jwt", "json-ld")
587
+ .option("--json", "JSON output")
588
+ .action((did, opts) => {
589
+ const db = _dbFromCtx(didv2);
590
+ const r = exportDID(db, did, { format: opts.format });
591
+ if (opts.json || opts.format === "jwt") return _json(r);
592
+ console.log(`Format: ${r.format}`);
593
+ console.log(`Document: ${JSON.stringify(r.document, null, 2)}`);
594
+ console.log(`Credentials: ${r.credentials.length}`);
595
+ console.log(`Reputation: ${r.reputationScore} Status: ${r.status}`);
596
+ });
597
+
598
+ /* ── Stats ───────────────────────────────────────── */
599
+
600
+ didv2
601
+ .command("stats")
602
+ .description("DID v2.0 stats")
603
+ .option("--json", "JSON output")
604
+ .action((opts) => {
605
+ const db = _dbFromCtx(didv2);
606
+ const s = getStats(db);
607
+ if (opts.json) return _json(s);
608
+ console.log(`DIDs: ${s.didCount} (${s.activeDIDs} active)`);
609
+ console.log(
610
+ `Credentials: ${s.credentialCount} (${s.activeCredentials} active)`,
611
+ );
612
+ console.log(
613
+ `Presentations: ${s.presentationCount} (${s.verifiedPresentations} verified)`,
614
+ );
615
+ console.log(`Recoveries: ${s.recoveryCount}`);
616
+ console.log(`Roaming log: ${s.roamingCount}`);
617
+ });
618
+
619
+ program.addCommand(didv2);
620
+ }