jsmdcui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,6 +34,8 @@ Flat buffer helpers (all 1-based line numbers, omit → cursor line):
34
34
  micro.getLine(n?) micro.putLine(text, n?) micro.delLine(n?)
35
35
  micro.getLines(from?, to?) micro.getLinesCount()
36
36
  micro.getAllText() — entire buffer as one string (lines joined by "\n")
37
+ micro.getAllAnsiText() — rendered ANSI document, or plain text when unavailable
38
+ micro.clickBufferCell(x, y) — activate a 1-based MDCUI cell, or goto in other buffers
37
39
  micro.putAllText(text) — replace entire buffer content; pushes undo
38
40
  micro.getSelection() micro.putSelection(text)
39
41
 
@@ -82,7 +84,7 @@ micro.on("init", () => {
82
84
  },
83
85
  async click(x,y,opt){
84
86
  x=x||1 ; y=y||1 ;
85
- await micro.cmd.goto(y+':'+x);
87
+ await micro.clickBufferCell(x, y);
86
88
  },
87
89
  async scroll(dx,dy){
88
90
  const pane = micro.CurPane();
@@ -111,54 +113,8 @@ micro.on("init", () => {
111
113
  bp.Insert(text);
112
114
  },
113
115
  async press(key, options){
114
- const bp = micro.CurPane();
115
- if (!bp) return;
116
-
117
- // modifiers bitmask: Alt=1, Ctrl=2, Meta=4, Shift=8
118
- const mod = options?.modifiers ?? 0;
119
- const ctrl = !!(mod & 2);
120
- const shift = !!(mod & 8);
121
-
122
- if (ctrl) {
123
- const ctrlMap = {
124
- a: () => micro.action.SelectAll(),
125
- c: () => micro.action.Copy(),
126
- x: () => micro.action.Cut(),
127
- v: () => micro.action.Paste(),
128
- z: () => micro.action.Undo(),
129
- y: () => micro.action.Redo(),
130
- s: () => micro.action.Save(),
131
- };
132
- const h = ctrlMap[key.toLowerCase()];
133
- if (h) await h();
134
- return;
135
- }
136
-
137
- const arrowAction = shift
138
- ? { ArrowUp: 'SelectUp', ArrowDown: 'SelectDown', ArrowLeft: 'SelectLeft', ArrowRight: 'SelectRight' }
139
- : { ArrowUp: 'CursorUp', ArrowDown: 'CursorDown', ArrowLeft: 'CursorLeft', ArrowRight: 'CursorRight' };
140
-
141
- const keyMap = {
142
- ...arrowAction,
143
- Enter: () => micro.action.InsertNewline(),
144
- Backspace: () => micro.action.Backspace(),
145
- Delete: () => micro.action.Delete(),
146
- Tab: () => micro.action.InsertTab(),
147
- Escape: () => micro.action.Escape(),
148
- Home: () => shift ? micro.action.SelectToStartOfLine() : micro.action.StartOfLine(),
149
- End: () => shift ? micro.action.SelectToEndOfLine() : micro.action.EndOfLine(),
150
- PageUp: () => shift ? micro.action.SelectPageUp() : micro.action.CursorPageUp(),
151
- PageDown: () => shift ? micro.action.SelectPageDown() : micro.action.CursorPageDown(),
152
- };
153
-
154
- const entry = keyMap[key];
155
- if (typeof entry === 'string') {
156
- await micro.action[entry]();
157
- } else if (typeof entry === 'function') {
158
- await entry();
159
- } else if (key.length === 1) {
160
- bp.Insert(key);
161
- }
116
+ const raw = cdpKeyToTerminalInput(key, options);
117
+ if (raw) await micro._dispatchRawInput(raw);
162
118
  },
163
119
  }
164
120
 
@@ -193,3 +149,53 @@ function toInteger(value) {
193
149
  const number = Number(value);
194
150
  return Number.isFinite(number) ? Math.trunc(number) : 0;
195
151
  }
152
+
153
+ function cdpKeyToTerminalInput(key, options = {}) {
154
+ const modifiers = Number(options.modifiers) || 0;
155
+ const alt = !!(modifiers & 1);
156
+ const ctrl = !!(modifiers & 2);
157
+ const meta = !!(modifiers & 4);
158
+ const shift = !!(modifiers & 8);
159
+ const modifierCode = 1 + (shift ? 1 : 0) + (alt || meta ? 2 : 0) + (ctrl ? 4 : 0);
160
+ const value = String(key ?? options.text ?? "");
161
+
162
+ const cursorFinal = {
163
+ ArrowUp: "A",
164
+ ArrowDown: "B",
165
+ ArrowRight: "C",
166
+ ArrowLeft: "D",
167
+ Home: "H",
168
+ End: "F",
169
+ }[value];
170
+ if (cursorFinal) {
171
+ return modifierCode === 1
172
+ ? `\x1b[${cursorFinal}`
173
+ : `\x1b[1;${modifierCode}${cursorFinal}`;
174
+ }
175
+
176
+ if (value === "PageUp" || value === "PageDown" || value === "Delete") {
177
+ const number = value === "PageUp" ? 5 : value === "PageDown" ? 6 : 3;
178
+ return modifierCode === 1
179
+ ? `\x1b[${number}~`
180
+ : `\x1b[${number};${modifierCode}~`;
181
+ }
182
+
183
+ if (value === "Tab") return shift ? "\x1b[Z" : "\t";
184
+ if (value === "Enter") return alt || meta ? "\x1b\r" : "\r";
185
+ if (value === "Backspace") return "\x7f";
186
+ if (value === "Escape") return "\x1b";
187
+
188
+ let text = typeof options.text === "string" && options.text
189
+ ? options.text
190
+ : value === "Space" ? " " : value;
191
+ if ([...text].length !== 1) return "";
192
+
193
+ if (ctrl) {
194
+ const code = text.toUpperCase().charCodeAt(0);
195
+ if (code >= 64 && code <= 95) text = String.fromCharCode(code & 31);
196
+ } else if (shift && /^[a-z]$/.test(text)) {
197
+ text = text.toUpperCase();
198
+ }
199
+
200
+ return alt || meta ? `\x1b${text}` : text;
201
+ }
@@ -35,6 +35,8 @@ Flat buffer helpers (all 1-based line numbers, omit → cursor line):
35
35
  micro.getLine(n?) micro.putLine(text, n?) micro.delLine(n?)
36
36
  micro.getLines(from?, to?) micro.getLinesCount()
37
37
  micro.getAllText() — entire buffer as one string (lines joined by "\n")
38
+ micro.getAllAnsiText() — rendered ANSI document, or plain text when unavailable
39
+ micro.clickBufferCell(x, y) — activate a 1-based MDCUI cell, or goto in other buffers
38
40
  micro.putAllText(text) — replace entire buffer content; pushes undo
39
41
  micro.getSelection() micro.putSelection(text)
40
42
 
@@ -107,4 +109,3 @@ micro.on("init", () => {
107
109
  });
108
110
 
109
111
  });
