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.
- package/README.md +36 -17
- package/apps/cli/bin/enigma.mjs +320 -42
- package/deploy/docker-compose.local-production-simulation.yml +10 -11
- package/docs/benchmark-attestation-network.md +487 -487
- package/docs/benchmark-reproducibility.md +10 -9
- package/docs/demo-proof-network.md +275 -275
- package/docs/developer-ecosystem.md +223 -223
- package/docs/developer-proof-quickstart.md +325 -325
- package/docs/enigma-memory-ready-conformance.md +376 -376
- package/docs/hosted-cloud-product.md +10 -0
- package/docs/install-anywhere.md +34 -17
- package/docs/installers-and-desktop.md +9 -7
- package/docs/proof-network-build-notes.md +240 -240
- package/docs/proof-network.md +257 -257
- package/docs/sdk-api.md +324 -324
- package/docs/solana-devnet-acceptance.md +48 -0
- package/docs/solana-proof-rail.md +453 -453
- package/examples/ci/github-actions.yml +6 -8
- package/package.json +8 -1
- package/packages/mcp-server/src/index.js +1 -1
- package/packages/passport/src/index.js +9 -5
- package/scripts/build-benchmark-proof-release.mjs +391 -0
- package/scripts/build-goal-completion-audit.mjs +11 -5
- package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
- package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
- package/scripts/build-installer-assets.mjs +126 -10
- package/scripts/build-production-handoff-packet.mjs +7 -6
- package/scripts/build-production-unblocker.mjs +409 -0
- package/scripts/build-proof-network-packet.mjs +1 -1
- package/scripts/release-audit.mjs +71 -2
- package/scripts/run-standard-memory-benchmarks.mjs +1 -1
- 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
|
|
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
|
-
##
|
|
11
|
+
## First run: install and inspect the safe local plan
|
|
12
12
|
|
|
13
|
-
The
|
|
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
|
|
45
|
+
enigma init --connect --overwrite
|
|
30
46
|
```
|
|
31
47
|
|
|
32
|
-
`--connect
|
|
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
|
|
70
|
+
enigma init --dry-run
|
|
71
|
+
enigma init --overwrite
|
|
55
72
|
```
|
|
56
73
|
|
|
57
|
-
`enigma
|
|
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
|
|
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
|
|
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
|
|
87
|
+
enigma init --connect --overwrite
|
|
71
88
|
```
|
|
72
89
|
|
|
73
|
-
`--connect
|
|
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
|
|
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
|
|
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
|
|
package/apps/cli/bin/enigma.mjs
CHANGED
|
@@ -842,15 +842,78 @@ async function persistState(bundlePath, vault) {
|
|
|
842
842
|
}
|
|
843
843
|
|
|
844
844
|
async function initCommand(flags, io) {
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
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 =
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
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
|
|
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:
|
|
1220
|
-
context_pack:
|
|
1221
|
-
export:
|
|
1222
|
-
verify_report:
|
|
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 ${
|
|
1229
|
-
`enigma connect generic-mcp --bundle ${
|
|
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
|
|
1537
|
+
query,
|
|
1428
1538
|
purpose: getFlag(flags, ['purpose'], 'local_context'),
|
|
1429
1539
|
limit: Number(getFlag(flags, ['limit'], 8)),
|
|
1430
|
-
optimize
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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);
|