enigma-memory 0.1.13 → 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 (32) hide show
  1. package/README.md +36 -17
  2. package/apps/cli/bin/enigma.mjs +320 -42
  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/demo-proof-network.md +275 -275
  7. package/docs/developer-ecosystem.md +223 -223
  8. package/docs/developer-proof-quickstart.md +325 -325
  9. package/docs/enigma-memory-ready-conformance.md +376 -376
  10. package/docs/hosted-cloud-product.md +10 -0
  11. package/docs/install-anywhere.md +34 -17
  12. package/docs/installers-and-desktop.md +9 -7
  13. package/docs/proof-network-build-notes.md +240 -240
  14. package/docs/proof-network.md +257 -257
  15. package/docs/sdk-api.md +324 -324
  16. package/docs/solana-devnet-acceptance.md +48 -0
  17. package/docs/solana-proof-rail.md +453 -453
  18. package/examples/ci/github-actions.yml +6 -8
  19. package/package.json +8 -1
  20. package/packages/mcp-server/src/index.js +1 -1
  21. package/packages/passport/src/index.js +9 -5
  22. package/scripts/build-benchmark-proof-release.mjs +391 -0
  23. package/scripts/build-goal-completion-audit.mjs +11 -5
  24. package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
  25. package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
  26. package/scripts/build-installer-assets.mjs +126 -10
  27. package/scripts/build-production-handoff-packet.mjs +7 -6
  28. package/scripts/build-production-unblocker.mjs +409 -0
  29. package/scripts/build-proof-network-packet.mjs +1 -1
  30. package/scripts/release-audit.mjs +71 -2
  31. package/scripts/run-standard-memory-benchmarks.mjs +1 -1
  32. package/scripts/wait-for-backend-ready.mjs +4 -2
package/README.md CHANGED
@@ -2,18 +2,34 @@
2
2
 
3
3
  Enigma Memory is a local-first AI Memory Passport. It gives you one canonical local memory vault, receipt-backed proof for Enigma-controlled events, and MCP connections into assistants such as Claude Desktop, Cursor, Kimi Code, and generic MCP clients.
4
4
 
5
- Start with the public test drive below. You do not need to understand relay, gateway, mesh, browser, desktop, or hosted infrastructure before trying Enigma locally.
5
+ Start with `enigma init --dry-run` below. You do not need to understand relay, gateway, mesh, browser, desktop, or hosted infrastructure before trying Enigma locally.
6
6
 
7
7
  The package path needs no database, provider credential, cloud credential, npm publishing token, or external account. Hosted cloud and BYOC operation are separate advanced modes that require real deployment credentials, domains, TLS, durable storage, KMS/secrets, monitoring, backups, and operator acceptance.
8
8
 
9
9
  Enigma does not claim that a closed provider deleted internal data, that model weights forgot, or that provider-native memory disappeared. It proves facts about Enigma-controlled vault state, receipts, checkpoints, and declared boundary operations.
10
10
 
11
- ## Public test drive: prove the local package path first
11
+ ## First run: install and inspect the safe local plan
12
12
 
13
- The fastest public test is the published npm package plus the local-only test drive:
13
+ The top public path is the published npm package plus the first-run planner:
14
14
 
15
15
  ```sh
16
16
  npm install -g enigma-memory
17
+ enigma init --dry-run
18
+ ```
19
+
20
+ `enigma init --dry-run` prints a public-safe JSON plan with exact next commands. It does not write local artifacts or third-party client configs, does not require provider credentials, hosted Enigma SaaS, Solana, or a browser extension, and states `provider_credentials_required:false`, `hosted_saas_live:false`, and `raw_memory_printed:false`.
21
+
22
+ When the plan looks right, create the local Memory Passport artifacts:
23
+
24
+ ```sh
25
+ enigma init --overwrite
26
+ ```
27
+
28
+ The execute path writes only local Enigma artifacts under the workspace `.enigma` path by default. It still does not write Claude, Cursor, Kimi, or other third-party app configs unless you explicitly add `--connect`.
29
+
30
+ Public demo path, preserved for reviewers who want the isolated proof/demo bundle:
31
+
32
+ ```sh
17
33
  enigma test-drive --overwrite
18
34
  ```
19
35
 
@@ -26,10 +42,10 @@ The test-drive output is a single public-safe JSON summary. It points to the loc
26
42
  When you are ready to connect real local clients that are already installed or already configured:
27
43
 