110
-
@@ -35,6 +35,8 @@ Flat buffer helpers (all 1-based line numbers, omit → cursor line):
35
35
  micro.getLine(n?) micro.putLine(text, n?) micro.delLine(n?)
36
36
  micro.getLines(from?, to?) micro.getLinesCount()
37
37
  micro.getAllText() — entire buffer as one string (lines joined by "\n")
38
+ micro.getAllAnsiText() — rendered ANSI document, or plain text when unavailable
39
+ micro.clickBufferCell(x, y) — activate a 1-based MDCUI cell, or goto in other buffers
38
40
  micro.putAllText(text) — replace entire buffer content; pushes undo
39
41
  micro.getSelection() micro.putSelection(text)
40
42
 
@@ -1,27 +1,231 @@
1
- # This is completely optional
2
- - I still recommend using the methods in the root README.md
3
- - Bun's Android build is currently not supported
1
+ # Bun Single-File Executable Bootstrap
4
2
 
5
- # Usage
6
- - First run `bun ./packAssets.sh` to bundle the assets into `assets.tar`
7
- - Then run the build script like this
3
+ Build a Bun application and its runtime assets into one executable while
4
+ keeping the regular main module free of Bun-specific asset imports.
8
5
 
9
- ```shell
10
- bun build --compile --bytecode --minify ./entry.mjs --outfile=binname
11
- ```
6
+ You can copy and adapt this build setup for your own project by changing its
7
+ main-module path and asset list as described below.
12
8
 
