enigma-memory 0.1.10 → 0.1.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.
Files changed (55) hide show
  1. package/README.md +38 -7
  2. package/apps/cli/bin/enigma.mjs +636 -49
  3. package/deploy/SIMULATION.md +152 -0
  4. package/deploy/docker-compose.local-production-simulation.yml +237 -0
  5. package/deploy/docker-compose.production.example.yml +19 -0
  6. package/deploy/kms-mock.mjs +64 -0
  7. package/deploy/nginx.local-production-simulation.conf +33 -0
  8. package/deploy/siem-mock.mjs +50 -0
  9. package/docs/benchmark-attestation-network.md +488 -0
  10. package/docs/benchmark-reproducibility.md +19 -2
  11. package/docs/blockchain-only-mechanisms.md +388 -0
  12. package/docs/demo-proof-network.md +275 -0
  13. package/docs/developer-ecosystem.md +62 -11
  14. package/docs/developer-proof-quickstart.md +325 -0
  15. package/docs/enigma-memory-ready-conformance.md +376 -0
  16. package/docs/enterprise-proof-control-plane.md +365 -0
  17. package/docs/market-category-narrative.md +398 -0
  18. package/docs/memory-drive-health-model.md +649 -0
  19. package/docs/memory-drive-strategy.md +458 -0
  20. package/docs/memory-passport-standard.md +445 -0
  21. package/docs/novelty-invention-candidates.md +161 -0
  22. package/docs/privacy-ledger-model.md +229 -0
  23. package/docs/proof-network-build-notes.md +240 -0
  24. package/docs/proof-network-claim-boundaries.md +318 -0
  25. package/docs/proof-network-dashboard-spec.md +773 -0
  26. package/docs/proof-network-glossary.md +27 -0
  27. package/docs/proof-network-launch-plan.md +421 -0
  28. package/docs/proof-network-operator-protocol.md +432 -0
  29. package/docs/proof-network-roadmap.md +431 -0
  30. package/docs/proof-network-test-plan.md +216 -0
  31. package/docs/proof-network-threat-model.md +373 -0
  32. package/docs/proof-network.md +257 -0
  33. package/docs/sdk-api.md +130 -10
  34. package/docs/solana-devnet-acceptance.md +226 -0
  35. package/docs/solana-proof-rail.md +453 -0
  36. package/examples/proof-network-anchor.json +37 -0
  37. package/examples/proof-network-attestation.json +35 -0
  38. package/examples/proof-network-grant.json +27 -0
  39. package/examples/proof-network-packet.json +71 -0
  40. package/package.json +40 -4
  41. package/packages/mcp-server/src/index.js +1 -1
  42. package/packages/proof-network/src/index.js +570 -0
  43. package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
  44. package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
  45. package/scripts/build-installer-assets.mjs +1 -1
  46. package/scripts/build-proof-network-packet.mjs +213 -0
  47. package/scripts/run-standard-memory-benchmarks.mjs +1 -1
  48. package/scripts/simulate-production-env.mjs +210 -0
  49. package/scripts/wait-for-backend-ready.mjs +101 -0
  50. package/specs/goal-completion-audit-v1.schema.json +1 -0
  51. package/specs/proof-network-anchor-batch-v1.schema.json +125 -0
  52. package/specs/proof-network-benchmark-attestation-v1.schema.json +103 -0
  53. package/specs/proof-network-capability-grant-v1.schema.json +132 -0
  54. package/specs/proof-network-packet-v1.schema.json +171 -0
  55. package/scripts/install-enigma-local.mjs +0 -270
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  import { createServer as createHttpServer } from 'node:http';
4
4
  import { realpathSync } from 'node:fs';
5
5
  import { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
6
- import { dirname, resolve } from 'node:path';
6
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
7
7
  import { pathToFileURL } from 'node:url';
8
8
  import { createVault, remember, recall, updateMemory, deleteMemory, exportBundle } from '../../../packages/vault/src/index.js';
9
9
  import { createPassport, compileContextPack } from '../../../packages/passport/src/index.js';
@@ -30,8 +30,24 @@ import {
30
30
  createSettlementBatch,
31
31
  verifyServiceSettlementReceipt,
32
32
  } from '../../../packages/settlement/src/index.js';
33
+ import {
34
+ assertNoPrivateProofPayload,
35
+ createBenchmarkAttestation,
36
+ createCapabilityGrant,
37
+ createCapabilityRevocation,
38
+ createProofNetworkAnchorBatch,
39
+ sha256Json as proofNetworkSha256Json,
40
+ validateBenchmarkAttestation,
41
+ validateCapabilityGrant,
42
+ validateCapabilityRevocation,
43
+ validateProofNetworkAnchorBatch,
44
+ validateProofNetworkPacket,
45
+ } from '../../../packages/proof-network/src/index.js';
33
46
 
34
47
  const DEFAULT_BUNDLE = '.enigma/bundle.json';
48
+ const DEFAULT_TEST_DRIVE_DIR = '.enigma/test-drive';
49
+ const DEFAULT_TEST_DRIVE_BUNDLE_NAME = 'bundle.json';
50
+ const DEFAULT_TEST_DRIVE_CROSS_MODEL_REPORT_NAME = 'cross-model-report.json';
35
51
  export const DEFAULT_RELAY_PORT = 8787;
36
52
  export const DEFAULT_GATEWAY_PORT = 8797;
37
53
  const DEFAULT_QUICKSTART_MEMORY = 'Enigma quickstart demo memory: local proof bundles can be created and verified without provider or cloud credentials.';
@@ -279,10 +295,10 @@ function quickstartOutputs(bundleInput, outDirInput) {
279
295
  };
280
296
  }
281
297
 
