enigma-memory 0.1.12 → 0.1.13

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.
@@ -28,7 +28,7 @@ import {
28
28
  } from 'enigma-memory/hosted-cloud';
29
29
 
30
30
  export const HOSTED_CUSTOMER_LIFECYCLE_PACKET_SCHEMA = HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA;
31
- export const HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET = '0.1.12';
31
+ export const HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET = '0.1.13';
32
32
 
33
33
  const PROVIDED = 'provided';
34
34
  const BLOCKED_MISSING = 'blocked_missing_evidence';
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
6
6
 
7
7
  export const INSTALLER_ASSET_SCHEMA = 'enigma.installer_assets.v1';
8
8
  export const INSTALLER_ASSET_PACKAGE = 'enigma-memory';
9
- export const INSTALLER_ASSET_VERSION = '0.1.12';
9
+ export const INSTALLER_ASSET_VERSION = '0.1.13';
10
10
  export const INSTALLER_ASSET_GENERATED_AT = '1970-01-01T00:00:00.000Z';
11
11
 
12
12
  const SCRIPT_PATH = fileURLToPath(import.meta.url);
@@ -15,7 +15,7 @@ import {
15
15
  validateProofNetworkPacket,
16
16
  } from '../packages/proof-network/src/index.js';
17
17
 
18
- export const PROOF_NETWORK_PACKET_RELEASE_TARGET = '0.1.12';
18
+ export const PROOF_NETWORK_PACKET_RELEASE_TARGET = '0.1.13';
19
19
 
20
20
  const HASH_RE = /^(?:sha256:)?[a-f0-9]{64}$/iu;