13
- - You'll get a binname executable
9
+ - Bundle an asset tree alongside the application code in one executable.
10
+ - Keep the regular main module available to the Node.js ESM execution path.
11
+ - Read embedded resources first with an optional external-file fallback.
12
+ - List, extract, or bypass embedded assets with built-in CLI flags.
13
+ - Build for the current platform or pass a Bun cross-compilation target.
14
14
 
15
- # Single Executable Intro
15
+ > This workflow is optional; the standard methods in the root README remain
16
+ > available. Bun's Android build is currently not supported.
16
17
 
17
- This folder contains the Bun single-exe bootstrap used by the project.
18
+ ## Quick start for jsmdcui
19
+
20
+ From the repository root, build for the current platform:
21
+
22
+ ```shell
23
+ bun ./src/index.js --build-exe
24
+ ./mdcui --version
25
+ ```
26
+
27
+ `--build-exe` runs `packAssets.sh` automatically and writes the `mdcui`
28
+ executable to the current directory. To pass a Bun compilation target, use:
29
+
30
+ ```shell
31
+ bun ./src/index.js --build-for <target>
32
+ ```
33
+
34
+ To perform the same steps manually, run these commands from `single-exe/`:
35
+
36
+ ```shell
37
+ bun ./packAssets.sh
38
+ bun build --format=esm --compile --minify --bytecode ./entry.mjs --outfile=mdcui
39
+ ```
40
+
41
+ ## Adapting this folder to another project
42
+
43
+ This folder is a reusable starting point, not a drop-in package. The current
44
+ `entry.mjs` and `packAssets.sh` contain jsmdcui paths, so another project must
45
+ complete the following integration steps.
46
+
47
+ The adopting project needs Bun for packing and compiling, a `tar` command for
48
+ `packAssets.sh`, and an ES-module setup. Keep `"type": "module"` in
49
+ `package.json`, or rename the copied `.js` modules to `.mjs` and update their
50
+ imports. The supported uncompiled Node path requires Node.js 20.11 or newer
51
+ because `compiled.js` uses `import.meta.dirname`.
52
+
53
+ `assetsHelper.js` and `compiled.js` are Node-compatible under those conditions.
54
+ `assetsLoader.mjs` and `entry.mjs` are Bun-only and must not be imported by the
55
+ regular Node entry path.
56
+
57
+ ### 1. Copy the bootstrap directory
58
+
59
+ Copy the entire `single-exe/` directory to the root of the other project and
60
+ keep its name and relative position unless you also update the paths in
61
+ `compiled.js` and `packAssets.sh`. A typical layout is:
62
+
63
+ ```text
64
+ my-project/
65
+ ├── single-exe/
66
+ │ ├── assetsHelper.js
67
+ │ ├── assetsLoader.mjs
68
+ │ ├── compiled.js
69
+ │ ├── entry.mjs
70
+ │ └── packAssets.sh
71
+ └── src/
72
+ └── index.js
73
+ ```
74
+
75
+ `assets.tar` is generated by `packAssets.sh`; it does not need to exist before
76
+ the first packing step.
77
+
78
+ ### 2. Point `entry.mjs` at the main program
79
+
80
+ Keep the asset loader as the first import and change the path passed to the
81
+ final `await import()` so it points to the other project's real entry module:
82
+
83
+ ```js
84
+ #!/usr/bin/env bun
85
+
86
+ import "./assetsLoader.mjs";
87
+ await globalThis.assetsLoaderPromise;
88
+ await import("../src/index.js");
89
+ ```
90
+
91
+ > **Important:** Keep the final import dynamic. Do not replace it with a static
92
+ > `import "../src/index.js"`, because static dependencies are evaluated before
93
+ > the asset Promise is awaited.
94
+
95
+ Only the Bun single-file executable build should use this bootstrap entry.
96
+ Continue to run the regular main module directly when using Node:
97
+
98
+ ```shell
99
+ node ./src/index.js
100
+ ```
101
+
102
+ ### 3. Choose which files to embed
103
+
104
+ Edit the resource list in `packAssets.sh`; the script runs `tar` for you. It
105
+ changes to the project root, writes `single-exe/assets.tar`, and packs every
106
+ listed runtime resource required by the compiled program. Paths stored in the
107
+ archive become the lookup keys used by `assetsHelper.js`; use keys such as
108
+ `public/app.css`, without a leading `./`. The normal `--build-exe` and
109
+ `--build-for` flows invoke this script automatically, so you do not need to run
110
+ `tar` yourself.
111
+
112
+ For example:
113
+
114
+ ```sh
115
+ #!/bin/sh
116
+
117
+ script_dir=$(dirname "$0")
118
+ cd "$script_dir/.." || exit 1
119
+
120
+ tar -cvf single-exe/assets.tar public templates README.md
121
+ ```
122
+
123
+ Do not retain jsmdcui's `demos`, `runtime`, `src/cui`, or `testapp.md` entries
124
+ unless the adopting project actually contains and needs them.
125
+
126
+ ### 4. Read embedded assets with an external fallback
127
+
128
+ Import the Node-compatible helpers from `assetsHelper.js`. They return `null`
129
+ when the embedded store is unavailable or a path is not present:
130
+
131
+ ```js
132
+ import { readFile } from "node:fs/promises";
133
+ import { resolve } from "node:path";
134
+ import { readInternalAssetText } from "../single-exe/assetsHelper.js";
135
+ import { REPO_ROOT } from "../single-exe/compiled.js";
136
+
137
+ async function readResourceText(path) {
138
+ return readInternalAssetText(path) ??
139
+ await readFile(resolve(REPO_ROOT, path), "utf8");
140
+ }
141
+ ```
142
+
143
+ In the source tree, `REPO_ROOT` is the project root. In a compiled executable,
144
+ it is the executable's directory, which is also where `--assets-extract`
145
+ places the external resource tree. Apply the same embedded-first fallback to
146
+ every file that must work in both modes. Use `readInternalAssetBytes()` when
147
+ a resource should be returned as bytes instead of decoded text.
148
+ Use `listInternalAssetPaths()` to list embedded asset paths and
149
+ `listInternalAssetDirs()` to list embedded directories.
150
+
151
+ ### 5. Add the optional build commands to the regular CLI
152
+
153
+ Before normal argument parsing, call `buildEarlyExit` from the regular main
154
+ module:
155
+
156
+ ```js
157
+ const compiledHelper = await import("../single-exe/compiled.js").catch(() => null);
158
+ await compiledHelper?.buildEarlyExit?.(process.argv, "my-bin");
159
+ ```
160
+
161
+ The second argument is the output filename; it defaults to `single.exe` when
162
+ omitted. This enables:
163
+
164
+ ```shell
165
+ bun ./src/index.js --build-exe
166
+ bun ./src/index.js --build-for <target>
167
+ ```
168
+
169
+ Both commands run `packAssets.sh` before `bun build`. The second form passes
170
+ `<target>` through as Bun's `--target=<target>` value.
171
+
172
+ Alternatively, build manually from inside `single-exe/`:
173
+
174
+ ```shell
175
+ bun ./packAssets.sh
176
+ bun build --format=esm --compile --minify --bytecode ./entry.mjs --outfile=my-bin
177
+ ```
178
+
179
+ ### 6. Verify both execution paths
180
+
181
+ Verify the compiled asset archive and then run the program normally:
182
+
183
+ ```shell
184
+ ./my-bin --assets-list
185
+ ./my-bin
186
+ ```
187
+
188
+ Also run the uncompiled main module with Node.js 20.11 or newer to verify that
189
+ all required files have a working external fallback:
190
+
191
+ ```shell
192
+ node ./src/index.js
193
+ ```
194
+
195
+ Use `./my-bin --assets-extract` to write the packed tree beside the executable.
196
+ After extraction, `./my-bin --assets-external` skips the embedded store and is
197
+ useful for testing the external-resource path.
198
+
199
+ ### Why `assetsLoaderPromise` is used
200
+
201
+ A more tightly coupled ESM design could export the assets with top-level
202
+ `await`, then make the main module import `assetsLoader.mjs` directly. This
203
+ project deliberately does not do that because `assetsLoader.mjs` contains
204
+ Bun's compiled-file import:
205
+
206
+ ```js
207
+ import assets from "./assets.tar" with { type: "file" };
208
+ ```
209
+
210
+ If the regular main module imported `assetsLoader.mjs`, that Bun-specific
211
+ `type: "file"` dependency would enter the main module graph. Node would then be
212
+ unable to load the program before it could select an external-file fallback.
213
+
214
+ Instead, only Bun's `entry.mjs` imports the Bun-specific loader, awaits its
215
+ Promise, and then dynamically imports the regular main module. The main module
216
+ does not import the loader, inspect the Promise, or contain Bun bootstrap code.
217
+ Under the supported Node.js 20.11+ ESM path, Node runs that clean main module
218
+ directly with external files. The Promise is therefore an intentional
219
+ Node-compatibility boundary inside the Bun-only bootstrap, not a failure to use
220
+ a more modern dependency or top-level-`await` design.
18
221
 