282
- async function buildQuickstartArtifacts(flags, { bundleInput = DEFAULT_BUNDLE, outDirInput = dirname(bundleInput), overwrite = false, write = true } = {}) {
298
+ async function buildQuickstartArtifacts(flags, { bundleInput = DEFAULT_BUNDLE, outDirInput = dirname(bundleInput), overwrite = false, write = true, checkExisting = true } = {}) {
283
299
  const paths = quickstartOutputs(bundleInput, outDirInput);
284
300
  ensureDistinctOutputPaths(paths.outputs.map((output) => output.path));
285
- await assertCanWriteQuickstartOutputs(paths.outputs, overwrite);
301
+ if (checkExisting) await assertCanWriteQuickstartOutputs(paths.outputs, overwrite);
286
302
 
287
303
  const vault = createVault({
288
304
  subjectId: String(getFlag(flags, ['subject', 'subject-id'], 'local-user')),
@@ -1133,6 +1149,39 @@ export async function quickstartCommand(flags, io) {
1133
1149
  return artifacts.verifyReport.ok === true ? 0 : 1;
1134
1150
  }
1135
1151
 
1152
+ function buildCrossModelProfileSummaries({ vault, passport, demoMemoryAddr, limit }) {
1153
+ const profiles = [];
1154
+ for (const profile of CROSS_MODEL_PROFILES) {
1155
+ const pack = compileContextPack({
1156
+ vault,
1157
+ passport,
1158
+ provider: profile.provider,
1159
+ model: profile.model,
1160
+ query: 'memory follows me across models',
1161
+ purpose: `cross_model_demo:${profile.id}`,
1162
+ memory_addresses: [demoMemoryAddr],
1163
+ limit,
1164
+ });
1165
+ const contextPack = publicContextPackSummary(pack);
1166
+ profiles.push({
1167
+ profile: profile.id,
1168
+ label: profile.label,
1169
+ provider: profile.provider,
1170
+ model: profile.model,
1171
+ context_pack_ref: contextPack.context_pack_ref,
1172
+ context_pack_id: contextPack.context_pack_id,
1173
+ context_pack_digest: contextPack.context_pack_digest,
1174
+ context_pack: contextPack,
1175
+ receipt_count: contextPack.receipt_count,
1176
+ memory_count: contextPack.memory_count,
1177
+ provider_native_memory_canonical: false,
1178
+ receipts: contextPack.receipts,
1179
+ claim_boundaries: { ...CROSS_MODEL_CLAIM_BOUNDARIES },
1180
+ });
1181
+ }
1182
+ return profiles;
1183
+ }
1184
+
1136
1185
  export async function crossModelDemoCommand(flags, io) {
1137
1186
  const bundleFlag = getFlag(flags, ['bundle', 'file']);
1138
1187
  if (bundleFlag === true || bundleFlag === '') throw new Error('Missing required --bundle.');
@@ -1189,35 +1238,7 @@ export async function crossModelDemoCommand(flags, io) {
1189
1238
  const limit = integerFlag(flags, ['limit'], 'limit', 1);
1190
1239
  if (limit < 1) throw new Error('--limit must be at least 1.');
1191
1240
  const receiptCountBeforeProfiles = Array.isArray(vault.receipts) ? vault.receipts.length : 0;
1192
- const profiles = [];
1193
- for (const profile of CROSS_MODEL_PROFILES) {
1194
- const pack = compileContextPack({
1195
- vault,
1196
- passport,
1197
- provider: profile.provider,
1198
- model: profile.model,
1199
- query: 'memory follows me across models',
1200
- purpose: `cross_model_demo:${profile.id}`,
1201
- memory_addresses: [demoMemoryAddr],
1202
- limit,
1203
- });
1204
- const contextPack = publicContextPackSummary(pack);
1205
- profiles.push({
1206
- profile: profile.id,
1207
- label: profile.label,
1208
- provider: profile.provider,
1209
- model: profile.model,
1210
- context_pack_ref: contextPack.context_pack_ref,
1211
- context_pack_id: contextPack.context_pack_id,
1212
- context_pack_digest: contextPack.context_pack_digest,
1213
- context_pack: contextPack,
1214
- receipt_count: contextPack.receipt_count,
1215
- memory_count: contextPack.memory_count,
1216
- provider_native_memory_canonical: false,
1217
- receipts: contextPack.receipts,
1218
- claim_boundaries: { ...CROSS_MODEL_CLAIM_BOUNDARIES },
1219
- });
1220
- }
1241
+ const profiles = buildCrossModelProfileSummaries({ vault, passport, demoMemoryAddr, limit });
1221
1242
 
1222
1243
  const bundle = await persistState(bundlePath, vault);
1223
1244
  const report = {
@@ -1327,20 +1348,14 @@ async function contextCommand(flags, io) {
1327
1348
  }
1328
1349
 
1329
1350
 
1330
- async function searchCommand(flags, io) {
1331
- const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1332
- const query = String(requireFlag(flags, ['query', 'q'], 'query'));
1333
- const limit = integerFlag(flags, ['limit'], 'limit', 8);
1334
- if (limit < 0) throw new Error('--limit must be non-negative.');
1335
- const includeContent = getFlag(flags, ['include-content', 'includeContent']) === true || getFlag(flags, ['include-content', 'includeContent']) === 'true';
1336
- const { vault } = await loadState(bundlePath);
1351
+ function memorySearchReport({ bundlePath, vault, query, limit, includeContent = false, now = '2026-01-01T00:00:00.000Z' }) {
1337
1352
  const roots = vault.__computeRoots();
1338
1353
  const queryTokens = searchTokensFrom(query);
1339
1354
  const { candidates, byAddress } = searchCandidates(vault, queryTokens);
1340
1355
  const plan = createMemoryOptimizationPlan({
1341
1356
  candidates,
1342
1357
  prompt: query,
1343
- now: getFlag(flags, ['now'], '2026-01-01T00:00:00.000Z'),
1358
+ now,
1344
1359
  });
1345
1360
  const planIndex = new Map(plan.items.map((item, index) => [item.address, index]));
1346
1361
  const selectedItems = plan.items
@@ -1381,7 +1396,7 @@ async function searchCommand(flags, io) {
1381
1396
  ...(includeContent ? { content: hit.content } : {}),
1382
1397
  };
1383
1398
  });
1384
- print({
1399
+ return {
1385
1400
  ok: true,
1386
1401
  schema: 'enigma.memory_search.v1',
1387
1402
  bundle: bundlePath,
@@ -1395,18 +1410,33 @@ async function searchCommand(flags, io) {
1395
1410
  claim_boundary: includeContent
1396
1411
  ? 'Search ran against the selected local bundle and includes plaintext only because --include-content was explicit; this does not prove provider deletion, provider-native memory state, or model forgetting.'
1397
1412
  : 'Search ran against the selected local bundle and redacts plaintext by default; refs, scores, tags, roots, and receipt refs are not provider deletion proof or model forgetting proof.',
1398
- }, io);
1399
- return 0;
1413
+ };
1400
1414
  }
1401
1415
 
1402
- async function statusCommand(flags, io) {
1416
+ async function searchCommand(flags, io) {
1403
1417
  const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1404
- const { stored, vault, passport } = await loadState(bundlePath);
1418
+ const query = String(requireFlag(flags, ['query', 'q'], 'query'));
1419
+ const limit = integerFlag(flags, ['limit'], 'limit', 8);
1420
+ if (limit < 0) throw new Error('--limit must be non-negative.');
1421
+ const includeContent = getFlag(flags, ['include-content', 'includeContent']) === true || getFlag(flags, ['include-content', 'includeContent']) === 'true';
1422
+ const { vault } = await loadState(bundlePath);
1423
+ print(memorySearchReport({
1424
+ bundlePath,
1425
+ vault,
1426
+ query,
1427
+ limit,
1428
+ includeContent,
1429
+ now: getFlag(flags, ['now'], '2026-01-01T00:00:00.000Z'),
1430
+ }), io);
1431
+ return 0;
1432
+ }
1433
+
1434
+ function passportStatusReport({ bundlePath, stored = {}, vault, passport }) {
1405
1435
  const roots = vault.__computeRoots();
1406
1436
  const activeCount = activeMemoryCount(vault);
1407
1437
  const tombstoneCount = vault.tombstones instanceof Map ? vault.tombstones.size : 0;
1408
1438
  const receiptCount = Array.isArray(vault.receipts) ? vault.receipts.length : 0;
1409
- print({
1439
+ return {
1410
1440
  ok: true,
1411
1441
  schema: 'enigma.passport_status.v1',
1412
1442
  bundle: bundlePath,
@@ -1434,10 +1464,317 @@ async function statusCommand(flags, io) {
1434
1464
  `enigma connect <client> --bundle "${bundlePath}"`,
1435
1465
  ],
1436
1466
  claim_boundary: 'Status reports local bundle counters, owner display fields, connector readiness hints, and commitment roots only; it does not expose raw memory, certify compliance, prove provider deletion, or prove model forgetting.',
1437
- }, io);
1467
+ };
1468
+ }
1469
+
1470
+ async function statusCommand(flags, io) {
1471
+ const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1472
+ const { stored, vault, passport } = await loadState(bundlePath);
1473
+ print(passportStatusReport({ bundlePath, stored, vault, passport }), io);
1438
1474
  return 0;
1439
1475
  }
1440
1476
 
1477
+ function testDrivePathDisplay(outDirInput, name) {
1478
+ return isAbsolute(outDirInput) ? join(outDirInput, name) : quickstartPathDisplay(outDirInput, name);
1479
+ }
1480
+
1481
+ function testDriveBundleDisplay(outDirInput) {
1482
+ return testDrivePathDisplay(outDirInput, DEFAULT_TEST_DRIVE_BUNDLE_NAME);
1483
+ }
1484
+
1485
+ function testDriveOutputs(outDirInput, bundleInput = testDriveBundleDisplay(outDirInput)) {
1486
+ const quickstart = quickstartOutputs(bundleInput, outDirInput);
1487
+ const contextPackDisplay = testDrivePathDisplay(outDirInput, QUICKSTART_ARTIFACT_NAMES.contextPack);
1488
+ const exportDisplay = testDrivePathDisplay(outDirInput, QUICKSTART_ARTIFACT_NAMES.export);
1489
+ const verifyReportDisplay = testDrivePathDisplay(outDirInput, QUICKSTART_ARTIFACT_NAMES.verifyReport);
1490
+ const crossModelReportDisplay = testDrivePathDisplay(outDirInput, DEFAULT_TEST_DRIVE_CROSS_MODEL_REPORT_NAME);
1491
+ const crossModelReportPath = resolve(quickstart.outDirPath, DEFAULT_TEST_DRIVE_CROSS_MODEL_REPORT_NAME);
1492
+ const artifacts = [
1493
+ { role: 'bundle', path: quickstart.bundlePath, display: bundleInput, schema: 'enigma.bundle.v1' },
1494
+ { role: 'context_pack', path: quickstart.contextPackPath, display: contextPackDisplay, schema: 'enigma.context_pack.v1' },
1495
+ { role: 'export', path: quickstart.exportPath, display: exportDisplay, schema: 'enigma.bundle.v1' },
1496
+ { role: 'verify_report', path: quickstart.verifyReportPath, display: verifyReportDisplay, schema: 'enigma.verify_report.v1' },
1497
+ { role: 'cross_model_report', path: crossModelReportPath, display: crossModelReportDisplay, schema: 'enigma.cross_model_demo.v1' },
1498
+ ];
1499
+ return {
1500
+ ...quickstart,
1501
+ contextPackDisplay,
1502
+ exportDisplay,
1503
+ verifyReportDisplay,
1504
+ crossModelReportPath,
1505
+ crossModelReportDisplay,
1506
+ artifacts,
1507
+ outputs: artifacts.map((artifact) => ({ path: artifact.path, display: artifact.display })),
1508
+ };
1509
+ }
1510
+
1511
+ function testDriveFileSummaries(artifacts, written) {
1512
+ return artifacts.map((artifact) => ({
1513
+ role: artifact.role,
1514
+ path: artifact.display,
1515
+ schema: artifact.schema,
1516
+ written: Boolean(written),
1517
+ }));
1518
+ }
1519
+
1520
+ function firstActiveMemoryAddress(vault) {
1521
+ if (!(vault.activeAddresses instanceof Set)) throw new Error('Test drive vault did not expose an active memory set.');
1522
+ const first = vault.activeAddresses.values().next();
1523
+ if (first.done) throw new Error('Test drive vault did not create a demo memory.');
1524
+ return first.value;
1525
+ }
1526
+
1527
+ function testDriveNextCommands(bundleDisplay, crossModelReportDisplay) {
1528
+ const quotedBundle = commandPath(bundleDisplay);
1529
+ const quotedReport = commandPath(crossModelReportDisplay);
1530
+ return [
1531
+ `enigma status --bundle ${quotedBundle}`,
1532
+ `enigma search --bundle ${quotedBundle} --query "local proof bundle"`,
1533
+ `enigma demo cross-model --bundle ${quotedBundle} --out ${quotedReport}`,
1534
+ 'node scripts/run-memory-benchmarks.mjs',
1535
+ ];
1536
+ }
1537
+
1538
+ function testDriveFlowCommands({ bundleDisplay, outDirInput, crossModelReportDisplay, overwrite }) {
1539
+ const overwriteSuffix = overwrite ? ' --overwrite' : '';
1540
+ const quotedBundle = commandPath(bundleDisplay);
1541
+ const quotedOutDir = commandPath(outDirInput);
1542
+ const quotedReport = commandPath(crossModelReportDisplay);
1543
+ return [
1544
+ `enigma quickstart --bundle ${quotedBundle} --out-dir ${quotedOutDir}${overwriteSuffix}`,
1545
+ `enigma status --bundle ${quotedBundle}`,
1546
+ `enigma search --bundle ${quotedBundle} --query "local proof bundle"`,
1547
+ `enigma demo cross-model --bundle ${quotedBundle} --out ${quotedReport}`,
1548
+ ];
1549
+ }
1550
+
1551
+ function testDriveBenchmarkPointers() {
1552
+ return [
1553
+ {
1554
+ command: 'node scripts/run-memory-benchmarks.mjs',
1555
+ public_safe: true,
1556
+ planned_only: true,
1557
+ requires_repo_checkout: true,
1558
+ external_provider_calls: false,
1559
+ raw_memory_included: false,
1560
+ claim_boundary: 'Runs deterministic local fixture operations only; it is not a provider comparison, hosted service proof, benchmark leadership claim, ROI claim, provider deletion proof, or model forgetting proof.',
1561
+ },
1562
+ {
1563
+ command: 'node scripts/download-standard-benchmarks.mjs --dry-run',
1564
+ public_safe: true,
1565
+ planned_only: true,
1566
+ requires_repo_checkout: true,
1567
+ external_provider_calls: false,
1568
+ raw_memory_included: false,
1569
+ claim_boundary: 'Plans official dataset downloads without fetching by default; raw benchmark records are not included in the public plan.',
1570
+ },
1571
+ {
1572
+ command: 'node scripts/run-standard-memory-benchmarks.mjs --locomo <path> --longmemeval <path>',
1573
+ public_safe: true,
1574
+ planned_only: true,
1575
+ requires_repo_checkout: true,
1576
+ external_provider_calls: false,
1577
+ raw_memory_included: false,
1578
+ claim_boundary: 'Runs local deterministic retrieval proxies against operator-supplied dataset files; it emits no provider API calls, competitor scores, benchmark leadership claim, or model-forgetting claim.',
1579
+ },
1580
+ ];
1581
+ }
1582
+
1583
+ function testDriveClaimBoundaries() {
1584
+ return {
1585
+ local_only: true,
1586
+ credentials_required: false,
1587
+ external_provider_calls: false,
1588
+ client_config_writes_performed: false,
1589
+ plaintext_memory_echoed: false,
1590
+ hosted_saas_live_claim: false,
1591
+ provider_native_memory_canonical: false,
1592
+ provider_deletion_proof: false,
1593
+ model_forgetting_proof: false,
1594
+ benchmark_leadership_claim: false,
1595
+ compliance_certification: false,
1596
+ };
1597
+ }
1598
+
1599
+ function publicTestDriveStatusSummary(summary, bundleDisplay) {
1600
+ return {
1601
+ ...summary,
1602
+ bundle: bundleDisplay,
1603
+ connector_readiness: {
1604
+ ...summary.connector_readiness,
1605
+ bundle: bundleDisplay,
1606
+ },
1607
+ next_recommended_commands: [
1608
+ `enigma remember --bundle ${commandPath(bundleDisplay)} --text-file <path>`,
1609
+ `enigma search --bundle ${commandPath(bundleDisplay)} --query <text>`,
1610
+ `enigma context --bundle ${commandPath(bundleDisplay)} --query <text>`,
1611
+ `enigma verify --bundle ${commandPath(bundleDisplay)}`,
1612
+ `enigma connect <client> --bundle ${commandPath(bundleDisplay)}`,
1613
+ ],
1614
+ };
1615
+ }
1616
+
1617
+ function publicTestDriveSearchSummary(summary, bundleDisplay) {
1618
+ return {
1619
+ ...summary,
1620
+ bundle: bundleDisplay,
1621
+ };
1622
+ }
1623
+
1624
+ function staticSetupSelection(requestedSelection) {
1625
+ return {
1626
+ ...requestedSelection,
1627
+ fallback_used: false,
1628
+ selected: requestedSelection.clients.map((clientId) => {
1629
+ const profile = getClientProfile(clientId);
1630
+ return publicSetupClientSelectionEntry({ client_id: clientId, display_name: profile.display_name }, requestedSelection.mode === 'default' ? 'default_setup_client' : 'explicit_client');
1631
+ }),
1632
+ skipped: [],
1633
+ connectable_client_ids: null,
1634
+ };
1635
+ }
1636
+
1637
+ export async function testDriveCommand(flags, io) {
1638
+ const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], DEFAULT_TEST_DRIVE_DIR);
1639
+ const bundleInput = pathFlag(flags, ['bundle', 'file'], testDriveBundleDisplay(outDirInput));
1640
+ const overwrite = booleanFlag(flags, ['overwrite'], false);
1641
+ const dryRun = booleanFlag(flags, ['dry-run', 'dryRun'], false);
1642
+ const outputs = testDriveOutputs(outDirInput, bundleInput);
1643
+ ensureDistinctOutputPaths(outputs.outputs.map((output) => output.path));
1644
+ if (!dryRun) await assertCanWriteQuickstartOutputs(outputs.outputs, overwrite);
1645
+
1646
+ const artifacts = await buildQuickstartArtifacts(flags, {
1647
+ bundleInput,
1648
+ outDirInput,
1649
+ overwrite,
1650
+ write: false,
1651
+ checkExisting: false,
1652
+ });
1653
+ const requestedSelection = setupClientIds(flags);
1654
+ const selection = requestedSelection.auto
1655
+ ? await setupAutoClientSelection(flags, artifacts, DEFAULT_SETUP_CLIENTS, 'auto')
1656
+ : staticSetupSelection(requestedSelection);
1657
+ const demoMemoryAddr = firstActiveMemoryAddress(artifacts.vault);
1658
+ const crossModelLimit = integerFlag(flags, ['limit'], 'limit', 1);
1659
+ if (crossModelLimit < 1) throw new Error('--limit must be at least 1.');
1660
+ const receiptCountBeforeProfiles = Array.isArray(artifacts.vault.receipts) ? artifacts.vault.receipts.length : 0;
1661
+ const profiles = buildCrossModelProfileSummaries({
1662
+ vault: artifacts.vault,
1663
+ passport: artifacts.passport,
1664
+ demoMemoryAddr,
1665
+ limit: crossModelLimit,
1666
+ });
1667
+ const finalExport = exportBundle({ vault: artifacts.vault, includePlaintext: false });
1668
+ const finalBundle = finalExport.bundle ?? finalExport;
1669
+ const finalVerifyReport = verifyBundle(finalBundle);
1670
+ const crossModelReport = {
1671
+ ok: true,
1672
+ schema: 'enigma.cross_model_demo.v1',
1673
+ command: 'enigma demo cross-model',
1674
+ story: 'One local Enigma memory is packaged as public-safe context pack references and receipts for ChatGPT, Claude, Kimi, Cursor, and a local LLM. No provider is called.',
1675
+ bundle_ref: bundleInput,
1676
+ bundle_supplied: true,
1677
+ bundle_created: true,
1678
+ demo_only_vault: true,
1679
+ memory_source: 'test_drive_demo',
1680
+ demo_memory_addr: demoMemoryAddr,
1681
+ profile_count: profiles.length,
1682
+ profiles,
1683
+ memory_count: activeMemoryCount(artifacts.vault),
1684
+ receipt_count: Array.isArray(finalBundle.receipts) ? finalBundle.receipts.length : 0,
1685
+ generated_receipt_count: (Array.isArray(finalBundle.receipts) ? finalBundle.receipts.length : 0) - receiptCountBeforeProfiles,
1686
+ provider_credentials_required: false,
1687
+ provider_native_memory_canonical: false,
1688
+ out_written: !dryRun,
1689
+ claim_boundaries: { ...CROSS_MODEL_CLAIM_BOUNDARIES },
1690
+ };
1691
+ const rawStatusSummary = passportStatusReport({
1692
+ bundlePath: outputs.bundlePath,
1693
+ vault: artifacts.vault,
1694
+ passport: artifacts.passport,
1695
+ stored: {
1696
+ owner: {
1697
+ subject_id: artifacts.vault.subject_id,
1698
+ display_name: artifacts.vault.display_name,
1699
+ },
1700
+ },
1701
+ });
1702
+ const statusSummary = publicTestDriveStatusSummary(rawStatusSummary, bundleInput);
1703
+ const rawSearchSummary = memorySearchReport({
1704
+ bundlePath: outputs.bundlePath,
1705
+ vault: artifacts.vault,
1706
+ query: 'local proof bundle',
1707
+ limit: 3,
1708
+ includeContent: false,
1709
+ now: getFlag(flags, ['now'], '2026-01-01T00:00:00.000Z'),
1710
+ });
1711
+ const searchSummary = publicTestDriveSearchSummary(rawSearchSummary, bundleInput);
1712
+
1713
+ if (!dryRun) {
1714
+ await writeJson(outputs.bundlePath, finalBundle);
1715
+ await writeJson(outputs.contextPackPath, publicContextPackSummary(artifacts.contextPack));
1716
+ await writeJson(outputs.exportPath, finalBundle);
1717
+ await writeJson(outputs.verifyReportPath, finalVerifyReport);
1718
+ await writeJson(outputs.crossModelReportPath, crossModelReport);
1719
+ }
1720
+
1721
+ const flowCommands = testDriveFlowCommands({
1722
+ bundleDisplay: bundleInput,
1723
+ outDirInput,
1724
+ crossModelReportDisplay: outputs.crossModelReportDisplay,
1725
+ overwrite,
1726
+ });
1727
+ const nextCommands = testDriveNextCommands(bundleInput, outputs.crossModelReportDisplay);
1728
+ const files = testDriveFileSummaries(outputs.artifacts, !dryRun);
1729
+ const packageJson = await readPackageJson();
1730
+ const ok = finalVerifyReport.ok === true && crossModelReport.ok === true && statusSummary.ok === true && searchSummary.ok === true;
1731
+ print({
1732
+ ok,
1733
+ schema: 'enigma.test_drive.v1',
1734
+ command: 'enigma test-drive',
1735
+ dry_run: dryRun,
1736
+ out_dir: outDirInput,
1737
+ bundle: bundleInput,
1738
+ install_command: `npm install -g ${packageJson.name ?? 'enigma-memory'}`,
1739
+ release_target: '0.1.12',
1740
+ artifacts_written: !dryRun,
1741
+ client_configs_written: false,
1742
+ client_config_write_required: false,
1743
+ memory_plaintext_echoed: false,
1744
+ provider_credentials_required: false,
1745
+ hosted_saas_live: false,
1746
+ files,
1747
+ files_written: dryRun ? [] : files.map((file) => file.path),
1748
+ files_planned: files.map((file) => file.path),
1749
+ commands_run: dryRun ? [] : flowCommands,
1750
+ commands_planned: dryRun ? flowCommands : [],
1751
+ next_commands: nextCommands,
1752
+ benchmark_pointers: testDriveBenchmarkPointers(),
1753
+ setup_summary: {
1754
+ schema: 'enigma.setup.v1',
1755
+ artifacts_written: !dryRun,
1756
+ bundle: bundleInput,
1757
+ context_pack: outputs.contextPackDisplay,
1758
+ export: outputs.exportDisplay,
1759
+ verify_report: outputs.verifyReportDisplay,
1760
+ selected_clients: selection.clients,
1761
+ client_selection: publicSetupClientSelection(selection),
1762
+ client_configs_written: false,
1763
+ provider_credentials_required: false,
1764
+ memory_plaintext_echoed: false,
1765
+ memory_count: Array.isArray(finalBundle.memory_objects) ? finalBundle.memory_objects.length : 0,
1766
+ receipt_count: Array.isArray(finalBundle.receipts) ? finalBundle.receipts.length : 0,
1767
+ context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
1768
+ verify_ok: finalVerifyReport.ok === true,
1769
+ },
1770
+ status_summary: statusSummary,
1771
+ search_summary: searchSummary,
1772
+ cross_model_summary: crossModelReport,
1773
+ claim_boundaries: testDriveClaimBoundaries(),
1774
+ }, io);
1775
+ return ok ? 0 : 1;
1776
+ }
1777
+
1441
1778
  async function exportCommand(flags, io) {
1442
1779
  const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1443
1780
  const { vault } = await loadState(bundlePath);
@@ -1764,6 +2101,229 @@ function integerFlag(flags, names, label = names[0], fallback = undefined) {
1764
2101
  return number;
1765
2102
  }
1766
2103
 
2104
+ function flagValues(flags, names) {
2105
+ const values = [];
2106
+ for (const name of names) {
2107
+ const value = getFlag(flags, [name]);
2108
+ const entries = Array.isArray(value) ? value : [value];
2109
+ for (const entry of entries) {
2110
+ if (entry === undefined || entry === true || entry === '') continue;
2111
+ for (const item of String(entry).split(',')) {
2112
+ const trimmed = item.trim();
2113
+ if (trimmed) values.push(trimmed);
2114
+ }
2115
+ }
2116
+ }
2117
+ return values;
2118
+ }
2119
+
2120
+ function chainWriteOrPrint(flags, io, artifact, summary) {
2121
+ if (flags.has('out')) {
2122
+ const outPath = resolve(String(requireFlag(flags, ['out'])));
2123
+ return writeJson(outPath, artifact).then(() => {
2124
+ print({
2125
+ ok: true,
2126
+ path: publicPathDisplay(String(requireFlag(flags, ['out'])), 'proof-network-artifact'),
2127
+ transaction_submitted: false,
2128
+ raw_memory_on_chain: false,
2129
+ ...summary,
2130
+ }, io);
2131
+ return 0;
2132
+ });
2133
+ }
2134
+ print(artifact, io);
2135
+ return 0;
2136
+ }
2137
+
2138
+ async function sha256PublicFile(path) {
2139
+ const bytes = await readFile(path);
2140
+ try {
2141
+ assertNoPrivateProofPayload(JSON.parse(bytes.toString('utf8')));
2142
+ } catch (error) {
2143
+ if (error instanceof SyntaxError) return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
2144
+ throw new Error('Report file contains private proof payload markers.');
2145
+ }
2146
+ return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
2147
+ }
2148
+
2149
+ function scoreFlags(flags) {
2150
+ const scores = {};
2151
+ for (const value of flagValues(flags, ['score', 'scores', 'metric', 'metrics'])) {
2152
+ const eq = value.indexOf('=');
2153
+ if (eq <= 0) throw new Error('--score values must use name=value.');
2154
+ const key = value.slice(0, eq).trim();
2155
+ const raw = value.slice(eq + 1).trim();
2156
+ if (!key || !raw) throw new Error('--score values must use name=value.');
2157
+ const numeric = Number(raw);
2158
+ scores[key] = Number.isFinite(numeric) && raw !== '' ? numeric : raw;
2159
+ }
2160
+ return scores;
2161
+ }
2162
+
2163
+
2164
+ function assertChainArtifact(validate, artifact) {
2165
+ const result = chainValidationResult(validate, artifact);
2166
+ if (!result.ok) throw new Error(result.errors?.join('; ') || 'Invalid proof-network artifact.');
2167
+ return artifact;
2168
+ }
2169
+ function chainValidationResult(validate, artifact) {
2170
+ assertNoPrivateProofPayload(artifact);
2171
+ const result = validate(artifact);
2172
+ if (result === false) return { ok: false };
2173
+ if (result && typeof result === 'object') return { ok: result.ok !== false, ...result };
2174
+ return { ok: true };
2175
+ }
2176
+
2177
+ function chainArtifactValidator(artifact) {
2178
+ const schema = String(artifact?.schema ?? artifact?.type ?? artifact?.artifact_type ?? '');
2179
+ if (schema === 'enigma.proof_network.anchor_batch.v1') return [schema, validateProofNetworkAnchorBatch];
2180
+ if (schema === 'enigma.proof_network.capability_grant.v1') return [schema, validateCapabilityGrant];
2181
+ if (schema === 'enigma.proof_network.capability_revocation.v1') return [schema, validateCapabilityRevocation];
2182
+ if (schema === 'enigma.proof_network.benchmark_attestation.v1') return [schema, validateBenchmarkAttestation];
2183
+ if (schema === 'enigma.proof_network.packet.v1') return [schema, validateProofNetworkPacket];
2184
+ throw new Error(`Unsupported proof-network artifact schema: ${schema || 'missing'}.`);
2185
+ }
2186
+
2187
+ export async function chainAnchorCommand(flags, io) {
2188
+ const roots = flagValues(flags, ['root', 'roots', 'memory-root', 'memoryRoot', 'receipt-root', 'receiptRoot', 'context-root', 'contextRoot', 'memory-commitment-root', 'memoryCommitmentRoot']);
2189
+ if (roots.length === 0) throw new Error('Missing required --root.');
2190
+ const refs = flagValues(flags, ['ref', 'refs', 'public-ref', 'publicRef']);
2191
+ const publicChainRef = getFlag(flags, ['public-chain-ref', 'publicChainRef', 'chain-ref', 'chainRef'], 'solana:local-plan');
2192
+ const batch = createProofNetworkAnchorBatch({
2193
+ roots,
2194
+ root_count: roots.length,
2195
+ commitment_count: roots.length,
2196
+ refs,
2197
+ public_chain_ref: publicChainRef,
2198
+ authority_ref: getFlag(flags, ['authority', 'authority-ref', 'authorityRef']),
2199
+ batch_ref: getFlag(flags, ['batch-ref', 'batchRef']),
2200
+ created_at: getFlag(flags, ['created-at', 'createdAt']),
2201
+ transaction_submitted: false,
2202
+ raw_memory_on_chain: false,
2203
+ });
2204
+ assertChainArtifact(validateProofNetworkAnchorBatch, batch);
2205
+ return chainWriteOrPrint(flags, io, batch, {
2206
+ artifact_type: batch.schema,
2207
+ anchor_batch_id: batch.anchor_batch_id,
2208
+ anchor_batch_hash: batch.anchor_batch_hash ?? proofNetworkSha256Json(batch),
2209
+ });
2210
+ }
2211
+
2212
+ export async function chainGrantCommand(flags, io) {
2213
+ const resourceRefs = flagValues(flags, ['resource-root', 'resource-roots', 'resourceRoot', 'resourceRoots', 'resource-ref', 'resource-refs', 'resourceRef', 'resourceRefs', 'ref', 'refs']);
2214
+ const capability = requireFlag(flags, ['capability', 'capability-id', 'capabilityId'], 'capability');
2215
+ const scope = requireFlag(flags, ['scope', 'scope-ref', 'scopeRef', 'capability-scope', 'capabilityScope'], 'scope');
2216
+ const policyHash = getFlag(flags, ['policy-hash', 'policyHash'], proofNetworkSha256Json({ capability, scope, resource_refs: resourceRefs }));
2217
+ const grant = createCapabilityGrant({
2218
+ issuer_ref: getFlag(flags, ['issuer', 'issuer-ref', 'issuerRef'], 'issuer:local-cli'),
2219
+ subject_ref: requireFlag(flags, ['subject', 'subject-ref', 'subjectRef'], 'subject'),
2220
+ capability,
2221
+ scope,
2222
+ scopes: scope,
2223
+ capability_scope: scope,
2224
+ resource_roots: resourceRefs.length ? resourceRefs : [policyHash],
2225
+ policy_hash: policyHash,
2226
+ expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
2227
+ grant_ref: getFlag(flags, ['grant-ref', 'grantRef']),
2228
+ issued_at: getFlag(flags, ['issued-at', 'issuedAt', 'created-at', 'createdAt']),
2229
+ transaction_submitted: false,
2230
+ raw_memory_on_chain: false,
2231
+ });
2232
+ assertChainArtifact(validateCapabilityGrant, grant);
2233
+ return chainWriteOrPrint(flags, io, grant, {
2234
+ artifact_type: grant.schema,
2235
+ capability_grant_id: grant.capability_grant_id,
2236
+ capability_grant_hash: grant.capability_grant_hash ?? proofNetworkSha256Json(grant),
2237
+ });
2238
+ }
2239
+
2240
+ export async function chainRevokeCommand(flags, io) {
2241
+ const grantValue = getFlag(flags, ['grant']);
2242
+ let grantHash = getFlag(flags, ['grant-hash', 'grantHash']);
2243
+ let grantId = getFlag(flags, ['grant-id', 'grantId']);
2244
+ if (grantValue !== undefined && grantValue !== true && grantValue !== '') {
2245
+ const grantString = String(grantValue);
2246
+ if (grantString.startsWith('sha256:')) {
2247
+ grantHash = grantHash ?? grantString;
2248
+ } else {
2249
+ const grantArtifact = await readJson(resolve(grantString));
2250
+ const grantValidation = validateCapabilityGrant(grantArtifact);
2251
+ if (!grantValidation.ok) throw new Error(`Grant artifact is invalid: ${grantValidation.errors.join('; ')}`);
2252
+ grantHash = grantHash ?? grantArtifact.capability_grant_hash;
2253
+ grantId = grantId ?? grantArtifact.capability_grant_id;
2254
+ }
2255
+ }
2256
+ const nullifierValue = getFlag(flags, ['nullifier-root', 'nullifierRoot', 'nullifier-ref', 'nullifierRef', 'nullifier']);
2257
+ const revocation = createCapabilityRevocation({
2258
+ grant_id: grantId,
2259
+ grant_hash: grantHash ?? requireFlag(flags, ['grant-hash', 'grantHash'], 'grant-hash'),
2260
+ reason_ref: requireFlag(flags, ['reason', 'revocation-reason', 'revocationReason'], 'reason'),
2261
+ revocation_reason: getFlag(flags, ['reason', 'revocation-reason', 'revocationReason']),
2262
+ revocation_ref: getFlag(flags, ['revocation-ref', 'revocationRef']),
2263
+ nullifier_root: nullifierValue && String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
2264
+ nullifier_ref: nullifierValue && !String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
2265
+ revoked_at: getFlag(flags, ['revoked-at', 'revokedAt']),
2266
+ transaction_submitted: false,
2267
+ raw_memory_on_chain: false,
2268
+ });
2269
+ assertChainArtifact(validateCapabilityRevocation, revocation);
2270
+ return chainWriteOrPrint(flags, io, revocation, {
2271
+ artifact_type: revocation.schema,
2272
+ capability_revocation_id: revocation.capability_revocation_id,
2273
+ capability_revocation_hash: revocation.capability_revocation_hash ?? proofNetworkSha256Json(revocation),
2274
+ });
2275
+ }
2276
+
2277
+ export async function chainAttestCommand(flags, io) {
2278
+ const reportHash = getFlag(flags, ['report-hash', 'reportHash']);
2279
+ const reportFile = getFlag(flags, ['report-file', 'reportFile']);
2280
+ const resolvedReportHash = reportHash || (reportFile ? await sha256PublicFile(resolve(String(reportFile))) : undefined);
2281
+ if (!resolvedReportHash) throw new Error('Missing required --report-hash or --report-file.');
2282
+ const scores = scoreFlags(flags);
2283
+ const metricsHash = getFlag(flags, ['metrics-hash', 'metricsHash'], proofNetworkSha256Json({ scores }));
2284
+ const attestation = createBenchmarkAttestation({
2285
+ report_hash: resolvedReportHash,
2286
+ report_file_hash: resolvedReportHash,
2287
+ dataset_ref: requireFlag(flags, ['dataset-ref', 'datasetRef', 'dataset-manifest', 'datasetManifest'], 'dataset-ref'),
2288
+ runner_ref: requireFlag(flags, ['runner-ref', 'runnerRef'], 'runner-ref'),
2289
+ package_ref: requireFlag(flags, ['package-ref', 'packageRef'], 'package-ref'),
2290
+ metrics: scores,
2291
+ metrics_hash: metricsHash,
2292
+ attestation_ref: getFlag(flags, ['attestation-ref', 'attestationRef']),
2293
+ created_at: getFlag(flags, ['created-at', 'createdAt']),
2294
+ transaction_submitted: false,
2295
+ raw_memory_on_chain: false,
2296
+ });
2297
+ assertChainArtifact(validateBenchmarkAttestation, attestation);
2298
+ return chainWriteOrPrint(flags, io, attestation, {
2299
+ artifact_type: attestation.schema,
2300
+ benchmark_attestation_id: attestation.benchmark_attestation_id,
2301
+ benchmark_attestation_hash: attestation.benchmark_attestation_hash ?? proofNetworkSha256Json(attestation),
2302
+ });
2303
+ }
2304
+
2305
+ export async function chainVerifyCommand(flags, io, positionalFile = undefined) {
2306
+ const inPath = resolve(String(requireFileArg(flags, ['file', 'in'], positionalFile, 'file')));
2307
+ const artifact = await readJson(inPath);
2308
+ const [schema, validate] = chainArtifactValidator(artifact);
2309
+ let result;
2310
+ try {
2311
+ result = chainValidationResult(validate, artifact);
2312
+ } catch (error) {
2313
+ result = { ok: false, error: { code: 'PROOF_NETWORK_INVALID', message: error.message } };
2314
+ }
2315
+ print({
2316
+ ok: result.ok === true,
2317
+ artifact_type: schema,
2318
+ artifact_hash: proofNetworkSha256Json(artifact),
2319
+ transaction_submitted: false,
2320
+ raw_memory_on_chain: false,
2321
+ validation: result,
2322
+ }, io);
2323
+ return result.ok === true ? 0 : 1;
2324
+ }
2325
+
2326
+
1767
2327
  export async function meterEventCommand(flags, io) {
1768
2328
  const event = createUsageEvent({
1769
2329
  tenant_id: requireFlag(flags, ['tenant', 'tenant-id', 'tenantId'], 'tenant'),
@@ -1945,6 +2505,7 @@ function usage() {
1945
2505
  'init',
1946
2506
  'setup',
1947
2507
  'quickstart',
2508
+ 'test-drive',
1948
2509
  'demo cross-model',
1949
2510
  'doctor',
1950
2511
  'install',
@@ -1981,6 +2542,11 @@ function usage() {
1981
2542
  'settlement receipt',
1982
2543
  'settlement verify',
1983
2544
  'settlement batch',
2545
+ 'chain anchor',
2546
+ 'chain grant',
2547
+ 'chain revoke',
2548
+ 'chain attest',
2549
+ 'chain verify',
1984
2550
  ],
1985
2551
  connector_options: {
1986
2552
  '--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
@@ -2024,6 +2590,13 @@ function usage() {
2024
2590
  '--memory-text <text>': 'Inline demo memory text for non-private demos only.',
2025
2591
  '--overwrite': 'Replace existing quickstart output files.',
2026
2592
  },
2593
+ test_drive_options: {
2594
+ '--out-dir <path>': `Isolated demo directory. Defaults to ${DEFAULT_TEST_DRIVE_DIR}.`,
2595
+ '--bundle <path>': `Bundle JSON to create. Defaults to ${DEFAULT_TEST_DRIVE_DIR}/${DEFAULT_TEST_DRIVE_BUNDLE_NAME}.`,
2596
+ '--client <id|auto>': 'Client setup planning passthrough. No client config files are written by test-drive.',
2597
+ '--overwrite': 'Replace existing test-drive artifact files.',
2598
+ '--dry-run': 'Plan the local test drive without writing artifacts.',
2599
+ },
2027
2600
  cross_model_demo_options: {
2028
2601
  '--bundle <path>': `Reuse a local Enigma bundle. If omitted, ${DEFAULT_CROSS_MODEL_DEMO_BUNDLE} is recreated as a demo-only local vault.`,
2029
2602
  '--memory-file <path>': 'Seed the demo from a local file without echoing plaintext. Alias: --text-file.',
@@ -2069,6 +2642,14 @@ function usage() {
2069
2642
  batch: 'enigma settlement batch --receipts <receipts.json> --batch-ref <ref> [--asset <asset>] [--out <file>]',
2070
2643
  boundary: 'Settlement artifacts contain commitment roots, capacity profiles, hashes, refs, prices, and claim boundaries only; no raw memory, prompts, provider responses, credentials, token ROI/profit, decentralization, or provider-invoice savings claim.',
2071
2644
  },
2645
+ chain: {
2646
+ anchor: 'enigma chain anchor --root <sha256:...> [--root <sha256:...>] [--ref <public-ref>] [--authority <public-authority-ref>] [--batch-ref <ref>] [--out <file>]',
2647
+ grant: 'enigma chain grant --subject <public-subject-ref> --capability <capability-id> --scope <scope-id> [--resource-ref <sha256:...>] [--policy-hash <sha256:...>] --expires-at <iso> [--grant-ref <public-ref>] [--out <file>]',
2648
+ revoke: 'enigma chain revoke --grant-hash <sha256:...> --reason <public-reason-code> [--revocation-ref <public-ref>] [--out <file>]',
2649
+ attest: 'enigma chain attest (--report-hash <sha256:...> | --report-file <report.json>) --dataset-ref <sha256:...> --runner-ref <public-runner-ref> --package-ref <public-package-ref> [--score name=value] [--out <file>]',
2650
+ verify: 'enigma chain verify --file <proof-artifact.json>',
2651
+ boundary: 'Proof Network chain commands are local planning commands only. They write public-safe hashes, roots, refs, counts, signatures, and booleans; they do not submit Solana transactions or put raw memory on chain.',
2652
+ },
2072
2653
  relay_gateway_options: {
2073
2654
  '--host <host>': 'Bind host. Defaults to 127.0.0.1.',
2074
2655
  '--port <port>': `Bind port. Defaults to ${DEFAULT_RELAY_PORT} for relay and ${DEFAULT_GATEWAY_PORT} for gateway.`,
@@ -2095,10 +2676,10 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2095
2676
  print(usage(), io);
2096
2677
  return 0;
2097
2678
  }
2098
- const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'demo', 'passport'];
2679
+ const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'chain', 'demo', 'passport'];
2099
2680
  const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
2100
2681
  const positionalFile = optionalPositional(argv[2]);
2101
- if ((flags.has('help') || argv.includes('-h')) && (command === 'setup' || command === 'search' || command === 'status' || (command === 'passport' && subcommand === 'status') || ((command === 'relay' || command === 'gateway') && (subcommand === 'serve' || subcommand === 'demo')) || (command === 'native-host' && (subcommand === 'manifest' || subcommand === 'install-plan')) || (command === 'demo' && subcommand === 'cross-model'))) {
2682
+ if ((command === 'chain' && (!subcommand || subcommand === '--help' || subcommand === '-h' || flags.has('help'))) || ((flags.has('help') || argv.includes('-h')) && (command === 'setup' || command === 'test-drive' || command === 'search' || command === 'status' || (command === 'passport' && subcommand === 'status') || ((command === 'relay' || command === 'gateway') && (subcommand === 'serve' || subcommand === 'demo')) || (command === 'native-host' && (subcommand === 'manifest' || subcommand === 'install-plan')) || (command === 'demo' && subcommand === 'cross-model')))) {
2102
2683
  print(usage(), io);
2103
2684
  return 0;
2104
2685
  }
@@ -2106,6 +2687,7 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2106
2687
  if (command === 'init') return await initCommand(flags, io);
2107
2688
  if (command === 'setup') return await setupCommand(flags, io);
2108
2689
  if (command === 'quickstart') return await quickstartCommand(flags, io);
2690
+ if (command === 'test-drive') return await testDriveCommand(flags, io);
2109
2691
  if (command === 'demo' && subcommand === 'cross-model') return await crossModelDemoCommand(flags, io);
2110
2692
  if (command === 'doctor') return await doctorCommand(flags, io);
2111
2693
  if (command === 'install') return await installCommand(flags, io);
@@ -2139,6 +2721,11 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2139
2721
  if (command === 'settlement' && subcommand === 'receipt') return await settlementReceiptCommand(flags, io);
2140
2722
  if (command === 'settlement' && subcommand === 'verify') return await settlementVerifyCommand(flags, io);
2141
2723
  if (command === 'settlement' && subcommand === 'batch') return await settlementBatchCommand(flags, io, positionalFile);
2724
+ if (command === 'chain' && subcommand === 'anchor') return await chainAnchorCommand(flags, io);
2725
+ if (command === 'chain' && subcommand === 'grant') return await chainGrantCommand(flags, io);
2726
+ if (command === 'chain' && subcommand === 'revoke') return await chainRevokeCommand(flags, io);
2727
+ if (command === 'chain' && subcommand === 'attest') return await chainAttestCommand(flags, io);
2728
+ if (command === 'chain' && subcommand === 'verify') return await chainVerifyCommand(flags, io, positionalFile);
2142
2729
  if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
2143
2730
  if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
2144
2731
  if (command === 'enterprise' && subcommand === 'demo') return await enterpriseDemoCommand(flags, io);