28
44
  ```sh
29
- enigma setup --connect-installed --overwrite
45
+ enigma init --connect --overwrite
30
46
  ```
31
47
 
32
- `--connect-installed` is the explicit client-config write path. It skips missing client configs instead of creating every default client config.
48
+ `--connect` is the explicit first-run client-config write path. With default client selection it skips missing client configs instead of creating every default client config.
33
49
 
34
50
  ## Enigma Proof Network
35
51
 
@@ -47,32 +63,33 @@ Prerequisites:
47
63
  - No database, package registry account, provider credential, or cloud credential for the local test-drive or setup paths
48
64
  - Git only when you choose the advanced source-checkout path
49
65
 
50
- Use Enigma as a one-time AI Memory Passport setup: install the package, create the local Enigma workspace once, then use the same memory/search/context/verify/connect loop from any supported client.
66
+ Use Enigma as a one-time AI Memory Passport setup: install the package, inspect the local plan, create the local Enigma workspace once, then use the same memory/search/context/verify/connect loop from any supported client.
51
67
 
52
68
  ```sh
53
69
  npm install -g enigma-memory
54
- enigma setup --overwrite
70
+ enigma init --dry-run
71
+ enigma init --overwrite
55
72
  ```
56
73
 
57
- `enigma setup --overwrite` is the safe default for creating a regular local workspace after the test drive. It writes local Enigma artifacts under the workspace `.enigma` path and emits deterministic, public-safe JSON without printing raw memory plaintext. It does not write Claude, Cursor, Kimi, or other third-party app configs.
74
+ `enigma init --overwrite` is the safe default for creating a regular local workspace after reviewing the plan. It writes local Enigma artifacts under the workspace `.enigma` path and emits deterministic, public-safe JSON without printing raw memory plaintext. It does not write Claude, Cursor, Kimi, or other third-party app configs.
58
75
 
59
- To let setup detect installed or already-configured clients and show the connector plan without mutating client configs:
76
+ To let first-run setup detect installed or already-configured clients and show the connector plan without mutating client configs:
60
77
 
61
78
  ```sh
62
- enigma setup --client auto --overwrite
79
+ enigma init --client auto --dry-run
63
80
  ```
64
81
 
65
- `--client auto` selects clients found by connector detection and falls back to the default setup client list when none are present. The setup output lists which clients were selected, which were skipped, and why.
82
+ `--client auto` selects clients found by connector detection and falls back to the default setup client list when none are present. The init output lists which clients were selected, which were skipped, and why.
66
83
 
67
84
  Only when you are ready to explicitly write connector entries for installed/config-present clients:
68
85
 
69
86
  ```sh
70
- enigma setup --connect-installed --overwrite
87
+ enigma init --connect --overwrite
71
88
  ```
72
89
 
73
- `--connect-installed` implies auto client selection and is an explicit client-config write flag. It skips missing client configs instead of creating every default client config. Only explicit write flags mutate client configs. Existing explicit connector writes remain available through `enigma connect <client>` without `--dry-run`, and existing `enigma setup --write-connectors` behavior for explicit/default setup clients is unchanged; keep `--dry-run` while reviewing a single planned MCP entry.
90
+ `--connect` implies installed/config-present client selection when no explicit `--client` is supplied and is an explicit client-config write flag. It skips missing client configs instead of creating every default client config. Existing setup commands remain available: `enigma setup --overwrite`, `enigma setup --client auto --overwrite`, and `enigma setup --connect-installed --overwrite`. Existing explicit connector writes remain available through `enigma connect <client>` without `--dry-run`; keep `--dry-run` while reviewing a single planned MCP entry.
74
91
 
75
- After setup, use the same local vault from the CLI or connected clients:
92
+ After init or setup, use the same local vault from the CLI or connected clients:
76
93
 
77
94
  ```sh
78
95
  enigma remember --text-file ./memory.txt
@@ -82,6 +99,8 @@ enigma verify --export ./.enigma/export.json
82
99
  enigma connect claude-desktop --dry-run
83
100
  ```
84
101
 
102
+ `enigma context --query ...` automatically applies local relevance scoring; `--optimize` is still accepted when you want explicit optimizer evidence or token/cost bounds.
103
+
85
104
  The local Enigma vault remains canonical. Provider-native memory is non-canonical and should be treated as a convenience cache only. Enigma receipts prove Enigma-controlled vault state, receipts, checkpoints, and declared boundary operations; they do not prove provider deletion, provider model forgetting, provider-native memory removal, hosted availability, ROI/savings, or compliance certification.
