enigma-memory 0.1.12 → 0.1.14

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 (35) hide show
  1. package/README.md +36 -17
  2. package/apps/cli/bin/enigma.mjs +425 -49
  3. package/deploy/docker-compose.local-production-simulation.yml +10 -11
  4. package/docs/benchmark-attestation-network.md +487 -487
  5. package/docs/benchmark-reproducibility.md +10 -9
  6. package/docs/client-connectors.md +512 -0
  7. package/docs/demo-proof-network.md +275 -275
  8. package/docs/developer-ecosystem.md +223 -223
  9. package/docs/developer-proof-quickstart.md +325 -325
  10. package/docs/enigma-memory-ready-conformance.md +376 -376
  11. package/docs/hosted-cloud-product.md +10 -0
  12. package/docs/install-anywhere.md +534 -0
  13. package/docs/installers-and-desktop.md +9 -7
  14. package/docs/proof-network-build-notes.md +240 -240
  15. package/docs/proof-network.md +257 -257
  16. package/docs/sdk-api.md +324 -322
  17. package/docs/solana-devnet-acceptance.md +48 -0
  18. package/docs/solana-proof-rail.md +453 -453
  19. package/examples/ci/github-actions.yml +7 -6
  20. package/package.json +11 -1
  21. package/packages/mcp-server/src/index.js +1 -1
  22. package/packages/passport/src/index.js +9 -5
  23. package/scripts/build-benchmark-proof-release.mjs +391 -0
  24. package/scripts/build-goal-completion-audit.mjs +11 -5
  25. package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
  26. package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
  27. package/scripts/build-installer-assets.mjs +126 -10
  28. package/scripts/build-production-handoff-packet.mjs +7 -6
  29. package/scripts/build-production-unblocker.mjs +409 -0
  30. package/scripts/build-proof-network-packet.mjs +1 -1
  31. package/scripts/install-enigma-local.mjs +270 -0
  32. package/scripts/release-audit.mjs +71 -2
  33. package/scripts/run-standard-memory-benchmarks.mjs +1 -1
  34. package/scripts/verify-registry-install.mjs +1 -0
  35. package/scripts/wait-for-backend-ready.mjs +4 -2
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createHash } from 'node:crypto';
3
3
  import { createServer as createHttpServer } from 'node:http';
