enigma-memory 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +55 -0
- package/README.md +379 -0
- package/apps/cli/bin/enigma.mjs +1117 -0
- package/apps/desktop/src/app.js +1327 -0
- package/apps/desktop/src/index.html +1373 -0
- package/apps/desktop/src/styles.css +386 -0
- package/apps/gateway/bin/enigma-gateway.mjs +52 -0
- package/apps/gateway/src/server.mjs +1403 -0
- package/apps/native-host/README.md +265 -0
- package/apps/native-host/bin/enigma-native-host.mjs +499 -0
- package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
- package/apps/relay/bin/enigma-relay.mjs +52 -0
- package/apps/relay/src/server.mjs +1571 -0
- package/apps/verifier/bin/enigma-verify.mjs +240 -0
- package/deploy/docker-compose.production.example.yml +150 -0
- package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
- package/package.json +196 -0
- package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
- package/packages/adapters/src/index.js +183 -0
- package/packages/boundary/src/index.js +468 -0
- package/packages/connectors/src/index.js +533 -0
- package/packages/core/src/index.js +766 -0
- package/packages/enterprise/src/index.js +505 -0
- package/packages/importers/src/index.js +1083 -0
- package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
- package/packages/mcp-server/src/index.js +1185 -0
- package/packages/mesh/src/index.js +531 -0
- package/packages/metering/PACKAGE_CONTRACT.md +20 -0
- package/packages/metering/src/index.js +246 -0
- package/packages/optimizer/src/index.js +707 -0
- package/packages/passport/src/index.js +651 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
- package/packages/settlement/src/index.js +369 -0
- package/packages/storage/PACKAGE_CONTRACT.md +23 -0
- package/packages/storage/src/index.js +392 -0
- package/packages/vault/src/index.js +904 -0
- package/scripts/build-ai-orchestration-plan.mjs +248 -0
- package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
- package/scripts/build-cloudflare-token-policy.mjs +239 -0
- package/scripts/build-cloudflare-token-request.mjs +314 -0
- package/scripts/build-demo-assets.mjs +263 -0
- package/scripts/build-edge-backend-workers.mjs +353 -0
- package/scripts/build-goal-completion-audit.mjs +398 -0
- package/scripts/build-hosted-probe-worker.mjs +191 -0
- package/scripts/build-operator-acceptance-packet.mjs +254 -0
- package/scripts/build-operator-evidence-starter.mjs +525 -0
- package/scripts/build-production-backend-env-kit.mjs +384 -0
- package/scripts/build-production-dependency-report.mjs +369 -0
- package/scripts/build-production-handoff-packet.mjs +475 -0
- package/scripts/build-production-readiness-manifest.mjs +209 -0
- package/scripts/build-production-status-board.mjs +297 -0
- package/scripts/build-production-storage-migration.mjs +86 -0
- package/scripts/build-production-workplan.mjs +371 -0
- package/scripts/build-review-packet.mjs +594 -0
- package/scripts/check.mjs +419 -0
- package/scripts/cloudflare-ops.mjs +1672 -0
- package/scripts/cloudflare-secret-env.mjs +128 -0
- package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
- package/scripts/infrastructure-readiness.mjs +944 -0
- package/scripts/install-enigma-local.mjs +270 -0
- package/scripts/memory-optimization-benchmark.mjs +242 -0
- package/scripts/monitor-live-endpoints.mjs +358 -0
- package/scripts/release-audit.mjs +5588 -0
- package/scripts/release-provenance.mjs +250 -0
- package/scripts/run-backend-readiness-smoke.mjs +220 -0
- package/scripts/validate-backup-restore-drill.mjs +166 -0
- package/scripts/validate-cloudflare-credentials.mjs +112 -0
- package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
- package/scripts/validate-domain-tls.mjs +248 -0
- package/scripts/validate-hosted-backend-live.mjs +319 -0
- package/scripts/validate-incident-drill.mjs +221 -0
- package/scripts/validate-kms-custody.mjs +235 -0
- package/scripts/validate-legal-compliance-approval.mjs +274 -0
- package/scripts/validate-monitoring-alerting.mjs +263 -0
- package/scripts/validate-network-access-policy.mjs +285 -0
- package/scripts/validate-operator-acceptance.mjs +298 -0
- package/scripts/validate-production-manifests.mjs +325 -0
- package/scripts/validate-public-site-security.mjs +252 -0
- package/scripts/validate-security-threat-model.mjs +285 -0
- package/scripts/validate-service-settlement.mjs +256 -0
- package/scripts/validate-support-sla.mjs +190 -0
- package/scripts/validate-tenant-policy-approval.mjs +228 -0
- package/scripts/validate-usage-metering.mjs +224 -0
- package/scripts/validate-whitepaper-claims.mjs +166 -0
- package/specs/boundary-manifest-v1.schema.json +35 -0
- package/specs/capsule-v1.schema.json +55 -0
- package/specs/claim-boundary-manifest-v1.schema.json +22 -0
- package/specs/connector-profile-v1.schema.json +62 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -0
- package/specs/enterprise-policy-v1.schema.json +59 -0
- package/specs/gateway-request-v1.schema.json +32 -0
- package/specs/goal-completion-audit-v1.schema.json +70 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
- package/specs/import-report-v1.schema.json +214 -0
- package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
- package/specs/memory-event-v1.schema.json +42 -0
- package/specs/mesh-node-v1.schema.json +126 -0
- package/specs/passport-v1.schema.json +50 -0
- package/specs/production-handoff-packet-v1.schema.json +149 -0
- package/specs/receipt-v1.schema.json +61 -0
- package/specs/relay-record-v1.schema.json +43 -0
- package/specs/state-checkpoint-v1.schema.json +37 -0
- package/specs/trust-bundle-v1.schema.json +56 -0
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer as createHttpServer } from 'node:http';
|
|
3
|
+
import { realpathSync } from 'node:fs';
|
|
4
|
+
import { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
7
|
+
import { createVault, remember, recall, updateMemory, deleteMemory, exportBundle } from '../../../packages/vault/src/index.js';
|
|
8
|
+
import { createPassport, compileContextPack } from '../../../packages/passport/src/index.js';
|
|
9
|
+
import { runBoundarySimulation } from '../../../packages/boundary/src/index.js';
|
|
10
|
+
import { startStdioServer } from '../../../packages/mcp-server/src/index.js';
|
|
11
|
+
import { runMeshDemo } from '../../../packages/mesh/src/index.js';
|
|
12
|
+
import { runEnterpriseDemo } from '../../../packages/enterprise/src/index.js';
|
|
13
|
+
import { connectClient, disconnectClient, doctorConnectors, getClientProfile, renderMcpConfig, supportedClients } from '../../../packages/connectors/src/index.js';
|
|
14
|
+
import { exportEnigmaCapsule, importChatGptExport, importClaudeMemory, importEnigmaCapsule, importLangGraphStore, importLettaAgentFile, importMem0Export, importZepGraphitiExport } from '../../../packages/importers/src/index.js';
|
|
15
|
+
import * as relayServer from '../../relay/src/server.mjs';
|
|
16
|
+
import * as gatewayServer from '../../gateway/src/server.mjs';
|
|
17
|
+
import { verifyBundle } from '../../verifier/bin/enigma-verify.mjs';
|
|
18
|
+
import { createNativeHostInstallPlan, createNativeHostManifest } from '../../native-host/bin/enigma-native-host.mjs';
|
|
19
|
+
import { aggregateUsageEvents, createUsageEvent } from '../../../packages/metering/src/index.js';
|
|
20
|
+
import {
|
|
21
|
+
createConsumerGpuCapacityProfile,
|
|
22
|
+
createOperatorServiceQuote,
|
|
23
|
+
createPermissionlessMemoryJob,
|
|
24
|
+
createServiceSettlementReceipt,
|
|
25
|
+
createSettlementBatch,
|
|
26
|
+
verifyServiceSettlementReceipt,
|
|
27
|
+
} from '../../../packages/settlement/src/index.js';
|
|
28
|
+
|
|
29
|
+
const DEFAULT_BUNDLE = '.enigma/bundle.json';
|
|
30
|
+
export const DEFAULT_RELAY_PORT = 8787;
|
|
31
|
+
export const DEFAULT_GATEWAY_PORT = 8797;
|
|
32
|
+
const PACKAGE_JSON_URL = new URL('../../../package.json', import.meta.url);
|
|
33
|
+
const SPECS_URL = new URL('../../../specs/', import.meta.url);
|
|
34
|
+
const IMPORTERS = Object.freeze({
|
|
35
|
+
chatgpt: importChatGptExport,
|
|
36
|
+
'chatgpt-export': importChatGptExport,
|
|
37
|
+
chatgpt_export: importChatGptExport,
|
|
38
|
+
claude: importClaudeMemory,
|
|
39
|
+
'claude-memory': importClaudeMemory,
|
|
40
|
+
claude_memory: importClaudeMemory,
|
|
41
|
+
mem0: importMem0Export,
|
|
42
|
+
'mem0-export': importMem0Export,
|
|
43
|
+
mem0_export: importMem0Export,
|
|
44
|
+
letta: importLettaAgentFile,
|
|
45
|
+
'letta-agent': importLettaAgentFile,
|
|
46
|
+
letta_agent: importLettaAgentFile,
|
|
47
|
+
letta_agent_file: importLettaAgentFile,
|
|
48
|
+
langgraph: importLangGraphStore,
|
|
49
|
+
'langgraph-store': importLangGraphStore,
|
|
50
|
+
langgraph_store: importLangGraphStore,
|
|
51
|
+
zep: importZepGraphitiExport,
|
|
52
|
+
graphiti: importZepGraphitiExport,
|
|
53
|
+
'zep-graphiti': importZepGraphitiExport,
|
|
54
|
+
zep_graphiti: importZepGraphitiExport,
|
|
55
|
+
zep_graphiti_export: importZepGraphitiExport,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const REQUIRED_PACKAGE_BINS = Object.freeze(['enigma', 'enigma-verify', 'enigma-mcp', 'enigma-relay', 'enigma-gateway', 'enigma-native-host']);
|
|
59
|
+
|
|
60
|
+
function parseArgs(argv) {
|
|
61
|
+
const flags = new Map();
|
|
62
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
63
|
+
const arg = argv[i];
|
|
64
|
+
if (!arg.startsWith('--')) continue;
|
|
65
|
+
const eq = arg.indexOf('=');
|
|
66
|
+
if (eq !== -1) {
|
|
67
|
+
flags.set(arg.slice(2, eq), arg.slice(eq + 1));
|
|
68
|
+
} else if (!argv[i + 1] || argv[i + 1].startsWith('--')) {
|
|
69
|
+
flags.set(arg.slice(2), true);
|
|
70
|
+
} else {
|
|
71
|
+
flags.set(arg.slice(2), argv[i + 1]);
|
|
72
|
+
i += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return flags;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getFlag(flags, names, fallback = undefined) {
|
|
79
|
+
for (const name of names) if (flags.has(name)) return flags.get(name);
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function requireFlag(flags, names, label = names[0]) {
|
|
84
|
+
const value = getFlag(flags, names);
|
|
85
|
+
if (value === undefined || value === true || value === '') throw new Error(`Missing required --${label}.`);
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function optionalPositional(value) {
|
|
90
|
+
return value && !String(value).startsWith('--') ? String(value) : undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function requireFileArg(flags, names, positional, label = names[0]) {
|
|
94
|
+
const value = getFlag(flags, names);
|
|
95
|
+
if (value !== undefined && value !== true && value !== '') return value;
|
|
96
|
+
if (positional) return positional;
|
|
97
|
+
throw new Error(`Missing required --${label}.`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function parseJson(value, fallback = {}) {
|
|
101
|
+
if (value === undefined || value === true || value === '') return fallback;
|
|
102
|
+
return JSON.parse(value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function parseList(value) {
|
|
106
|
+
if (value === undefined || value === true || value === '') return [];
|
|
107
|
+
return String(value).split(',').map((item) => item.trim()).filter(Boolean);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function parseOptionalNumber(value) {
|
|
111
|
+
if (value === undefined || value === true || value === '') return undefined;
|
|
112
|
+
return Number(value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function print(value, io) {
|
|
116
|
+
io.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function readJson(path) {
|
|
120
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function memoryTextFromFlags(flags) {
|
|
124
|
+
const inlineText = getFlag(flags, ['text', 'memory']);
|
|
125
|
+
const textFile = getFlag(flags, ['text-file', 'textFile', 'memory-file', 'memoryFile']);
|
|
126
|
+
if (inlineText !== undefined && textFile !== undefined) throw new Error('Use either --text or --text-file, not both.');
|
|
127
|
+
if (textFile !== undefined) {
|
|
128
|
+
if (textFile === true || textFile === '') throw new Error('Missing required --text-file.');
|
|
129
|
+
return readFile(resolve(String(textFile)), 'utf8');
|
|
130
|
+
}
|
|
131
|
+
return requireFlag(flags, ['text', 'memory'], 'text');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function writeJson(path, value) {
|
|
135
|
+
await mkdir(dirname(path), { recursive: true });
|
|
136
|
+
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function fileExists(path) {
|
|
140
|
+
try {
|
|
141
|
+
await access(path);
|
|
142
|
+
return true;
|
|
143
|
+
} catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function readPackageJson() {
|
|
149
|
+
return readJson(PACKAGE_JSON_URL);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function packageFileUrl(path) {
|
|
153
|
+
return new URL(`../../../${String(path).replace(/^\.\//, '')}`, import.meta.url);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function nodeMajor(version) {
|
|
157
|
+
return Number(String(version).split('.')[0]);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function minimumNodeMajor(range) {
|
|
161
|
+
const match = String(range ?? '').match(/>=\s*(\d+)/);
|
|
162
|
+
return match ? Number(match[1]) : 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function schemaFiles() {
|
|
166
|
+
return (await readdir(SPECS_URL)).filter((name) => name.endsWith('.schema.json')).sort();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function connectorOptions(flags, includeBundle = true) {
|
|
170
|
+
const options = {};
|
|
171
|
+
if (includeBundle) options.bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
172
|
+
const configPath = getFlag(flags, ['config', 'config-path']);
|
|
173
|
+
if (configPath && configPath !== true) options.configPath = resolve(String(configPath));
|
|
174
|
+
const serverName = getFlag(flags, ['server-name']);
|
|
175
|
+
if (serverName && serverName !== true) options.serverName = String(serverName);
|
|
176
|
+
const mcpCommand = getFlag(flags, ['mcp-command', 'command']);
|
|
177
|
+
if (mcpCommand && mcpCommand !== true) options.mcpCommand = String(mcpCommand);
|
|
178
|
+
if (getFlag(flags, ['dry-run', 'dryRun'], false) === true) options.dryRun = true;
|
|
179
|
+
return options;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function publicCapsuleImportResult(result) {
|
|
183
|
+
return {
|
|
184
|
+
...result,
|
|
185
|
+
memory_candidates: Array.isArray(result.memory_candidates)
|
|
186
|
+
? result.memory_candidates.map(({ content: _content, metadata: _metadata, ...candidate }) => candidate)
|
|
187
|
+
: [],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function ensureBundle(bundlePath, flags = {}) {
|
|
192
|
+
const existed = await fileExists(bundlePath);
|
|
193
|
+
if (existed) return { created: false, bundle: await readJson(bundlePath) };
|
|
194
|
+
const vault = createVault({
|
|
195
|
+
subjectId: String(getFlag(flags, ['subject', 'subject-id'], 'local-user')),
|
|
196
|
+
displayName: String(getFlag(flags, ['display-name', 'name'], 'Local user')),
|
|
197
|
+
passphrase: String(getFlag(flags, ['passphrase'], 'local-development-passphrase')),
|
|
198
|
+
});
|
|
199
|
+
const bundle = await persistState(bundlePath, vault);
|
|
200
|
+
return { created: true, bundle };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function listenAddress(server) {
|
|
204
|
+
const address = server.address();
|
|
205
|
+
if (typeof address === 'string') return { path: address };
|
|
206
|
+
return { host: address?.address, port: address?.port, family: address?.family };
|
|
207
|
+
}
|
|
208
|
+
function requireStringFlag(flags, names, label = names[0]) {
|
|
209
|
+
const value = getFlag(flags, names);
|
|
210
|
+
if (value === undefined) return undefined;
|
|
211
|
+
if (value === true || value === '') throw new Error(`Missing required --${label}.`);
|
|
212
|
+
return String(value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function loadOrCreateState({ flags, createState, loadStateFromFile, saveStateToFile }) {
|
|
216
|
+
const stateFileFlag = requireStringFlag(flags, ['state-file'], 'state-file');
|
|
217
|
+
if (stateFileFlag === undefined) return { state: createState(), stateFile: undefined };
|
|
218
|
+
const stateFile = resolve(stateFileFlag);
|
|
219
|
+
await mkdir(dirname(stateFile), { recursive: true });
|
|
220
|
+
const state = await fileExists(stateFile) ? await loadStateFromFile(stateFile) : createState();
|
|
221
|
+
await saveStateToFile(state, stateFile);
|
|
222
|
+
return { state, stateFile };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function stateMutatingRelayRequest(req) {
|
|
226
|
+
if (String(req.method ?? 'GET').toUpperCase() !== 'POST') return false;
|
|
227
|
+
const pathname = new URL(req.url ?? '/', 'http://127.0.0.1').pathname;
|
|
228
|
+
return pathname === '/relay/push'
|
|
229
|
+
|| pathname === '/witness/checkpoint'
|
|
230
|
+
|| pathname === '/pairing/challenge'
|
|
231
|
+
|| pathname === '/pairing/complete';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function stateMutatingGatewayRequest(req) {
|
|
235
|
+
const method = String(req.method ?? 'GET').toUpperCase();
|
|
236
|
+
const pathname = new URL(req.url ?? '/', 'http://127.0.0.1').pathname;
|
|
237
|
+
return (method === 'PUT' && pathname === '/policy')
|
|
238
|
+
|| (method === 'POST' && (pathname === '/gateway/evaluate' || pathname === '/gateway/decision'));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function createPersistentHttpServer({ state, stateFile, io, service, handleRequest, saveStateToFile, stateMutatingRequest }) {
|
|
242
|
+
let pendingSave = Promise.resolve();
|
|
243
|
+
let server;
|
|
244
|
+
const saveState = () => {
|
|
245
|
+
if (stateFile === undefined) return pendingSave;
|
|
246
|
+
pendingSave = pendingSave.catch(() => undefined).then(() => saveStateToFile(state, stateFile));
|
|
247
|
+
pendingSave.catch((error) => {
|
|
248
|
+
io.stderr?.write?.(`${service} state persistence failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
249
|
+
server.close();
|
|
250
|
+
});
|
|
251
|
+
return pendingSave;
|
|
252
|
+
};
|
|
253
|
+
server = createHttpServer((req, res) => {
|
|
254
|
+
const shouldSave = stateFile !== undefined && stateMutatingRequest(req);
|
|
255
|
+
Promise.resolve(handleRequest(state, req, res)).then(() => {
|
|
256
|
+
if (shouldSave && res.statusCode < 400) return saveState();
|
|
257
|
+
return undefined;
|
|
258
|
+
}).catch((error) => {
|
|
259
|
+
if (!res.headersSent) {
|
|
260
|
+
res.writeHead(500, { 'content-type': 'application/json; charset=utf-8' });
|
|
261
|
+
res.end(JSON.stringify({ ok: false, error: { code: 'SERVER_ERROR' } }));
|
|
262
|
+
}
|
|
263
|
+
io.stderr?.write?.(`${service} request failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
server.persistState = saveState;
|
|
267
|
+
server.waitForStatePersistence = () => pendingSave;
|
|
268
|
+
return server;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function createServiceServer({ flags, io, service, createState, handleRequest, loadStateFromFile, saveStateToFile, stateMutatingRequest }) {
|
|
272
|
+
const { state, stateFile } = await loadOrCreateState({ flags, createState, loadStateFromFile, saveStateToFile });
|
|
273
|
+
return createPersistentHttpServer({ state, stateFile, io, service, handleRequest, saveStateToFile, stateMutatingRequest });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
async function serveHttpCommand({ flags, io, service, createServer, defaultPort }) {
|
|
278
|
+
const host = String(getFlag(flags, ['host'], '127.0.0.1'));
|
|
279
|
+
const port = Number(getFlag(flags, ['port'], defaultPort));
|
|
280
|
+
const server = await createServer();
|
|
281
|
+
await new Promise((resolveListen, rejectListen) => {
|
|
282
|
+
const onError = (error) => {
|
|
283
|
+
server.off('listening', onListening);
|
|
284
|
+
rejectListen(error);
|
|
285
|
+
};
|
|
286
|
+
const onListening = () => {
|
|
287
|
+
server.off('error', onError);
|
|
288
|
+
resolveListen();
|
|
289
|
+
};
|
|
290
|
+
server.once('error', onError);
|
|
291
|
+
server.once('listening', onListening);
|
|
292
|
+
server.listen({ host, port });
|
|
293
|
+
});
|
|
294
|
+
print({ ok: true, service, listening: true, address: listenAddress(server) }, io);
|
|
295
|
+
if (getFlag(flags, ['once'], false) === true) {
|
|
296
|
+
await server.persistState?.();
|
|
297
|
+
await server.waitForStatePersistence?.();
|
|
298
|
+
await new Promise((resolveClose, rejectClose) => server.close((error) => (error ? rejectClose(error) : resolveClose())));
|
|
299
|
+
return 0;
|
|
300
|
+
}
|
|
301
|
+
await new Promise((resolveClose) => server.once('close', resolveClose));
|
|
302
|
+
return 0;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function reviveVault(stored) {
|
|
306
|
+
if (stored.schema !== 'enigma.vault_bundle.v1') {
|
|
307
|
+
if (stored.vault?.schema === 'enigma.vault.local.v1') return stored.vault;
|
|
308
|
+
throw new Error(`Unsupported Enigma bundle schema: ${stored.schema ?? '<missing>'}`);
|
|
309
|
+
}
|
|
310
|
+
const signingKeyPair = stored.keyring?.privateKey
|
|
311
|
+
? { key_id: stored.keyring.signer?.key_id, publicKey: stored.keyring.publicKey, privateKey: stored.keyring.privateKey }
|
|
312
|
+
: undefined;
|
|
313
|
+
const vault = createVault({
|
|
314
|
+
vault_id: stored.vault?.vault_id,
|
|
315
|
+
tenant_id: stored.vault?.tenant_id,
|
|
316
|
+
subject_id: stored.vault?.subject_id,
|
|
317
|
+
actor_id: stored.vault?.actor_id,
|
|
318
|
+
policy_id: stored.vault?.policy_id,
|
|
319
|
+
vault_key: stored.keyring?.vault_key_b64,
|
|
320
|
+
address_key: stored.keyring?.address_key_b64,
|
|
321
|
+
signingKeyPair,
|
|
322
|
+
now: stored.vault?.created_at,
|
|
323
|
+
});
|
|
324
|
+
if (stored.keyring?.signer) vault.signer = stored.keyring.signer;
|
|
325
|
+
vault.created_at = stored.vault?.created_at ?? vault.created_at;
|
|
326
|
+
vault.updated_at = stored.vault?.updated_at ?? vault.updated_at;
|
|
327
|
+
vault.sequence = Number.isInteger(stored.vault?.sequence) ? stored.vault.sequence : 0;
|
|
328
|
+
vault.events = Array.isArray(stored.events) ? stored.events : [];
|
|
329
|
+
vault.receipts = Array.isArray(stored.receipts) ? stored.receipts : [];
|
|
330
|
+
vault.memories = new Map((stored.memory_objects ?? []).map((record) => [record.memory_addr, { ...record }]));
|
|
331
|
+
vault.activeAddresses = new Set(stored.active_memory_addresses ?? []);
|
|
332
|
+
vault.tombstones = new Map((stored.tombstones ?? []).map((tombstone) => [tombstone.memory_addr, tombstone]));
|
|
333
|
+
const roots = vault.__computeRoots();
|
|
334
|
+
vault.active_set_root = roots.active_set_root;
|
|
335
|
+
vault.receipt_log_root = roots.receipt_log_root;
|
|
336
|
+
return vault;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function loadState(bundlePath) {
|
|
340
|
+
const stored = await readJson(bundlePath);
|
|
341
|
+
const vault = reviveVault(stored);
|
|
342
|
+
return { stored, vault, passport: createPassport({ vault }) };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function persistState(bundlePath, vault) {
|
|
346
|
+
const exported = exportBundle({ vault, includePlaintext: false });
|
|
347
|
+
const bundle = exported.bundle ?? exported;
|
|
348
|
+
await writeJson(bundlePath, bundle);
|
|
349
|
+
return bundle;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function initCommand(flags, io) {
|
|
353
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
354
|
+
const vault = createVault({
|
|
355
|
+
subjectId: String(getFlag(flags, ['subject', 'subject-id'], 'local-user')),
|
|
356
|
+
displayName: String(getFlag(flags, ['display-name', 'name'], 'Local user')),
|
|
357
|
+
passphrase: String(getFlag(flags, ['passphrase'], 'local-development-passphrase')),
|
|
358
|
+
});
|
|
359
|
+
const bundle = await persistState(bundlePath, vault);
|
|
360
|
+
print({ ok: true, bundle: bundlePath, schema: bundle.schema, subject_id: bundle.vault?.subject_id }, io);
|
|
361
|
+
return 0;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async function rememberCommand(flags, io) {
|
|
365
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
366
|
+
const { vault, passport } = await loadState(bundlePath);
|
|
367
|
+
const result = remember({
|
|
368
|
+
vault,
|
|
369
|
+
passport,
|
|
370
|
+
text: await memoryTextFromFlags(flags),
|
|
371
|
+
purpose: getFlag(flags, ['purpose'], 'user_memory'),
|
|
372
|
+
purpose_tags: parseList(getFlag(flags, ['tags'])),
|
|
373
|
+
metadata: parseJson(getFlag(flags, ['metadata']), {}),
|
|
374
|
+
});
|
|
375
|
+
await persistState(bundlePath, vault);
|
|
376
|
+
print({ ok: true, memory_addr: result.memory_addr, receipt_id: result.receipt?.receipt_id }, io);
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function recallCommand(flags, io) {
|
|
381
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
382
|
+
const { vault, passport } = await loadState(bundlePath);
|
|
383
|
+
const result = recall({
|
|
384
|
+
vault,
|
|
385
|
+
passport,
|
|
386
|
+
memory_addr: requireFlag(flags, ['id', 'memory-addr'], 'id'),
|
|
387
|
+
purpose: getFlag(flags, ['purpose'], 'local_recall'),
|
|
388
|
+
});
|
|
389
|
+
await persistState(bundlePath, vault);
|
|
390
|
+
print(result, io);
|
|
391
|
+
return 0;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async function updateCommand(flags, io) {
|
|
395
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
396
|
+
const { vault, passport } = await loadState(bundlePath);
|
|
397
|
+
const result = updateMemory({
|
|
398
|
+
vault,
|
|
399
|
+
passport,
|
|
400
|
+
memory_addr: requireFlag(flags, ['id', 'memory-addr'], 'id'),
|
|
401
|
+
text: requireFlag(flags, ['text', 'memory'], 'text'),
|
|
402
|
+
metadata: parseJson(getFlag(flags, ['metadata']), {}),
|
|
403
|
+
});
|
|
404
|
+
await persistState(bundlePath, vault);
|
|
405
|
+
print({ ok: true, old_memory_addr: result.old_memory_addr, memory_addr: result.memory_addr, receipt_id: result.receipt?.receipt_id }, io);
|
|
406
|
+
return 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function deleteCommand(flags, io) {
|
|
410
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
411
|
+
const { vault, passport } = await loadState(bundlePath);
|
|
412
|
+
const result = deleteMemory({
|
|
413
|
+
vault,
|
|
414
|
+
passport,
|
|
415
|
+
memory_addr: requireFlag(flags, ['id', 'memory-addr'], 'id'),
|
|
416
|
+
reason: getFlag(flags, ['reason'], 'user_delete'),
|
|
417
|
+
});
|
|
418
|
+
await persistState(bundlePath, vault);
|
|
419
|
+
print({ ok: true, memory_addr: result.memory_addr, receipt_id: result.receipt?.receipt_id }, io);
|
|
420
|
+
return 0;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function contextCommand(flags, io) {
|
|
424
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
425
|
+
const { vault, passport } = await loadState(bundlePath);
|
|
426
|
+
const pack = compileContextPack({
|
|
427
|
+
vault,
|
|
428
|
+
passport,
|
|
429
|
+
query: getFlag(flags, ['query', 'q'], ''),
|
|
430
|
+
purpose: getFlag(flags, ['purpose'], 'local_context'),
|
|
431
|
+
limit: Number(getFlag(flags, ['limit'], 8)),
|
|
432
|
+
optimize: getFlag(flags, ['optimize']) === true || getFlag(flags, ['optimize']) === 'true',
|
|
433
|
+
max_estimated_tokens: parseOptionalNumber(getFlag(flags, ['max-estimated-tokens', 'maxEstimatedTokens'])),
|
|
434
|
+
price_per_million_tokens: parseOptionalNumber(getFlag(flags, ['price-per-million-tokens', 'pricePerMillionTokens'])),
|
|
435
|
+
currency: getFlag(flags, ['currency']),
|
|
436
|
+
});
|
|
437
|
+
await persistState(bundlePath, vault);
|
|
438
|
+
const out = getFlag(flags, ['out']);
|
|
439
|
+
if (out && out !== true) await writeJson(resolve(String(out)), pack);
|
|
440
|
+
print(pack, io);
|
|
441
|
+
return 0;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async function exportCommand(flags, io) {
|
|
445
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
446
|
+
const { vault } = await loadState(bundlePath);
|
|
447
|
+
const exported = exportBundle({ vault, includePlaintext: false });
|
|
448
|
+
const bundle = exported.bundle ?? exported;
|
|
449
|
+
await writeJson(bundlePath, bundle);
|
|
450
|
+
const out = resolve(String(getFlag(flags, ['out'], 'enigma-export.json')));
|
|
451
|
+
await writeJson(out, bundle);
|
|
452
|
+
print({ ok: true, export: out, receipt_count: Array.isArray(bundle.receipts) ? bundle.receipts.length : 0 }, io);
|
|
453
|
+
return 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function verifyCommand(flags, io) {
|
|
457
|
+
const path = resolve(String(getFlag(flags, ['bundle', 'file', 'export'], DEFAULT_BUNDLE)));
|
|
458
|
+
const report = verifyBundle(await readJson(path));
|
|
459
|
+
print(report, io);
|
|
460
|
+
return report.ok ? 0 : 1;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async function boundaryRunCommand(flags, io) {
|
|
464
|
+
const manifestPath = getFlag(flags, ['manifest']);
|
|
465
|
+
const tracePath = getFlag(flags, ['trace']);
|
|
466
|
+
const report = runBoundarySimulation({
|
|
467
|
+
scenario: String(getFlag(flags, ['scenario'], 'committed_crossing')),
|
|
468
|
+
manifest: manifestPath && manifestPath !== true ? await readJson(resolve(String(manifestPath))) : undefined,
|
|
469
|
+
trace: tracePath && tracePath !== true ? await readJson(resolve(String(tracePath))) : undefined,
|
|
470
|
+
});
|
|
471
|
+
print(report, io);
|
|
472
|
+
return report?.ok === false || report?.verdict === 'FAIL' || report?.status === 'FAIL' ? 1 : 0;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export async function mcpServeCommand(_flags, io) {
|
|
476
|
+
const server = startStdioServer({
|
|
477
|
+
input: io.stdin ?? process.stdin,
|
|
478
|
+
output: io.stdout ?? process.stdout,
|
|
479
|
+
errorOutput: io.stderr ?? process.stderr,
|
|
480
|
+
});
|
|
481
|
+
if (server?.done) await server.done;
|
|
482
|
+
return 0;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export async function meshDemoCommand(_flags, io) {
|
|
486
|
+
print(runMeshDemo(), io);
|
|
487
|
+
return 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export async function enterpriseDemoCommand(_flags, io) {
|
|
491
|
+
print(runEnterpriseDemo(), io);
|
|
492
|
+
return 0;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export async function doctorCommand(flags, io) {
|
|
496
|
+
const packageJson = await readPackageJson();
|
|
497
|
+
const requiredNodeMajor = minimumNodeMajor(packageJson.engines?.node);
|
|
498
|
+
const currentNodeMajor = nodeMajor(process.versions.node);
|
|
499
|
+
const binMap = packageJson.bin && typeof packageJson.bin === 'object' && !Array.isArray(packageJson.bin) ? packageJson.bin : {};
|
|
500
|
+
const binEntries = await Promise.all(REQUIRED_PACKAGE_BINS.map(async (name) => {
|
|
501
|
+
const target = binMap[name];
|
|
502
|
+
const declared = typeof target === 'string' && target.length > 0;
|
|
503
|
+
return {
|
|
504
|
+
name,
|
|
505
|
+
target: declared ? target : null,
|
|
506
|
+
declared,
|
|
507
|
+
exists: declared ? await fileExists(packageFileUrl(target)) : false,
|
|
508
|
+
};
|
|
509
|
+
}));
|
|
510
|
+
const schemas = await schemaFiles();
|
|
511
|
+
const selectedClient = getFlag(flags, ['client']);
|
|
512
|
+
const doctorOptions = selectedClient && selectedClient !== true
|
|
513
|
+
? { ...connectorOptions(flags), clientId: String(selectedClient) }
|
|
514
|
+
: { ...connectorOptions(flags), clientId: undefined };
|
|
515
|
+
const connectorDoctor = await doctorConnectors(doctorOptions);
|
|
516
|
+
const profile = getClientProfile(String(selectedClient && selectedClient !== true ? selectedClient : 'generic-mcp'), connectorOptions(flags));
|
|
517
|
+
const checks = {
|
|
518
|
+
node: {
|
|
519
|
+
ok: requiredNodeMajor === 0 || currentNodeMajor >= requiredNodeMajor,
|
|
520
|
+
current: process.versions.node,
|
|
521
|
+
required: packageJson.engines?.node ?? null,
|
|
522
|
+
},
|
|
523
|
+
package_bins: {
|
|
524
|
+
ok: binEntries.every((entry) => entry.declared && entry.exists),
|
|
525
|
+
required: REQUIRED_PACKAGE_BINS,
|
|
526
|
+
entries: binEntries,
|
|
527
|
+
missing: binEntries.filter((entry) => !entry.declared).map((entry) => entry.name),
|
|
528
|
+
missing_targets: binEntries.filter((entry) => entry.declared && !entry.exists).map((entry) => entry.name),
|
|
529
|
+
},
|
|
530
|
+
bundle_default_path: {
|
|
531
|
+
ok: DEFAULT_BUNDLE === '.enigma/bundle.json',
|
|
532
|
+
path: DEFAULT_BUNDLE,
|
|
533
|
+
resolved: resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE))),
|
|
534
|
+
},
|
|
535
|
+
schemas: {
|
|
536
|
+
ok: schemas.length > 0,
|
|
537
|
+
count: schemas.length,
|
|
538
|
+
files: schemas,
|
|
539
|
+
},
|
|
540
|
+
mcp_command_name: {
|
|
541
|
+
ok: profile.command === 'enigma-mcp',
|
|
542
|
+
command: profile.command,
|
|
543
|
+
expected: 'enigma-mcp',
|
|
544
|
+
},
|
|
545
|
+
connectors: connectorDoctor,
|
|
546
|
+
};
|
|
547
|
+
const ok = Object.values(checks).every((check) => check.ok !== false);
|
|
548
|
+
print({
|
|
549
|
+
ok,
|
|
550
|
+
node: checks.node,
|
|
551
|
+
package_bins: checks.package_bins,
|
|
552
|
+
bundle_default_path: checks.bundle_default_path,
|
|
553
|
+
schema_count: checks.schemas.count,
|
|
554
|
+
schemas: checks.schemas,
|
|
555
|
+
mcp_command_name: checks.mcp_command_name.command,
|
|
556
|
+
connectors: checks.connectors,
|
|
557
|
+
checks,
|
|
558
|
+
}, io);
|
|
559
|
+
return ok ? 0 : 1;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export async function installCommand(flags, io) {
|
|
563
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE)));
|
|
564
|
+
const bundleState = await ensureBundle(bundlePath, flags);
|
|
565
|
+
const selectedClient = getFlag(flags, ['client']);
|
|
566
|
+
const clients = selectedClient && selectedClient !== true ? [String(selectedClient)] : supportedClients;
|
|
567
|
+
const snippets = {};
|
|
568
|
+
const profiles = [];
|
|
569
|
+
for (const client of clients) {
|
|
570
|
+
snippets[client] = renderMcpConfig(client, { ...connectorOptions(flags), bundlePath });
|
|
571
|
+
profiles.push(getClientProfile(client, { ...connectorOptions(flags), bundlePath }));
|
|
572
|
+
}
|
|
573
|
+
const out = getFlag(flags, ['out']);
|
|
574
|
+
if (out && out !== true) await writeJson(resolve(String(out)), { schema: 'enigma.install_snippets.v1', snippets });
|
|
575
|
+
print({
|
|
576
|
+
ok: true,
|
|
577
|
+
bundle: bundlePath,
|
|
578
|
+
bundle_created: bundleState.created,
|
|
579
|
+
schema: bundleState.bundle.schema,
|
|
580
|
+
mcp_command: connectorOptions(flags).mcpCommand ?? 'enigma-mcp',
|
|
581
|
+
clients: profiles,
|
|
582
|
+
mcp_config_snippets: snippets,
|
|
583
|
+
out: out && out !== true ? resolve(String(out)) : undefined,
|
|
584
|
+
}, io);
|
|
585
|
+
return 0;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export async function connectCommand(client, flags, io) {
|
|
589
|
+
if (!client) throw new Error('Missing required client.');
|
|
590
|
+
const result = await connectClient(client, connectorOptions(flags));
|
|
591
|
+
print(result, io);
|
|
592
|
+
return result.ok ? 0 : 1;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export async function disconnectCommand(client, flags, io) {
|
|
596
|
+
if (!client) throw new Error('Missing required client.');
|
|
597
|
+
const result = await disconnectClient(client, connectorOptions(flags, false));
|
|
598
|
+
print(result, io);
|
|
599
|
+
return result.ok ? 0 : 1;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export async function importCommand(source, flags, io, positionalFile = undefined) {
|
|
603
|
+
if (!source) throw new Error('Missing required import source.');
|
|
604
|
+
const importer = IMPORTERS[String(source).toLowerCase()];
|
|
605
|
+
if (!importer) throw new Error(`Unsupported import source: ${source}`);
|
|
606
|
+
const file = resolve(requireFileArg(flags, ['file', 'source-file', 'path'], positionalFile, 'file'));
|
|
607
|
+
const input = await readFile(file, 'utf8');
|
|
608
|
+
const options = {};
|
|
609
|
+
const now = getFlag(flags, ['now']);
|
|
610
|
+
if (now && now !== true) options.now = String(now);
|
|
611
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle'], DEFAULT_BUNDLE)));
|
|
612
|
+
let vault;
|
|
613
|
+
if (getFlag(flags, ['write-vault'], false) === true) {
|
|
614
|
+
await ensureBundle(bundlePath, flags);
|
|
615
|
+
({ vault } = await loadState(bundlePath));
|
|
616
|
+
options.vault = vault;
|
|
617
|
+
}
|
|
618
|
+
const report = importer(input, options);
|
|
619
|
+
if (vault) await persistState(bundlePath, vault);
|
|
620
|
+
const out = getFlag(flags, ['out']);
|
|
621
|
+
if (out && out !== true) await writeJson(resolve(String(out)), report);
|
|
622
|
+
print({ ...report, source_file: file, bundle: vault ? bundlePath : undefined, out: out && out !== true ? resolve(String(out)) : undefined }, io);
|
|
623
|
+
return report.memory_candidates?.length > 0 || report.ok === true ? 0 : 1;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export async function capsuleExportCommand(flags, io, positionalFile = undefined) {
|
|
627
|
+
const file = resolve(requireFileArg(flags, ['file', 'report'], positionalFile, 'file'));
|
|
628
|
+
const input = await readJson(file);
|
|
629
|
+
const now = getFlag(flags, ['now']);
|
|
630
|
+
const capsule = exportEnigmaCapsule({
|
|
631
|
+
reports: Array.isArray(input) ? input : (input.reports ?? input.report ?? input),
|
|
632
|
+
memory_candidates: input.memory_candidates ?? input.memoryCandidates,
|
|
633
|
+
now: now && now !== true ? String(now) : undefined,
|
|
634
|
+
});
|
|
635
|
+
const out = resolve(String(getFlag(flags, ['out'], 'enigma-capsule.json')));
|
|
636
|
+
await writeJson(out, capsule);
|
|
637
|
+
print({
|
|
638
|
+
ok: capsule.schema === 'enigma.import_capsule.v1',
|
|
639
|
+
schema: capsule.schema,
|
|
640
|
+
capsule_id: capsule.capsule_id,
|
|
641
|
+
out,
|
|
642
|
+
public_artifacts: capsule.public_artifacts,
|
|
643
|
+
verifier_metadata: capsule.verifier_metadata,
|
|
644
|
+
}, io);
|
|
645
|
+
return 0;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export async function capsuleImportCommand(flags, io, positionalFile = undefined) {
|
|
649
|
+
const file = resolve(requireFileArg(flags, ['file', 'capsule'], positionalFile, 'file'));
|
|
650
|
+
const capsule = await readJson(file);
|
|
651
|
+
const bundlePath = resolve(String(getFlag(flags, ['bundle'], DEFAULT_BUNDLE)));
|
|
652
|
+
let vault;
|
|
653
|
+
const options = {};
|
|
654
|
+
const now = getFlag(flags, ['now']);
|
|
655
|
+
if (now && now !== true) options.now = String(now);
|
|
656
|
+
if (getFlag(flags, ['write-vault'], false) === true) {
|
|
657
|
+
await ensureBundle(bundlePath, flags);
|
|
658
|
+
({ vault } = await loadState(bundlePath));
|
|
659
|
+
options.vault = vault;
|
|
660
|
+
}
|
|
661
|
+
const result = importEnigmaCapsule(capsule, options);
|
|
662
|
+
if (vault) await persistState(bundlePath, vault);
|
|
663
|
+
print({ ...publicCapsuleImportResult(result), source_file: file, bundle: vault ? bundlePath : undefined }, io);
|
|
664
|
+
return result.ok ? 0 : 1;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export async function relayDemoCommand(_flags, io) {
|
|
668
|
+
print(relayServer.runRelayDemo(), io);
|
|
669
|
+
return 0;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export async function relayServeCommand(flags, io) {
|
|
673
|
+
return serveHttpCommand({
|
|
674
|
+
flags,
|
|
675
|
+
io,
|
|
676
|
+
service: 'enigma-relay',
|
|
677
|
+
createServer: () => createServiceServer({
|
|
678
|
+
flags,
|
|
679
|
+
io,
|
|
680
|
+
service: 'enigma-relay',
|
|
681
|
+
createState: relayServer.createRelayState,
|
|
682
|
+
handleRequest: relayServer.handleRelayRequest,
|
|
683
|
+
loadStateFromFile: relayServer.loadRelayStateFromFile,
|
|
684
|
+
saveStateToFile: relayServer.saveRelayStateToFile,
|
|
685
|
+
stateMutatingRequest: stateMutatingRelayRequest,
|
|
686
|
+
}),
|
|
687
|
+
defaultPort: DEFAULT_RELAY_PORT,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export async function gatewayDemoCommand(_flags, io) {
|
|
692
|
+
print(gatewayServer.runGatewayDemo(), io);
|
|
693
|
+
return 0;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export async function gatewayServeCommand(flags, io) {
|
|
697
|
+
return serveHttpCommand({
|
|
698
|
+
flags,
|
|
699
|
+
io,
|
|
700
|
+
service: 'enigma-gateway',
|
|
701
|
+
createServer: () => createServiceServer({
|
|
702
|
+
flags,
|
|
703
|
+
io,
|
|
704
|
+
service: 'enigma-gateway',
|
|
705
|
+
createState: gatewayServer.createGatewayState,
|
|
706
|
+
handleRequest: gatewayServer.handleGatewayRequest,
|
|
707
|
+
loadStateFromFile: gatewayServer.loadGatewayStateFromFile,
|
|
708
|
+
saveStateToFile: gatewayServer.saveGatewayStateToFile,
|
|
709
|
+
stateMutatingRequest: stateMutatingGatewayRequest,
|
|
710
|
+
}),
|
|
711
|
+
defaultPort: DEFAULT_GATEWAY_PORT,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export async function nativeHostManifestCommand(flags, io) {
|
|
716
|
+
const manifest = createNativeHostManifest({
|
|
717
|
+
browser: requireFlag(flags, ['browser']),
|
|
718
|
+
hostPath: requireFlag(flags, ['host-path', 'hostPath'], 'host-path'),
|
|
719
|
+
extensionId: requireFlag(flags, ['extension-id', 'extensionId'], 'extension-id'),
|
|
720
|
+
});
|
|
721
|
+
if (flags.has('out')) {
|
|
722
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
723
|
+
await writeJson(outPath, manifest);
|
|
724
|
+
print({ ok: true, path: outPath }, io);
|
|
725
|
+
} else {
|
|
726
|
+
print(manifest, io);
|
|
727
|
+
}
|
|
728
|
+
return 0;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function defaultNativeHostInstallPlanOs(platform = process.platform) {
|
|
732
|
+
if (platform === 'win32') return 'windows';
|
|
733
|
+
if (platform === 'darwin') return 'macos';
|
|
734
|
+
return 'linux';
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function defaultNativeHostInstallPlanHome(os) {
|
|
738
|
+
if (os === 'windows') return process.env.USERPROFILE ?? process.env.HOME;
|
|
739
|
+
return process.env.HOME ?? process.env.USERPROFILE;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export async function nativeHostInstallPlanCommand(flags, io) {
|
|
743
|
+
const os = String(getFlag(flags, ['os'], defaultNativeHostInstallPlanOs())).toLowerCase();
|
|
744
|
+
const plan = createNativeHostInstallPlan({
|
|
745
|
+
browser: requireFlag(flags, ['browser']),
|
|
746
|
+
manifestPath: requireFlag(flags, ['manifest']),
|
|
747
|
+
os,
|
|
748
|
+
homeDir: getFlag(flags, ['home', 'home-dir', 'homeDir'], defaultNativeHostInstallPlanHome(os)),
|
|
749
|
+
});
|
|
750
|
+
print(plan, io);
|
|
751
|
+
return 0;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function numberFlag(flags, names, label = names[0], fallback = undefined) {
|
|
755
|
+
const value = getFlag(flags, names, fallback);
|
|
756
|
+
if (value === undefined) return undefined;
|
|
757
|
+
if (value === true || value === '') throw new Error(`Missing required --${label}.`);
|
|
758
|
+
const number = Number(value);
|
|
759
|
+
if (!Number.isFinite(number)) throw new Error(`--${label} must be a finite number.`);
|
|
760
|
+
return number;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function integerFlag(flags, names, label = names[0], fallback = undefined) {
|
|
764
|
+
const number = numberFlag(flags, names, label, fallback);
|
|
765
|
+
if (number === undefined) return undefined;
|
|
766
|
+
if (!Number.isSafeInteger(number)) throw new Error(`--${label} must be an integer.`);
|
|
767
|
+
return number;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export async function meterEventCommand(flags, io) {
|
|
771
|
+
const event = createUsageEvent({
|
|
772
|
+
tenant_id: requireFlag(flags, ['tenant', 'tenant-id', 'tenantId'], 'tenant'),
|
|
773
|
+
meter_id: getFlag(flags, ['meter', 'meter-id', 'meterId'], 'default'),
|
|
774
|
+
provider: requireFlag(flags, ['provider']),
|
|
775
|
+
model: requireFlag(flags, ['model']),
|
|
776
|
+
operation: getFlag(flags, ['operation'], 'memory.inference'),
|
|
777
|
+
timestamp: getFlag(flags, ['timestamp', 'created-at', 'createdAt']),
|
|
778
|
+
prompt_tokens: integerFlag(flags, ['prompt-tokens', 'promptTokens', 'input-tokens', 'inputTokens'], 'prompt-tokens', 0),
|
|
779
|
+
completion_tokens: integerFlag(flags, ['completion-tokens', 'completionTokens', 'output-tokens', 'outputTokens'], 'completion-tokens', 0),
|
|
780
|
+
memory_baseline_tokens: integerFlag(flags, ['memory-baseline-tokens', 'memoryBaselineTokens', 'baseline-prompt-tokens', 'baselinePromptTokens'], 'memory-baseline-tokens', 0),
|
|
781
|
+
memory_optimized_tokens: integerFlag(flags, ['memory-optimized-tokens', 'memoryOptimizedTokens', 'optimized-prompt-tokens', 'optimizedPromptTokens'], 'memory-optimized-tokens', 0),
|
|
782
|
+
pricing: {
|
|
783
|
+
currency: getFlag(flags, ['currency'], 'USD'),
|
|
784
|
+
input_price_per_million_tokens: numberFlag(flags, ['input-price-per-million-tokens', 'inputPricePerMillionTokens', 'price-per-million-tokens', 'pricePerMillionTokens'], 'price-per-million-tokens', 0),
|
|
785
|
+
output_price_per_million_tokens: numberFlag(flags, ['output-price-per-million-tokens', 'outputPricePerMillionTokens', 'price-per-million-tokens', 'pricePerMillionTokens'], 'price-per-million-tokens', 0),
|
|
786
|
+
},
|
|
787
|
+
});
|
|
788
|
+
if (flags.has('out')) {
|
|
789
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
790
|
+
await writeJson(outPath, event);
|
|
791
|
+
print({ ok: true, path: outPath, event_id: event.event_id, event_hash: event.event_hash }, io);
|
|
792
|
+
} else {
|
|
793
|
+
print(event, io);
|
|
794
|
+
}
|
|
795
|
+
return 0;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export async function meterAggregateCommand(flags, io, positionalFile) {
|
|
799
|
+
const inPath = resolve(String(requireFileArg(flags, ['events', 'in'], positionalFile, 'events')));
|
|
800
|
+
const source = await readJson(inPath);
|
|
801
|
+
const aggregate = aggregateUsageEvents({
|
|
802
|
+
events: Array.isArray(source) ? source : source.events,
|
|
803
|
+
tenant_id: getFlag(flags, ['tenant', 'tenant-id', 'tenantId']),
|
|
804
|
+
meter_id: getFlag(flags, ['meter', 'meter-id', 'meterId'], 'aggregate'),
|
|
805
|
+
generated_at: getFlag(flags, ['generated-at', 'generatedAt']),
|
|
806
|
+
});
|
|
807
|
+
if (flags.has('out')) {
|
|
808
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
809
|
+
await writeJson(outPath, aggregate);
|
|
810
|
+
print({ ok: true, path: outPath, aggregate_id: aggregate.aggregate_id, aggregate_hash: aggregate.aggregate_hash }, io);
|
|
811
|
+
} else {
|
|
812
|
+
print(aggregate, io);
|
|
813
|
+
}
|
|
814
|
+
return 0;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
export async function settlementJobCommand(flags, io) {
|
|
818
|
+
const job = createPermissionlessMemoryJob({
|
|
819
|
+
tenant_id: requireFlag(flags, ['tenant', 'tenant-id', 'tenantId'], 'tenant'),
|
|
820
|
+
job_type: requireFlag(flags, ['job-type', 'jobType'], 'job-type'),
|
|
821
|
+
memory_commitment_root: requireFlag(flags, ['memory-root', 'memory-commitment-root', 'memoryCommitmentRoot'], 'memory-root'),
|
|
822
|
+
policy_hash: requireFlag(flags, ['policy-hash', 'policyHash'], 'policy-hash'),
|
|
823
|
+
usage_event_hash: requireFlag(flags, ['usage-event-hash', 'usageEventHash'], 'usage-event-hash'),
|
|
824
|
+
requested_at: getFlag(flags, ['requested-at', 'requestedAt']),
|
|
825
|
+
expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
|
|
826
|
+
max_price_amount: numberFlag(flags, ['max-price-amount', 'maxPriceAmount'], 'max-price-amount'),
|
|
827
|
+
payment_asset: getFlag(flags, ['payment-asset', 'paymentAsset', 'asset'], 'USDC'),
|
|
828
|
+
});
|
|
829
|
+
if (flags.has('out')) {
|
|
830
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
831
|
+
await writeJson(outPath, job);
|
|
832
|
+
print({ ok: true, path: outPath, job_id: job.job_id, job_hash: job.job_hash }, io);
|
|
833
|
+
} else {
|
|
834
|
+
print(job, io);
|
|
835
|
+
}
|
|
836
|
+
return 0;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
export async function settlementCapacityCommand(flags, io) {
|
|
840
|
+
const profile = createConsumerGpuCapacityProfile({
|
|
841
|
+
operator_id: requireFlag(flags, ['operator', 'operator-id', 'operatorId'], 'operator'),
|
|
842
|
+
accelerator_class: requireFlag(flags, ['accelerator-class', 'acceleratorClass'], 'accelerator-class'),
|
|
843
|
+
hardware_ref: requireFlag(flags, ['hardware-ref', 'hardwareRef'], 'hardware-ref'),
|
|
844
|
+
region: requireFlag(flags, ['region'], 'region'),
|
|
845
|
+
model_family: requireFlag(flags, ['model-family', 'modelFamily'], 'model-family'),
|
|
846
|
+
model_refs: parseList(requireFlag(flags, ['model-ref', 'model-refs', 'modelRefs'], 'model-ref')),
|
|
847
|
+
observed_at: getFlag(flags, ['observed-at', 'observedAt']),
|
|
848
|
+
expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
|
|
849
|
+
vram_gb: numberFlag(flags, ['vram-gb', 'vramGb'], 'vram-gb'),
|
|
850
|
+
max_context_window_tokens: numberFlag(flags, ['max-context-window-tokens', 'maxContextWindowTokens'], 'max-context-window-tokens'),
|
|
851
|
+
available_context_tokens_per_minute: numberFlag(flags, ['available-context-tokens-per-minute', 'availableContextTokensPerMinute'], 'available-context-tokens-per-minute'),
|
|
852
|
+
p95_latency_ms: numberFlag(flags, ['p95-latency-ms', 'p95LatencyMs'], 'p95-latency-ms'),
|
|
853
|
+
price_per_million_context_tokens: numberFlag(flags, ['price-per-million-context-tokens', 'pricePerMillionContextTokens'], 'price-per-million-context-tokens'),
|
|
854
|
+
asset: getFlag(flags, ['asset', 'settlement-asset', 'settlementAsset'], 'USDC'),
|
|
855
|
+
capacity_ref: requireFlag(flags, ['capacity-ref', 'capacityRef'], 'capacity-ref'),
|
|
856
|
+
terms_ref: requireFlag(flags, ['terms-ref', 'termsRef'], 'terms-ref'),
|
|
857
|
+
});
|
|
858
|
+
if (flags.has('out')) {
|
|
859
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
860
|
+
await writeJson(outPath, profile);
|
|
861
|
+
print({ ok: true, path: outPath, capacity_profile_hash: profile.capacity_profile_hash }, io);
|
|
862
|
+
} else {
|
|
863
|
+
print(profile, io);
|
|
864
|
+
}
|
|
865
|
+
return 0;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export async function settlementQuoteCommand(flags, io) {
|
|
869
|
+
const jobPath = resolve(String(requireFileArg(flags, ['job'], undefined, 'job')));
|
|
870
|
+
const capacityProfilePath = getFlag(flags, ['capacity-profile', 'capacityProfile']);
|
|
871
|
+
const capacityProfile = capacityProfilePath ? await readJson(resolve(String(capacityProfilePath))) : null;
|
|
872
|
+
const job = await readJson(jobPath);
|
|
873
|
+
const quote = createOperatorServiceQuote({
|
|
874
|
+
job,
|
|
875
|
+
operator_id: requireFlag(flags, ['operator', 'operator-id', 'operatorId'], 'operator'),
|
|
876
|
+
service_kind: requireFlag(flags, ['service-kind', 'serviceKind'], 'service-kind'),
|
|
877
|
+
quoted_at: getFlag(flags, ['quoted-at', 'quotedAt']),
|
|
878
|
+
expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
|
|
879
|
+
price_amount: numberFlag(flags, ['price-amount', 'priceAmount'], 'price-amount'),
|
|
880
|
+
asset: getFlag(flags, ['asset', 'payment-asset', 'paymentAsset']),
|
|
881
|
+
capacity_ref: capacityProfile ? capacityProfile.capacity_ref : requireFlag(flags, ['capacity-ref', 'capacityRef'], 'capacity-ref'),
|
|
882
|
+
terms_ref: requireFlag(flags, ['terms-ref', 'termsRef'], 'terms-ref'),
|
|
883
|
+
capacity_profile: capacityProfile,
|
|
884
|
+
});
|
|
885
|
+
if (flags.has('out')) {
|
|
886
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
887
|
+
await writeJson(outPath, quote);
|
|
888
|
+
print({ ok: true, path: outPath, quote_id: quote.quote_id, quote_hash: quote.quote_hash }, io);
|
|
889
|
+
} else {
|
|
890
|
+
print(quote, io);
|
|
891
|
+
}
|
|
892
|
+
return 0;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
export async function settlementReceiptCommand(flags, io) {
|
|
896
|
+
const job = await readJson(resolve(String(requireFileArg(flags, ['job'], undefined, 'job'))));
|
|
897
|
+
const quote = await readJson(resolve(String(requireFileArg(flags, ['quote'], undefined, 'quote'))));
|
|
898
|
+
const receipt = createServiceSettlementReceipt({
|
|
899
|
+
job,
|
|
900
|
+
quote,
|
|
901
|
+
completed_at: getFlag(flags, ['completed-at', 'completedAt']),
|
|
902
|
+
settled_amount: numberFlag(flags, ['settled-amount', 'settledAmount'], 'settled-amount'),
|
|
903
|
+
settlement_ref: requireFlag(flags, ['settlement-ref', 'settlementRef'], 'settlement-ref'),
|
|
904
|
+
service_receipt_ref: requireFlag(flags, ['service-receipt-ref', 'serviceReceiptRef'], 'service-receipt-ref'),
|
|
905
|
+
});
|
|
906
|
+
if (flags.has('out')) {
|
|
907
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
908
|
+
await writeJson(outPath, receipt);
|
|
909
|
+
print({ ok: true, path: outPath, settlement_receipt_id: receipt.settlement_receipt_id, settlement_receipt_hash: receipt.settlement_receipt_hash }, io);
|
|
910
|
+
} else {
|
|
911
|
+
print(receipt, io);
|
|
912
|
+
}
|
|
913
|
+
return 0;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
export async function settlementVerifyCommand(flags, io) {
|
|
917
|
+
const job = await readJson(resolve(String(requireFileArg(flags, ['job'], undefined, 'job'))));
|
|
918
|
+
const quote = await readJson(resolve(String(requireFileArg(flags, ['quote'], undefined, 'quote'))));
|
|
919
|
+
const receipt = await readJson(resolve(String(requireFileArg(flags, ['receipt'], undefined, 'receipt'))));
|
|
920
|
+
const result = verifyServiceSettlementReceipt({ job, quote, receipt });
|
|
921
|
+
print(result, io);
|
|
922
|
+
return result.ok ? 0 : 1;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export async function settlementBatchCommand(flags, io, positionalFile) {
|
|
926
|
+
const receiptsPath = resolve(String(requireFileArg(flags, ['receipts', 'in'], positionalFile, 'receipts')));
|
|
927
|
+
const source = await readJson(receiptsPath);
|
|
928
|
+
const batch = createSettlementBatch({
|
|
929
|
+
receipts: Array.isArray(source) ? source : source.receipts,
|
|
930
|
+
asset: getFlag(flags, ['asset']),
|
|
931
|
+
batch_ref: requireFlag(flags, ['batch-ref', 'batchRef'], 'batch-ref'),
|
|
932
|
+
generated_at: getFlag(flags, ['generated-at', 'generatedAt']),
|
|
933
|
+
});
|
|
934
|
+
if (flags.has('out')) {
|
|
935
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
936
|
+
await writeJson(outPath, batch);
|
|
937
|
+
print({ ok: true, path: outPath, batch_id: batch.batch_id, batch_hash: batch.batch_hash }, io);
|
|
938
|
+
} else {
|
|
939
|
+
print(batch, io);
|
|
940
|
+
}
|
|
941
|
+
return 0;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
function usage() {
|
|
945
|
+
return {
|
|
946
|
+
usage: 'enigma <command> [options]',
|
|
947
|
+
commands: [
|
|
948
|
+
'init',
|
|
949
|
+
'doctor',
|
|
950
|
+
'install',
|
|
951
|
+
'connect <client>',
|
|
952
|
+
'disconnect <client>',
|
|
953
|
+
'remember',
|
|
954
|
+
'recall',
|
|
955
|
+
'update',
|
|
956
|
+
'delete',
|
|
957
|
+
'context',
|
|
958
|
+
'export',
|
|
959
|
+
'import <source>',
|
|
960
|
+
'capsule export',
|
|
961
|
+
'capsule import',
|
|
962
|
+
'verify',
|
|
963
|
+
'boundary run',
|
|
964
|
+
'mcp serve',
|
|
965
|
+
'relay demo',
|
|
966
|
+
'relay serve',
|
|
967
|
+
'gateway demo',
|
|
968
|
+
'gateway serve',
|
|
969
|
+
'native-host manifest',
|
|
970
|
+
'native-host install-plan',
|
|
971
|
+
'mesh demo',
|
|
972
|
+
'enterprise demo',
|
|
973
|
+
'meter event',
|
|
974
|
+
'meter aggregate',
|
|
975
|
+
'settlement job',
|
|
976
|
+
'settlement capacity',
|
|
977
|
+
'settlement quote',
|
|
978
|
+
'settlement receipt',
|
|
979
|
+
'settlement verify',
|
|
980
|
+
'settlement batch',
|
|
981
|
+
],
|
|
982
|
+
connector_options: {
|
|
983
|
+
'--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
|
|
984
|
+
'--config <path>': 'Client MCP JSON config path to read/write.',
|
|
985
|
+
'--server-name <name>': 'MCP server key; defaults to enigma.',
|
|
986
|
+
'--mcp-command <command>': 'Command rendered in MCP config; defaults to enigma-mcp. Alias: --command.',
|
|
987
|
+
'--dry-run': 'Print planned config without writing.',
|
|
988
|
+
},
|
|
989
|
+
remember_options: {
|
|
990
|
+
'--text <text>': 'Inline local memory text. Avoid for private content because argv can be logged by process tooling.',
|
|
991
|
+
'--text-file <path>': 'Read local memory text from a file so private smoke input is not exposed in shell argv. Aliases: --memory-file, --textFile, --memoryFile.',
|
|
992
|
+
},
|
|
993
|
+
native_host: {
|
|
994
|
+
bin: 'enigma-native-host',
|
|
995
|
+
host_name: 'com.enigma.native_host',
|
|
996
|
+
bundle_env: 'ENIGMA_BUNDLE',
|
|
997
|
+
manifests: [
|
|
998
|
+
'apps/native-host/manifests/com.enigma.native_host.chrome.json',
|
|
999
|
+
'apps/native-host/manifests/com.enigma.native_host.edge.json',
|
|
1000
|
+
'apps/native-host/manifests/com.enigma.native_host.firefox.json',
|
|
1001
|
+
],
|
|
1002
|
+
generator: 'enigma native-host manifest --browser <chrome|edge|firefox> --host-path <absolute path> --extension-id <id> [--out <file>]',
|
|
1003
|
+
install_plan: 'enigma native-host install-plan --browser <chrome|edge|firefox> --manifest <absolute path> [--os <windows|macos|linux>] [--home <absolute path>]',
|
|
1004
|
+
generator_options: {
|
|
1005
|
+
'--browser <chrome|edge|firefox>': 'Browser manifest format to generate or plan.',
|
|
1006
|
+
'--host-path <absolute path>': 'Absolute path to the installed enigma-native-host executable.',
|
|
1007
|
+
'--extension-id <id>': 'Browser extension id allowed to connect to the native host.',
|
|
1008
|
+
'--out <file>': 'Write manifest JSON to a file instead of stdout.',
|
|
1009
|
+
},
|
|
1010
|
+
install_plan_options: {
|
|
1011
|
+
'--browser <chrome|edge|firefox>': 'Browser whose native messaging registration targets should be planned.',
|
|
1012
|
+
'--manifest <absolute path>': 'Absolute path to the generated native messaging manifest to register manually.',
|
|
1013
|
+
'--os <windows|macos|linux>': 'Target operating system. Defaults to the current operating system.',
|
|
1014
|
+
'--home <absolute path>': 'Target user home directory used to compute per-user manifest locations.',
|
|
1015
|
+
},
|
|
1016
|
+
boundary: 'Browser native messaging returns local context plus receipt summaries only; provider-native memory remains cache only.',
|
|
1017
|
+
},
|
|
1018
|
+
metering: {
|
|
1019
|
+
event: 'enigma meter event --tenant <id> --provider <id> --model <id> --prompt-tokens <n> --completion-tokens <n> --memory-baseline-tokens <n> --memory-optimized-tokens <n> --price-per-million-tokens <n> [--out <file>]',
|
|
1020
|
+
aggregate: 'enigma meter aggregate --events <events.json> [--tenant <id>] [--out <file>]',
|
|
1021
|
+
boundary: 'Metering artifacts contain counts, hashes, identifiers, pricing inputs, and claim boundaries only; no prompts, completions, provider responses, credentials, token ROI, or provider-invoice savings claim.',
|
|
1022
|
+
},
|
|
1023
|
+
settlement: {
|
|
1024
|
+
job: 'enigma settlement job --tenant <id> --job-type <type> --memory-root <sha256:...> --policy-hash <sha256:...> --usage-event-hash <sha256:...> --max-price-amount <n> --payment-asset <asset> --expires-at <iso> [--out <file>]',
|
|
1025
|
+
capacity: 'enigma settlement capacity --operator <id> --accelerator-class <consumer_gpu|workstation_gpu|edge_gpu> --hardware-ref <ref> --region <region> --model-family <family> --model-ref <id[,id]> --vram-gb <n> --max-context-window-tokens <n> --available-context-tokens-per-minute <n> --p95-latency-ms <n> --price-per-million-context-tokens <n> --capacity-ref <ref> --terms-ref <ref> --expires-at <iso> [--asset <asset>] [--out <file>]',
|
|
1026
|
+
quote: 'enigma settlement quote --job <job.json> --operator <id> --service-kind <kind> --price-amount <n> --asset <asset> --capacity-ref <ref> --terms-ref <ref> --expires-at <iso> [--capacity-profile <profile.json>] [--out <file>]',
|
|
1027
|
+
receipt: 'enigma settlement receipt --job <job.json> --quote <quote.json> --settled-amount <n> --settlement-ref <ref> --service-receipt-ref <ref> [--out <file>]',
|
|
1028
|
+
verify: 'enigma settlement verify --job <job.json> --quote <quote.json> --receipt <receipt.json>',
|
|
1029
|
+
batch: 'enigma settlement batch --receipts <receipts.json> --batch-ref <ref> [--asset <asset>] [--out <file>]',
|
|
1030
|
+
boundary: 'Settlement artifacts contain commitment roots, capacity profiles, hashes, refs, prices, and claim boundaries only; no raw memory, prompts, provider responses, credentials, token ROI/profit, decentralization, or provider-invoice savings claim.',
|
|
1031
|
+
},
|
|
1032
|
+
relay_gateway_options: {
|
|
1033
|
+
'--host <host>': 'Bind host. Defaults to 127.0.0.1.',
|
|
1034
|
+
'--port <port>': `Bind port. Defaults to ${DEFAULT_RELAY_PORT} for relay and ${DEFAULT_GATEWAY_PORT} for gateway.`,
|
|
1035
|
+
'--state-file <path>': 'Load and persist local relay/gateway demo state as JSON.',
|
|
1036
|
+
'--once': 'Start, report the listening address, persist state when configured, then close.',
|
|
1037
|
+
},
|
|
1038
|
+
kimi_code: {
|
|
1039
|
+
gui_path_note: 'GUI-launched Kimi Code may not inherit your shell PATH; pass --mcp-command with an absolute enigma-mcp path when needed.',
|
|
1040
|
+
example: 'enigma connect kimi-code --bundle "$HOME/.enigma/bundle.json" --mcp-command "/absolute/path/to/enigma-mcp"',
|
|
1041
|
+
tools: ['enigma_init', 'enigma_remember', 'enigma_search', 'enigma_context_pack', 'enigma_delete', 'enigma_verify_receipts'],
|
|
1042
|
+
},
|
|
1043
|
+
connector_write_behavior: 'Config writes preserve unrelated settings and sibling MCP servers. Existing configs are backed up only when the semantic JSON config changes; reconnecting an identical config is idempotent.',
|
|
1044
|
+
claim_boundaries: 'Connectors configure local MCP access to an Enigma bundle. They do not make provider-native memory canonical and do not prove provider deletion or model forgetting.',
|
|
1045
|
+
import_sources: Object.keys(IMPORTERS),
|
|
1046
|
+
clients: supportedClients,
|
|
1047
|
+
bundle: DEFAULT_BUNDLE,
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
export async function main(argv = process.argv.slice(2), io = { stdout: process.stdout, stderr: process.stderr }) {
|
|
1052
|
+
const command = argv[0];
|
|
1053
|
+
const subcommand = argv[1];
|
|
1054
|
+
if (!command || command === '--help' || command === '-h') {
|
|
1055
|
+
print(usage(), io);
|
|
1056
|
+
return 0;
|
|
1057
|
+
}
|
|
1058
|
+
const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement'];
|
|
1059
|
+
const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
|
|
1060
|
+
const positionalFile = optionalPositional(argv[2]);
|
|
1061
|
+
if ((flags.has('help') || argv.includes('-h')) && (((command === 'relay' || command === 'gateway') && (subcommand === 'serve' || subcommand === 'demo')) || (command === 'native-host' && (subcommand === 'manifest' || subcommand === 'install-plan')))) {
|
|
1062
|
+
print(usage(), io);
|
|
1063
|
+
return 0;
|
|
1064
|
+
}
|
|
1065
|
+
try {
|
|
1066
|
+
if (command === 'init') return await initCommand(flags, io);
|
|
1067
|
+
if (command === 'doctor') return await doctorCommand(flags, io);
|
|
1068
|
+
if (command === 'install') return await installCommand(flags, io);
|
|
1069
|
+
if (command === 'connect') return await connectCommand(subcommand, flags, io);
|
|
1070
|
+
if (command === 'disconnect') return await disconnectCommand(subcommand, flags, io);
|
|
1071
|
+
if (command === 'remember') return await rememberCommand(flags, io);
|
|
1072
|
+
if (command === 'recall') return await recallCommand(flags, io);
|
|
1073
|
+
if (command === 'update') return await updateCommand(flags, io);
|
|
1074
|
+
if (command === 'delete') return await deleteCommand(flags, io);
|
|
1075
|
+
if (command === 'context') return await contextCommand(flags, io);
|
|
1076
|
+
if (command === 'export') return await exportCommand(flags, io);
|
|
1077
|
+
if (command === 'import') return await importCommand(subcommand, flags, io, positionalFile);
|
|
1078
|
+
if (command === 'capsule' && subcommand === 'export') return await capsuleExportCommand(flags, io, positionalFile);
|
|
1079
|
+
if (command === 'capsule' && subcommand === 'import') return await capsuleImportCommand(flags, io, positionalFile);
|
|
1080
|
+
if (command === 'verify') return await verifyCommand(flags, io);
|
|
1081
|
+
if (command === 'boundary' && subcommand === 'run') return await boundaryRunCommand(flags, io);
|
|
1082
|
+
if (command === 'mcp' && subcommand === 'serve') return await mcpServeCommand(flags, io);
|
|
1083
|
+
if (command === 'relay' && subcommand === 'demo') return await relayDemoCommand(flags, io);
|
|
1084
|
+
if (command === 'relay' && subcommand === 'serve') return await relayServeCommand(flags, io);
|
|
1085
|
+
if (command === 'gateway' && subcommand === 'demo') return await gatewayDemoCommand(flags, io);
|
|
1086
|
+
if (command === 'gateway' && subcommand === 'serve') return await gatewayServeCommand(flags, io);
|
|
1087
|
+
if (command === 'native-host' && subcommand === 'manifest') return await nativeHostManifestCommand(flags, io);
|
|
1088
|
+
if (command === 'meter' && subcommand === 'event') return await meterEventCommand(flags, io);
|
|
1089
|
+
if (command === 'meter' && subcommand === 'aggregate') return await meterAggregateCommand(flags, io, positionalFile);
|
|
1090
|
+
if (command === 'settlement' && subcommand === 'job') return await settlementJobCommand(flags, io);
|
|
1091
|
+
if (command === 'settlement' && subcommand === 'capacity') return await settlementCapacityCommand(flags, io);
|
|
1092
|
+
if (command === 'settlement' && subcommand === 'quote') return await settlementQuoteCommand(flags, io);
|
|
1093
|
+
if (command === 'settlement' && subcommand === 'receipt') return await settlementReceiptCommand(flags, io);
|
|
1094
|
+
if (command === 'settlement' && subcommand === 'verify') return await settlementVerifyCommand(flags, io);
|
|
1095
|
+
if (command === 'settlement' && subcommand === 'batch') return await settlementBatchCommand(flags, io, positionalFile);
|
|
1096
|
+
if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
|
|
1097
|
+
if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
|
|
1098
|
+
if (command === 'enterprise' && subcommand === 'demo') return await enterpriseDemoCommand(flags, io);
|
|
1099
|
+
throw new Error(`Unknown command: ${[command, subcommand].filter(Boolean).join(' ')}`);
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
print({ ok: false, error: { code: 'CLI_ERROR', message: error.message } }, io);
|
|
1102
|
+
return 2;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function isMainModule(metaUrl) {
|
|
1106
|
+
if (!process.argv[1]) return false;
|
|
1107
|
+
try {
|
|
1108
|
+
return metaUrl === pathToFileURL(realpathSync(process.argv[1])).href;
|
|
1109
|
+
} catch {
|
|
1110
|
+
return metaUrl === pathToFileURL(process.argv[1]).href;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
if (isMainModule(import.meta.url)) {
|
|
1116
|
+
process.exitCode = await main();
|
|
1117
|
+
}
|