86
105
 
87
106
  One-off public test drive without a global install:
@@ -195,7 +214,7 @@ Supported connector profiles are:
195
214
  - `opencode`
196
215
  - `generic-mcp`
197
216
 
198
- After `enigma test-drive --overwrite` proves the local package path and `enigma setup --overwrite` creates a regular local workspace, preview a client connection before writing anything:
217
+ After `enigma init --dry-run` previews the local package path and `enigma init --overwrite` creates a regular local workspace, preview a client connection before writing anything:
199
218
 
200
219
  ```sh
201
220
  enigma connect claude-desktop --dry-run
@@ -204,9 +223,9 @@ enigma connect kimi-code --dry-run
204
223
  enigma connect generic-mcp --dry-run
205
224
  ```
206
225
 
207
- For the one-time setup flow, `enigma setup --client auto --overwrite` reports the installed/config-present clients that connector detection selected and the clients it skipped with reasons. It remains read-only for client configs. `enigma setup --connect-installed --overwrite` is the explicit setup-time write path for installed/config-present clients only; missing configs are skipped rather than created.
226
+ For the one-time setup flow, `enigma init --client auto --dry-run` reports the installed/config-present clients that connector detection selected and the clients it skipped with reasons. It remains read-only for client configs. `enigma init --connect --overwrite` is the explicit init-time write path for installed/config-present clients by default; missing configs are skipped rather than created. The older `enigma setup --client auto --overwrite` and `enigma setup --connect-installed --overwrite` commands remain available.
208
227
 
209
- Remove `--dry-run` from `enigma connect <client>` only after you are ready for Enigma to merge the `mcpServers.enigma` entry into that specific client config. The safe default setup command never writes third-party app configs.
228
+ Remove `--dry-run` from `enigma connect <client>` only after you are ready for Enigma to merge the `mcpServers.enigma` entry into that specific client config. The safe default init/setup command never writes third-party app configs.
210
229
 
211
230
  Manual MCP entry for Claude Desktop, Cursor, Kimi Code, or any generic MCP client:
212
231
 
@@ -842,15 +842,78 @@ async function persistState(bundlePath, vault) {
842
842
  }
843
843
 
844
844
  async function initCommand(flags, io) {
845
- const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
846
- const vault = createVault({
847
- subjectId: String(getFlag(flags, ['subject', 'subject-id'], 'local-user')),
848
- displayName: String(getFlag(flags, ['display-name', 'name'], 'Local user')),
849
- passphrase: String(getFlag(flags, ['passphrase'], 'local-development-passphrase')),
850
- });
851
- const bundle = await persistState(bundlePath, vault);
852
- print({ ok: true, bundle: bundlePath, schema: bundle.schema, subject_id: bundle.vault?.subject_id }, io);
853
- 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;
854
917
  }
855
918
 
856
919
  function setupClientIds(flags) {
@@ -992,6 +1055,21 @@ function setupNextCommands(bundleInput, exportDisplay, clients, writeConnectors)
992
1055
  return commands;
993
1056
  }
994
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));
1070
+ return commands;
1071
+ }
1072
+
995
1073
  function doctorNextCommands(bundleDisplay, client) {
996
1074
  const clientId = client ?? DEFAULT_SETUP_CLIENTS[0];
997
1075
  return [
@@ -1130,6 +1208,33 @@ function publicSetupClientSelection(selection) {
1130
1208
  };
1131
1209
  }
1132
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
+
1133
1238
  export async function setupCommand(flags, io) {
1134
1239
  const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
1135
1240
  const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], dirname(bundleInput));
@@ -1147,18 +1252,13 @@ export async function setupCommand(flags, io) {
1147
1252
  } catch (error) {
1148
1253
  throw publicSetupError(error, rawDisplays, displays);
1149
1254
  }
1150
- const selection = connectInstalled || requestedSelection.auto
1151
- ? await setupAutoClientSelection(flags, artifacts, DEFAULT_SETUP_CLIENTS, connectInstalled ? 'connect_installed' : 'auto')
1152
- : {
1153
- ...requestedSelection,
1154
- fallback_used: false,
1155
- selected: requestedSelection.clients.map((clientId) => {
1156
- const profile = getClientProfile(clientId);
1157
- return publicSetupClientSelectionEntry({ client_id: clientId, display_name: profile.display_name }, requestedSelection.mode === 'default' ? 'default_setup_client' : 'explicit_client');
1158
- }),
1159
- skipped: [],
1160
- connectable_client_ids: null,
1161
- };
1255
+ const selection = await setupClientSelection(
1256
+ flags,
1257
+ artifacts,
1258
+ requestedSelection,
1259
+ connectInstalled || requestedSelection.auto,
1260
+ connectInstalled ? 'connect_installed' : 'auto',
1261
+ );
1162
1262
  const clients = selection.clients;