4
- import { realpathSync } from 'node:fs';
5
- import { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
4
+ import { constants as fsConstants, realpathSync } from 'node:fs';
5
+ import { access, mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
6
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';
@@ -574,6 +574,86 @@ function minimumNodeMajor(range) {
574
574
  return match ? Number(match[1]) : 0;
575
575
  }
576
576
 
577
+ function npmUserAgentCheck(userAgent = process.env.npm_config_user_agent) {
578
+ const raw = typeof userAgent === 'string' ? userAgent.trim() : '';
579
+ const npmToken = raw.split(/\s+/).find((token) => token.startsWith('npm/'));
580
+ const version = npmToken ? npmToken.slice(4) : null;
581
+ return {
582
+ ok: true,
583
+ detected: version !== null,
584
+ name: version === null ? null : 'npm',
585
+ version,
586
+ source: version === null ? null : 'npm_config_user_agent',
587
+ };
588
+ }
589
+
590
+ async function statIfExists(path) {
591
+ try {
592
+ return await stat(path);
593
+ } catch (error) {
594
+ if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR') return null;
595
+ throw error;
596
+ }
597
+ }
598
+
599
+ async function nearestExistingAncestor(path) {
600
+ let current = resolve(path);
601
+ for (;;) {
602
+ const stats = await statIfExists(current);
603
+ if (stats !== null) return { path: current, stats };
604
+ const parent = dirname(current);
605
+ if (parent === current) return null;
606
+ current = parent;
607
+ }
608
+ }
609
+
610
+ function publicParentDisplay(path, label) {
611
+ const value = String(path);
612
+ if (/^<[^>]+>$/.test(value)) return `<${label}>`;
613
+ const parent = dirname(value);
614
+ return parent === '' ? '.' : publicPathDisplay(parent, label);
615
+ }
616
+
617
+ async function writableVaultPathCheck(bundleInput, displayInput = bundleInput) {
618
+ const bundlePath = resolve(String(bundleInput));
619
+ const parentPath = dirname(bundlePath);
620
+ const targetStats = await statIfExists(bundlePath);
621
+ const nearest = await nearestExistingAncestor(parentPath);
622
+ let ok = false;
623
+ let reason = null;
624
+ let parentExists = false;
625
+ let nearestExistingParent = null;
626
+ if (targetStats?.isDirectory()) {
627
+ reason = 'target_is_directory';
628
+ } else if (nearest === null) {
629
+ reason = 'no_existing_parent';
630
+ } else if (!nearest.stats.isDirectory()) {
631
+ reason = 'nearest_parent_not_directory';
632
+ nearestExistingParent = '<existing-parent-path>';
633
+ } else {
634
+ parentExists = nearest.path === parentPath;
635
+ nearestExistingParent = parentExists ? publicParentDisplay(displayInput, 'bundle-dir') : '<existing-parent-dir>';
636
+ try {
637
+ await access(nearest.path, fsConstants.W_OK);
638
+ ok = true;
639
+ } catch {
640
+ reason = 'parent_not_writable';
641
+ }
642
+ }
643
+ return {
644
+ ok,
645
+ path: publicPathDisplay(displayInput, 'bundle-path'),
646
+ parent: publicParentDisplay(displayInput, 'bundle-dir'),
647
+ parent_exists: parentExists,
648
+ nearest_existing_parent: nearestExistingParent,
649
+ target_exists: targetStats !== null,
650
+ target_is_directory: targetStats?.isDirectory() === true,
651
+ writable: ok,
652
+ reason,
653
+ hint: ok ? null : 'Choose a writable --bundle path or create a writable parent directory.',
654
+ };
655
+ }
656
+
577
657
  async function schemaFiles() {
578
658
  return (await readdir(SPECS_URL)).filter((name) => name.endsWith('.schema.json')).sort();
579
659
  }
@@ -762,15 +842,78 @@ async function persistState(bundlePath, vault) {
762
842
  }
763
843
 
764
844
  async function initCommand(flags, io) {
765
- const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
766
- const vault = createVault({
767
- subjectId: String(getFlag(flags, ['subject', 'subject-id'], 'local-user')),
768
- displayName: String(getFlag(flags, ['display-name', 'name'], 'Local user')),
769
- passphrase: String(getFlag(flags, ['passphrase'], 'local-development-passphrase')),
770
- });
771
- const bundle = await persistState(bundlePath, vault);
772
- print({ ok: true, bundle: bundlePath, schema: bundle.schema, subject_id: bundle.vault?.subject_id }, io);
773
- return 0;
845
+ const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
846
+ const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], dirname(bundleInput));
847
+ const requestedSelection = setupClientIds(flags);
848
+ const overwrite = booleanFlag(flags, ['overwrite'], false);
849
+ const dryRun = booleanFlag(flags, ['dry-run', 'dryRun'], false);
850
+ const connectRequested = booleanFlag(flags, ['connect'], false);
851
+ const displays = setupPublicDisplays(bundleInput, outDirInput);
852
+ const rawDisplays = setupRawDisplays(bundleInput, outDirInput);
853
+ let artifacts;
854
+ try {
855
+ artifacts = await buildQuickstartArtifacts(flags, { bundleInput, outDirInput, overwrite, write: !dryRun });
856
+ } catch (error) {
857
+ throw publicSetupError(error, rawDisplays, displays);
858
+ }
859
+
860
+ const autoSelect = requestedSelection.auto || (connectRequested && requestedSelection.mode === 'default');
861
+ const selection = await setupClientSelection(
862
+ flags,
863
+ artifacts,
864
+ requestedSelection,
865
+ autoSelect,
866
+ connectRequested && requestedSelection.mode === 'default' ? 'connect_installed' : requestedSelection.mode,
867
+ );
868
+ const clients = selection.clients;
869
+ const connectorWritesRequested = connectRequested && !dryRun;
870
+ const writeClientIds = connectRequested && selection.connectable_client_ids ? selection.connectable_client_ids : null;
871
+ const connectors = await setupConnectorPlans(flags, artifacts, clients, connectorWritesRequested, displays, writeClientIds);
872
+ const doctor = await setupDoctorChecks(flags, artifacts, clients, displays);
873
+ const ok = artifacts.verifyReport.ok === true;
874
+ const anyConnectorWritePerformed = connectors.some((connector) => connector.connect_plan.writes_performed === true);
875
+
876
+ print({
877
+ ok,
878
+ schema: artifacts.bundle.schema,
879
+ command: 'enigma init',
880
+ onboarding_schema: 'enigma.init.v1',
881
+ dry_run: dryRun,
882
+ artifacts_written: !dryRun,
883
+ bundle: displays.bundle,
884
+ out_dir: publicPathDisplay(outDirInput, 'out-dir'),
885
+ context_pack: displays.context_pack,
886
+ export: displays.export,
887
+ verify_report: displays.verify_report,
888
+ subject_id: artifacts.bundle.vault?.subject_id,
889
+ client_configs_written: anyConnectorWritePerformed,
890
+ client_config_write_requested: connectorWritesRequested,
891
+ connector_write_mode: connectRequested ? (selection.connectable_client_ids ? 'installed_only' : 'selected_clients') : 'plan_only',
892
+ connect_requested: connectRequested,
893
+ selected_clients: clients,
894
+ skipped_clients: selection.skipped,
895
+ client_selection: publicSetupClientSelection(selection),
896
+ connector_write_skips: connectorWriteSkips(connectors),
897
+ connectors,
898
+ mcp_config_snippets: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.mcp_config_snippet])),
899
+ connect_plans: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.connect_plan])),
900
+ memory_source: setupMemorySource(flags),
901
+ memory_plaintext_echoed: false,
902
+ raw_memory_printed: false,
903
+ memory_count: Array.isArray(artifacts.bundle.memory_objects) ? artifacts.bundle.memory_objects.length : 0,
904
+ receipt_count: Array.isArray(artifacts.bundle.receipts) ? artifacts.bundle.receipts.length : 0,
905
+ context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
906
+ verify_ok: ok,
907
+ provider_credentials_required: false,
908
+ hosted_saas_live: false,
909
+ solana_required: false,
910
+ browser_extension_required: false,
911
+ provider_native_memory_canonical: false,
912
+ next_commands: initNextCommands({ dryRun, bundleDisplay: displays.bundle, outDirDisplay: publicPathDisplay(outDirInput, 'out-dir'), exportDisplay: displays.export, clients, requestedSelection, connectRequested, overwrite, connectorWritesPerformed: anyConnectorWritePerformed }),
913
+ checks: doctor.checks,
914
+ claim_boundaries: { ...SETUP_CLAIM_BOUNDARIES, hosted_saas_live: false, raw_memory_printed: false, solana_required: false, browser_extension_required: false },
915
+ }, io);
916
+ return ok ? 0 : 1;
774
917
  }
