enigma-memory 0.1.0 → 0.1.2

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.
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env node
2
+ import { execFile } from 'node:child_process';
3
+ import { mkdir, mkdtemp } from 'node:fs/promises';
4
+ import { readFileSync } from 'node:fs';
5
+ import { dirname, isAbsolute, join, resolve as resolvePath } from 'node:path';
6
+ import { tmpdir } from 'node:os';
7
+ import { promisify } from 'node:util';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ export const REGISTRY_INSTALL_SCHEMA = 'enigma.registry_install_verifier.v1';
11
+ export const REQUIRED_NODE_MAJOR = 24;
12
+
13
+ const execFileAsync = promisify(execFile);
14
+ const SCRIPT_PATH = fileURLToPath(import.meta.url);
15
+ const PACKAGE_DIR = resolvePath(dirname(SCRIPT_PATH), '..');
16
+ const PACKAGE_JSON = JSON.parse(readFileSync(resolvePath(PACKAGE_DIR, 'package.json'), 'utf8'));
17
+ const PACKAGE_BINS = Object.freeze({ ...PACKAGE_JSON.bin });
18
+ const PACKAGE_NAME_RE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
19
+ const PACKAGE_VERSION_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u;
20
+ const PACKAGE_SPEC_RE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u;
21
+
22
+ export const DEFAULT_REGISTRY_PACKAGE = PACKAGE_JSON.name ?? 'enigma-memory';
23
+ export const DEFAULT_REGISTRY_VERSION = PACKAGE_JSON.version;
24
+ export const REGISTRY_INSTALL_CHECKS = Object.freeze([
25
+ Object.freeze({ step: 'check_enigma_help', bin: 'enigma', args: Object.freeze(['--help']) }),
26
+ Object.freeze({ step: 'check_enigma_doctor', bin: 'enigma', args: Object.freeze(['doctor']) }),
27
+ Object.freeze({ step: 'check_enigma_relay_demo', bin: 'enigma-relay', args: Object.freeze(['demo']) }),
28
+ Object.freeze({ step: 'check_enigma_gateway_demo', bin: 'enigma-gateway', args: Object.freeze(['demo']) }),
29
+ ]);
30
+
31
+ function readRequiredValue(argv, index, flag) {
32
+ const value = argv[index + 1];
33
+ if (value === undefined || value.startsWith('--')) throw new Error(`Missing value for ${flag}.`);
34
+ return value;
35
+ }
36
+
37
+ function commandForPlatform(base, platform) {
38
+ return platform === 'win32' ? `${base}.cmd` : base;
39
+ }
40
+
41
+ function rejectControlCharacters(value, label) {
42
+ const text = String(value ?? '');
43
+ if (text.length === 0) throw new Error(`${label} must not be empty.`);
44
+ if (text.includes('\0') || text.includes('\n') || text.includes('\r')) throw new Error(`${label} contains an invalid control character.`);
45
+ return text;
46
+ }
47
+
48
+ export function usage() {
49
+ return `Usage: node scripts/verify-registry-install.mjs [--execute] [--package <name>] [--version <version>] [--tmp-dir <path>] [--skip-network]\n\nDry-run is the default and prints the public-safe planned command set. Execute mode installs the package into a temporary prefix and runs selected installed bin files directly. --skip-network validates the plan without running npm install or installed bins.\n`;
50
+ }
51
+
52
+ export function parseRegistryInstallArgs(argv = process.argv.slice(2)) {
53
+ const options = {
54
+ dryRun: true,
55
+ execute: false,
56
+ packageName: DEFAULT_REGISTRY_PACKAGE,
57
+ packageVersion: DEFAULT_REGISTRY_VERSION,
58
+ tmpDir: undefined,
59
+ skipNetwork: false,
60
+ };
61
+ let sawDryRun = false;
62
+ let sawExecute = false;
63
+
64
+ for (let index = 0; index < argv.length; index += 1) {
65
+ const arg = argv[index];
66
+ if (arg === '--help' || arg === '-h') {
67
+ options.help = true;
68
+ } else if (arg === '--dry-run') {
69
+ sawDryRun = true;
70
+ options.dryRun = true;
71
+ options.execute = false;
72
+ } else if (arg === '--execute') {
73
+ sawExecute = true;
74
+ options.dryRun = false;
75
+ options.execute = true;
76
+ } else if (arg === '--package') {
77
+ options.packageName = readRequiredValue(argv, index, arg);
78
+ index += 1;
79
+ } else if (arg === '--version') {
80
+ options.packageVersion = readRequiredValue(argv, index, arg);
81
+ index += 1;
82
+ } else if (arg === '--tmp-dir') {
83
+ options.tmpDir = readRequiredValue(argv, index, arg);
84
+ index += 1;
85
+ } else if (arg === '--skip-network') {
86
+ options.skipNetwork = true;
87
+ } else {
88
+ throw new Error('Unknown argument.');
89
+ }
90
+ }
91
+
92
+ if (sawDryRun && sawExecute) throw new Error('Use either --dry-run or --execute, not both.');
93
+ validatePackageName(options.packageName);
94
+ validatePackageVersion(options.packageVersion);
95
+ if (options.tmpDir !== undefined) rejectControlCharacters(options.tmpDir, 'Temporary directory');
96
+ return options;
97
+ }
98
+
99
+ export function nodeMajor(version) {
100
+ const match = String(version ?? '').trim().match(/^v?(\d+)(?:\.\d+){0,2}(?:[-+].*)?$/u);
101
+ if (!match) throw new Error('Invalid Node version override.');
102
+ return Number(match[1]);
103
+ }
104
+
105
+ export function validateNodeVersion(version = process.versions.node, requiredMajor = REQUIRED_NODE_MAJOR) {
106
+ const major = nodeMajor(version);
107
+ if (!Number.isSafeInteger(major) || major < requiredMajor) {
108
+ throw new Error(`Node >=${requiredMajor} is required for the registry install verifier.`);
109
+ }
110
+ return { ok: true, required: `>=${requiredMajor}`, current_major: major };
111
+ }
112
+
113
+ export function validatePackageName(name) {
114
+ const value = rejectControlCharacters(name, 'Package name');
115
+ if (!PACKAGE_NAME_RE.test(value)) throw new Error('Package name must be a deterministic npm package name.');
116
+ return value;
117
+ }
118
+
119
+ export function validatePackageVersion(version) {
120
+ const value = rejectControlCharacters(version, 'Package version');
121
+ if (!PACKAGE_VERSION_RE.test(value)) throw new Error('Package version must be an exact semver version.');
122
+ return value;
123
+ }
124
+
125
+ function packageSpec(packageName, packageVersion) {
126
+ return `${validatePackageName(packageName)}@${validatePackageVersion(packageVersion)}`;
127
+ }
128
+
129
+ function packageInstallDirectory(prefix, packageName) {
130
+ const parts = packageName.startsWith('@') ? packageName.split('/') : [packageName];
131
+ return join(prefix, 'node_modules', ...parts);
132
+ }
133
+
134
+ function normalizeSeparators(value) {
135
+ return String(value).replace(/\\/gu, '/');
136
+ }
137
+
138
+ function replaceAllPathForms(value, from, to) {
139
+ if (!from || from.includes('<')) return value;
140
+ const normalizedFrom = normalizeSeparators(from);
141
+ const normalizedValue = normalizeSeparators(value);
142
+ if (normalizedValue === normalizedFrom) return to;
143
+ if (normalizedValue.startsWith(`${normalizedFrom}/`)) return `${to}${normalizedValue.slice(normalizedFrom.length)}`;
144
+ return normalizedValue.split(normalizedFrom).join(to);
145
+ }
146
+
147
+ export function redactPublicPath(value, replacements = []) {
148
+ let redacted = String(value ?? '');
149
+ const sorted = [...replacements]
150
+ .filter((entry) => entry && typeof entry.path === 'string' && entry.path.length > 0)
151
+ .sort((left, right) => right.path.length - left.path.length);
152
+ for (const entry of sorted) redacted = replaceAllPathForms(redacted, entry.path, entry.label);
153
+ redacted = redacted.replace(/[A-Za-z]:[\\/][^\s"'\])},]+/gu, '<absolute-path>');
154
+ redacted = redacted.replace(/(^|[\s"'(\[{:,])\/(?:[^/\s"'\])},]+\/)+[^/\s"'\])},]+/gu, '$1<absolute-path>');
155
+ if (redacted.startsWith('/')) return '<absolute-path>';
156
+ if (redacted.startsWith('\\\\')) return '<absolute-path>';
157
+ return redacted;
158
+ }
159
+
160
+ function publicCommandFor(command) {
161
+ if (command.kind === 'npm_install') {
162
+ return {
163
+ command: 'npm',
164
+ args: ['install', '--prefix', '<temp-prefix>', command.package_spec],
165
+ };
166
+ }
167
+ return {
168
+ command: command.bin,
169
+ args: [...command.bin_args],
170
+ };
171
+ }
172
+
173
+ function npmInstallCommand(platform, nodeCommand, runtime, prefix, spec) {
174
+ const npmCliPath = runtime.npmCliPath ?? process.env.npm_execpath;
175
+ if (platform === 'win32' && typeof npmCliPath === 'string' && npmCliPath.length > 0) {
176
+ return {
177
+ command: nodeCommand,
178
+ args: [npmCliPath, 'install', '--prefix', prefix, spec],
179
+ };
180
+ }
181
+ return {
182
+ command: commandForPlatform('npm', platform),
183
+ args: ['install', '--prefix', prefix, spec],
184
+ };
185
+ }
186
+
187
+ function commandBasename(command) {
188
+ const normalized = normalizeSeparators(command);
189
+ return normalized.slice(normalized.lastIndexOf('/') + 1).toLowerCase();
190
+ }
191
+
192
+ export function buildRegistryInstallPlan(options = {}, runtime = {}) {
193
+ const platform = runtime.platform ?? process.platform;
194
+ const cwd = runtime.cwd ?? process.cwd();
195
+ const packageName = validatePackageName(options.packageName ?? DEFAULT_REGISTRY_PACKAGE);
196
+ const packageVersion = validatePackageVersion(options.packageVersion ?? DEFAULT_REGISTRY_VERSION);
197
+ const spec = packageSpec(packageName, packageVersion);
198
+ const requestedTmpDir = options.tmpDir === undefined ? undefined : rejectControlCharacters(options.tmpDir, 'Temporary directory');
199
+ const prefix = requestedTmpDir === undefined ? (runtime.tmpDir ?? '<temp-prefix>') : (isAbsolute(requestedTmpDir) ? resolvePath(requestedTmpDir) : resolvePath(cwd, requestedTmpDir));
200
+ const installedPackageDir = packageInstallDirectory(prefix, packageName);
201
+ const nodeCommand = String(runtime.nodeCommand ?? process.execPath);
202
+ const installCommand = npmInstallCommand(platform, nodeCommand, runtime, prefix, spec);
203
+ const commands = [
204
+ {
205
+ step: 'install_package',
206
+ kind: 'npm_install',
207
+ command: installCommand.command,
208
+ args: installCommand.args,
209
+ package_spec: spec,
210
+ network: true,
211
+ },
212
+ ];
213
+
214
+ for (const check of REGISTRY_INSTALL_CHECKS) {
215
+ const relativeBinPath = PACKAGE_BINS[check.bin];
216
+ if (!relativeBinPath) throw new Error(`Package bin ${check.bin} is not declared.`);
217
+ commands.push({
218
+ step: check.step,
219
+ kind: 'bin_check',
220
+ bin: check.bin,
221
+ command: nodeCommand,
222
+ args: [join(installedPackageDir, relativeBinPath), ...check.args],
223
+ bin_args: [...check.args],
224
+ network: false,
225
+ });
226
+ }
227
+
228
+ const plan = {
229
+ packageName,
230
+ packageVersion,
231
+ packageSpec: spec,
232
+ prefix,
233
+ prefixKind: requestedTmpDir === undefined ? 'temporary' : (isAbsolute(requestedTmpDir) ? 'absolute' : 'relative'),
234
+ execute: options.execute === true,
235
+ dryRun: options.execute === true ? false : true,
236
+ skipNetwork: options.skipNetwork === true,
237
+ commands,
238
+ };
239
+ validateRegistryInstallPlan(plan);
240
+ return plan;
241
+ }
242
+
243
+ export function validateCommandSpec(spec) {
244
+ if (!spec || typeof spec !== 'object' || Array.isArray(spec)) throw new Error('Registry verifier command spec must be an object.');
245
+ const command = rejectControlCharacters(spec.command, 'Command name');
246
+ const args = Array.isArray(spec.args) ? spec.args.map(String) : [];
247
+ for (const [index, arg] of args.entries()) rejectControlCharacters(arg, `Command argument ${index}`);
248
+
249
+ if (spec.kind === 'npm_install') {
250
+ const directNpmInstall = (command === 'npm' || command === 'npm.cmd')
251
+ && args.length === 4
252
+ && args[0] === 'install'
253
+ && args[1] === '--prefix'
254
+ && PACKAGE_SPEC_RE.test(args[3]);
255
+ const nodeNpmCliInstall = (commandBasename(command) === 'node' || commandBasename(command) === 'node.exe')
256
+ && args.length === 5
257
+ && args[1] === 'install'
258
+ && args[2] === '--prefix'
259
+ && PACKAGE_SPEC_RE.test(args[4]);
260
+ if (!directNpmInstall && !nodeNpmCliInstall) {
261
+ throw new Error('Registry install command must be exactly npm install --prefix <tmp> <package>@<version>.');
262
+ }
263
+ return true;
264
+ }
265
+
266
+ if (spec.kind === 'bin_check') {
267
+ if (!REGISTRY_INSTALL_CHECKS.some((check) => check.step === spec.step && check.bin === spec.bin)) throw new Error('Registry bin check is not allowlisted.');
268
+ if (args.length < 1) throw new Error('Registry bin check must run an installed bin file.');
269
+ return true;
270
+ }
271
+
272
+ throw new Error('Registry verifier command is not allowlisted.');
273
+ }
274
+
275
+ export function validateRegistryInstallPlan(plan) {
276
+ if (!plan || typeof plan !== 'object' || Array.isArray(plan)) throw new Error('Registry install plan must be an object.');
277
+ if (plan.commands?.length !== REGISTRY_INSTALL_CHECKS.length + 1) throw new Error('Registry install plan has an unexpected command count.');
278
+ if (plan.commands[0]?.step !== 'install_package' || plan.commands[0]?.kind !== 'npm_install') throw new Error('Registry install plan must begin with package installation.');
279
+ for (const [index, check] of REGISTRY_INSTALL_CHECKS.entries()) {
280
+ const command = plan.commands[index + 1];
281
+ if (command?.step !== check.step || command?.kind !== 'bin_check' || command?.bin !== check.bin) {
282
+ throw new Error('Registry install plan has an unexpected bin check order.');
283
+ }
284
+ }
285
+ for (const command of plan.commands) validateCommandSpec(command);
286
+ return true;
287
+ }
288
+
289
+ function statusForCommand(plan, result) {
290
+ if (plan.skipNetwork) return 'validated';
291
+ if (!plan.execute) return 'preview';
292
+ if (!result) return 'skipped';
293
+ return result.ok === true ? 'passed' : 'failed';
294
+ }
295
+
296
+ export function summarizeRegistryInstallResult(plan, commandResults = [], node = validateNodeVersion()) {
297
+ const resultByStep = new Map(commandResults.map((result) => [result.step, result]));
298
+ const commands = plan.commands.map((command) => {
299
+ const publicSpec = publicCommandFor(command);
300
+ const result = resultByStep.get(command.step);
301
+ const record = {
302
+ step: command.step,
303
+ command: publicSpec.command,
304
+ args: publicSpec.args,
305
+ status: statusForCommand(plan, result),
306
+ network: command.network === true,
307
+ };
308
+ if (result?.exitCode !== undefined) record.exit_code = result.exitCode;
309
+ return record;
310
+ });
311
+ const expectedRuns = plan.execute && !plan.skipNetwork ? plan.commands.length : 0;
312
+ const executedAll = expectedRuns === 0 || commandResults.length === expectedRuns;
313
+ const commandOk = commandResults.every((result) => result.ok === true);
314
+ return {
315
+ schema: REGISTRY_INSTALL_SCHEMA,
316
+ ok: plan.skipNetwork ? true : (!plan.execute || (executedAll && commandOk)),
317
+ mode: plan.skipNetwork ? 'skip-network' : (plan.execute ? 'execute' : 'dry-run'),
318
+ dry_run: plan.dryRun,
319
+ execute: plan.execute,
320
+ skip_network: plan.skipNetwork,
321
+ public_safe: true,
322
+ node,
323
+ package: {
324
+ name: plan.packageName,
325
+ version: plan.packageVersion,
326
+ spec: plan.packageSpec,
327
+ },
328
+ install_prefix: '<temp-prefix>',
329
+ commands,
330
+ safety: {
331
+ default_dry_run: true,
332
+ requires_execute_for_mutation: true,
333
+ skip_network_runs_no_commands: plan.skipNetwork,
334
+ shell: false,
335
+ prints_local_absolute_paths: false,
336
+ prints_response_bodies: false,
337
+ prints_raw_memory: false,
338
+ prints_secrets: false,
339
+ },
340
+ };
341
+ }
342
+
343
+ async function runCommand(command, execFileImpl) {
344
+ try {
345
+ await execFileImpl(command.command, command.args, { windowsHide: true });
346
+ return { step: command.step, ok: true, exitCode: 0 };
347
+ } catch (error) {
348
+ return {
349
+ step: command.step,
350
+ ok: false,
351
+ exitCode: Number.isInteger(error?.code) ? error.code : 1,
352
+ };
353
+ }
354
+ }
355
+
356
+ export async function runRegistryInstallVerification(argv = process.argv.slice(2), runtime = {}) {
357
+ const parsedOptions = Array.isArray(argv) ? parseRegistryInstallArgs(argv) : { ...argv };
358
+ const node = validateNodeVersion(parsedOptions.nodeVersion ?? runtime.nodeVersion ?? process.versions.node);
359
+ const needsTempPrefix = parsedOptions.execute === true && parsedOptions.skipNetwork !== true && parsedOptions.tmpDir === undefined;
360
+ const options = { ...parsedOptions };
361
+
362
+ if (needsTempPrefix) {
363
+ const mkdtempImpl = runtime.mkdtempImpl ?? mkdtemp;
364
+ const tmpRoot = runtime.tmpRoot ?? tmpdir();
365
+ options.tmpDir = await mkdtempImpl(join(tmpRoot, 'enigma-registry-install-'));
366
+ }
367
+
368
+ const plan = buildRegistryInstallPlan(options, runtime);
369
+ if (plan.skipNetwork || !plan.execute) return summarizeRegistryInstallResult(plan, [], node);
370
+
371
+ const mkdirImpl = runtime.mkdirImpl ?? mkdir;
372
+ await mkdirImpl(plan.prefix, { recursive: true });
373
+ const execFileImpl = runtime.execFileImpl ?? execFileAsync;
374
+ const commandResults = [];
375
+ for (const command of plan.commands) {
376
+ const result = await runCommand(command, execFileImpl);
377
+ commandResults.push(result);
378
+ if (result.ok !== true) break;
379
+ }
380
+ return summarizeRegistryInstallResult(plan, commandResults, node);
381
+ }
382
+
383
+ function safeErrorMessage(error) {
384
+ const message = String(error?.message ?? error);
385
+ if (/^(Missing value|Unknown argument|Use either|Invalid Node version|Node >=|Package name|Package version|Temporary directory|Registry verifier|Registry install|Registry bin|Package bin)/u.test(message)) return message;
386
+ return 'Registry install verification failed.';
387
+ }
388
+
389
+ export function registryInstallCliOutput(output) {
390
+ if (output.mode === 'dry-run') return output.commands;
391
+ return output;
392
+ }
393
+
394
+ async function main() {
395
+ const args = parseRegistryInstallArgs();
396
+ if (args.help) {
397
+ process.stdout.write(usage());
398
+ return;
399
+ }
400
+ const output = await runRegistryInstallVerification(args);
401
+ process.stdout.write(`${JSON.stringify(registryInstallCliOutput(output), null, 2)}\n`);
402
+ if (output.ok !== true) process.exitCode = 1;
403
+ }
404
+
405
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolvePath(process.argv[1])) {
406
+ main().catch((error) => {
407
+ process.stdout.write(`${JSON.stringify({ schema: REGISTRY_INSTALL_SCHEMA, ok: false, public_safe: true, error: { code: 'REGISTRY_INSTALL_VERIFICATION_FAILED', message: safeErrorMessage(error) } }, null, 2)}\n`);
408
+ process.exitCode = 1;
409
+ });
410
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "enigma": {
4
+ "command": "enigma-mcp",
5
+ "env": {
6
+ "ENIGMA_BUNDLE": "<ENIGMA_BUNDLE>"
7
+ }
8
+ }
9
+ }
10
+ }