19
222
  ## Entry Flow
20
223
 
21
224
  - `entry.mjs` imports `assetsLoader.mjs` first
22
225
  - `assetsLoader.mjs` loads `assets.tar` with `Bun.Archive` and mounts it as `globalThis.internalAssets`
23
226
  - `assetsLoaderPromise` is exposed on `globalThis`
24
- - The main program waits for `assetsLoaderPromise` if it exists
227
+ - `entry.mjs` awaits `assetsLoaderPromise`
228
+ - `entry.mjs` dynamically imports the main program after the assets are ready
25
229
 
26
230
  That keeps the main program bootable even if asset loading reports errors.
27
231
 
@@ -32,6 +236,12 @@ That keeps the main program bootable even if asset loading reports errors.
32
236
  - Asset loading never rejects the bootstrap promise
33
237
  - When loading succeeds, the archive is available through `globalThis.internalAssets`
34
238
 
239
+ This loader is not zero-copy: it materializes every bundled file in memory and
240
+ keeps the resulting bytes in `globalThis.internalAssets`. Large asset archives
241
+ can therefore increase startup and ongoing RAM usage. For workloads where that
242
+ matters, I also wrote an experimental Linux-only zero-copy hack:
243
+ [bun-assets-zerocopy](https://github.com/jjtseng93/bun-assets-zerocopy).
244
+
35
245
  ## CLI Flags
36
246
 
37
247
  - `--assets-list`
@@ -46,35 +256,3 @@ That keeps the main program bootable even if asset loading reports errors.
46
256
  - Skips loading bundled assets into `globalThis.internalAssets`
47
257
  - Forces the main program and runtime helpers to use the external file tree
48
258
  - Keeps the bootstrap alive while leaving `internalAssets` falsy
49
-
50
- ## Adapting this folder
51
-
52
- This single-exe folder is intended for reuse by other projects. Usually you
53
- only need to edit these project-specific files first:
54
-
55
- - `entry.mjs`
56
- - `packAssets.sh`
57
-
58
- Then the main program can import `buildEarlyExit` from `compiled.js` and call
59
- it before normal CLI parsing. `--build-exe` and `--build-for <target>` will run
60
- `packAssets.sh` first, so `assets.tar` is generated as part of the build flow.
61
-
62
- ```js
63
- const compiledHelper = await import("./single-exe/compiled.js").catch(() => null);
64
- await compiledHelper?.buildEarlyExit?.(process.argv, "my-bin");
65
- ```
66
-
67
- - `--build-exe` builds with no Bun target.
68
- - `--build-for <target>` passes `<target>` to `bun build --target=<target>`.
69
- - The second argument is the output filename. If omitted, it defaults to `single.exe`.
70
-
71
- The main program should also switch its repo/resource root when running as a
72
- compiled binary. Use `IS_COMPILED` and `REPO_ROOT` from
73
- `compiled.js`; when compiled, treat the executable directory as the repo root
74
- used for external fallback files such as `static/`, `README.md`, or other files
75
- packed by `packAssets.sh`.
76
-
77
- ```js
78
- const compiledHelper = await import("./single-exe/compiled.js").catch(() => null);
79
- const repoRoot = compiledHelper?.REPO_ROOT
80
- ```
@@ -12,9 +12,12 @@ const SINGLE_EXE_DIR = resolve(REPO_ROOT, "single-exe");
12
12
  const SINGLE_EXE_ENTRY = resolve(SINGLE_EXE_DIR, "entry.mjs");
13
13
 
14
14
 
15
- export function isCompiledBinary() {
16
- const argv = process.argv
17
- return Boolean(argv?.[1]?.startsWith?.("/$bunfs/"));
15
+ export function isCompiledBinary(argv = process.argv) {
16
+ const entry = argv?.[1];
17
+ return Boolean(
18
+ entry?.startsWith?.("/$bunfs/") ||
19
+ entry?.startsWith?.("B:/~BUN")
20
+ );
18
21
  }
19
22
 
20
23
  export function getExeDirname() {
@@ -3,7 +3,8 @@
3
3
  // 1. Injects assets to global.internalAssets
4
4
  // as { "./path/in/tar":file.bytes() }
5
5
  // 2. Sets global.assetsLoaderPromise
6
- import "./assetsLoader.mjs"
7
-
8
- import "../src/index.js"
6
+ // 3. Starts the main program only after the assets are ready
7
+ import "./assetsLoader.mjs";
9
8
 
9
+ await globalThis.assetsLoaderPromise;
10
+ await import("../src/index.js");
@@ -4,4 +4,4 @@ sd=$(dirname "$0")
4
4
 
5
5
  cd "$sd"/..
6
6
 
7
- tar -cvf single-exe/assets.tar demos runtime README.md CHANGELOG.md src/cui/server.mjs src/cui/rpc.mjs testapp.md
7
+ tar -cvf single-exe/assets.tar demos runtime README.md CHANGELOG.md cdp-maze.js src/cui/server.mjs src/cui/rpc.mjs testapp.md
@@ -1,7 +1,7 @@
1
1
  import { appendFileSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
 
4
- export const KITTY_DEBUG_LOG = resolve(import.meta.dir, "../..", "kitty-placement.log");
4
+ export const KITTY_DEBUG_LOG = resolve(import.meta.dirname, "../..", "kitty-placement.log");
5
5
  export const KITTY_DEBUG_ENABLED = /^(1|true|yes|on)$/i.test(
6
6
  String(process.env.JSMDCUI_KITTY_DEBUG ?? ""),
7
7
  );
package/src/index.js CHANGED
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- let mainPromise = globalThis.assetsLoaderPromise ||
4
- Promise.resolve();
5
-
6
3
  const jsStart = globalThis.Bun ? Bun.nanoseconds() : Date.now() * 1e6;
7
4
  const checkpoints = [
8
5
  { name: "Bun Engine Boot", time: 0 },
@@ -147,7 +144,12 @@ if(!globalThis.Bun)
147
144
  //console.log(process.argv)
148
145
 
149
146
  console.error('Ran by node, changed to run by bun')
150
- process.execve(bunbinary,process.argv,process.env);
147
+ const launched = child_process.spawnSync(bunbinary, process.argv.slice(1), {
148
+ stdio: "inherit",
149
+ env: process.env,
150
+ });
151
+ if (launched.error) throw launched.error;
152
+ process.exit(launched.status ?? 1);
151
153
  }
152
154
  catch(e){
153
155
  console.log(`
@@ -1092,6 +1094,7 @@ function parseArgs(argv) {
1092
1094
  cat: false,
1093
1095
  docs: false,
1094
1096
  exportReadme: false,
1097
+ exportCdpMaze: false,
1095
1098
  changelog: false,
1096
1099
  testapp: false,
1097
1100
  demoList: false,
@@ -1103,6 +1106,7 @@ function parseArgs(argv) {
1103
1106
  debug: false,
1104
1107
  profile: false,
1105
1108
  plugin: "",
1109
+ cdpMaze: false,
1106
1110
  cdpPort: 0,
1107
1111
  cdpAddress: "",
1108
1112
  kittyMode: "off",
@@ -1136,9 +1140,14 @@ function parseArgs(argv) {
1136
1140
  }
1137
1141
  else if (arg === "--docs" || arg === "--readme") flags.docs = true;
1138
1142
  else if (arg === "--export-readme") flags.exportReadme = true;
1143
+ else if (arg === "--export-cdp-maze") flags.exportCdpMaze = true;
1139
1144
  else if (arg === "--changelog") flags.changelog = true;
1140
1145
  else if (arg === "--testapp.md") flags.testapp = true;
1141
1146
  else if (arg === "--demo-list") flags.demoList = true;
1147
+ else if (arg === "--cdp-maze") {
1148
+ flags.cdpMaze = true;
1149
+ flags.demo = { option: arg, filename: "maze.md", asset: "demos/maze.md" };
1150
+ }
1142
1151
  else if (arg === "--demo") {
1143
1152
  flags.demo = { option: arg, filename: "testapp.md", asset: "testapp.md" };
1144
1153
  }
@@ -1178,6 +1187,8 @@ function parseArgs(argv) {
1178
1187
  }
1179
1188
  }
1180
1189
 
1190
+ if (flags.cdpMaze && !flags.cdpPort) flags.cdpPort = 9222;
1191
+
1181
1192
  return { flags, files };
1182
1193
  }
1183
1194
 
@@ -1220,6 +1231,8 @@ Settings:
1220
1231
  List all setting names and defaults, then exit.
1221
1232
 
1222
1233
  CDP:
1234
+ --cdp-maze
1235
+ Open the maze demo, start CDP on localhost:9222, and solve it automatically
1223
1236
  --remote-debugging-port=PORT
1224
1237
  Start CDP (Chrome DevTools Protocol) server on PORT at launch
1225
1238
  --remote-debugging-address=ADDRESS
@@ -1234,6 +1247,8 @@ Information:
1234
1247
  Show ${pkg.name}'s README.md & exit
1235
1248
  --export-readme
1236
1249
  Write or overwrite ./README.md with the bundled README.md & exit
1250
+ --export-cdp-maze
1251
+ Write or overwrite ./cdp-maze.js with the bundled CDP maze solver & exit
1237
1252
  --changelog
1238
1253
  Show CHANGELOG.md & exit
1239
1254
  -profile, --profile
@@ -8003,6 +8018,12 @@ async function exportReadme() {
8003
8018
  console.log(`Wrote ${readmePath}`);
8004
8019
  }
8005
8020
 
8021
+ async function exportCdpMaze() {
8022
+ const outputPath = resolve("cdp-maze.js");
8023
+ await Bun.write(outputPath, await bundledMarkdownSource("cdp-maze.js"));
8024
+ console.log(`Wrote ${outputPath}`);
8025
+ }
8026
+
8006
8027
  async function printChangelogDocs() {
8007
8028
  const changelog = readInternalAssetText("CHANGELOG.md") ?? await Bun.file(join(REPO_ROOT, "CHANGELOG.md")).text();
8008
8029
  process.stdout.write(Bun.markdown.ansi(changelog, { hyperlinks: true }));
@@ -8124,6 +8145,10 @@ async function main() {
8124
8145
  await exportReadme();
8125
8146
  return;
8126
8147
  }
8148
+ if (flags.exportCdpMaze) {
8149
+ await exportCdpMaze();
8150
+ return;
8151
+ }
8127
8152
  if (flags.changelog) {
8128
8153
  await printChangelogDocs();
8129
8154
  return;
@@ -8370,6 +8395,23 @@ async function main() {
8370
8395
  if (flags.cdpAddress) cdpArgs.push(`--address=${flags.cdpAddress}`);
8371
8396
  await app.handleCommand(`cdp ${cdpArgs.join(" ")}`);
8372
8397
  }
8398
+
8399
+ if (flags.cdpMaze) {
8400
+ const solverHost = !flags.cdpAddress || flags.cdpAddress === "0.0.0.0"
8401
+ ? "127.0.0.1"
8402
+ : flags.cdpAddress;
8403
+ const solverUrl = `ws://${solverHost}:${flags.cdpPort}/devtools/browser/cdp-server`;
8404
+ setTimeout(async () => {
8405
+ try {
8406
+ const { runCdpMaze } = await import("../cdp-maze.js");
8407
+ app.message = await runCdpMaze(solverUrl);
8408
+ app.render?.();
8409
+ } catch (error) {
8410
+ app.message = `CDP maze solver failed: ${error?.message || error}`;
8411
+ app.render?.();
8412
+ }
8413
+ }, 3000);
8414
+ }
8373
8415
 
8374
8416
  if (flags.profile) {
8375
8417
  addCheckpoint("Clipboard Probing");
@@ -8837,9 +8879,6 @@ async function catFiles(files, colorscheme, syntaxDefinitions, encoding = DEFAUL
8837
8879
  }
8838
8880
 
8839
8881
 
8840
- mainPromise.then(r=>{
8841
-
8842
-
8843
8882
  main().catch((error) => {
8844
8883
  try {
8845
8884
  (_activeTtyStream ?? process.stdin).setRawMode?.(false);
@@ -8849,6 +8888,3 @@ main().catch((error) => {
8849
8888
  process.exit(1);
8850
8889
  }
8851
8890
  });
8852
-
8853
-
8854
- })
package/src/lua/engine.js CHANGED
@@ -2,7 +2,6 @@ import { existsSync } from "node:fs";
2
2
  import { readInternalAssetBytes } from "../runtime/assets.js";
3
3
  import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
- import { isCompiledBinary, resolveCompiledBaseDir } from "../runtime/compiled.js";
6
5
  import { REPO_ROOT } from "../../single-exe/compiled.js";
7
6
 
8
7
  export async function createLuaEngine() {
@@ -44,9 +43,7 @@ async function resolveLuaWasmLocation() {
44
43
  }
45
44
  }
46
45
 
47
- const fallbackPath = isCompiledBinary(process.argv)
48
- ? join(resolveCompiledBaseDir({ argv: process.argv }), wasmAssetPath)
49
- : join(REPO_ROOT, wasmAssetPath);
46
+ const fallbackPath = join(REPO_ROOT, wasmAssetPath);
50
47
 
51
48
  return existsSync(fallbackPath) ? fallbackPath : undefined;
52
49
  }