enigma-memory 0.1.4 → 0.1.5
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/docs/benchmark-reproducibility.md +122 -26
- package/docs/developer-ecosystem.md +12 -2
- package/docs/memory-benchmarks.md +41 -9
- package/docs/sdk-api.md +1 -1
- package/examples/ci/github-actions.yml +27 -1
- package/package.json +5 -1
- package/packages/mcp-server/src/index.js +1 -1
- package/scripts/build-installer-assets.mjs +1 -1
- package/scripts/download-standard-benchmarks.mjs +399 -0
- package/scripts/run-standard-memory-benchmarks.mjs +1070 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { createWriteStream as defaultCreateWriteStream } from 'node:fs';
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { mkdir as defaultMkdir, writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
7
|
+
|
|
8
|
+
export const STANDARD_BENCHMARK_DATASET_MANIFEST_SCHEMA = 'enigma.standard_benchmark_dataset_manifest.v1';
|
|
9
|
+
export const STANDARD_BENCHMARK_DATASET_PLAN_SCHEMA = 'enigma.standard_benchmark_dataset_download_plan.v1';
|
|
10
|
+
export const DEFAULT_DATASET_DIR = '.enigma/benchmarks/datasets';
|
|
11
|
+
export const DEFAULT_MANIFEST_FILE_NAME = 'standard-benchmark-dataset-manifest.json';
|
|
12
|
+
|
|
13
|
+
export const DATASET_IDS = Object.freeze([
|
|
14
|
+
'locomo',
|
|
15
|
+
'longmemeval-oracle',
|
|
16
|
+
'longmemeval-s',
|
|
17
|
+
'longmemeval-m',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const DATASET_SELECTIONS = Object.freeze([...DATASET_IDS, 'all']);
|
|
21
|
+
|
|
22
|
+
export const STANDARD_BENCHMARK_DATASETS = Object.freeze({
|
|
23
|
+
locomo: Object.freeze({
|
|
24
|
+
id: 'locomo',
|
|
25
|
+
display_name: 'LoCoMo',
|
|
26
|
+
file_name: 'locomo10.json',
|
|
27
|
+
source_url: 'https://raw.githubusercontent.com/snap-research/locomo/main/data/locomo10.json',
|
|
28
|
+
license: 'CC BY-NC 4.0',
|
|
29
|
+
usage_boundaries: Object.freeze([
|
|
30
|
+
'Official LoCoMo data is non-commercial; review the upstream license before use or redistribution.',
|
|
31
|
+
'Use as a long-term conversational-memory benchmark source, not as proof of provider deletion, model forgetting, ROI, savings, compliance, or benchmark leadership.',
|
|
32
|
+
'Public reports must keep raw conversation text out of generated manifests and shared summaries.',
|
|
33
|
+
]),
|
|
34
|
+
}),
|
|
35
|
+
'longmemeval-oracle': Object.freeze({
|
|
36
|
+
id: 'longmemeval-oracle',
|
|
37
|
+
display_name: 'LongMemEval Oracle',
|
|
38
|
+
file_name: 'longmemeval_oracle.json',
|
|
39
|
+
source_url: 'https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned/resolve/main/longmemeval_oracle.json',
|
|
40
|
+
license: 'Review the upstream Hugging Face dataset card and LongMemEval repository terms before use or redistribution.',
|
|
41
|
+
usage_boundaries: Object.freeze([
|
|
42
|
+
'Oracle split includes evidence sessions and is useful for retrieval/proxy controls; it is not a live provider comparison by itself.',
|
|
43
|
+
'LongMemEval covers information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention.',
|
|
44
|
+
'Public reports must keep raw question, answer, and conversation text out of generated manifests and shared summaries.',
|
|
45
|
+
]),
|
|
46
|
+
}),
|
|
47
|
+
'longmemeval-s': Object.freeze({
|
|
48
|
+
id: 'longmemeval-s',
|
|
49
|
+
display_name: 'LongMemEval S cleaned',
|
|
50
|
+
file_name: 'longmemeval_s_cleaned.json',
|
|
51
|
+
source_url: 'https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned/resolve/main/longmemeval_s_cleaned.json',
|
|
52
|
+
license: 'Review the upstream Hugging Face dataset card and LongMemEval repository terms before use or redistribution.',
|
|
53
|
+
usage_boundaries: Object.freeze([
|
|
54
|
+
'Cleaned LongMemEval S is for reproducible benchmark preparation; it is not a live provider comparison by itself.',
|
|
55
|
+
'LongMemEval covers information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention.',
|
|
56
|
+
'Public reports must keep raw question, answer, and conversation text out of generated manifests and shared summaries.',
|
|
57
|
+
]),
|
|
58
|
+
}),
|
|
59
|
+
'longmemeval-m': Object.freeze({
|
|
60
|
+
id: 'longmemeval-m',
|
|
61
|
+
display_name: 'LongMemEval M cleaned',
|
|
62
|
+
file_name: 'longmemeval_m_cleaned.json',
|
|
63
|
+
source_url: 'https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned/resolve/main/longmemeval_m_cleaned.json',
|
|
64
|
+
license: 'Review the upstream Hugging Face dataset card and LongMemEval repository terms before use or redistribution.',
|
|
65
|
+
usage_boundaries: Object.freeze([
|
|
66
|
+
'Cleaned LongMemEval M is large long-memory benchmark data; it is not a live provider comparison by itself.',
|
|
67
|
+
'LongMemEval covers information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention.',
|
|
68
|
+
'Public reports must keep raw question, answer, and conversation text out of generated manifests and shared summaries.',
|
|
69
|
+
]),
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function joinOutputPath(base, fileName) {
|
|
74
|
+
const trimmed = String(base).replace(/[\\/]+$/, '');
|
|
75
|
+
if (!trimmed) {
|
|
76
|
+
return fileName;
|
|
77
|
+
}
|
|
78
|
+
return trimmed.includes('\\') ? join(trimmed, fileName) : `${trimmed}/${fileName}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const DEFAULT_DATASET_OUTPUT_FILES = Object.freeze(
|
|
82
|
+
Object.fromEntries(DATASET_IDS.map((id) => [id, joinOutputPath(DEFAULT_DATASET_DIR, STANDARD_BENCHMARK_DATASETS[id].file_name)])),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
export const STANDARD_BENCHMARK_DATASET_URLS = Object.freeze(
|
|
86
|
+
Object.fromEntries(DATASET_IDS.map((id) => [id, STANDARD_BENCHMARK_DATASETS[id].source_url])),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
export const STANDARD_BENCHMARK_DATASET_FILE_NAMES = Object.freeze(
|
|
90
|
+
Object.fromEntries(DATASET_IDS.map((id) => [id, STANDARD_BENCHMARK_DATASETS[id].file_name])),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
export const LONGMEMEVAL_TASK_CATEGORIES = Object.freeze([
|
|
94
|
+
'information extraction',
|
|
95
|
+
'multi-session reasoning',
|
|
96
|
+
'temporal reasoning',
|
|
97
|
+
'knowledge updates',
|
|
98
|
+
'abstention',
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
function fail(message) {
|
|
102
|
+
throw new Error(message);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function takeValue(argv, index, flag) {
|
|
106
|
+
const value = argv[index + 1];
|
|
107
|
+
if (!value || value.startsWith('--')) {
|
|
108
|
+
fail(`${flag} requires a value`);
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function parseDownloadArgs(argv = process.argv.slice(2)) {
|
|
114
|
+
const options = {
|
|
115
|
+
outDir: DEFAULT_DATASET_DIR,
|
|
116
|
+
dataset: 'all',
|
|
117
|
+
dryRun: true,
|
|
118
|
+
manifestPath: undefined,
|
|
119
|
+
help: false,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
123
|
+
const arg = argv[index];
|
|
124
|
+
if (arg === '--help' || arg === '-h') {
|
|
125
|
+
options.help = true;
|
|
126
|
+
} else if (arg === '--out-dir') {
|
|
127
|
+
options.outDir = takeValue(argv, index, arg);
|
|
128
|
+
index += 1;
|
|
129
|
+
} else if (arg === '--dataset') {
|
|
130
|
+
options.dataset = takeValue(argv, index, arg);
|
|
131
|
+
index += 1;
|
|
132
|
+
} else if (arg === '--dry-run') {
|
|
133
|
+
options.dryRun = true;
|
|
134
|
+
} else if (arg === '--execute') {
|
|
135
|
+
options.dryRun = false;
|
|
136
|
+
} else if (arg === '--manifest') {
|
|
137
|
+
options.manifestPath = takeValue(argv, index, arg);
|
|
138
|
+
index += 1;
|
|
139
|
+
} else {
|
|
140
|
+
fail(`Unknown option: ${arg}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!DATASET_SELECTIONS.includes(options.dataset)) {
|
|
145
|
+
fail(`Unsupported dataset "${options.dataset}". Expected one of: ${DATASET_SELECTIONS.join(', ')}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return options;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function selectedDatasetIds(selection = 'all') {
|
|
152
|
+
if (!DATASET_SELECTIONS.includes(selection)) {
|
|
153
|
+
fail(`Unsupported dataset "${selection}". Expected one of: ${DATASET_SELECTIONS.join(', ')}`);
|
|
154
|
+
}
|
|
155
|
+
return selection === 'all' ? [...DATASET_IDS] : [selection];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function createDatasetDownloadPlan(options = {}) {
|
|
159
|
+
const outDir = options.outDir ?? DEFAULT_DATASET_DIR;
|
|
160
|
+
const dataset = options.dataset ?? 'all';
|
|
161
|
+
const dryRun = options.dryRun ?? true;
|
|
162
|
+
const manifestPath = options.manifestPath ?? joinOutputPath(outDir, DEFAULT_MANIFEST_FILE_NAME);
|
|
163
|
+
const datasetIds = selectedDatasetIds(dataset);
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
schema: STANDARD_BENCHMARK_DATASET_PLAN_SCHEMA,
|
|
167
|
+
public_safe: true,
|
|
168
|
+
dry_run: Boolean(dryRun),
|
|
169
|
+
execute_required_for_download: Boolean(dryRun),
|
|
170
|
+
raw_dataset_content_included: false,
|
|
171
|
+
selected_dataset: dataset,
|
|
172
|
+
output_directory: outDir,
|
|
173
|
+
manifest_path: manifestPath,
|
|
174
|
+
planned_fetches: datasetIds.map((id) => {
|
|
175
|
+
const datasetInfo = STANDARD_BENCHMARK_DATASETS[id];
|
|
176
|
+
return {
|
|
177
|
+
dataset: datasetInfo.id,
|
|
178
|
+
display_name: datasetInfo.display_name,
|
|
179
|
+
source_url: datasetInfo.source_url,
|
|
180
|
+
license: datasetInfo.license,
|
|
181
|
+
usage_boundaries: [...datasetInfo.usage_boundaries],
|
|
182
|
+
file_name: datasetInfo.file_name,
|
|
183
|
+
output_file: joinOutputPath(outDir, datasetInfo.file_name),
|
|
184
|
+
content_included: false,
|
|
185
|
+
};
|
|
186
|
+
}),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function assertFetchResponse(response, datasetId) {
|
|
191
|
+
if (!response || response.ok === false) {
|
|
192
|
+
const status = response?.status ? ` HTTP ${response.status}` : '';
|
|
193
|
+
fail(`Failed to fetch ${datasetId}.${status}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function sha256Hex(buffer) {
|
|
198
|
+
return createHash('sha256').update(buffer).digest('hex');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function responseHasStreamBody(response) {
|
|
202
|
+
return response?.body
|
|
203
|
+
&& (typeof response.body.getReader === 'function' || typeof response.body[Symbol.asyncIterator] === 'function');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function normalizeBodyChunk(chunk, datasetId) {
|
|
207
|
+
if (typeof chunk === 'string') {
|
|
208
|
+
return Buffer.from(chunk, 'utf8');
|
|
209
|
+
}
|
|
210
|
+
if (chunk instanceof ArrayBuffer) {
|
|
211
|
+
return new Uint8Array(chunk);
|
|
212
|
+
}
|
|
213
|
+
if (ArrayBuffer.isView(chunk)) {
|
|
214
|
+
return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
215
|
+
}
|
|
216
|
+
fail(`Fetch response stream for ${datasetId} yielded an unsupported chunk type`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function waitForWritableEvent(writer, eventName) {
|
|
220
|
+
await new Promise((resolveEvent, rejectEvent) => {
|
|
221
|
+
const cleanup = () => {
|
|
222
|
+
writer.off(eventName, onEvent);
|
|
223
|
+
writer.off('error', onError);
|
|
224
|
+
};
|
|
225
|
+
const onEvent = () => {
|
|
226
|
+
cleanup();
|
|
227
|
+
resolveEvent();
|
|
228
|
+
};
|
|
229
|
+
const onError = (error) => {
|
|
230
|
+
cleanup();
|
|
231
|
+
rejectEvent(error);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
writer.once(eventName, onEvent);
|
|
235
|
+
writer.once('error', onError);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function writeStreamChunk(writer, chunk) {
|
|
240
|
+
if (!writer.write(chunk)) {
|
|
241
|
+
await waitForWritableEvent(writer, 'drain');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function* responseBodyChunks(body) {
|
|
246
|
+
if (typeof body.getReader === 'function') {
|
|
247
|
+
const reader = body.getReader();
|
|
248
|
+
try {
|
|
249
|
+
while (true) {
|
|
250
|
+
const { done, value } = await reader.read();
|
|
251
|
+
if (done) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
yield value;
|
|
255
|
+
}
|
|
256
|
+
} finally {
|
|
257
|
+
reader.releaseLock?.();
|
|
258
|
+
}
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
yield* body;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function streamResponseToFile(response, outputFile, datasetId, hooks) {
|
|
266
|
+
const createWriteStreamImpl = hooks.createWriteStream ?? defaultCreateWriteStream;
|
|
267
|
+
const writer = createWriteStreamImpl(outputFile);
|
|
268
|
+
const finished = new Promise((resolveFinished, rejectFinished) => {
|
|
269
|
+
writer.once('finish', resolveFinished);
|
|
270
|
+
writer.once('error', rejectFinished);
|
|
271
|
+
});
|
|
272
|
+
finished.catch(() => {});
|
|
273
|
+
const hash = createHash('sha256');
|
|
274
|
+
let byteSize = 0;
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
for await (const chunk of responseBodyChunks(response.body)) {
|
|
278
|
+
const normalizedChunk = normalizeBodyChunk(chunk, datasetId);
|
|
279
|
+
byteSize += normalizedChunk.byteLength;
|
|
280
|
+
hash.update(normalizedChunk);
|
|
281
|
+
await writeStreamChunk(writer, normalizedChunk);
|
|
282
|
+
}
|
|
283
|
+
writer.end();
|
|
284
|
+
await finished;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
writer.destroy?.(error);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
byteSize,
|
|
292
|
+
sha256: hash.digest('hex'),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function responseToBuffer(response, datasetId) {
|
|
297
|
+
assertFetchResponse(response, datasetId);
|
|
298
|
+
if (typeof response.arrayBuffer === 'function') {
|
|
299
|
+
return Buffer.from(await response.arrayBuffer());
|
|
300
|
+
}
|
|
301
|
+
if (typeof response.text === 'function') {
|
|
302
|
+
return Buffer.from(await response.text(), 'utf8');
|
|
303
|
+
}
|
|
304
|
+
fail(`Fetch response for ${datasetId} does not expose body, arrayBuffer() or text()`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export async function executeDatasetDownloadPlan(plan, hooks = {}) {
|
|
308
|
+
const fetchImpl = hooks.fetch ?? globalThis.fetch;
|
|
309
|
+
if (typeof fetchImpl !== 'function') {
|
|
310
|
+
fail('No fetch implementation is available; use Node 24+ or pass a fetch hook.');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const mkdirImpl = hooks.mkdir ?? defaultMkdir;
|
|
314
|
+
const writeFileImpl = hooks.writeFile ?? defaultWriteFile;
|
|
315
|
+
const now = hooks.now ?? (() => new Date().toISOString());
|
|
316
|
+
const fetchedAt = now();
|
|
317
|
+
const records = [];
|
|
318
|
+
|
|
319
|
+
for (const fetchPlan of plan.planned_fetches) {
|
|
320
|
+
const response = await fetchImpl(fetchPlan.source_url, { redirect: 'follow' });
|
|
321
|
+
assertFetchResponse(response, fetchPlan.dataset);
|
|
322
|
+
await mkdirImpl(dirname(fetchPlan.output_file), { recursive: true });
|
|
323
|
+
|
|
324
|
+
let downloaded;
|
|
325
|
+
if (responseHasStreamBody(response)) {
|
|
326
|
+
downloaded = await streamResponseToFile(response, fetchPlan.output_file, fetchPlan.dataset, hooks);
|
|
327
|
+
} else {
|
|
328
|
+
const bytes = await responseToBuffer(response, fetchPlan.dataset);
|
|
329
|
+
await writeFileImpl(fetchPlan.output_file, bytes);
|
|
330
|
+
downloaded = {
|
|
331
|
+
byteSize: bytes.byteLength,
|
|
332
|
+
sha256: sha256Hex(bytes),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
records.push({
|
|
336
|
+
dataset: fetchPlan.dataset,
|
|
337
|
+
display_name: fetchPlan.display_name,
|
|
338
|
+
source_url: fetchPlan.source_url,
|
|
339
|
+
license: fetchPlan.license,
|
|
340
|
+
usage_boundaries: fetchPlan.usage_boundaries,
|
|
341
|
+
file_name: fetchPlan.file_name,
|
|
342
|
+
output_file: fetchPlan.output_file,
|
|
343
|
+
byte_size: downloaded.byteSize,
|
|
344
|
+
sha256: downloaded.sha256,
|
|
345
|
+
fetched_at: fetchedAt,
|
|
346
|
+
content_included: false,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const manifest = {
|
|
351
|
+
schema: STANDARD_BENCHMARK_DATASET_MANIFEST_SCHEMA,
|
|
352
|
+
public_safe: true,
|
|
353
|
+
raw_dataset_content_included: false,
|
|
354
|
+
generated_at: now(),
|
|
355
|
+
output_directory: plan.output_directory,
|
|
356
|
+
datasets: records,
|
|
357
|
+
claim_boundaries: [
|
|
358
|
+
'Manifest records downloaded file sizes, checksums, licenses, and source URLs only; it contains no raw dataset records.',
|
|
359
|
+
'Downloaded datasets support retrieval/evidence-coverage or other reviewed benchmark scoring; they do not create provider, competitor, model-forgetting, deletion, ROI, savings, compliance, or benchmark-leadership claims.',
|
|
360
|
+
'Provider-key LLM answer scoring is out of scope for this downloader and must be added only with reviewed credentials and scorer boundaries.',
|
|
361
|
+
],
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
await mkdirImpl(dirname(plan.manifest_path), { recursive: true });
|
|
365
|
+
await writeFileImpl(plan.manifest_path, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
366
|
+
return manifest;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export async function runDownloadCommand(options = {}, hooks = {}) {
|
|
370
|
+
const plan = createDatasetDownloadPlan(options);
|
|
371
|
+
if (plan.dry_run) {
|
|
372
|
+
return plan;
|
|
373
|
+
}
|
|
374
|
+
return executeDatasetDownloadPlan(plan, hooks);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function usage() {
|
|
378
|
+
return `Usage: node scripts/download-standard-benchmarks.mjs [options]\n\nOptions:\n --out-dir <path> Dataset output directory (default: ${DEFAULT_DATASET_DIR})\n --dataset <name> One of: ${DATASET_SELECTIONS.join(', ')} (default: all)\n --dry-run Print planned public-safe fetches without downloading (default)\n --execute Download selected datasets and write a public-safe manifest\n --manifest <path> Manifest path (default: <out-dir>/${DEFAULT_MANIFEST_FILE_NAME})\n -h, --help Show this help\n`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async function main() {
|
|
382
|
+
const options = parseDownloadArgs();
|
|
383
|
+
if (options.help) {
|
|
384
|
+
process.stdout.write(usage());
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const result = await runDownloadCommand(options);
|
|
388
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const invokedPath = process.argv[1] ? resolve(process.argv[1]) : '';
|
|
392
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
393
|
+
|
|
394
|
+
if (isAbsolute(invokedPath) && invokedPath === modulePath) {
|
|
395
|
+
main().catch((error) => {
|
|
396
|
+
process.stderr.write(`${error.message}\n`);
|
|
397
|
+
process.exitCode = 1;
|
|
398
|
+
});
|
|
399
|
+
}
|