1163
1263
  const writeClientIds = connectInstalled ? selection.connectable_client_ids : null;
1164
1264
  const connectors = await setupConnectorPlans(flags, artifacts, clients, connectorWritesRequested, displays, writeClientIds);
@@ -1182,28 +1282,26 @@ export async function setupCommand(flags, io) {
1182
1282
  verify_report: displays.verify_report,
1183
1283
  memory_source: setupMemorySource(flags),
1184
1284
  memory_plaintext_echoed: false,
1285
+ raw_memory_printed: false,
1185
1286
  memory_count: Array.isArray(artifacts.bundle.memory_objects) ? artifacts.bundle.memory_objects.length : 0,
1186
1287
  receipt_count: Array.isArray(artifacts.bundle.receipts) ? artifacts.bundle.receipts.length : 0,
1187
1288
  context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
1188
1289
  verify_ok: artifacts.verifyReport.ok === true,
1189
1290
  provider_credentials_required: false,
1291
+ hosted_saas_live: false,
1292
+ solana_required: false,
1293
+ browser_extension_required: false,
1190
1294
  provider_native_memory_canonical: false,
1191
1295
  selected_clients: clients,
1192
1296
  skipped_clients: selection.skipped,
1193
1297
  client_selection: publicSetupClientSelection(selection),
1194
- connector_write_skips: connectors
1195
- .filter((connector) => connector.write_skipped_reason)
1196
- .map((connector) => ({
1197
- client_id: connector.client_id,
1198
- display_name: connector.display_name,
1199
- reason: connector.write_skipped_reason,
1200
- })),
1298
+ connector_write_skips: connectorWriteSkips(connectors),
1201
1299
  connectors,
1202
1300
  mcp_config_snippets: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.mcp_config_snippet])),
1203
1301
  connect_plans: Object.fromEntries(connectors.map((connector) => [connector.client_id, connector.connect_plan])),
1204
1302
  next_commands: setupNextCommands(displays.bundle, displays.export, clients, connectorWritesRequested && (!connectInstalled || anyConnectorWritePerformed)),
1205
1303
  checks: doctor.checks,
1206
- 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 },
1207
1305
  }, io);
1208
1306
  return ok ? 0 : 1;
1209
1307
  }
@@ -1212,21 +1310,29 @@ export async function quickstartCommand(flags, io) {
1212
1310
  const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
1213
1311
  const outDirInput = pathFlag(flags, ['out-dir', 'outDir'], dirname(bundleInput));
1214
1312
  const overwrite = booleanFlag(flags, ['overwrite'], false);
1215
- 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 });
1216
1322
 
