numbl 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/dist-cli/cli.js +921 -730
  2. package/package.json +1 -1
package/dist-cli/cli.js CHANGED
@@ -7,15 +7,17 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/cli.ts
9
9
  import {
10
- readFileSync as readFileSync4,
10
+ readFileSync as readFileSync5,
11
11
  readSync as readSync3,
12
- readdirSync as readdirSync2,
13
- statSync as statSync2,
12
+ readdirSync as readdirSync3,
13
+ statSync as statSync3,
14
14
  existsSync as existsSync2,
15
15
  writeFileSync as writeFileSync3,
16
- appendFileSync as appendFileSync2
16
+ appendFileSync as appendFileSync2,
17
+ mkdirSync as mkdirSync2
17
18
  } from "fs";
18
- import { delimiter, dirname as dirname2, join as join4, relative, resolve as resolve2 } from "path";
19
+ import { delimiter, dirname as dirname2, join as join5, relative, resolve as resolve2 } from "path";
20
+ import { homedir as homedir3 } from "os";
19
21
  import { fileURLToPath as fileURLToPath2 } from "url";
20
22
  import { createRequire } from "module";
21
23
  import { execSync } from "child_process";
@@ -28720,6 +28722,20 @@ registerIBuiltin({
28720
28722
  apply: () => RTV.char("")
28721
28723
  })
28722
28724
  });