775
918
 
776
919
  function setupClientIds(flags) {
@@ -908,10 +1051,34 @@ function setupNextCommands(bundleInput, exportDisplay, clients, writeConnectors)
908
1051
  `enigma context --bundle ${commandPath(bundleInput)} --query "project context"`,
909
1052
  `enigma verify --export ${commandPath(exportDisplay)}`,
910
1053
  ];
911
- if (!writeConnectors) commands.push(`enigma connect ${primaryClient} --bundle ${commandPath(bundleInput)}`);
1054
+ if (!writeConnectors) commands.push(`enigma connect ${primaryClient} --bundle ${commandPath(bundleInput)} --dry-run`);
1055
+ return commands;
1056
+ }
1057
+
1058
+ function initExecuteCommand(bundleDisplay, outDirDisplay, requestedSelection, connectRequested, overwrite) {
1059
+ let command = `enigma init --bundle ${commandPath(bundleDisplay)} --out-dir ${commandPath(outDirDisplay)}`;
1060
+ for (const client of requestedSelection.explicit_clients) command += ` --client ${client}`;
1061
+ if (requestedSelection.auto) command += ' --client auto';
1062
+ if (connectRequested) command += ' --connect';
1063
+ if (overwrite) command += ' --overwrite';
1064
+ return command;
1065
+ }
1066
+
1067
+ function initNextCommands({ dryRun, bundleDisplay, outDirDisplay, exportDisplay, clients, requestedSelection, connectRequested, overwrite, connectorWritesPerformed }) {
1068
+ const commands = dryRun ? [initExecuteCommand(bundleDisplay, outDirDisplay, requestedSelection, connectRequested, overwrite || dryRun)] : [];
1069
+ commands.push(...setupNextCommands(bundleDisplay, exportDisplay, clients, connectRequested && connectorWritesPerformed));
912
1070
  return commands;
913
1071
  }
914
1072
 