1217
1323
  print({
1218
1324
  ok: artifacts.verifyReport.ok === true,
1219
- bundle: bundleInput,
1220
- context_pack: artifacts.contextPackDisplay,
1221
- export: artifacts.exportDisplay,
1222
- verify_report: artifacts.verifyReportDisplay,
1325
+ bundle: displays.bundle,
1326
+ context_pack: displays.context_pack,
1327
+ export: displays.export,
1328
+ verify_report: displays.verify_report,
1223
1329
  memory_count: Array.isArray(artifacts.bundle.memory_objects) ? artifacts.bundle.memory_objects.length : 0,
1224
1330
  receipt_count: Array.isArray(artifacts.bundle.receipts) ? artifacts.bundle.receipts.length : 0,
1225
1331
  context_item_count: Array.isArray(artifacts.contextPack.memories) ? artifacts.contextPack.memories.length : 0,
1226
1332
  verify_ok: artifacts.verifyReport.ok === true,
1227
1333
  next_commands: [
1228
- `enigma verify --export ${artifacts.exportDisplay}`,
1229
- `enigma connect generic-mcp --bundle ${bundleInput} --dry-run`,
1334
+ `enigma verify --export ${displays.export}`,
1335
+ `enigma connect generic-mcp --bundle ${displays.bundle} --dry-run`,
1230
1336
  ],
1231
1337
  claim_boundaries: {
1232
1338
  local_only: true,
@@ -1421,13 +1527,17 @@ async function deleteCommand(flags, io) {
1421
1527
  async function contextCommand(flags, io) {
1422
1528
  const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
1423
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;
1424
1534
  const pack = compileContextPack({
1425
1535
  vault,
1426
1536
  passport,
1427
- query: getFlag(flags, ['query', 'q'], ''),
1537
+ query,
1428
1538
  purpose: getFlag(flags, ['purpose'], 'local_context'),
1429
1539
  limit: Number(getFlag(flags, ['limit'], 8)),
1430
- optimize: getFlag(flags, ['optimize']) === true || getFlag(flags, ['optimize']) === 'true',
1540
+ optimize,
1431
1541
  max_estimated_tokens: parseOptionalNumber(getFlag(flags, ['max-estimated-tokens', 'maxEstimatedTokens'])),
1432
1542
  price_per_million_tokens: parseOptionalNumber(getFlag(flags, ['price-per-million-tokens', 'pricePerMillionTokens'])),
1433
1543
  currency: getFlag(flags, ['currency']),
@@ -1828,7 +1938,7 @@ export async function testDriveCommand(flags, io) {
1828
1938
  out_dir: outDirInput,
1829
1939
  bundle: bundleInput,
1830
1940
  install_command: `npm install -g ${packageJson.name ?? 'enigma-memory'}`,
1831
- release_target: '0.1.13',
1941
+ release_target: '0.1.14',
1832
1942
  artifacts_written: !dryRun,
1833
1943
  client_configs_written: false,
1834
1944
  client_config_write_required: false,
@@ -2279,7 +2389,162 @@ function chainArtifactValidator(artifact) {
2279
2389
  if (schema === 'enigma.proof_network.capability_revocation.v1') return [schema, validateCapabilityRevocation];
2280
2390
  if (schema === 'enigma.proof_network.benchmark_attestation.v1') return [schema, validateBenchmarkAttestation];
2281
2391
  if (schema === 'enigma.proof_network.packet.v1') return [schema, validateProofNetworkPacket];
2282
- 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;
2283
2548
  }
2284
2549
 
2285
2550
  export async function chainAnchorCommand(flags, io) {
@@ -2645,6 +2910,7 @@ function usage() {
2645
2910
  'chain revoke',
2646
2911
  'chain attest',
2647
2912
  'chain verify',
2913
+ 'chain submit-solana',
2648
2914
  ],
2649
2915
  connector_options: {
2650
2916
  '--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
@@ -2668,6 +2934,16 @@ function usage() {
2668
2934
  'enigma status --bundle <path>': 'Show local Memory Passport counts, roots, owner display fields, connector readiness, and next commands.',
2669
2935
  'enigma passport status --bundle <path>': 'Alias for enigma status.',
2670
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
+ },
2671
2947
  setup_options: {
2672
2948
  '--bundle <path>': 'Bundle JSON to create. Defaults to .enigma/bundle.json.',
2673
2949
  '--out-dir <path>': 'Directory for context-pack.json, export.json, and verify-report.json. Defaults to the bundle directory.',
@@ -2746,7 +3022,8 @@ function usage() {
2746
3022
  revoke: 'enigma chain revoke --grant-hash <sha256:...> --reason <public-reason-code> [--revocation-ref <public-ref>] [--out <file>]',
2747
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>]',
2748
3024
  verify: 'enigma chain verify --file <proof-artifact.json>',
2749
- 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.',
2750
3027
  },
2751
3028
  relay_gateway_options: {
2752
3029
  '--host <host>': 'Bind host. Defaults to 127.0.0.1.',
@@ -2777,7 +3054,7 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2777
3054
  const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'chain', 'demo', 'passport'];
2778
3055
  const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
2779
3056
  const positionalFile = optionalPositional(argv[2]);
2780
- 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')))) {
2781
3058
  print(usage(), io);
2782
3059
  return 0;
2783
3060
  }
@@ -2824,6 +3101,7 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
2824
3101
  if (command === 'chain' && subcommand === 'revoke') return await chainRevokeCommand(flags, io);
2825
3102
  if (command === 'chain' && subcommand === 'attest') return await chainAttestCommand(flags, io);
2826
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);
2827
3105
  if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
2828
3106
  if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
2829
3107
  if (command === 'enterprise' && subcommand === 'demo') return await enterpriseDemoCommand(flags, io);