28725
+ registerIBuiltin({
28726
+ name: "isnumbl",
28727
+ resolve: (argTypes) => {
28728
+ if (argTypes.length !== 0) return null;
28729
+ return {
28730
+ outputTypes: [{ kind: "boolean" }],
28731
+ apply: () => true
28732
+ };
28733
+ },
28734
+ jitEmit: (_args, types) => {
28735
+ if (types.length !== 0) return null;
28736
+ return "1";
28737
+ }
28738
+ });
28723
28739
  registerIBuiltin({
28724
28740
  name: "ishold",
28725
28741
  resolve: () => ({
@@ -29031,6 +29047,7 @@ var SPECIAL_BUILTIN_NAMES = [
29031
29047
  "mfilename",
29032
29048
  "addpath",
29033
29049
  "rmpath",
29050
+ "savepath",
29034
29051
  "path",
29035
29052
  "mkdir",
29036
29053
  "websave",
@@ -30041,6 +30058,10 @@ function registerSpecialBuiltins(rt) {
30041
30058
  if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
30042
30059
  return 0;
30043
30060
  });
30061
+ registerSpecial("savepath", () => {
30062
+ rt.output("Warning: savepath is a no-op in numbl\n");
30063
+ return 0;
30064
+ });
30044
30065
  registerSpecial("input", (_nargout, args) => {
30045
30066
  const margs = args.map((a) => ensureRuntimeValue(a));
30046
30067
  const prompt = margs.length >= 1 ? toString(margs[0]) : "";
@@ -35455,18 +35476,57 @@ registerIBuiltin({
35455
35476
  };
35456
35477
  }
35457
35478
  });
35479
+ function str2doubleScalar(s) {
35480
+ s = s.trim();
35481
+ if (s === "") return NaN;
35482
+ s = s.replace(/,/g, "");
35483
+ const complexFull = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*([+-]\s*(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*[ij]$/i;
35484
+ const mFull = complexFull.exec(s);
35485
+ if (mFull) {
35486
+ const real = Number(mFull[1]);
35487
+ const imag = Number(mFull[2].replace(/\s/g, ""));
35488
+ if (!isNaN(real) && !isNaN(imag)) return real;
35489
+ }
35490
+ const pureImag = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*[ij]$/i;
35491
+ const mImag = pureImag.exec(s);
35492
+ if (mImag) {
35493
+ }
35494
+ const n = Number(s);
35495
+ return isNaN(n) ? NaN : n;
35496
+ }
35458
35497
  registerIBuiltin({
35459
35498
  name: "str2double",
35460
35499
  resolve: (argTypes) => {
35461
35500
  if (argTypes.length !== 1) return null;
35462
- if (!isTextType(argTypes[0])) return null;
35463
- return {
35464
- outputTypes: [{ kind: "number" }],
35465
- apply: (args) => {
35466
- const s = toString(args[0]).trim();
35467
- return RTV.num(s === "" ? NaN : Number(s));
35468
- }
35469
- };
35501
+ const t = argTypes[0];
35502
+ if (isTextType(t)) {
35503
+ return {
35504
+ outputTypes: [{ kind: "number" }],
35505
+ apply: (args) => RTV.num(str2doubleScalar(toString(args[0])))
35506
+ };
35507
+ }
35508
+ if (t.kind === "cell") {
35509
+ return {
35510
+ outputTypes: [{ kind: "tensor", isComplex: false }],
35511
+ apply: (args) => {
35512
+ const cell = args[0];
35513
+ if (typeof cell !== "object" || cell === null || cell.kind !== "cell")
35514
+ throw new RuntimeError("str2double: expected cell array");
35515
+ const c = cell;
35516
+ const data = new FloatXArray(c.data.length);
35517
+ for (let i = 0; i < c.data.length; i++) {
35518
+ const el = c.data[i];
35519
+ if (isRuntimeString(el) || isRuntimeChar(el)) {
35520
+ data[i] = str2doubleScalar(toString(el));
35521
+ } else {
35522
+ data[i] = NaN;
35523
+ }
35524
+ }
35525
+ return RTV.tensor(data, c.shape.slice());
35526
+ }
35527
+ };
35528
+ }
35529
+ return null;
35470
35530
  }
35471
35531
  });
35472
35532
  registerIBuiltin({
@@ -44569,13 +44629,20 @@ function getSourceLine(getSource, file, line) {
44569
44629
  }
44570
44630
 
44571
44631
  // src/numbl-core/version.ts
44572
- var NUMBL_VERSION = "0.1.0";
44632
+ var NUMBL_VERSION = "0.1.1";
44573
44633
 
44574
44634
  // src/cli-repl.ts
44575
44635
  import { createInterface } from "readline";
44576
- import { readFileSync as readFileSync2, readSync, writeFileSync, appendFileSync } from "fs";
44577
- import { join as join2 } from "path";
44578
- import { homedir } from "os";
44636
+ import {
44637
+ openSync as openSync2,
44638
+ closeSync as closeSync2,
44639
+ readFileSync as readFileSync4,
44640
+ readSync as readSync2,
44641
+ writeFileSync as writeFileSync2,
44642
+ appendFileSync
44643
+ } from "fs";
44644
+ import { join as join4 } from "path";
44645
+ import { homedir as homedir2 } from "os";
44579
44646
 
44580
44647
  // src/numbl-core/jsUserFunctions.ts
44581
44648
  function funcNameFromFile(fileName) {
@@ -50309,681 +50376,239 @@ ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated";
50309
50376
  }
50310
50377
  }
50311
50378
 
50312
- // src/cli-system.ts
50313
- var NodeSystemAdapter = class {
50314
- getEnv(name) {
50315
- return process.env[name];
50379
+ // src/cli-fileio.ts
50380
+ import {
50381
+ openSync,
50382
+ closeSync,
50383
+ readSync,
50384
+ writeSync,
50385
+ readFileSync as readFileSync3,
50386
+ writeFileSync,
50387
+ statSync as statSync2,
50388
+ fstatSync,
50389
+ mkdirSync,
50390
+ unlinkSync,
50391
+ readdirSync as readdirSync2,
50392
+ rmSync,
50393
+ rmdirSync
50394
+ } from "fs";
50395
+ import { inflateRawSync } from "zlib";
50396
+ import { execFileSync } from "child_process";
50397
+ import { homedir, tmpdir } from "os";
50398
+ import { join as join3, resolve, dirname, basename } from "path";
50399
+
50400
+ // src/cli-scan.ts
50401
+ import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
50402
+ import { join as join2 } from "path";
50403
+ function scanMFiles(dirPath, excludeFile) {
50404
+ const files = [];
50405
+ let entries;
50406
+ try {
50407
+ entries = readdirSync(dirPath);
50408
+ } catch {
50409
+ return files;
50316
50410
  }
50317
- getAllEnv() {
50318
- const result = {};
50319
- for (const [k, v] of Object.entries(process.env)) {
50320
- if (v !== void 0) result[k] = v;
50411
+ for (const entry of entries) {
50412
+ const fullPath = join2(dirPath, entry);
50413
+ if (excludeFile && fullPath === excludeFile) {
50414
+ continue;
50415
+ }
50416
+ try {
50417
+ const stat = statSync(fullPath);
50418
+ if (stat.isDirectory()) {
50419
+ if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
50420
+ files.push(...scanMFiles(fullPath, excludeFile));
50421
+ }
50422
+ } else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".js"))) {
50423
+ const source = readFileSync2(fullPath, "utf-8");
50424
+ files.push({
50425
+ name: fullPath,
50426
+ source
50427
+ });
50428
+ } else if (stat.isFile() && entry.endsWith(".wasm")) {
50429
+ const data = readFileSync2(fullPath);
50430
+ files.push({
50431
+ name: fullPath,
50432
+ source: "",
50433
+ data: new Uint8Array(data)
50434
+ });
50435
+ }
50436
+ } catch (err) {
50437
+ console.warn(
50438
+ `Warning: could not read ${fullPath}: ${err instanceof Error ? err.message : String(err)}`
50439
+ );
50321
50440
  }
50322
- return result;
50323
- }
50324
- setEnv(name, value) {
50325
- process.env[name] = value;
50326
- }
50327
- cwd() {
50328
- return process.cwd();
50329
- }
50330
- chdir(dir) {
50331
- process.chdir(dir);
50332
- }
50333
- platform() {
50334
- return process.platform;
50335
- }
50336
- arch() {
50337
- return process.arch;
50338
50441
  }
50339
- };
50442
+ return files;
50443
+ }
50340
50444
 
50341
- // src/cli-repl.ts
50342
- var HISTORY_FILE = join2(homedir(), ".numbl_history");
50343
- var HISTORY_MAX = 1e3;
50344
- function loadHistory() {
50345
- try {
50346
- const content = readFileSync2(HISTORY_FILE, "utf8");
50347
- return content.split("\n").filter((line) => line.length > 0).map((line) => line.replace(/\\n/g, "\n").replace(/\\\\/g, "\\"));
50348
- } catch {
50349
- return [];
50445
+ // src/cli-fileio.ts
50446
+ function expandTilde(filepath) {
50447
+ if (filepath.startsWith("~/")) {
50448
+ return join3(homedir(), filepath.slice(2));
50350
50449
  }
50450
+ return filepath;
50351
50451
  }
50352
- function saveHistoryEntry(entry, hist) {
50353
- try {
50354
- if (hist.length <= HISTORY_MAX) {
50355
- const encoded = entry.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
50356
- appendFileSync(HISTORY_FILE, encoded + "\n", "utf8");
50357
- } else {
50358
- const trimmed = hist.slice(-HISTORY_MAX);
50359
- const content = trimmed.map((e) => e.replace(/\\/g, "\\\\").replace(/\n/g, "\\n")).join("\n") + "\n";
50360
- writeFileSync(HISTORY_FILE, content, "utf8");
50361
- }
50362
- } catch {
50452
+ function permissionToFlags(permission) {
50453
+ switch (permission) {
50454
+ case "r":
50455
+ return "r";
50456
+ case "w":
50457
+ return "w";
50458
+ case "a":
50459
+ return "a";
50460
+ case "r+":
50461
+ return "r+";
50462
+ case "w+":
50463
+ return "w+";
50464
+ case "a+":
50465
+ return "a+";
50466
+ default:
50467
+ return permission;
50363
50468
  }
50364
50469
  }
50365
- async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nativeBridge2, optimization) {
50366
- let variableValues = {};
50367
- let holdState = false;
50368
- const workspaceFiles = [...initialWorkspaceFiles];
50369
- const searchPaths = [...initialSearchPaths ?? []];
50370
- const system = new NodeSystemAdapter();
50371
- const onInput = (prompt) => {
50372
- process.stdout.write(prompt);
50373
- const buf2 = Buffer.alloc(1);
50374
- let line = "";
50375
- while (true) {
50376
- const bytesRead = readSync(0, buf2, 0, 1, null);
50377
- if (bytesRead === 0) break;
50378
- const ch = buf2.toString("utf8");
50379
- if (ch === "\n") break;
50380
- if (ch === "\r") continue;
50381
- line += ch;
50470
+ var READ_CHUNK_SIZE = 8192;
50471
+ var NodeFileIOAdapter = class {
50472
+ nextFid = 3;
50473
+ // 0=stdin, 1=stdout, 2=stderr reserved
50474
+ openFiles = /* @__PURE__ */ new Map();
50475
+ fopen(filename, permission) {
50476
+ try {
50477
+ const flags = permissionToFlags(permission);
50478
+ const fd = openSync(expandTilde(filename), flags);
50479
+ const fid = this.nextFid++;
50480
+ this.openFiles.set(fid, {
50481
+ fd,
50482
+ permission,
50483
+ lastError: "",
50484
+ buffer: "",
50485
+ eof: false,
50486
+ pos: 0
50487
+ });
50488
+ return fid;
50489
+ } catch (e) {
50490
+ return -1;
50382
50491
  }
50383
- return line;
50384
- };
50385
- console.log(
50386
- "numbl REPL \u2014 type 'exit' or press Ctrl+D to quit, Alt+Enter for new line"
50387
- );
50388
- if (!process.stdin.isTTY) {
50389
- const rl = createInterface({
50390
- input: process.stdin,
50391
- output: process.stdout,
50392
- prompt: ">> "
50393
- });
50394
- rl.prompt();
50395
- for await (const line of rl) {
50396
- const trimmed = line.trim();
50397
- if (trimmed === "exit" || trimmed === "quit") break;
50398
- if (trimmed === "") {
50399
- rl.prompt();
50400
- continue;
50401
- }
50402
- try {
50403
- const result = executeCode(
50404
- trimmed,
50405
- {
50406
- displayResults: true,
50407
- onOutput: (text) => process.stdout.write(text),
50408
- onDrawnow,
50409
- onInput,
50410
- initialVariableValues: variableValues,
50411
- initialHoldState: holdState,
50412
- optimization,
50413
- system
50414
- },
50415
- workspaceFiles,
50416
- "repl",
50417
- searchPaths,
50418
- nativeBridge2
50419
- );
50420
- variableValues = result.variableValues;
50421
- holdState = result.holdState;
50422
- if (result.searchPaths) {
50423
- searchPaths.length = 0;
50424
- searchPaths.push(...result.searchPaths);
50425
- workspaceFiles.length = 0;
50426
- workspaceFiles.push(...result.workspaceFiles ?? []);
50427
- }
50428
- if (result.plotInstructions.length > 0 && onDrawnow) {
50429
- onDrawnow(result.plotInstructions);
50492
+ }
50493
+ fclose(fidOrAll) {
50494
+ if (fidOrAll === "all") {
50495
+ for (const [, entry2] of this.openFiles) {
50496
+ try {
50497
+ closeSync(entry2.fd);
50498
+ } catch {
50430
50499
  }
50431
- } catch (error) {
50432
- const diags = diagnoseErrors(error, trimmed, "repl", workspaceFiles);
50433
- console.error(formatDiagnostics(diags));
50434
50500
  }
50435
- rl.prompt();
50501
+ this.openFiles.clear();
50502
+ return 0;
50436
50503
  }
50437
- console.log("");
50438
- process.exit(0);
50439
- }
50440
- const stdin = process.stdin;
50441
- const stdout = process.stdout;
50442
- stdin.setRawMode(true);
50443
- stdin.resume();
50444
- stdout.write("\x1B[?2004h");
50445
- const PS1 = ">> ";
50446
- const PS2 = " ";
50447
- let buf = [""];
50448
- let row = 0;
50449
- let col = 0;
50450
- let sRow = 0;
50451
- const hist = loadHistory();
50452
- let hIdx = -1;
50453
- let hStash = "";
50454
- let hPrefix = "";
50455
- let pasting = false;
50456
- let pasteBuf = [];
50457
- let busy = false;
50458
- function display() {
50459
- if (sRow > 0) stdout.write(`\x1B[${sRow}A`);
50460
- stdout.write("\r\x1B[J");
50461
- for (let i = 0; i < buf.length; i++) {
50462
- stdout.write((i === 0 ? PS1 : PS2) + buf[i]);
50463
- if (i < buf.length - 1) stdout.write("\r\n");
50504
+ const entry = this.openFiles.get(fidOrAll);
50505
+ if (!entry) return -1;
50506
+ try {
50507
+ closeSync(entry.fd);
50508
+ } catch {
50509
+ return -1;
50464
50510
  }
50465
- const fromEnd = buf.length - 1 - row;
50466
- if (fromEnd > 0) stdout.write(`\x1B[${fromEnd}A`);
50467
- const pLen = row === 0 ? PS1.length : PS2.length;
50468
- stdout.write(`\x1B[${pLen + col + 1}G`);
50469
- sRow = row;
50511
+ this.openFiles.delete(fidOrAll);
50512
+ return 0;
50470
50513
  }
50471
- function resetInput() {
50472
- buf = [""];
50473
- row = col = sRow = 0;
50474
- hIdx = -1;
50475
- hStash = "";
50476
- hPrefix = "";
50477
- stdout.write(PS1);
50514
+ fgetl(fid) {
50515
+ const entry = this.getEntry(fid);
50516
+ if (!entry) return -1;
50517
+ return this.readLine(entry, false);
50478
50518
  }
50479
- function cleanup() {
50480
- stdout.write("\x1B[?2004l");
50481
- stdin.setRawMode(false);
50482
- stdin.pause();
50519
+ fgets(fid) {
50520
+ const entry = this.getEntry(fid);
50521
+ if (!entry) return -1;
50522
+ return this.readLine(entry, true);
50483
50523
  }
50484
- function insertNewline() {
50485
- const after = buf[row].slice(col);
50486
- buf[row] = buf[row].slice(0, col);
50487
- buf.splice(row + 1, 0, after);
50488
- row++;
50489
- col = 0;
50490
- display();
50524
+ fileread(filename) {
50525
+ return readFileSync3(expandTilde(filename), "utf-8");
50491
50526
  }
50492
- function exec2() {
50493
- const code = buf.join("\n").trim();
50494
- const below = buf.length - 1 - sRow;
50495
- if (below > 0) stdout.write(`\x1B[${below}B`);
50496
- stdout.write("\r\n");
50497
- sRow = 0;
50498
- if (!code) {
50499
- resetInput();
50500
- return;
50527
+ feof(fid) {
50528
+ const entry = this.getEntry(fid);
50529
+ if (!entry) return 1;
50530
+ if (entry.buffer.length > 0) return 0;
50531
+ if (entry.eof) return 1;
50532
+ const buf = Buffer.alloc(1);
50533
+ try {
50534
+ const bytesRead = readSync(entry.fd, buf, 0, 1, null);
50535
+ if (bytesRead === 0) {
50536
+ entry.eof = true;
50537
+ return 1;
50538
+ }
50539
+ entry.buffer = buf.toString("utf-8", 0, bytesRead);
50540
+ return 0;
50541
+ } catch {
50542
+ entry.eof = true;
50543
+ return 1;
50501
50544
  }
50502
- if (code === "exit" || code === "quit") {
50503
- cleanup();
50504
- console.log("");
50505
- process.exit(0);
50545
+ }
50546
+ ferror(fid) {
50547
+ const entry = this.getEntry(fid);
50548
+ if (!entry) return "Invalid file identifier";
50549
+ return entry.lastError;
50550
+ }
50551
+ fwrite(fid, text) {
50552
+ const entry = this.getEntry(fid);
50553
+ if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50554
+ try {
50555
+ writeSync(entry.fd, text);
50556
+ entry.lastError = "";
50557
+ } catch (e) {
50558
+ entry.lastError = e instanceof Error ? e.message : String(e);
50559
+ throw e;
50506
50560
  }
50507
- const entry = buf.join("\n");
50508
- hist.push(entry);
50509
- saveHistoryEntry(entry, hist);
50510
- hIdx = -1;
50511
- busy = true;
50512
- stdin.setRawMode(false);
50561
+ }
50562
+ freadBytes(fid, count) {
50563
+ const entry = this.getEntry(fid);
50564
+ if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50565
+ if (entry.buffer.length > 0) {
50566
+ entry.buffer = "";
50567
+ }
50568
+ const buf = Buffer.alloc(count);
50513
50569
  try {
50514
- const result = executeCode(
50515
- code,
50516
- {
50517
- displayResults: true,
50518
- onOutput: (text) => stdout.write(text),
50519
- onDrawnow,
50520
- onInput,
50521
- initialVariableValues: variableValues,
50522
- initialHoldState: holdState,
50523
- optimization
50524
- },
50525
- workspaceFiles,
50526
- "repl",
50527
- searchPaths,
50528
- nativeBridge2
50529
- );
50530
- variableValues = result.variableValues;
50531
- holdState = result.holdState;
50532
- if (result.searchPaths) {
50533
- searchPaths.length = 0;
50534
- searchPaths.push(...result.searchPaths);
50535
- workspaceFiles.length = 0;
50536
- workspaceFiles.push(...result.workspaceFiles ?? []);
50537
- }
50538
- if (result.plotInstructions.length > 0 && onDrawnow) {
50539
- onDrawnow(result.plotInstructions);
50540
- }
50541
- } catch (error) {
50542
- const diags = diagnoseErrors(error, code, "repl", workspaceFiles);
50543
- console.error(formatDiagnostics(diags));
50570
+ const bytesRead = readSync(entry.fd, buf, 0, count, entry.pos);
50571
+ entry.pos += bytesRead;
50572
+ if (bytesRead === 0) entry.eof = true;
50573
+ else if (bytesRead < count) entry.eof = true;
50574
+ entry.lastError = "";
50575
+ return new Uint8Array(buf.buffer, buf.byteOffset, bytesRead);
50576
+ } catch (e) {
50577
+ entry.lastError = e instanceof Error ? e.message : String(e);
50578
+ entry.eof = true;
50579
+ return new Uint8Array(0);
50544
50580
  }
50545
- stdin.setRawMode(true);
50546
- busy = false;
50547
- resetInput();
50548
50581
  }
50549
- function handlePaste(text) {
50550
- text = text.replace(/(\r\n|\r|\n)$/, "");
50551
- const lines = text.split(/\r\n|\r|\n/);
50552
- if (lines.length === 1) {
50553
- buf[row] = buf[row].slice(0, col) + lines[0] + buf[row].slice(col);
50554
- col += lines[0].length;
50555
- } else {
50556
- const after = buf[row].slice(col);
50557
- buf[row] = buf[row].slice(0, col) + lines[0];
50558
- for (let j = 1; j < lines.length; j++) {
50559
- buf.splice(row + j, 0, lines[j]);
50560
- }
50561
- row += lines.length - 1;
50562
- col = buf[row].length;
50563
- buf[row] += after;
50582
+ fwriteBytes(fid, data) {
50583
+ const entry = this.getEntry(fid);
50584
+ if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50585
+ try {
50586
+ const written = writeSync(entry.fd, data, 0, data.length, entry.pos);
50587
+ entry.pos += written;
50588
+ entry.lastError = "";
50589
+ return written;
50590
+ } catch (e) {
50591
+ entry.lastError = e instanceof Error ? e.message : String(e);
50592
+ throw e;
50564
50593
  }
50565
- display();
50566
50594
  }
50567
- function navHistory(dir) {
50568
- if (hist.length === 0) return;
50569
- if (hIdx === -1 && dir > 0) return;
50570
- if (hIdx === -1) {
50571
- hStash = buf.join("\n");
50572
- hPrefix = hStash;
50573
- if (hPrefix.length > 0) {
50574
- for (let k = hist.length - 1; k >= 0; k--) {
50575
- if (hist[k].startsWith(hPrefix)) {
50576
- hIdx = k;
50577
- break;
50578
- }
50579
- }
50580
- if (hIdx === -1) return;
50581
- } else {
50582
- hIdx = hist.length - 1;
50583
- }
50584
- } else {
50585
- let found = false;
50586
- if (dir < 0) {
50587
- for (let k = hIdx - 1; k >= 0; k--) {
50588
- if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
50589
- hIdx = k;
50590
- found = true;
50591
- break;
50592
- }
50593
- }
50594
- if (!found) return;
50595
+ fseek(fid, offset, origin) {
50596
+ const entry = this.getEntry(fid);
50597
+ if (!entry) return -1;
50598
+ entry.buffer = "";
50599
+ entry.eof = false;
50600
+ try {
50601
+ if (origin === -1) {
50602
+ entry.pos = offset;
50603
+ } else if (origin === 0) {
50604
+ entry.pos += offset;
50595
50605
  } else {
50596
- for (let k = hIdx + 1; k < hist.length; k++) {
50597
- if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
50598
- hIdx = k;
50599
- found = true;
50600
- break;
50601
- }
50602
- }
50603
- if (!found) {
50604
- buf = hStash.split("\n");
50605
- hIdx = -1;
50606
- row = buf.length - 1;
50607
- col = buf[row].length;
50608
- display();
50609
- return;
50610
- }
50606
+ const size = fstatSync(entry.fd).size;
50607
+ entry.pos = size + offset;
50611
50608
  }
50612
- }
50613
- buf = hist[hIdx].split("\n");
50614
- row = buf.length - 1;
50615
- col = buf[row].length;
50616
- display();
50617
- }
50618
- function handleCSI(seq) {
50619
- switch (seq) {
50620
- case "A":
50621
- if (buf.length > 1 && row > 0) {
50622
- row--;
50623
- col = Math.min(col, buf[row].length);
50624
- display();
50625
- } else {
50626
- navHistory(-1);
50627
- }
50628
- break;
50629
- case "B":
50630
- if (buf.length > 1 && row < buf.length - 1) {
50631
- row++;
50632
- col = Math.min(col, buf[row].length);
50633
- display();
50634
- } else {
50635
- navHistory(1);
50636
- }
50637
- break;
50638
- case "C":
50639
- if (col < buf[row].length) {
50640
- col++;
50641
- display();
50642
- } else if (row < buf.length - 1) {
50643
- row++;
50644
- col = 0;
50645
- display();
50646
- }
50647
- break;
50648
- case "D":
50649
- if (col > 0) {
50650
- col--;
50651
- display();
50652
- } else if (row > 0) {
50653
- row--;
50654
- col = buf[row].length;
50655
- display();
50656
- }
50657
- break;
50658
- case "H":
50659
- // Home
50660
- case "1~":
50661
- col = 0;
50662
- display();
50663
- break;
50664
- case "F":
50665
- // End
50666
- case "4~":
50667
- col = buf[row].length;
50668
- display();
50669
- break;
50670
- case "3~":
50671
- if (col < buf[row].length) {
50672
- buf[row] = buf[row].slice(0, col) + buf[row].slice(col + 1);
50673
- display();
50674
- } else if (row < buf.length - 1) {
50675
- buf[row] += buf[row + 1];
50676
- buf.splice(row + 1, 1);
50677
- display();
50678
- }
50679
- break;
50680
- case "13;2u":
50681
- insertNewline();
50682
- break;
50683
- }
50684
- }
50685
- resetInput();
50686
- return new Promise((resolve3) => {
50687
- stdin.on("data", (chunk) => {
50688
- if (busy) return;
50689
- const data = chunk.toString("utf8");
50690
- let i = 0;
50691
- while (i < data.length) {
50692
- if (busy) return;
50693
- if (data.startsWith("\x1B[200~", i)) {
50694
- pasting = true;
50695
- pasteBuf = [];
50696
- i += 6;
50697
- continue;
50698
- }
50699
- if (data.startsWith("\x1B[201~", i)) {
50700
- pasting = false;
50701
- handlePaste(pasteBuf.join(""));
50702
- i += 6;
50703
- continue;
50704
- }
50705
- if (pasting) {
50706
- const end = data.indexOf("\x1B[201~", i);
50707
- if (end >= 0) {
50708
- pasteBuf.push(data.slice(i, end));
50709
- pasting = false;
50710
- handlePaste(pasteBuf.join(""));
50711
- i = end + 6;
50712
- } else {
50713
- pasteBuf.push(data.slice(i));
50714
- i = data.length;
50715
- }
50716
- continue;
50717
- }
50718
- if (data[i] === "\x1B" && i + 1 < data.length && (data[i + 1] === "\r" || data[i + 1] === "\n")) {
50719
- insertNewline();
50720
- i += 2;
50721
- continue;
50722
- }
50723
- if (data.startsWith("\x1B[", i)) {
50724
- let j = i + 2;
50725
- while (j < data.length && (data.charCodeAt(j) < 64 || data.charCodeAt(j) > 126))
50726
- j++;
50727
- if (j >= data.length) {
50728
- i = data.length;
50729
- continue;
50730
- }
50731
- handleCSI(data.slice(i + 2, j + 1));
50732
- i = j + 1;
50733
- continue;
50734
- }
50735
- if (data[i] === "\x1B") {
50736
- i++;
50737
- continue;
50738
- }
50739
- const code = data.charCodeAt(i);
50740
- i++;
50741
- if (code === 13 || code === 10) {
50742
- try {
50743
- exec2();
50744
- } catch (err) {
50745
- console.error("Unexpected REPL error:", err);
50746
- busy = false;
50747
- resetInput();
50748
- }
50749
- } else if (code === 127 || code === 8) {
50750
- if (col > 0) {
50751
- buf[row] = buf[row].slice(0, col - 1) + buf[row].slice(col);
50752
- col--;
50753
- display();
50754
- } else if (row > 0) {
50755
- col = buf[row - 1].length;
50756
- buf[row - 1] += buf[row];
50757
- buf.splice(row, 1);
50758
- row--;
50759
- display();
50760
- }
50761
- } else if (code === 1) {
50762
- col = 0;
50763
- display();
50764
- } else if (code === 5) {
50765
- col = buf[row].length;
50766
- display();
50767
- } else if (code === 11) {
50768
- buf[row] = buf[row].slice(0, col);
50769
- display();
50770
- } else if (code === 21) {
50771
- buf[row] = buf[row].slice(col);
50772
- col = 0;
50773
- display();
50774
- } else if (code === 3) {
50775
- const below = buf.length - 1 - sRow;
50776
- if (below > 0) stdout.write(`\x1B[${below}B`);
50777
- stdout.write("\r\n^C\r\n");
50778
- sRow = 0;
50779
- resetInput();
50780
- } else if (code === 4) {
50781
- if (buf.length === 1 && buf[0] === "") {
50782
- stdout.write("\r\n");
50783
- cleanup();
50784
- resolve3();
50785
- return;
50786
- }
50787
- } else if (code === 12) {
50788
- stdout.write("\x1B[2J\x1B[H");
50789
- sRow = 0;
50790
- display();
50791
- } else if (code >= 32) {
50792
- buf[row] = buf[row].slice(0, col) + data[i - 1] + buf[row].slice(col);
50793
- col++;
50794
- display();
50795
- }
50796
- }
50797
- });
50798
- });
50799
- }
50800
-
50801
- // src/cli-fileio.ts
50802
- import {
50803
- openSync,
50804
- closeSync,
50805
- readSync as readSync2,
50806
- writeSync,
50807
- readFileSync as readFileSync3,
50808
- writeFileSync as writeFileSync2,
50809
- statSync,
50810
- fstatSync,
50811
- mkdirSync,
50812
- unlinkSync,
50813
- readdirSync,
50814
- rmSync,
50815
- rmdirSync
50816
- } from "fs";
50817
- import { inflateRawSync } from "zlib";
50818
- import { execFileSync } from "child_process";
50819
- import { homedir as homedir2, tmpdir } from "os";
50820
- import { join as join3, resolve, dirname, basename } from "path";
50821
- function expandTilde(filepath) {
50822
- if (filepath.startsWith("~/")) {
50823
- return join3(homedir2(), filepath.slice(2));
50824
- }
50825
- return filepath;
50826
- }
50827
- function permissionToFlags(permission) {
50828
- switch (permission) {
50829
- case "r":
50830
- return "r";
50831
- case "w":
50832
- return "w";
50833
- case "a":
50834
- return "a";
50835
- case "r+":
50836
- return "r+";
50837
- case "w+":
50838
- return "w+";
50839
- case "a+":
50840
- return "a+";
50841
- default:
50842
- return permission;
50843
- }
50844
- }
50845
- var READ_CHUNK_SIZE = 8192;
50846
- var NodeFileIOAdapter = class {
50847
- nextFid = 3;
50848
- // 0=stdin, 1=stdout, 2=stderr reserved
50849
- openFiles = /* @__PURE__ */ new Map();
50850
- fopen(filename, permission) {
50851
- try {
50852
- const flags = permissionToFlags(permission);
50853
- const fd = openSync(expandTilde(filename), flags);
50854
- const fid = this.nextFid++;
50855
- this.openFiles.set(fid, {
50856
- fd,
50857
- permission,
50858
- lastError: "",
50859
- buffer: "",
50860
- eof: false,
50861
- pos: 0
50862
- });
50863
- return fid;
50864
- } catch (e) {
50865
- return -1;
50866
- }
50867
- }
50868
- fclose(fidOrAll) {
50869
- if (fidOrAll === "all") {
50870
- for (const [, entry2] of this.openFiles) {
50871
- try {
50872
- closeSync(entry2.fd);
50873
- } catch {
50874
- }
50875
- }
50876
- this.openFiles.clear();
50877
- return 0;
50878
- }
50879
- const entry = this.openFiles.get(fidOrAll);
50880
- if (!entry) return -1;
50881
- try {
50882
- closeSync(entry.fd);
50883
- } catch {
50884
- return -1;
50885
- }
50886
- this.openFiles.delete(fidOrAll);
50887
- return 0;
50888
- }
50889
- fgetl(fid) {
50890
- const entry = this.getEntry(fid);
50891
- if (!entry) return -1;
50892
- return this.readLine(entry, false);
50893
- }
50894
- fgets(fid) {
50895
- const entry = this.getEntry(fid);
50896
- if (!entry) return -1;
50897
- return this.readLine(entry, true);
50898
- }
50899
- fileread(filename) {
50900
- return readFileSync3(expandTilde(filename), "utf-8");
50901
- }
50902
- feof(fid) {
50903
- const entry = this.getEntry(fid);
50904
- if (!entry) return 1;
50905
- if (entry.buffer.length > 0) return 0;
50906
- if (entry.eof) return 1;
50907
- const buf = Buffer.alloc(1);
50908
- try {
50909
- const bytesRead = readSync2(entry.fd, buf, 0, 1, null);
50910
- if (bytesRead === 0) {
50911
- entry.eof = true;
50912
- return 1;
50913
- }
50914
- entry.buffer = buf.toString("utf-8", 0, bytesRead);
50915
- return 0;
50916
- } catch {
50917
- entry.eof = true;
50918
- return 1;
50919
- }
50920
- }
50921
- ferror(fid) {
50922
- const entry = this.getEntry(fid);
50923
- if (!entry) return "Invalid file identifier";
50924
- return entry.lastError;
50925
- }
50926
- fwrite(fid, text) {
50927
- const entry = this.getEntry(fid);
50928
- if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50929
- try {
50930
- writeSync(entry.fd, text);
50931
- entry.lastError = "";
50932
- } catch (e) {
50933
- entry.lastError = e instanceof Error ? e.message : String(e);
50934
- throw e;
50935
- }
50936
- }
50937
- freadBytes(fid, count) {
50938
- const entry = this.getEntry(fid);
50939
- if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50940
- if (entry.buffer.length > 0) {
50941
- entry.buffer = "";
50942
- }
50943
- const buf = Buffer.alloc(count);
50944
- try {
50945
- const bytesRead = readSync2(entry.fd, buf, 0, count, entry.pos);
50946
- entry.pos += bytesRead;
50947
- if (bytesRead === 0) entry.eof = true;
50948
- else if (bytesRead < count) entry.eof = true;
50949
- entry.lastError = "";
50950
- return new Uint8Array(buf.buffer, buf.byteOffset, bytesRead);
50951
- } catch (e) {
50952
- entry.lastError = e instanceof Error ? e.message : String(e);
50953
- entry.eof = true;
50954
- return new Uint8Array(0);
50955
- }
50956
- }
50957
- fwriteBytes(fid, data) {
50958
- const entry = this.getEntry(fid);
50959
- if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
50960
- try {
50961
- const written = writeSync(entry.fd, data, 0, data.length, entry.pos);
50962
- entry.pos += written;
50963
- entry.lastError = "";
50964
- return written;
50965
- } catch (e) {
50966
- entry.lastError = e instanceof Error ? e.message : String(e);
50967
- throw e;
50968
- }
50969
- }
50970
- fseek(fid, offset, origin) {
50971
- const entry = this.getEntry(fid);
50972
- if (!entry) return -1;
50973
- entry.buffer = "";
50974
- entry.eof = false;
50975
- try {
50976
- if (origin === -1) {
50977
- entry.pos = offset;
50978
- } else if (origin === 0) {
50979
- entry.pos += offset;
50980
- } else {
50981
- const size = fstatSync(entry.fd).size;
50982
- entry.pos = size + offset;
50983
- }
50984
- return 0;
50985
- } catch {
50986
- return -1;
50609
+ return 0;
50610
+ } catch {
50611
+ return -1;
50987
50612
  }
50988
50613
  }
50989
50614
  ftell(fid) {
@@ -50999,7 +50624,7 @@ var NodeFileIOAdapter = class {
50999
50624
  }
51000
50625
  existsPath(path) {
51001
50626
  try {
51002
- const s = statSync(expandTilde(path));
50627
+ const s = statSync2(expandTilde(path));
51003
50628
  return s.isDirectory() ? "dir" : "file";
51004
50629
  } catch {
51005
50630
  return null;
@@ -51077,7 +50702,7 @@ var NodeFileIOAdapter = class {
51077
50702
  );
51078
50703
  let entries;
51079
50704
  try {
51080
- entries = readdirSync(dir);
50705
+ entries = readdirSync2(dir);
51081
50706
  } catch {
51082
50707
  return;
51083
50708
  }
@@ -51150,7 +50775,7 @@ var NodeFileIOAdapter = class {
51150
50775
  }
51151
50776
  const outPath = join3(dest, entryName);
51152
50777
  mkdirSync(dirname(outPath), { recursive: true });
51153
- writeFileSync2(outPath, fileData);
50778
+ writeFileSync(outPath, fileData);
51154
50779
  extracted.push(outPath);
51155
50780
  }
51156
50781
  return extracted;
@@ -51164,7 +50789,7 @@ var NodeFileIOAdapter = class {
51164
50789
  return this.listDirGlob(p2);
51165
50790
  }
51166
50791
  try {
51167
- const s = statSync(p2);
50792
+ const s = statSync2(p2);
51168
50793
  if (s.isDirectory()) {
51169
50794
  const absDir = resolve(p2);
51170
50795
  const results = [];
@@ -51176,7 +50801,7 @@ var NodeFileIOAdapter = class {
51176
50801
  mtimeMs: s.mtimeMs
51177
50802
  });
51178
50803
  try {
51179
- const parentStat = statSync(resolve(absDir, ".."));
50804
+ const parentStat = statSync2(resolve(absDir, ".."));
51180
50805
  results.push({
51181
50806
  name: "..",
51182
50807
  folder: absDir,
@@ -51193,10 +50818,10 @@ var NodeFileIOAdapter = class {
51193
50818
  mtimeMs: 0
51194
50819
  });
51195
50820
  }
51196
- const entries = readdirSync(absDir);
50821
+ const entries = readdirSync2(absDir);
51197
50822
  for (const entry of entries) {
51198
50823
  try {
51199
- const es = statSync(join3(absDir, entry));
50824
+ const es = statSync2(join3(absDir, entry));
51200
50825
  results.push({
51201
50826
  name: entry,
51202
50827
  folder: absDir,
@@ -51238,14 +50863,14 @@ var NodeFileIOAdapter = class {
51238
50863
  const results = [];
51239
50864
  let entries;
51240
50865
  try {
51241
- entries = readdirSync(absDir);
50866
+ entries = readdirSync2(absDir);
51242
50867
  } catch {
51243
50868
  return [];
51244
50869
  }
51245
50870
  for (const entry of entries) {
51246
50871
  if (re2.test(entry)) {
51247
50872
  try {
51248
- const es = statSync(join3(absDir, entry));
50873
+ const es = statSync2(join3(absDir, entry));
51249
50874
  results.push({
51250
50875
  name: entry,
51251
50876
  folder: absDir,
@@ -51270,7 +50895,7 @@ var NodeFileIOAdapter = class {
51270
50895
  const results = [];
51271
50896
  const walkDir = (dir) => {
51272
50897
  try {
51273
- const ds = statSync(dir);
50898
+ const ds = statSync2(dir);
51274
50899
  results.push({
51275
50900
  name: ".",
51276
50901
  folder: dir,
@@ -51288,7 +50913,7 @@ var NodeFileIOAdapter = class {
51288
50913
  });
51289
50914
  }
51290
50915
  try {
51291
- const ps = statSync(resolve(dir, ".."));
50916
+ const ps = statSync2(resolve(dir, ".."));
51292
50917
  results.push({
51293
50918
  name: "..",
51294
50919
  folder: dir,
@@ -51307,14 +50932,14 @@ var NodeFileIOAdapter = class {
51307
50932
  }
51308
50933
  let entries;
51309
50934
  try {
51310
- entries = readdirSync(dir);
50935
+ entries = readdirSync2(dir);
51311
50936
  } catch {
51312
50937
  return;
51313
50938
  }
51314
50939
  const subdirs = [];
51315
50940
  for (const entry of entries) {
51316
50941
  try {
51317
- const es = statSync(join3(dir, entry));
50942
+ const es = statSync2(join3(dir, entry));
51318
50943
  results.push({
51319
50944
  name: entry,
51320
50945
  folder: dir,
@@ -51347,7 +50972,7 @@ var NodeFileIOAdapter = class {
51347
50972
  const buf = Buffer.alloc(READ_CHUNK_SIZE);
51348
50973
  let bytesRead;
51349
50974
  try {
51350
- bytesRead = readSync2(entry.fd, buf, 0, READ_CHUNK_SIZE, null);
50975
+ bytesRead = readSync(entry.fd, buf, 0, READ_CHUNK_SIZE, null);
51351
50976
  entry.lastError = "";
51352
50977
  } catch (e) {
51353
50978
  entry.lastError = e instanceof Error ? e.message : String(e);
@@ -51375,11 +51000,573 @@ var NodeFileIOAdapter = class {
51375
51000
  }
51376
51001
  };
51377
51002
 
51003
+ // src/cli-system.ts
51004
+ var NodeSystemAdapter = class {
51005
+ getEnv(name) {
51006
+ return process.env[name];
51007
+ }
51008
+ getAllEnv() {
51009
+ const result = {};
51010
+ for (const [k, v] of Object.entries(process.env)) {
51011
+ if (v !== void 0) result[k] = v;
51012
+ }
51013
+ return result;
51014
+ }
51015
+ setEnv(name, value) {
51016
+ process.env[name] = value;
51017
+ }
51018
+ cwd() {
51019
+ return process.cwd();
51020
+ }
51021
+ chdir(dir) {
51022
+ process.chdir(dir);
51023
+ }
51024
+ platform() {
51025
+ return process.platform;
51026
+ }
51027
+ arch() {
51028
+ return process.arch;
51029
+ }
51030
+ };
51031
+
51032
+ // src/cli-repl.ts
51033
+ var HISTORY_FILE = join4(homedir2(), ".numbl_history");
51034
+ var HISTORY_MAX = 1e3;
51035
+ function loadHistory() {
51036
+ try {
51037
+ const content = readFileSync4(HISTORY_FILE, "utf8");
51038
+ return content.split("\n").filter((line) => line.length > 0).map((line) => line.replace(/\\n/g, "\n").replace(/\\\\/g, "\\"));
51039
+ } catch {
51040
+ return [];
51041
+ }
51042
+ }
51043
+ function saveHistoryEntry(entry, hist) {
51044
+ try {
51045
+ if (hist.length <= HISTORY_MAX) {
51046
+ const encoded = entry.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
51047
+ appendFileSync(HISTORY_FILE, encoded + "\n", "utf8");
51048
+ } else {
51049
+ const trimmed = hist.slice(-HISTORY_MAX);
51050
+ const content = trimmed.map((e) => e.replace(/\\/g, "\\\\").replace(/\n/g, "\\n")).join("\n") + "\n";
51051
+ writeFileSync2(HISTORY_FILE, content, "utf8");
51052
+ }
51053
+ } catch {
51054
+ }
51055
+ }
51056
+ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nativeBridge2, optimization) {
51057
+ let variableValues = {};
51058
+ let holdState = false;
51059
+ const workspaceFiles = [...initialWorkspaceFiles];
51060
+ const searchPaths = [...initialSearchPaths ?? []];
51061
+ const fileIO = new NodeFileIOAdapter();
51062
+ const system = new NodeSystemAdapter();
51063
+ const onInput = (prompt) => {
51064
+ process.stdout.write(prompt);
51065
+ const ttyFd = openSync2("/dev/tty", "r");
51066
+ try {
51067
+ const buf2 = Buffer.alloc(1);
51068
+ let line = "";
51069
+ while (true) {
51070
+ const bytesRead = readSync2(ttyFd, buf2, 0, 1, null);
51071
+ if (bytesRead === 0) break;
51072
+ const ch = buf2.toString("utf8");
51073
+ if (ch === "\n") break;
51074
+ if (ch === "\r") continue;
51075
+ line += ch;
51076
+ }
51077
+ return line;
51078
+ } finally {
51079
+ closeSync2(ttyFd);
51080
+ }
51081
+ };
51082
+ console.log(
51083
+ "numbl REPL \u2014 type 'exit' or press Ctrl+D to quit, Alt+Enter for new line"
51084
+ );
51085
+ if (!process.stdin.isTTY) {
51086
+ const rl = createInterface({
51087
+ input: process.stdin,
51088
+ output: process.stdout,
51089
+ prompt: ">> "
51090
+ });
51091
+ rl.prompt();
51092
+ for await (const line of rl) {
51093
+ const trimmed = line.trim();
51094
+ if (trimmed === "exit" || trimmed === "quit") break;
51095
+ if (trimmed === "") {
51096
+ rl.prompt();
51097
+ continue;
51098
+ }
51099
+ try {
51100
+ const result = executeCode(
51101
+ trimmed,
51102
+ {
51103
+ displayResults: true,
51104
+ onOutput: (text) => process.stdout.write(text),
51105
+ onDrawnow,
51106
+ onInput,
51107
+ initialVariableValues: variableValues,
51108
+ initialHoldState: holdState,
51109
+ optimization,
51110
+ fileIO,
51111
+ system
51112
+ },
51113
+ workspaceFiles,
51114
+ "repl",
51115
+ searchPaths,
51116
+ nativeBridge2
51117
+ );
51118
+ variableValues = result.variableValues;
51119
+ holdState = result.holdState;
51120
+ if (result.searchPaths) {
51121
+ searchPaths.length = 0;
51122
+ searchPaths.push(...result.searchPaths);
51123
+ workspaceFiles.length = 0;
51124
+ workspaceFiles.push(...result.workspaceFiles ?? []);
51125
+ }
51126
+ if (result.plotInstructions.length > 0 && onDrawnow) {
51127
+ onDrawnow(result.plotInstructions);
51128
+ }
51129
+ } catch (error) {
51130
+ const diags = diagnoseErrors(error, trimmed, "repl", workspaceFiles);
51131
+ console.error(formatDiagnostics(diags));
51132
+ }
51133
+ rl.prompt();
51134
+ }
51135
+ console.log("");
51136
+ process.exit(0);
51137
+ }
51138
+ const stdin = process.stdin;
51139
+ const stdout = process.stdout;
51140
+ stdin.setRawMode(true);
51141
+ stdin.resume();
51142
+ stdout.write("\x1B[?2004h");
51143
+ const PS1 = ">> ";
51144
+ const PS2 = " ";
51145
+ let buf = [""];
51146
+ let row = 0;
51147
+ let col = 0;
51148
+ let sRow = 0;
51149
+ const hist = loadHistory();
51150
+ let hIdx = -1;
51151
+ let hStash = "";
51152
+ let hPrefix = "";
51153
+ let pasting = false;
51154
+ let pasteBuf = [];
51155
+ let busy = false;
51156
+ function display() {
51157
+ if (sRow > 0) stdout.write(`\x1B[${sRow}A`);
51158
+ stdout.write("\r\x1B[J");
51159
+ for (let i = 0; i < buf.length; i++) {
51160
+ stdout.write((i === 0 ? PS1 : PS2) + buf[i]);
51161
+ if (i < buf.length - 1) stdout.write("\r\n");
51162
+ }
51163
+ const fromEnd = buf.length - 1 - row;
51164
+ if (fromEnd > 0) stdout.write(`\x1B[${fromEnd}A`);
51165
+ const pLen = row === 0 ? PS1.length : PS2.length;
51166
+ stdout.write(`\x1B[${pLen + col + 1}G`);
51167
+ sRow = row;
51168
+ }
51169
+ function resetInput() {
51170
+ buf = [""];
51171
+ row = col = sRow = 0;
51172
+ hIdx = -1;
51173
+ hStash = "";
51174
+ hPrefix = "";
51175
+ stdout.write(PS1);
51176
+ }
51177
+ function cleanup() {
51178
+ stdout.write("\x1B[?2004l");
51179
+ stdin.setRawMode(false);
51180
+ stdin.pause();
51181
+ }
51182
+ function insertNewline() {
51183
+ const after = buf[row].slice(col);
51184
+ buf[row] = buf[row].slice(0, col);
51185
+ buf.splice(row + 1, 0, after);
51186
+ row++;
51187
+ col = 0;
51188
+ display();
51189
+ }
51190
+ function exec2() {
51191
+ const code = buf.join("\n").trim();
51192
+ const below = buf.length - 1 - sRow;
51193
+ if (below > 0) stdout.write(`\x1B[${below}B`);
51194
+ stdout.write("\r\n");
51195
+ sRow = 0;
51196
+ if (!code) {
51197
+ resetInput();
51198
+ return;
51199
+ }
51200
+ if (code === "exit" || code === "quit") {
51201
+ cleanup();
51202
+ console.log("");
51203
+ process.exit(0);
51204
+ }
51205
+ const entry = buf.join("\n");
51206
+ hist.push(entry);
51207
+ saveHistoryEntry(entry, hist);
51208
+ hIdx = -1;
51209
+ busy = true;
51210
+ stdin.setRawMode(false);
51211
+ stdin.pause();
51212
+ try {
51213
+ const result = executeCode(
51214
+ code,
51215
+ {
51216
+ displayResults: true,
51217
+ onOutput: (text) => stdout.write(text),
51218
+ onDrawnow,
51219
+ onInput,
51220
+ initialVariableValues: variableValues,
51221
+ initialHoldState: holdState,
51222
+ optimization,
51223
+ fileIO,
51224
+ system
51225
+ },
51226
+ workspaceFiles,
51227
+ "repl",
51228
+ searchPaths,
51229
+ nativeBridge2
51230
+ );
51231
+ variableValues = result.variableValues;
51232
+ holdState = result.holdState;
51233
+ if (result.searchPaths) {
51234
+ searchPaths.length = 0;
51235
+ searchPaths.push(...result.searchPaths);
51236
+ workspaceFiles.length = 0;
51237
+ workspaceFiles.push(...result.workspaceFiles ?? []);
51238
+ }
51239
+ if (result.plotInstructions.length > 0 && onDrawnow) {
51240
+ onDrawnow(result.plotInstructions);
51241
+ }
51242
+ } catch (error) {
51243
+ const diags = diagnoseErrors(error, code, "repl", workspaceFiles);
51244
+ console.error(formatDiagnostics(diags));
51245
+ }
51246
+ stdin.resume();
51247
+ stdin.setRawMode(true);
51248
+ busy = false;
51249
+ resetInput();
51250
+ }
51251
+ function handlePaste(text) {
51252
+ text = text.replace(/(\r\n|\r|\n)$/, "");
51253
+ const lines = text.split(/\r\n|\r|\n/);
51254
+ if (lines.length === 1) {
51255
+ buf[row] = buf[row].slice(0, col) + lines[0] + buf[row].slice(col);
51256
+ col += lines[0].length;
51257
+ } else {
51258
+ const after = buf[row].slice(col);
51259
+ buf[row] = buf[row].slice(0, col) + lines[0];
51260
+ for (let j = 1; j < lines.length; j++) {
51261
+ buf.splice(row + j, 0, lines[j]);
51262
+ }
51263
+ row += lines.length - 1;
51264
+ col = buf[row].length;
51265
+ buf[row] += after;
51266
+ }
51267
+ display();
51268
+ }
51269
+ function navHistory(dir) {
51270
+ if (hist.length === 0) return;
51271
+ if (hIdx === -1 && dir > 0) return;
51272
+ if (hIdx === -1) {
51273
+ hStash = buf.join("\n");
51274
+ hPrefix = hStash;
51275
+ if (hPrefix.length > 0) {
51276
+ for (let k = hist.length - 1; k >= 0; k--) {
51277
+ if (hist[k].startsWith(hPrefix)) {
51278
+ hIdx = k;
51279
+ break;
51280
+ }
51281
+ }
51282
+ if (hIdx === -1) return;
51283
+ } else {
51284
+ hIdx = hist.length - 1;
51285
+ }
51286
+ } else {
51287
+ let found = false;
51288
+ if (dir < 0) {
51289
+ for (let k = hIdx - 1; k >= 0; k--) {
51290
+ if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
51291
+ hIdx = k;
51292
+ found = true;
51293
+ break;
51294
+ }
51295
+ }
51296
+ if (!found) return;
51297
+ } else {
51298
+ for (let k = hIdx + 1; k < hist.length; k++) {
51299
+ if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
51300
+ hIdx = k;
51301
+ found = true;
51302
+ break;
51303
+ }
51304
+ }
51305
+ if (!found) {
51306
+ buf = hStash.split("\n");
51307
+ hIdx = -1;
51308
+ row = buf.length - 1;
51309
+ col = buf[row].length;
51310
+ display();
51311
+ return;
51312
+ }
51313
+ }
51314
+ }
51315
+ buf = hist[hIdx].split("\n");
51316
+ row = buf.length - 1;
51317
+ col = buf[row].length;
51318
+ display();
51319
+ }
51320
+ function handleCSI(seq) {
51321
+ switch (seq) {
51322
+ case "A":
51323
+ if (buf.length > 1 && row > 0) {
51324
+ row--;
51325
+ col = Math.min(col, buf[row].length);
51326
+ display();
51327
+ } else {
51328
+ navHistory(-1);
51329
+ }
51330
+ break;
51331
+ case "B":
51332
+ if (buf.length > 1 && row < buf.length - 1) {
51333
+ row++;
51334
+ col = Math.min(col, buf[row].length);
51335
+ display();
51336
+ } else {
51337
+ navHistory(1);
51338
+ }
51339
+ break;
51340
+ case "C":
51341
+ if (col < buf[row].length) {
51342
+ col++;
51343
+ display();
51344
+ } else if (row < buf.length - 1) {
51345
+ row++;
51346
+ col = 0;
51347
+ display();
51348
+ }
51349
+ break;
51350
+ case "D":
51351
+ if (col > 0) {
51352
+ col--;
51353
+ display();
51354
+ } else if (row > 0) {
51355
+ row--;
51356
+ col = buf[row].length;
51357
+ display();
51358
+ }
51359
+ break;
51360
+ case "H":
51361
+ // Home
51362
+ case "1~":
51363
+ col = 0;
51364
+ display();
51365
+ break;
51366
+ case "F":
51367
+ // End
51368
+ case "4~":
51369
+ col = buf[row].length;
51370
+ display();
51371
+ break;
51372
+ case "3~":
51373
+ if (col < buf[row].length) {
51374
+ buf[row] = buf[row].slice(0, col) + buf[row].slice(col + 1);
51375
+ display();
51376
+ } else if (row < buf.length - 1) {
51377
+ buf[row] += buf[row + 1];
51378
+ buf.splice(row + 1, 1);
51379
+ display();
51380
+ }
51381
+ break;
51382
+ case "13;2u":
51383
+ insertNewline();
51384
+ break;
51385
+ }
51386
+ }
51387
+ resetInput();
51388
+ return new Promise((resolve3) => {
51389
+ stdin.on("data", (chunk) => {
51390
+ if (busy) return;
51391
+ const data = chunk.toString("utf8");
51392
+ let i = 0;
51393
+ while (i < data.length) {
51394
+ if (busy) return;
51395
+ if (data.startsWith("\x1B[200~", i)) {
51396
+ pasting = true;
51397
+ pasteBuf = [];
51398
+ i += 6;
51399
+ continue;
51400
+ }
51401
+ if (data.startsWith("\x1B[201~", i)) {
51402
+ pasting = false;
51403
+ handlePaste(pasteBuf.join(""));
51404
+ i += 6;
51405
+ continue;
51406
+ }
51407
+ if (pasting) {
51408
+ const end = data.indexOf("\x1B[201~", i);
51409
+ if (end >= 0) {
51410
+ pasteBuf.push(data.slice(i, end));
51411
+ pasting = false;
51412
+ handlePaste(pasteBuf.join(""));
51413
+ i = end + 6;
51414
+ } else {
51415
+ pasteBuf.push(data.slice(i));
51416
+ i = data.length;
51417
+ }
51418
+ continue;
51419
+ }
51420
+ if (data[i] === "\x1B" && i + 1 < data.length && (data[i + 1] === "\r" || data[i + 1] === "\n")) {
51421
+ insertNewline();
51422
+ i += 2;
51423
+ continue;
51424
+ }
51425
+ if (data.startsWith("\x1B[", i)) {
51426
+ let j = i + 2;
51427
+ while (j < data.length && (data.charCodeAt(j) < 64 || data.charCodeAt(j) > 126))
51428
+ j++;
51429
+ if (j >= data.length) {
51430
+ i = data.length;
51431
+ continue;
51432
+ }
51433
+ handleCSI(data.slice(i + 2, j + 1));
51434
+ i = j + 1;
51435
+ continue;
51436
+ }
51437
+ if (data[i] === "\x1B") {
51438
+ i++;
51439
+ continue;
51440
+ }
51441
+ const code = data.charCodeAt(i);
51442
+ i++;
51443
+ if (code === 13 || code === 10) {
51444
+ try {
51445
+ exec2();
51446
+ } catch (err) {
51447
+ console.error("Unexpected REPL error:", err);
51448
+ busy = false;
51449
+ resetInput();
51450
+ }
51451
+ } else if (code === 127 || code === 8) {
51452
+ if (col > 0) {
51453
+ buf[row] = buf[row].slice(0, col - 1) + buf[row].slice(col);
51454
+ col--;
51455
+ display();
51456
+ } else if (row > 0) {
51457
+ col = buf[row - 1].length;
51458
+ buf[row - 1] += buf[row];
51459
+ buf.splice(row, 1);
51460
+ row--;
51461
+ display();
51462
+ }
51463
+ } else if (code === 1) {
51464
+ col = 0;
51465
+ display();
51466
+ } else if (code === 5) {
51467
+ col = buf[row].length;
51468
+ display();
51469
+ } else if (code === 11) {
51470
+ buf[row] = buf[row].slice(0, col);
51471
+ display();
51472
+ } else if (code === 21) {
51473
+ buf[row] = buf[row].slice(col);
51474
+ col = 0;
51475
+ display();
51476
+ } else if (code === 3) {
51477
+ const below = buf.length - 1 - sRow;
51478
+ if (below > 0) stdout.write(`\x1B[${below}B`);
51479
+ stdout.write("\r\n^C\r\n");
51480
+ sRow = 0;
51481
+ resetInput();
51482
+ } else if (code === 4) {
51483
+ if (buf.length === 1 && buf[0] === "") {
51484
+ stdout.write("\r\n");
51485
+ cleanup();
51486
+ resolve3();
51487
+ return;
51488
+ }
51489
+ } else if (code === 12) {
51490
+ stdout.write("\x1B[2J\x1B[H");
51491
+ sRow = 0;
51492
+ display();
51493
+ } else if (code >= 32) {
51494
+ buf[row] = buf[row].slice(0, col) + data[i - 1] + buf[row].slice(col);
51495
+ col++;
51496
+ display();
51497
+ }
51498
+ }
51499
+ });
51500
+ });
51501
+ }
51502
+
51503
+ // src/vfs/unzipToFiles.ts
51504
+ import { inflateSync } from "fflate";
51505
+ var TEXT_DECODER = new TextDecoder("utf-8");
51506
+ function unzipToFiles(zipData) {
51507
+ let eocdOffset = -1;
51508
+ for (let i = zipData.length - 22; i >= 0; i--) {
51509
+ if (zipData[i] === 80 && zipData[i + 1] === 75 && zipData[i + 2] === 5 && zipData[i + 3] === 6) {
51510
+ eocdOffset = i;
51511
+ break;
51512
+ }
51513
+ }
51514
+ if (eocdOffset === -1) throw new Error("Invalid ZIP file");
51515
+ const view = new DataView(
51516
+ zipData.buffer,
51517
+ zipData.byteOffset,
51518
+ zipData.byteLength
51519
+ );
51520
+ const cdOffset = view.getUint32(eocdOffset + 16, true);
51521
+ const cdEntries = view.getUint16(eocdOffset + 10, true);
51522
+ const files = [];
51523
+ let pos = cdOffset;
51524
+ for (let i = 0; i < cdEntries; i++) {
51525
+ if (view.getUint32(pos, true) !== 33639248) {
51526
+ throw new Error("Corrupt ZIP central directory");
51527
+ }
51528
+ const method = view.getUint16(pos + 10, true);
51529
+ const nameLen = view.getUint16(pos + 28, true);
51530
+ const extraLen = view.getUint16(pos + 30, true);
51531
+ const commentLen = view.getUint16(pos + 32, true);
51532
+ const localHeaderOffset = view.getUint32(pos + 42, true);
51533
+ const entryName = TEXT_DECODER.decode(
51534
+ zipData.subarray(pos + 46, pos + 46 + nameLen)
51535
+ );
51536
+ pos += 46 + nameLen + extraLen + commentLen;
51537
+ if (entryName.endsWith("/")) continue;
51538
+ const localPos = localHeaderOffset;
51539
+ if (view.getUint32(localPos, true) !== 67324752) {
51540
+ throw new Error("Corrupt ZIP local header");
51541
+ }
51542
+ const localNameLen = view.getUint16(localPos + 26, true);
51543
+ const localExtraLen = view.getUint16(localPos + 28, true);
51544
+ const compressedSize = view.getUint32(localPos + 18, true);
51545
+ const dataStart = localPos + 30 + localNameLen + localExtraLen;
51546
+ const compressedData = zipData.subarray(
51547
+ dataStart,
51548
+ dataStart + compressedSize
51549
+ );
51550
+ let content;
51551
+ if (method === 0) {
51552
+ content = new Uint8Array(compressedData);
51553
+ } else if (method === 8) {
51554
+ content = inflateSync(compressedData);
51555
+ } else {
51556
+ throw new Error(
51557
+ `Unsupported ZIP compression method ${method} for ${entryName}`
51558
+ );
51559
+ }
51560
+ files.push({ path: entryName, content });
51561
+ }
51562
+ return files;
51563
+ }
51564
+
51378
51565
  // src/cli.ts
51379
51566
  var __filename = fileURLToPath2(import.meta.url);
51380
51567
  var __dirname = dirname2(__filename);
51381
- var packageDir = join4(__dirname, "..");
51382
- var addonPath = join4(packageDir, "build", "Release", "numbl_addon.node");
51568
+ var packageDir = join5(__dirname, "..");
51569
+ var addonPath = join5(packageDir, "build", "Release", "numbl_addon.node");
51383
51570
  var nativeAddonLoaded = false;
51384
51571
  if (!process.env.NUMBL_NO_NATIVE) {
51385
51572
  try {
@@ -51408,62 +51595,51 @@ try {
51408
51595
  nativeBridge = { load: (path) => koffi.load(path) };
51409
51596
  } catch {
51410
51597
  }
51411
- function scanMFiles(dirPath, excludeFile) {
51412
- const files = [];
51413
- let entries;
51414
- try {
51415
- entries = readdirSync2(dirPath);
51416
- } catch {
51417
- return files;
51598
+ var MHL_URL = "https://github.com/mip-org/mip-core/releases/download/mip-main/mip-main-any.mhl";
51599
+ var mipCoreDir = join5(
51600
+ homedir3(),
51601
+ ".numbl",
51602
+ "mip",
51603
+ "packages",
51604
+ "mip-org",
51605
+ "core",
51606
+ "mip"
51607
+ );
51608
+ var mipCoreSearchPath = join5(mipCoreDir, "mip");
51609
+ async function ensureMipCorePackage() {
51610
+ if (existsSync2(join5(mipCoreSearchPath, "mip.m"))) return;
51611
+ console.error("Installing mip core package...");
51612
+ const resp = await fetch(MHL_URL);
51613
+ if (!resp.ok) {
51614
+ console.error(
51615
+ `Warning: failed to download mip core package (HTTP ${resp.status})`
51616
+ );
51617
+ return;
51418
51618
  }
51419
- for (const entry of entries) {
51420
- const fullPath = join4(dirPath, entry);
51421
- if (excludeFile && fullPath === excludeFile) {
51422
- continue;
51423
- }
51424
- try {
51425
- const stat = statSync2(fullPath);
51426
- if (stat.isDirectory()) {
51427
- if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
51428
- files.push(...scanMFiles(fullPath, excludeFile));
51429
- }
51430
- } else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".js"))) {
51431
- const source = readFileSync4(fullPath, "utf-8");
51432
- files.push({
51433
- name: fullPath,
51434
- source
51435
- });
51436
- } else if (stat.isFile() && entry.endsWith(".wasm")) {
51437
- const data = readFileSync4(fullPath);
51438
- files.push({
51439
- name: fullPath,
51440
- source: "",
51441
- data: new Uint8Array(data)
51442
- });
51443
- }
51444
- } catch (err) {
51445
- console.warn(
51446
- `Warning: could not read ${fullPath}: ${err instanceof Error ? err.message : String(err)}`
51447
- );
51448
- }
51619
+ const buf = new Uint8Array(await resp.arrayBuffer());
51620
+ const files = unzipToFiles(buf);
51621
+ for (const f of files) {
51622
+ const dest = join5(mipCoreDir, f.path);
51623
+ mkdirSync2(dirname2(dest), { recursive: true });
51624
+ writeFileSync3(dest, f.content);
51449
51625
  }
51450
- return files;
51626
+ console.error("mip core package installed.");
51451
51627
  }
51452
51628
  function findTestFiles(dir) {
51453
51629
  const results = [];
51454
51630
  function walk(current) {
51455
51631
  let entries;
51456
51632
  try {
51457
- entries = readdirSync2(current);
51633
+ entries = readdirSync3(current);
51458
51634
  } catch {
51459
51635
  return;
51460
51636
  }
51461
51637
  entries.sort();
51462
51638
  for (const entry of entries) {
51463
- const fullPath = join4(current, entry);
51639
+ const fullPath = join5(current, entry);
51464
51640
  let stat;
51465
51641
  try {
51466
- stat = statSync2(fullPath);
51642
+ stat = statSync3(fullPath);
51467
51643
  } catch {
51468
51644
  continue;
51469
51645
  }
@@ -51472,7 +51648,7 @@ function findTestFiles(dir) {
51472
51648
  walk(fullPath);
51473
51649
  }
51474
51650
  } else if (stat.isFile() && entry.endsWith(".m")) {
51475
- const content = readFileSync4(fullPath, "utf-8");
51651
+ const content = readFileSync5(fullPath, "utf-8");
51476
51652
  if (content.includes("SUCCESS")) {
51477
51653
  results.push(fullPath);
51478
51654
  }
@@ -51514,7 +51690,7 @@ async function runTests(dir, optimization) {
51514
51690
  const failedScripts = [];
51515
51691
  for (const filepath of testFiles) {
51516
51692
  const rel = relative(process.cwd(), filepath);
51517
- const source = readFileSync4(filepath, "utf-8");
51693
+ const source = readFileSync5(filepath, "utf-8");
51518
51694
  const mainFileName = filepath;
51519
51695
  const scriptDir = dirname2(filepath);
51520
51696
  const searchPaths = [scriptDir];
@@ -51729,8 +51905,9 @@ async function cmdRun(args) {
51729
51905
  console.error("Error: numbl run accepts only one file argument");
51730
51906
  process.exit(1);
51731
51907
  }
51908
+ await ensureMipCorePackage();
51732
51909
  const filepath = resolve2(process.cwd(), opts.positional[0]);
51733
- const code = readFileSync4(filepath, "utf-8");
51910
+ const code = readFileSync5(filepath, "utf-8");
51734
51911
  const mainFileName = filepath;
51735
51912
  const searchPaths = [];
51736
51913
  let workspaceFiles = [];
@@ -51743,6 +51920,10 @@ async function cmdRun(args) {
51743
51920
  searchPaths.push(p2);
51744
51921
  workspaceFiles.push(...scanMFiles(p2));
51745
51922
  }
51923
+ if (existsSync2(mipCoreSearchPath)) {
51924
+ searchPaths.push(mipCoreSearchPath);
51925
+ workspaceFiles.push(...scanMFiles(mipCoreSearchPath));
51926
+ }
51746
51927
  await executeWithOptions(
51747
51928
  code,
51748
51929
  mainFileName,
@@ -51761,12 +51942,17 @@ async function cmdEval(args) {
51761
51942
  console.error("Error: numbl eval accepts only one code argument");
51762
51943
  process.exit(1);
51763
51944
  }
51945
+ await ensureMipCorePackage();
51764
51946
  const searchPaths = [];
51765
51947
  const workspaceFiles = [];
51766
51948
  for (const p2 of opts.extraPaths) {
51767
51949
  searchPaths.push(p2);
51768
51950
  workspaceFiles.push(...scanMFiles(p2));
51769
51951
  }
51952
+ if (existsSync2(mipCoreSearchPath)) {
51953
+ searchPaths.push(mipCoreSearchPath);
51954
+ workspaceFiles.push(...scanMFiles(mipCoreSearchPath));
51955
+ }
51770
51956
  await executeWithOptions(
51771
51957
  opts.positional[0],
51772
51958
  "eval.m",
@@ -51978,13 +52164,13 @@ function finalizeDumpFile(dumpFile, mainFileName, jsCode) {
51978
52164
  }
51979
52165
  let jitContent = "";
51980
52166
  try {
51981
- jitContent = readFileSync4(dumpFile, "utf-8");
52167
+ jitContent = readFileSync5(dumpFile, "utf-8");
51982
52168
  } catch {
51983
52169
  }
51984
52170
  writeFileSync3(dumpFile, header + jsCode + "\n" + jitContent);
51985
52171
  }
51986
52172
  async function cmdBuildAddon() {
51987
- const bindingGyp = join4(packageDir, "binding.gyp");
52173
+ const bindingGyp = join5(packageDir, "binding.gyp");
51988
52174
  if (!existsSync2(bindingGyp)) {
51989
52175
  console.error(
51990
52176
  "Error: binding.gyp not found in package directory: " + packageDir
@@ -52030,8 +52216,13 @@ function cmdListBuiltins() {
52030
52216
  }
52031
52217
  async function cmdRepl(args) {
52032
52218
  const opts = parseOptions(args);
52219
+ await ensureMipCorePackage();
52033
52220
  const replSearchPaths = [...opts.extraPaths];
52034
52221
  const replFiles = opts.extraPaths.flatMap((d) => scanMFiles(d));
52222
+ if (existsSync2(mipCoreSearchPath)) {
52223
+ replSearchPaths.push(mipCoreSearchPath);
52224
+ replFiles.push(...scanMFiles(mipCoreSearchPath));
52225
+ }
52035
52226
  const replPlotOpts = opts.plotPort !== void 0 ? { port: opts.plotPort, host: "0.0.0.0" } : void 0;
52036
52227
  const { onDrawnow: replDrawnow } = createPlotHandler(
52037
52228
  !opts.plot,
@@ -52097,7 +52288,7 @@ function cmdShowProfile(args) {
52097
52288
  console.error(`Error: profile file not found: ${filepath}`);
52098
52289
  process.exit(1);
52099
52290
  }
52100
- const data = JSON.parse(readFileSync4(filepath, "utf-8"));
52291
+ const data = JSON.parse(readFileSync5(filepath, "utf-8"));
52101
52292
  const fmt = (n, decimals = 1) => n.toFixed(decimals);
52102
52293
  const pad = (s, w) => s.padStart(w);
52103
52294
  const execTime = data.executionTimeMs || 1;
@@ -52179,7 +52370,7 @@ async function main() {
52179
52370
  break;
52180
52371
  case "run-tests": {
52181
52372
  const testOpts = parseOptions(rest);
52182
- const dir = testOpts.positional.length > 0 ? testOpts.positional[0] : join4(packageDir, "numbl_test_scripts");
52373
+ const dir = testOpts.positional.length > 0 ? testOpts.positional[0] : join5(packageDir, "numbl_test_scripts");
52183
52374
  await runTests(dir, testOpts.optimization);
52184
52375
  break;
52185
52376
  }