1073
+ function doctorNextCommands(bundleDisplay, client) {
1074
+ const clientId = client ?? DEFAULT_SETUP_CLIENTS[0];
1075
+ return [
1076
+ `enigma setup --bundle ${commandPath(bundleDisplay)}`,
1077
+ `enigma doctor --bundle ${commandPath(bundleDisplay)} --client ${clientId}`,
1078
+ `enigma connect ${clientId} --bundle ${commandPath(bundleDisplay)}`,
1079
+ ];
1080
+ }
1081
+
915
1082
  async function setupDoctorChecks(flags, artifacts, clients, displays) {
916
1083
  const packageJson = await readPackageJson();
917
1084
  const requiredNodeMajor = minimumNodeMajor(packageJson.engines?.node);
@@ -938,12 +1105,15 @@ async function setupDoctorChecks(flags, artifacts, clients, displays) {
938
1105
  const doctor = await doctorConnectors({ ...connectorBaseOptions, clientId: client });
939
1106
  connectorClients.push(...doctor.clients);
940
1107
  }
1108
+ const vaultPath = await writableVaultPathCheck(artifacts.bundlePath, displays.bundle);
941
1109
  const checks = {
942
1110
  node: {
943
1111
  ok: requiredNodeMajor === 0 || currentNodeMajor >= requiredNodeMajor,
944
1112
  current: process.versions.node,
945
1113
  required: packageJson.engines?.node ?? null,
946
1114
  },
1115
+ npm: npmUserAgentCheck(),
1116
+ vault_path: vaultPath,
947
1117
  package_bins: {
948
1118
  ok: binEntries.every((entry) => entry.declared && entry.exists),
949
1119
  required: REQUIRED_PACKAGE_BINS,
@@ -1038,6 +1208,33 @@ function publicSetupClientSelection(selection) {
1038
1208
  };
1039
1209
  }
1040
1210
 
1211
+ function setupStaticClientSelection(requestedSelection) {
1212
+ return {
1213
+ ...requestedSelection,
1214
+ fallback_used: false,
1215
+ selected: requestedSelection.clients.map((clientId) => {
1216
+ const profile = getClientProfile(clientId);
1217
+ return publicSetupClientSelectionEntry({ client_id: clientId, display_name: profile.display_name }, requestedSelection.mode === 'default' ? 'default_setup_client' : 'explicit_client');
1218
+ }),
1219
+ skipped: [],
1220
+ connectable_client_ids: null,
1221
+ };
1222
+ }
1223
+
1224
+ async function setupClientSelection(flags, artifacts, requestedSelection, autoSelect, mode) {
1225
+ return autoSelect ? setupAutoClientSelection(flags, artifacts, DEFAULT_SETUP_CLIENTS, mode) : setupStaticClientSelection(requestedSelection);
1226
+ }
1227
+
1228
+ function connectorWriteSkips(connectors) {
1229
+ return connectors
1230
+ .filter((connector) => connector.write_skipped_reason)
1231
+ .map((connector) => ({
1232
+ client_id: connector.client_id,
1233
+ display_name: connector.display_name,
1234
+ reason: connector.write_skipped_reason,
1235
+ }));
1236
+ }
1237
+
1041
1238
  export async function setupCommand(flags, io) {
1042
1239
  const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
1043
1240
  const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], dirname(bundleInput));
@@ -1055,18 +1252,13 @@ export async function setupCommand(flags, io) {
1055
1252
  } catch (error) {
1056
1253
  throw publicSetupError(error, rawDisplays, displays);
1057
1254
  }
1058
- const selection = connectInstalled || requestedSelection.auto
1059
- ? await setupAutoClientSelection(flags, artifacts, DEFAULT_SETUP_CLIENTS, connectInstalled ? 'connect_installed' : 'auto')
1060
- : {
1061
- ...requestedSelection,
1062
- fallback_used: false,
1063
- selected: requestedSelection.clients.map((clientId) => {
1064
- const profile = getClientProfile(clientId);
1065
- return publicSetupClientSelectionEntry({ client_id: clientId, display_name: profile.display_name }, requestedSelection.mode === 'default' ? 'default_setup_client' : 'explicit_client');
1066
- }),
1067
- skipped: [],
1068
- connectable_client_ids: null,
1069
- };
1255
+ const selection = await setupClientSelection(
1256
+ flags,
1257
+ artifacts,
1258
+ requestedSelection,
1259
+ connectInstalled || requestedSelection.auto,
1260
+ connectInstalled ? 'connect_installed' : 'auto',
1261
+ );
1070
1262
  const clients = selection.clients;
1071
1263
  const writeClientIds = connectInstalled ? selection.connectable_client_ids : null;
1072
1264
  const connectors = await setupConnectorPlans(flags, artifacts, clients, connectorWritesRequested, displays, writeClientIds);
@@ -1090,28 +1282,26 @@ export async function setupCommand(flags, io) {
1090
1282
  verify_report: displays.verify_report,
1091
1283
  memory_source: setupMemorySource(flags),
1092
1284
  memory_plaintext_echoed: false,
1285
+ raw_memory_printed: false,
1093
1286
  memory_count: Array.isArray(artifacts.bundle.memory_objects) ? artifacts.bundle.memory_objects.length : 0,
1094
1287
  receipt_count: Array.isArray(artifacts.bundle.receipts) ? artifacts.bundle.receipts.length : 0,
1095
1288
  context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
1096
1289
  verify_ok: artifacts.verifyReport.ok === true,
1097
1290
  provider_credentials_required: false,
1291
+ hosted_saas_live: false,
1292
+ solana_required: false,
1293
+ browser_extension_required: false,
1098
1294
  provider_native_memory_canonical: false,
1099
1295
  selected_clients: clients,
1100
1296
  skipped_clients: selection.skipped,
1101
1297
  client_selection: publicSetupClientSelection(selection),
1102
- connector_write_skips: connectors
1103
- .filter((connector) => connector.write_skipped_reason)
1104
- .map((connector) => ({
1105
- client_id: connector.client_id,
1106
- display_name: connector.display_name,
1107
- reason: connector.write_skipped_reason,
1108
- })),
1298
+ connector_write_skips: connectorWriteSkips(connectors),
1109
1299
  connectors,
1110
1300
  mcp_config_snippets: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.mcp_config_snippet])),
1111
1301
  connect_plans: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.connect_plan])),
1112
1302
  next_commands: setupNextCommands(displays.bundle, displays.export, clients, connectorWritesRequested && (!connectInstalled || anyConnectorWritePerformed)),
1113
1303
  checks: doctor.checks,
1114
- claim_boundaries: { ...SETUP_CLAIM_BOUNDARIES },
1304
+ claim_boundaries: { ...SETUP_CLAIM_BOUNDARIES, hosted_saas_live: false, raw_memory_printed: false, solana_required: false, browser_extension_required: false },
1115
1305
  }, io);
1116
1306
  return ok ? 0 : 1;
1117
1307
  }
@@ -1120,21 +1310,29 @@ export async function quickstartCommand(flags, io) {
1120
1310
  const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
1121
1311
  const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], dirname(bundleInput));
1122
1312
  const overwrite = booleanFlag(flags, ['overwrite'], false);