21
21
  const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|\b(?:raw[\s_-]*memory|plaintext[\s_-]*prompts?|plain[\s_-]*text[\s_-]*prompts?|private[\s_-]*prompts?|provider[\s_-]*responses?|full[\s_-]*transcript|decrypted[\s_-]*memory|credentials?|secrets?|passwords?|private[\s_-]*keys?|api[\s_-]*key[\s_-]*(?:secret|material|value)|api[\s_-]*secrets?|access[\s_-]*tokens?|refresh[\s_-]*tokens?|token[\s_-]*values?|credential[\s_-]*material|tenant[\s_-]*names?)\b)/iu;
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env node
2
+ import { execFile } from 'node:child_process';
3
+ import { mkdir } from 'node:fs/promises';
4
+ import { dirname, isAbsolute, resolve as resolvePath } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ export const INSTALLER_SCHEMA = 'enigma.local_installer.v1';
9
+ export const REQUIRED_NODE_MAJOR = 24;
10
+ export const DEFAULT_BUNDLE_PATH = '.enigma/bundle.json';
11
+
12
+ const execFileAsync = promisify(execFile);
13
+ const SCRIPT_PATH = fileURLToPath(import.meta.url);
14
+ const DEFAULT_PACKAGE_DIR = resolvePath(dirname(SCRIPT_PATH), '..');
15
+ const SAFE_COMMAND_RE = /^[A-Za-z0-9._-]+$/u;
16
+
17
+ function readRequiredValue(argv, index, flag) {
18
+ const value = argv[index + 1];
19
+ if (value === undefined || value.startsWith('--')) throw new Error(`Missing value for ${flag}.`);
20
+ return value;
21
+ }
22
+
23
+ export function usage() {
24
+ return `Usage: node scripts/install-enigma-local.mjs [--dry-run|--execute] [--init-vault] [--bundle <path>]\n\nDry-run is the default. Execute mode runs npm install -g . from the local checkout.\nNo network download command is generated, and vault initialization runs only when --init-vault is present.\n`;
25
+ }
26
+
27
+ export function parseInstallerArgs(argv = process.argv.slice(2)) {
28
+ const options = {
29
+ dryRun: true,
30
+ execute: false,
31
+ initVault: false,
32
+ bundlePath: DEFAULT_BUNDLE_PATH,
33
+ packageDir: DEFAULT_PACKAGE_DIR,
34
+ subject: 'local-user',
35
+ displayName: 'Local user',
36
+ };
37
+ let sawDryRun = false;
38
+ let sawExecute = false;
39
+
40
+ for (let index = 0; index < argv.length; index += 1) {
41
+ const arg = argv[index];
42
+ if (arg === '--help' || arg === '-h') {
43
+ options.help = true;
44
+ } else if (arg === '--dry-run') {
45
+ sawDryRun = true;
46
+ options.dryRun = true;
47
+ options.execute = false;
48
+ } else if (arg === '--execute') {
49
+ sawExecute = true;
50
+ options.dryRun = false;
51
+ options.execute = true;
52
+ } else if (arg === '--init-vault') {
53
+ options.initVault = true;
54
+ } else if (arg === '--no-init-vault') {
55
+ options.initVault = false;
56
+ } else if (arg === '--bundle') {
57
+ options.bundlePath = readRequiredValue(argv, index, arg);
58
+ index += 1;
59
+ } else if (arg === '--package-dir') {
60
+ options.packageDir = readRequiredValue(argv, index, arg);
61
+ index += 1;
62
+ } else if (arg === '--subject') {
63
+ options.subject = readRequiredValue(argv, index, arg);
64
+ index += 1;
65
+ } else if (arg === '--display-name') {
66
+ options.displayName = readRequiredValue(argv, index, arg);
67
+ index += 1;
68
+ } else {
69
+ throw new Error('Unknown argument.');
70
+ }
71
+ }
72
+
73
+ if (sawDryRun && sawExecute) throw new Error('Use either --dry-run or --execute, not both.');
74
+ return options;
75
+ }
76
+
77
+ export function nodeMajor(version) {
78
+ const match = String(version ?? '').trim().match(/^v?(\d+)(?:\.\d+){0,2}(?:[-+].*)?$/u);
79
+ if (!match) throw new Error('Invalid Node version override.');
80
+ return Number(match[1]);
81
+ }
82
+
83
+ export function validateNodeVersion(version = process.versions.node, requiredMajor = REQUIRED_NODE_MAJOR) {
84
+ const major = nodeMajor(version);
85
+ if (!Number.isSafeInteger(major) || major < requiredMajor) {
86
+ throw new Error(`Node >=${requiredMajor} is required for the local Enigma installer.`);
87
+ }
88
+ return { ok: true, required: `>=${requiredMajor}`, current_major: major };
89
+ }
90
+
91
+ function commandForPlatform(base, platform) {
92
+ return platform === 'win32' ? `${base}.cmd` : base;
93
+ }
94
+
95
+ function rejectUnsafeArg(arg, label) {
96
+ const value = String(arg ?? '');
97
+ if (value.length === 0) throw new Error(`${label} must not be empty.`);
98
+ if (value.includes('\0') || value.includes('\n') || value.includes('\r')) throw new Error(`${label} contains an invalid control character.`);
99
+ }
100
+
101
+ export function validateCommandSpec(spec) {
102
+ if (!spec || typeof spec !== 'object' || Array.isArray(spec)) throw new Error('Installer command spec must be an object.');
103
+ const command = String(spec.command ?? '');
104
+ if (!SAFE_COMMAND_RE.test(command)) throw new Error('Installer command name is not safe.');
105
+ const args = Array.isArray(spec.args) ? spec.args.map(String) : [];
106
+ for (const [index, arg] of args.entries()) rejectUnsafeArg(arg, `Installer command argument ${index}`);
107
+
108
+ if (command === 'npm' || command === 'npm.cmd') {
109
+ if (args.length !== 3 || args[0] !== 'install' || args[1] !== '-g' || args[2] !== '.') {
110
+ throw new Error('Installer npm command must be exactly npm install -g .');
111
+ }
112
+ return true;
113
+ }
114
+
115
+ if (command === 'enigma' || command === 'enigma.cmd') {
116
+ const bundleIndex = args.indexOf('--bundle');
117
+ if (args[0] !== 'init' || bundleIndex === -1 || bundleIndex + 1 >= args.length) {
118
+ throw new Error('Installer Enigma command must initialize a bundle with --bundle.');
119
+ }
120
+ return true;
121
+ }
122
+
123
+ throw new Error('Installer command is not allowlisted.');
124
+ }
125
+
126
+ function publicCommand(command) {
127
+ if (command.step === 'install_package') return { command: 'npm', args: ['install', '-g', '.'] };
128
+ return { command: 'enigma', args: ['init', '--bundle', '<bundle-path>', '--subject', '<subject>', '--display-name', '<display-name>'] };
129
+ }
130
+
131
+ export function buildInstallerPlan(options = {}, runtime = {}) {
132
+ const platform = runtime.platform ?? process.platform;
133
+ const cwd = runtime.cwd ?? process.cwd();
134
+ const requestedPackageDir = String(options.packageDir ?? DEFAULT_PACKAGE_DIR);
135
+ rejectUnsafeArg(requestedPackageDir, 'Package directory');
136
+ const packageDir = resolvePath(requestedPackageDir);
137
+ const requestedBundlePath = String(options.bundlePath ?? DEFAULT_BUNDLE_PATH);
138
+ rejectUnsafeArg(requestedBundlePath, 'Bundle path');
139
+ const bundlePath = isAbsolute(requestedBundlePath) ? resolvePath(requestedBundlePath) : resolvePath(cwd, requestedBundlePath);
140
+
141
+ const commands = [
142
+ {
143
+ step: 'install_package',
144
+ command: commandForPlatform('npm', platform),
145
+ args: ['install', '-g', '.'],
146
+ cwd: packageDir,
147
+ mutates_global_state: true,
148
+ },
149
+ ];
150
+
151
+ if (options.initVault === true) {
152
+ commands.push({
153
+ step: 'initialize_vault',
154
+ command: commandForPlatform('enigma', platform),
155
+ args: ['init', '--bundle', bundlePath, '--subject', String(options.subject ?? 'local-user'), '--display-name', String(options.displayName ?? 'Local user')],
156
+ cwd: packageDir,
157
+ mutates_local_filesystem: true,
158
+ });
159
+ }
160
+
161
+ for (const command of commands) validateCommandSpec(command);
162
+
163
+ return {
164
+ dryRun: options.execute === true ? false : true,
165
+ execute: options.execute === true,
166
+ packageDir,
167
+ bundlePath,
168
+ bundlePathKind: requestedBundlePath === DEFAULT_BUNDLE_PATH ? 'default' : (isAbsolute(requestedBundlePath) ? 'absolute' : 'relative'),
169
+ initVault: options.initVault === true,
170
+ commands,
171
+ };
172
+ }
173
+
174
+ function publicCommandRecords(plan, resultByStep = new Map()) {
175
+ return plan.commands.map((command) => {
176
+ const publicSpec = publicCommand(command);
177
+ const runResult = resultByStep.get(command.step);
178
+ return {
179
+ step: command.step,
180
+ command: publicSpec.command,
181
+ args: publicSpec.args,
182
+ status: plan.execute ? (runResult?.ok ? 'executed' : 'pending') : 'preview',
183
+ mutates: command.mutates_global_state === true ? 'global_npm_install' : 'local_bundle_file',
184
+ };
185
+ });
186
+ }
187
+
188
+ function publicOutput(plan, node, commandResults = []) {
189
+ const resultByStep = new Map(commandResults.map((result) => [result.step, result]));
190
+ const commands = publicCommandRecords(plan, resultByStep);
191
+ return {
192
+ schema: INSTALLER_SCHEMA,
193
+ ok: commandResults.every((result) => result.ok !== false),
194
+ mode: plan.execute ? 'execute' : 'dry-run',
195
+ dry_run: plan.dryRun,
196
+ execute: plan.execute,
197
+ public_safe: true,
198
+ node,
199
+ package_source: {
200
+ kind: 'local_checkout',
201
+ install_boundary: 'Runs npm install -g . against the checked-out package only; it does not download Enigma from a registry.',
202
+ },
203
+ bundle: {
204
+ path: '<bundle-path>',
205
+ path_kind: plan.bundlePathKind,
206
+ initialize_requested: plan.initVault,
207
+ initialized: plan.execute && plan.initVault && resultByStep.get('initialize_vault')?.ok === true,
208
+ },
209
+ commands,
210
+ preview: {
211
+ commands,
212
+ },
213
+ safety: {
214
+ default_dry_run: true,
215
+ requires_execute_for_mutation: true,
216
+ shell: false,
217
+ network_download_command: false,
218
+ prints_local_absolute_paths: false,
219
+ prints_secrets: false,
220
+ },
221
+ };
222
+ }
223
+
224
+ async function runCommand(command, execFileImpl) {
225
+ try {
226
+ await execFileImpl(command.command, command.args, { cwd: command.cwd, windowsHide: true });
227
+ return { step: command.step, ok: true };
228
+ } catch {
229
+ throw new Error(`Installer command failed at ${command.step}.`);
230
+ }
231
+ }
232
+
233
+ export async function runInstallEnigmaLocal(argv = process.argv.slice(2), runtime = {}) {
234
+ const options = Array.isArray(argv) ? parseInstallerArgs(argv) : { ...argv };
235
+ const node = validateNodeVersion(options.nodeVersion ?? runtime.nodeVersion ?? process.versions.node);
236
+ const plan = buildInstallerPlan(options, runtime);
237
+ if (plan.dryRun) return publicOutput(plan, node);
238
+
239
+ const mkdirImpl = runtime.mkdirImpl ?? mkdir;
240
+ if (options.initVault === true) await mkdirImpl(dirname(plan.bundlePath), { recursive: true });
241
+ const execFileImpl = runtime.execFileImpl ?? execFileAsync;
242
+ const commandResults = [];
243
+ for (const command of plan.commands) {
244
+ commandResults.push(await runCommand(command, execFileImpl));
245
+ }
246
+ return publicOutput(plan, node, commandResults);
247
+ }
248
+
249
+ function safeErrorMessage(error) {
250
+ const message = String(error?.message ?? error);
251
+ if (/^(Missing value|Unknown argument|Use either|Invalid Node version|Node >=|Installer command)/u.test(message)) return message;
252
+ return 'Local Enigma installer failed.';
253
+ }
254
+
255
+ async function main() {
256
+ const args = parseInstallerArgs();
257
+ if (args.help) {
258
+ process.stdout.write(usage());
259
+ return;
260
+ }
261
+ const output = await runInstallEnigmaLocal(args);
262
+ process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
263
+ }
264
+
265
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolvePath(process.argv[1])) {
266
+ main().catch((error) => {
267
+ process.stdout.write(`${JSON.stringify({ schema: INSTALLER_SCHEMA, ok: false, public_safe: true, error: { code: 'LOCAL_INSTALLER_FAILED', message: safeErrorMessage(error) } }, null, 2)}\n`);
268
+ process.exitCode = 1;
269
+ });
270
+ }
@@ -995,7 +995,7 @@ function buildSuiteReport(datasetRows, topK, options) {
995
995
  generated_at: options.generated_at ?? new Date().toISOString(),
996
996
  package: {
997
997
  name: 'enigma-memory',
998
- version: '0.1.12',
998
+ version: '0.1.13',
999
999
  },
1000
1000
  public_safe: true,
1001
1001
  top_k: topK,
@@ -24,6 +24,7 @@ export const DEFAULT_REGISTRY_VERSION = PACKAGE_JSON.version;
24
24
  export const REGISTRY_INSTALL_CHECKS = Object.freeze([
25
25
  Object.freeze({ step: 'check_enigma_help', bin: 'enigma', args: Object.freeze(['--help']) }),
26
26
  Object.freeze({ step: 'check_enigma_doctor', bin: 'enigma', args: Object.freeze(['doctor']) }),
27
+ Object.freeze({ step: 'check_enigma_test_drive_dry_run', bin: 'enigma', args: Object.freeze(['test-drive', '--dry-run']) }),
27
28
  Object.freeze({ step: 'check_enigma_relay_demo', bin: 'enigma-relay', args: Object.freeze(['demo']) }),
28
29
  Object.freeze({ step: 'check_enigma_gateway_demo', bin: 'enigma-gateway', args: Object.freeze(['demo']) }),
29
30
  ]);