1123
- const artifacts = await buildQuickstartArtifacts(flags, { bundleInput, outDirInput, overwrite, write: true });
1313
+ const displays = setupPublicDisplays(bundleInput, outDirInput);
1314
+ const rawOutputs = quickstartOutputs(bundleInput, outDirInput);
1315
+ await assertCanWriteQuickstartOutputs([
1316
+ { path: rawOutputs.bundlePath, display: displays.bundle },
1317
+ { path: rawOutputs.contextPackPath, display: displays.context_pack },
1318
+ { path: rawOutputs.exportPath, display: displays.export },
1319
+ { path: rawOutputs.verifyReportPath, display: displays.verify_report },
1320
+ ], overwrite);
1321
+ const artifacts = await buildQuickstartArtifacts(flags, { bundleInput, outDirInput, overwrite, write: true, checkExisting: false });
1124
1322
 
1125
1323
  print({
1126
1324
  ok: artifacts.verifyReport.ok === true,
1127
- bundle: bundleInput,
1128
- context_pack: artifacts.contextPackDisplay,
1129
- export: artifacts.exportDisplay,
1130
- verify_report: artifacts.verifyReportDisplay,
1325
+ bundle: displays.bundle,
1326
+ context_pack: displays.context_pack,
1327
+ export: displays.export,
1328
+ verify_report: displays.verify_report,
1131
1329
  memory_count: Array.isArray(artifacts.bundle.memory_objects) ? artifacts.bundle.memory_objects.length : 0,
1132
1330
  receipt_count: Array.isArray(artifacts.bundle.receipts) ? artifacts.bundle.receipts.length : 0,
1133
1331
  context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
1134
1332
  verify_ok: artifacts.verifyReport.ok === true,
1135
1333
  next_commands: [
1136
- `enigma verify --export ${artifacts.exportDisplay}`,
1137
- `enigma connect generic-mcp --bundle ${bundleInput} --dry-run`,
1334
+ `enigma verify --export ${displays.export}`,
1335
+ `enigma connect generic-mcp --bundle ${displays.bundle} --dry-run`,
1138
1336
  ],
1139
1337
  claim_boundaries: {
1140
1338
  local_only: true,
@@ -1329,13 +1527,17 @@ async function deleteCommand(flags, io) {
1329
1527
  async function contextCommand(flags, io) {
1330
1528
  const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1331
1529
  const { vault, passport } = await loadState(bundlePath);
1530
+ const query = getFlag(flags, ['query', 'q'], '');
1531
+ const optimize = getFlag(flags, ['optimize']) === true
1532
+ || getFlag(flags, ['optimize']) === 'true'
1533
+ || String(query).trim().length > 0;
1332
1534
  const pack = compileContextPack({
1333
1535
  vault,
1334
1536
  passport,
1335
- query: getFlag(flags, ['query', 'q'], ''),
1537
+ query,
1336
1538
  purpose: getFlag(flags, ['purpose'], 'local_context'),
1337
1539
  limit: Number(getFlag(flags, ['limit'], 8)),
1338
- optimize: getFlag(flags, ['optimize']) === true || getFlag(flags, ['optimize']) === 'true',
1540
+ optimize,
1339
1541
  max_estimated_tokens: parseOptionalNumber(getFlag(flags, ['max-estimated-tokens', 'maxEstimatedTokens'])),
1340
1542
  price_per_million_tokens: parseOptionalNumber(getFlag(flags, ['price-per-million-tokens', 'pricePerMillionTokens'])),
1341
1543
  currency: getFlag(flags, ['currency']),
@@ -1531,7 +1733,7 @@ function testDriveNextCommands(bundleDisplay, crossModelReportDisplay) {
1531
1733
  `enigma status --bundle ${quotedBundle}`,
1532
1734
  `enigma search --bundle ${quotedBundle} --query "local proof bundle"`,
1533
1735
  `enigma demo cross-model --bundle ${quotedBundle} --out ${quotedReport}`,
1534
- 'node scripts/run-memory-benchmarks.mjs',
1736
+ 'enigma setup --overwrite',
1535
1737
  ];
1536
1738
  }
1537
1739
 
@@ -1736,7 +1938,7 @@ export async function testDriveCommand(flags, io) {
1736
1938
  out_dir: outDirInput,
1737
1939
  bundle: bundleInput,
1738
1940
  install_command: `npm install -g ${packageJson.name ?? 'enigma-memory'}`,
1739
- release_target: '0.1.12',
1941
+ release_target: '0.1.14',
1740
1942
  artifacts_written: !dryRun,
1741
1943
  client_configs_written: false,
1742
1944
  client_config_write_required: false,
@@ -1842,10 +2044,11 @@ export async function doctorCommand(flags, io) {
1842
2044
  };
1843
2045
  }));
1844
2046
  const schemas = await schemaFiles();
2047
+ const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
1845
2048
  const selectedClient = getFlag(flags, ['client']);
1846
2049
  const doctorOptions = selectedClient && selectedClient !== true
1847
- ? { ...connectorOptions(flags), clientId: String(selectedClient) }
1848
- : { ...connectorOptions(flags), clientId: undefined };
2050
+ ? { ...connectorOptions(flags), clientId: String(selectedClient), redactPaths: true }
2051
+ : { ...connectorOptions(flags), clientId: undefined, redactPaths: true };
1849
2052
  const connectorDoctor = await doctorConnectors(doctorOptions);
1850
2053
  const profile = getClientProfile(String(selectedClient && selectedClient !== true ? selectedClient : 'generic-mcp'), connectorOptions(flags));
1851
2054
  const checks = {
@@ -1854,6 +2057,7 @@ export async function doctorCommand(flags, io) {
1854
2057
  current: process.versions.node,
1855
2058
  required: packageJson.engines?.node ?? null,
1856
2059
  },
2060
+ npm: npmUserAgentCheck(),
1857
2061
  package_bins: {
1858
2062
  ok: binEntries.every((entry) => entry.declared && entry.exists),
1859
2063
  required: REQUIRED_PACKAGE_BINS,
@@ -1864,8 +2068,9 @@ export async function doctorCommand(flags, io) {
1864
2068
  bundle_default_path: {
1865
2069
  ok: DEFAULT_BUNDLE === '.enigma/bundle.json',
1866
2070
  path: DEFAULT_BUNDLE,
1867
- resolved: resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE))),
2071
+ resolved: publicPathDisplay(resolve(bundleInput), 'bundle-path'),
1868
2072
  },
2073
+ vault_path: await writableVaultPathCheck(resolve(bundleInput), publicPathDisplay(bundleInput, 'bundle-path')),
1869
2074
  schemas: {
1870
2075
  ok: schemas.length > 0,
1871
2076
  count: schemas.length,
@@ -1883,11 +2088,14 @@ export async function doctorCommand(flags, io) {
1883
2088
  ok,
1884
2089
  node: checks.node,
1885
2090
  package_bins: checks.package_bins,
2091
+ npm: checks.npm,
2092
+ vault_path: checks.vault_path,
1886
2093
  bundle_default_path: checks.bundle_default_path,
1887
2094
  schema_count: checks.schemas.count,
1888
2095
  schemas: checks.schemas,
1889
2096
  mcp_command_name: checks.mcp_command_name.command,
1890
2097
  connectors: checks.connectors,
2098
+ next_commands: doctorNextCommands(checks.vault_path.path, String(selectedClient && selectedClient !== true ? selectedClient : 'generic-mcp')),
1891
2099
  checks,
1892
2100
  }, io);
1893
2101
  return ok ? 0 : 1;
@@ -2181,7 +2389,162 @@ function chainArtifactValidator(artifact) {
2181
2389
  if (schema === 'enigma.proof_network.capability_revocation.v1') return [schema, validateCapabilityRevocation];
2182
2390
  if (schema === 'enigma.proof_network.benchmark_attestation.v1') return [schema, validateBenchmarkAttestation];
2183
2391
  if (schema === 'enigma.proof_network.packet.v1') return [schema, validateProofNetworkPacket];
2184
- throw new Error(`Unsupported proof-network artifact schema: ${schema || 'missing'}.`);
2392
+ throw new Error(schema ? 'Unsupported proof-network artifact schema.' : 'Unsupported proof-network artifact schema: missing.');
2393
+ }
2394
+
2395
+ const SOLANA_SUBMIT_CLUSTERS = new Set(['devnet', 'testnet', 'mainnet-beta', 'localnet']);
2396
+ const SOLANA_MEMO_PROGRAM_ID = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
2397
+
2398
+ function solanaSubmitCluster(flags) {
2399
+ const cluster = String(requireFlag(flags, ['cluster'], 'cluster'));
2400
+ if (!SOLANA_SUBMIT_CLUSTERS.has(cluster)) {
2401
+ throw new Error('--cluster must be one of devnet, testnet, mainnet-beta, or localnet.');
2402
+ }
2403
+ return cluster;
2404
+ }
2405
+
2406
+ function createSolanaProofMemoRef(schema, artifact, cluster) {
2407
+ const artifactHash = proofNetworkSha256Json(artifact);
2408
+ const proofCommitment = proofNetworkSha256Json({
2409
+ rail: 'solana-memo-v1',
2410
+ cluster,
2411
+ artifact_type: schema,
2412
+ artifact_hash: artifactHash,
2413
+ });
2414
+ return {
2415
+ v: 1,
2416
+ protocol: 'enigma-proof-network',
2417
+ rail: 'solana-memo',
2418
+ cluster,
2419
+ artifact_type: schema,
2420
+ artifact_hash: artifactHash,
2421
+ proof_commitment: proofCommitment,
2422
+ };
2423
+ }
2424
+
2425
+ function solanaSubmitRpcLabel(flags, cluster) {
2426
+ return getFlag(flags, ['rpc']) ? '<custom-rpc>' : `${cluster}:default`;
2427
+ }
2428
+
2429
+ function solanaSubmitDryRunExplanation() {
2430
+ return 'Dry run only. Execute mode would submit one Solana Memo instruction containing only memo_ref JSON: schema, artifact hash, cluster, and compact proof commitment. The raw artifact body, memory, prompts, transcripts, embeddings, provider responses, private keys, and local paths are not included.';
2431
+ }
2432
+
2433
+ async function loadSolanaWeb3() {
2434
+ try {
2435
+ return await import('@solana/web3.js');
2436
+ } catch {
2437
+ throw new Error('Solana execute mode requires optional dependency @solana/web3.js. Install package dependencies before using --execute.');
2438
+ }
2439
+ }
2440
+
2441
+ async function readSolanaKeypair(path) {
2442
+ let parsed;
2443
+ try {
2444
+ parsed = JSON.parse(await readFile(path, 'utf8'));
2445
+ } catch {
2446
+ throw new Error('Unable to read a valid Solana --keypair JSON array.');
2447
+ }
2448
+ if (!Array.isArray(parsed) || parsed.length === 0) throw new Error('Solana --keypair must be a JSON array of secret-key bytes.');
2449
+ const bytes = new Uint8Array(parsed.length);
2450
+ for (let i = 0; i < parsed.length; i += 1) {
2451
+ const value = parsed[i];
2452
+ if (!Number.isInteger(value) || value < 0 || value > 255) throw new Error('Solana --keypair must be a JSON array of secret-key bytes.');
2453
+ bytes[i] = value;
2454
+ }
2455
+ return bytes;
2456
+ }
2457
+
2458
+ function solanaSubmitRpcUrl(flags, cluster, clusterApiUrl) {
2459
+ const rpc = getFlag(flags, ['rpc']);
2460
+ if (rpc !== undefined && rpc !== true && rpc !== '') return String(lastFlagValue(rpc));
2461
+ if (cluster === 'localnet') return 'http://127.0.0.1:8899';
2462
+ return clusterApiUrl(cluster);
2463
+ }
2464
+
2465
+ async function submitSolanaMemoTransaction(flags, cluster, memoRef) {
2466
+ const keypairPath = resolve(String(requireFlag(flags, ['keypair'], 'keypair')));
2467
+ const secretKey = await readSolanaKeypair(keypairPath);
2468
+ const { Connection, Keypair, PublicKey, Transaction, TransactionInstruction, clusterApiUrl, sendAndConfirmTransaction } = await loadSolanaWeb3();
2469
+ let payer;
2470
+ try {
2471
+ payer = Keypair.fromSecretKey(secretKey);
2472
+ } catch {
2473
+ throw new Error('Solana --keypair could not be loaded as a signer.');
2474
+ }
2475
+ const connection = new Connection(solanaSubmitRpcUrl(flags, cluster, clusterApiUrl), 'confirmed');
2476
+ const memoBytes = Buffer.from(JSON.stringify(memoRef), 'utf8');
2477
+ const transaction = new Transaction().add(new TransactionInstruction({
2478
+ keys: [],
2479
+ programId: new PublicKey(SOLANA_MEMO_PROGRAM_ID),
2480
+ data: memoBytes,
2481
+ }));
2482
+ try {
2483
+ return await sendAndConfirmTransaction(connection, transaction, [payer], { commitment: 'confirmed' });
2484
+ } catch {
2485
+ throw new Error('Solana submission failed before a public-safe transaction signature was returned.');
2486
+ }
2487
+ }
2488
+
2489
+ export async function chainSubmitSolanaCommand(flags, io, positionalFile = undefined) {
2490
+ const inPath = resolve(String(requireFileArg(flags, ['file', 'in'], positionalFile, 'file')));
2491
+ const cluster = solanaSubmitCluster(flags);
2492
+ let artifact;
2493
+ try {
2494
+ artifact = await readJson(inPath);
2495
+ } catch {
2496
+ throw new Error('Unable to read a valid proof artifact JSON file.');
2497
+ }
2498
+ assertNoPrivateProofPayload(artifact);
2499
+ const [schema, validate] = chainArtifactValidator(artifact);
2500
+ const result = chainValidationResult(validate, artifact);
2501
+ if (result.ok !== true) throw new Error(result.errors?.join('; ') || 'Invalid proof-network artifact.');
2502
+ const memoRef = createSolanaProofMemoRef(schema, artifact, cluster);
2503
+ const execute = booleanFlag(flags, ['execute'], false);
2504
+ if (!execute) {
2505
+ print({
2506
+ ok: true,
2507
+ command: 'chain submit-solana',
2508
+ mode: 'dry-run',
2509
+ chain: 'solana',
2510
+ cluster,
2511
+ rpc_endpoint: solanaSubmitRpcLabel(flags, cluster),
2512
+ transaction_submitted: false,
2513
+ raw_memory_on_chain: false,
2514
+ artifact_type: schema,
2515
+ artifact_hash: memoRef.artifact_hash,
2516
+ proof_commitment: memoRef.proof_commitment,
2517
+ memo_program: SOLANA_MEMO_PROGRAM_ID,
2518
+ memo_ref: memoRef,
2519
+ would_submit: {
2520
+ instruction_count: 1,
2521
+ program: 'spl-memo',
2522
+ payload: 'memo_ref',
2523
+ },
2524
+ validation: result,
2525
+ explanation: solanaSubmitDryRunExplanation(),
2526
+ }, io);
2527
+ return 0;
2528
+ }
2529
+ const signature = await submitSolanaMemoTransaction(flags, cluster, memoRef);
2530
+ print({
2531
+ ok: true,
2532
+ command: 'chain submit-solana',
2533
+ mode: 'execute',
2534
+ chain: 'solana',
2535
+ cluster,
2536
+ rpc_endpoint: solanaSubmitRpcLabel(flags, cluster),
2537
+ transaction_submitted: true,
2538
+ raw_memory_on_chain: false,
2539
+ signature,
2540
+ artifact_type: schema,
2541
+ artifact_hash: memoRef.artifact_hash,
2542
+ proof_commitment: memoRef.proof_commitment,
2543
+ memo_program: SOLANA_MEMO_PROGRAM_ID,
2544
+ memo_ref: memoRef,
2545
+ validation: result,
2546
+ }, io);
2547
+ return 0;
2185
2548
  }
2186
2549
 
2187
2550
  export async function chainAnchorCommand(flags, io) {
@@ -2547,6 +2910,7 @@ function usage() {
2547
2910
  'chain revoke',
2548
2911
  'chain attest',
2549
2912
  'chain verify',
2913
+ 'chain submit-solana',
2550
2914
  ],
2551
2915
  connector_options: {
2552
2916
  '--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
@@ -2570,6 +2934,16 @@ function usage() {
2570
2934
  'enigma status --bundle <path>': 'Show local Memory Passport counts, roots, owner display fields, connector readiness, and next commands.',
2571
2935
  'enigma passport status --bundle <path>': 'Alias for enigma status.',
2572
2936
  },
2937
+ init_options: {
2938
+ '--dry-run': 'Print the first-run plan without writing local artifacts or client configs.',
2939
+ '--bundle <path>': 'Bundle JSON to create. Defaults to .enigma/bundle.json.',
2940
+ '--out-dir <path>': 'Directory for context-pack.json, export.json, and verify-report.json. Defaults to the bundle directory.',
2941
+ '--client <id|auto>': `Client to plan; repeat or comma-separate. Use auto to plan installed/config-present clients, falling back to ${DEFAULT_SETUP_CLIENTS.join(', ')}.`,
2942
+ '--connect': 'Explicitly write selected client MCP configs; with default client selection, writes only installed/config-present client configs and skips missing configs.',
2943
+ '--memory-file <path>': 'Read local memory text from a file without echoing plaintext. Alias: --text-file.',
2944
+ '--memory-text <text>': 'Inline demo-only memory text. Avoid for private content because argv can be logged.',
2945
+ '--overwrite': 'Replace existing local first-run artifacts.',
2946
+ },
2573
2947
  setup_options: {
2574
2948
  '--bundle <path>': 'Bundle JSON to create. Defaults to .enigma/bundle.json.',
2575
2949
  '--out-dir <path>': 'Directory for context-pack.json, export.json, and verify-report.json. Defaults to the bundle directory.',
@@ -2648,7 +3022,8 @@ function usage() {
2648
3022
  revoke: 'enigma chain revoke --grant-hash <sha256:...> --reason <public-reason-code> [--revocation-ref <public-ref>] [--out <file>]',
2649
3023
  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
3024
  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.',
3025
+ submit_solana: 'enigma chain submit-solana --file <proof-artifact.json> --cluster <devnet|testnet|mainnet-beta|localnet> [--rpc <url>] [--execute --keypair <solana-keypair.json>]',
3026
+ boundary: 'Proof Network chain commands default to local planning and dry-run validation. submit-solana only submits a Solana Memo transaction when --execute is passed; it carries compact public-safe commitment/ref JSON, never raw memory or artifact bodies.',
2652
3027
  },
2653
3028
  relay_gateway_options: {
2654
3029
  '--host <host>': 'Bind host. Defaults to 127.0.0.1.',
@@ -2679,7 +3054,7 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2679
3054
  const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'chain', 'demo', 'passport'];
2680
3055
  const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
2681
3056
  const positionalFile = optionalPositional(argv[2]);
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')))) {
3057
+ if ((command === 'chain' && (!subcommand || subcommand === '--help' || subcommand === '-h' || flags.has('help'))) || ((flags.has('help') || argv.includes('-h')) && (command === 'init' || 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')))) {
2683
3058
  print(usage(), io);
2684
3059
  return 0;
2685
3060
  }
@@ -2726,6 +3101,7 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2726
3101
  if (command === 'chain' && subcommand === 'revoke') return await chainRevokeCommand(flags, io);
2727
3102
  if (command === 'chain' && subcommand === 'attest') return await chainAttestCommand(flags, io);
2728
3103
  if (command === 'chain' && subcommand === 'verify') return await chainVerifyCommand(flags, io, positionalFile);
3104
+ if (command === 'chain' && subcommand === 'submit-solana') return await chainSubmitSolanaCommand(flags, io, positionalFile);
2729
3105
  if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
2730
3106
  if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
2731
3107
  if (command === 'enterprise' && subcommand === 'demo') return await enterpriseDemoCommand(flags, io);