jsmdcui 0.11.2 → 0.12.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,53 @@
2
2
 
3
3
  All notable user-visible changes to jsmdcui are documented here.
4
4
 
5
+ ## [0.12.0] - 2026-07-27
6
+
7
+ This release makes Markdown images embedded by Bun's HTML bundler available to
8
+ the compiled terminal UI, adds environment-controlled Kitty rendering, and
9
+ consolidates the reusable single-executable asset helpers.
10
+
11
+ ### Added
12
+
13
+ - Add `JSMDCUI_KITTY_MODE=off|compat|extended` as an environment-controlled
14
+ alternative to the Kitty command-line flags. Explicit `--kitty` and
15
+ `--kitty-compat` arguments continue to take precedence.
16
+ - Preserve each generated WUI image source in `data-mdcui-src`. Bun can rewrite
17
+ the normal `src` to its content-hashed public asset path while the original
18
+ Markdown reference remains available for TUI lookup.
19
+ - Add reusable HTML bundle helpers to `single-exe/assetsHelper.js`. They match
20
+ compiled public image paths to `homepage.files`, canonicalize HTML entities
21
+ and percent-encoded image references, and build a Markdown-reference-to-bunfs
22
+ image map from `homepage.index`.
23
+ - Export the bundled `homepage` from generated Markdown server modules so a
24
+ compiled TUI can inspect the same HTML asset manifest without starting the
25
+ WUI server.
26
+
27
+ ### Changed
28
+
29
+ - Reuse images already embedded by Bun's HTML bundler instead of copying a
30
+ second image archive into the executable. The compiled TUI builds the image
31
+ path map once on first Kitty use, caches it, and reads image bytes lazily from
32
+ Bun's compiled virtual filesystem (`/$bunfs/root/...` on POSIX systems or
33
+ `B:/~BUN/...` on Windows).
34
+ - Load the bundled homepage only when running a compiled executable with
35
+ `global.MDCUI_MAIN` configured. Source-tree launches retain the existing
36
+ filesystem and authorized HTTP image fallbacks without importing a generated
37
+ server module.
38
+ - Consolidate runtime asset access on `single-exe/assetsHelper.js` and remove
39
+ the duplicate `src/runtime/assets.js` implementation.
40
+
41
+ ### Fixed
42
+
43
+ - Match compiled Markdown images independently of Bun's build-entry-relative
44
+ `homepage.files[].input` paths. This fixes images whose Markdown-relative
45
+ path and bundle-entry-relative path have different spellings.
46
+ - Normalize bare `process.env.JSMDCUI_KITTY_MODE=compat` build definitions into
47
+ JavaScript string literals before forwarding them to `bun build`.
48
+ - Use the global `process` binding for Kitty-mode build constants, allowing Bun
49
+ to replace `process.env.JSMDCUI_KITTY_MODE` at build time instead of missing
50
+ an imported and renamed `node:process` binding.
51
+
5
52
  ## [0.11.2] - 2026-07-26
6
53
 
7
54
  ### Added
package/README.md CHANGED
@@ -153,6 +153,7 @@ bun src/index.js --wui testapp.md
153
153
  | `bun src/index.js app.md` | Render `app.md` as a read-only terminal UI and write five generated files beside it. |
154
154
  | `bun src/index.js --kitty app.md` | Display Markdown images with Kitty graphics and the jsgotty MIME extension. |
155
155
  | `bun src/index.js --kitty-compat app.md` | Convert Markdown images to PNG with `Bun.Image` and display them using the standard Kitty graphics protocol without the non-standard MIME `U` field. |
156
+ | `JSMDCUI_KITTY_MODE=compat bun src/index.js app.md` | Enable `compat` or `extended` Kitty mode without passing a Kitty command-line flag; the default and invalid values are `off`. |
156
157
  | `bun src/index.js --kitty --allow-url URL.md` | Download trusted HTTP(S) Markdown and its HTTP(S) images, then display supported images with Kitty graphics. |
157
158
  | `JSMDCUI_KITTY_DEBUG=1 bun src/index.js --kitty app.md` | Enable Kitty image placement logging to `kitty-placement.log`. |
158
159
  | `bun src/index.js --check app.md` | Check heading and fenced-block IDs for collisions, print line-by-line details, and exit. |
@@ -576,6 +577,36 @@ supported HTTP(S) images with Kitty graphics, combine the options:
576
577
  bun src/index.js --kitty --allow-url https://example.com/app.md
577
578
  ```
578
579
 
580
+ Images referenced by an app built with `--build-md-exe` are also available to
581
+ the compiled TUI. Bun embeds them through the generated WUI HTML bundle;
582
+ jsmdcui preserves the original Markdown reference, maps it to Bun's
583
+ content-hashed compiled asset (`/$bunfs/root/...` on POSIX systems or
584
+ `B:/~BUN/...` on Windows), and reads the image lazily when Kitty rendering
585
+ needs it. The executable does not need a second copy in the tar asset archive;
586
+ the runtime uses the path reported by Bun rather than assuming either platform
587
+ prefix.
588
+
589
+ To make a no-argument compiled app enable standard Kitty-compatible rendering
590
+ immediately, inline the environment-mode value at build time:
591
+
592
+ ```sh
593
+ npx jsmdcui --build-md-exe myapp.md \
594
+ --define process.env.JSMDCUI_KITTY_MODE=compat
595
+ ```
596
+
597
+ For the jsgotty MIME extension, use `extended` instead:
598
+
599
+ ```sh
600
+ npx jsmdcui --build-md-exe myapp.md \
601
+ --define process.env.JSMDCUI_KITTY_MODE=extended
602
+ ```
603
+
604
+ The jsmdcui build wrapper quotes these bare string values before forwarding
605
+ them to Bun. At the call site, `process` must be the Node/Bun global. Do not
606
+ write `import process from "node:process"`: Bun renames that imported binding
607
+ during bundling, so a define targeting `process.env.JSMDCUI_KITTY_MODE` cannot
608
+ match and inline it.
609
+
579
610
  ### CDP control for TUI automation
580
611
 
581
612
  The terminal UI can expose a Chrome DevTools Protocol (CDP) server, so another
@@ -783,6 +814,10 @@ npx jsmdcui --build-md-exe myapp.md
783
814
 
784
815
  This is a convenience alias for
785
816
  `--build-exe --define global.MDCUI_MAIN=myapp.md`.
817
+ The generated HTML images are embedded by Bun and can be displayed by the
818
+ compiled TUI. Add
819
+ `--define process.env.JSMDCUI_KITTY_MODE=compat` after the Markdown path when
820
+ the executable should enable Kitty-compatible images on a no-argument launch.
786
821
 
787
822
  For cross-compilation, specify the Bun target before the Markdown file:
788
823
 
@@ -791,7 +826,7 @@ npx jsmdcui --build-md-for bun-linux-x64-v1.3.14 myapp.md
791
826
  ```
792
827
 
793
828
  This similarly expands to
794
- `--build-for bun-linux-x64 --define global.MDCUI_MAIN=myapp.md`. Both aliases
829
+ `--build-for bun-linux-x64-v1.3.14 --define global.MDCUI_MAIN=myapp.md`. Both aliases
795
830
  are expanded before any generated application files are written.
796
831
 
797
832
  Place every build define after `--build-exe`, or after the target argument of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsmdcui",
3
- "version": "0.11.2",
3
+ "version": "0.12.0",
4
4
  "description": "Markdown as a Common UI for Terminals and Web Browsers",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/runmd.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import path from 'node:path'
4
4
  import { pathToFileURL } from 'node:url'
5
- import { readInternalAssetText } from './src/runtime/assets.js'
5
+ import { readInternalAssetText } from './single-exe/assetsHelper.js'
6
6
  import { fenceEventMap } from './src/cui/fence-events.mjs'
7
7
  import { REPO_ROOT } from './single-exe/compiled.js'
8
8
 
@@ -470,7 +470,8 @@ ${moduleScript}
470
470
  md += `\n${moduleScript}\n`;
471
471
  }
472
472
  }
473
-
473
+
474
+ md = annotateWuiImageSources(md)
474
475
 
475
476
  await Bun.write(mdpath+".html",md)
476
477
  logWroteFile("html", mdpath+".html")
@@ -478,6 +479,17 @@ ${moduleScript}
478
479
  return md;
479
480
  }
480
481
 
482
+ function annotateWuiImageSources(html)
483
+ {
484
+ return String(html).replace(/<img\b[^>]*>/gi, tag => {
485
+ if (/\bdata-mdcui-src\s*=/i.test(tag)) return tag
486
+ const src = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i)
487
+ if (!src) return tag
488
+ const attribute = ` data-mdcui-src=${src[1]}${src[2]}${src[1]}`
489
+ return tag.replace(/\s*\/?>$/, ending => `${attribute}${ending}`)
490
+ })
491
+ }
492
+
481
493
  export function charFromPoint(tui,row,col)
482
494
  {
483
495
  tui = tui.split('\n')[row-1] || ""
@@ -153,6 +153,7 @@ bun src/index.js --wui testapp.md
153
153
  | `bun src/index.js app.md` | Render `app.md` as a read-only terminal UI and write five generated files beside it. |
154
154
  | `bun src/index.js --kitty app.md` | Display Markdown images with Kitty graphics and the jsgotty MIME extension. |
155
155
  | `bun src/index.js --kitty-compat app.md` | Convert Markdown images to PNG with `Bun.Image` and display them using the standard Kitty graphics protocol without the non-standard MIME `U` field. |
156
+ | `JSMDCUI_KITTY_MODE=compat bun src/index.js app.md` | Enable `compat` or `extended` Kitty mode without passing a Kitty command-line flag; the default and invalid values are `off`. |
156
157
  | `bun src/index.js --kitty --allow-url URL.md` | Download trusted HTTP(S) Markdown and its HTTP(S) images, then display supported images with Kitty graphics. |
157
158
  | `JSMDCUI_KITTY_DEBUG=1 bun src/index.js --kitty app.md` | Enable Kitty image placement logging to `kitty-placement.log`. |
158
159
  | `bun src/index.js --check app.md` | Check heading and fenced-block IDs for collisions, print line-by-line details, and exit. |
@@ -791,7 +792,7 @@ npx jsmdcui --build-md-for bun-linux-x64-v1.3.14 myapp.md
791
792
  ```
792
793
 
793
794
  This similarly expands to
794
- `--build-for bun-linux-x64 --define global.MDCUI_MAIN=myapp.md`. Both aliases
795
+ `--build-for bun-linux-x64-v1.3.14 --define global.MDCUI_MAIN=myapp.md`. Both aliases
795
796
  are expanded before any generated application files are written.
796
797
 
797
798
  Place every build define after `--build-exe`, or after the target argument of
@@ -44,8 +44,15 @@ need quotes. `stringifyNonPrimitiveDefineValues()` converts a bare value with
44
44
  `JSON.stringify()` before it reaches Bun. jsmdcui uses it for
45
45
  `global.MDCUI_MAIN`.
46
46
 
47
- The switch defines below are presence-based: `=0` and `=false` still enable
48
- them. Omit a switch define to disable it; examples consistently use `=1`.
47
+ `global.MDCUI_MAIN` is a jsmdcui application convention, not a name reserved by
48
+ the single-executable helpers. An adopting project can use
49
+ `global.MY_EMBEDDED_APP`, or any other build expression, as long as it updates
50
+ its own call sites and passes the same name to
51
+ `stringifyNonPrimitiveDefineValues()`.
52
+
53
+ The jsmdcui switch defines below are presence-based: `=0` and `=false` still
54
+ enable them. Omit a switch define to disable it; examples consistently use
55
+ `=1`.
49
56
 
50
57
  - `MDCUI_DEFAULT_EDIT=1`: editable-text default.
51
58
  - `MDCUI_DEFAULT_DEMO=1`: no-argument `testapp.md` TUI.
@@ -209,6 +216,111 @@ a resource should be returned as bytes instead of decoded text.
209
216
  Use `listInternalAssetPaths()` to list embedded asset paths and
210
217
  `listInternalAssetDirs()` to list embedded directories.
211
218
 
219
+ #### Reuse images from a compiled HTML bundle
220
+
221
+ Bun exposes an imported HTML entry as a `homepage` object in a compiled
222
+ executable. Its `index` points to the compiled HTML and its `files` array lists
223
+ the content-hashed assets under Bun's compiled virtual filesystem: paths
224
+ normally begin with `/$bunfs/root/` on POSIX systems and `B:/~BUN/` on
225
+ Windows. The helpers can turn image references preserved in that HTML into a
226
+ lazy path map without copying the image bytes into `internalAssets`. Always use
227
+ the path returned by `homepage.files`; do not hard-code either platform prefix.
228
+
229
+ Before compiling, preserve each original image reference in a custom
230
+ attribute. Its name belongs to the adopting project; it is not fixed by the
231
+ helper. This example chooses `data-original-image`. Bun rewrites `src` but
232
+ leaves the custom attribute intact:
233
+
234
+ ```html
235
+ <!-- Input -->
236
+ <img src="./images/photo.jpg" data-original-image="./images/photo.jpg">
237
+
238
+ <!-- Compiled HTML -->
239
+ <img src="/photo-abcd1234.jpg" data-original-image="./images/photo.jpg">
240
+ ```
241
+
242
+ Export the imported HTML bundle from a module that both the web server and
243
+ terminal runtime can load:
244
+
245
+ ```js
246
+ import homepage from "./index.html";
247
+
248
+ export { homepage };
249
+ ```
250
+
251
+ Build and cache the map only in a compiled executable. Guard the import first:
252
+ a source-tree launch does not necessarily have the generated server or HTML
253
+ module.
254
+
255
+ ```js
256
+ import {
257
+ buildHtmlBundleImageMap,
258
+ canonicalHtmlBundleImageHref,
259
+ } from "../single-exe/assetsHelper.js";
260
+ import { IS_COMPILED } from "../single-exe/compiled.js";
261
+
262
+ let imageMapPromise = null;
263
+ const imageSourceAttribute = "data-original-image";
264
+
265
+ function getBundledImageMap() {
266
+ if (!IS_COMPILED || !global.MY_EMBEDDED_APP) return null;
267
+
268
+ imageMapPromise ??= import(global.MY_EMBEDDED_APP + "-server.js")
269
+ .then(module => buildHtmlBundleImageMap(
270
+ module.homepage,
271
+ imageSourceAttribute,
272
+ ));
273
+
274
+ return imageMapPromise;
275
+ }
276
+
277
+ const images = await getBundledImageMap();
278
+ const key = canonicalHtmlBundleImageHref(originalImageHref);
279
+ const bundledPath = images?.get(key);
280
+ const bytes = bundledPath ? await Bun.file(bundledPath).bytes() : null;
281
+ ```
282
+
283
+ `global.MY_EMBEDDED_APP` is only an example build-time module selector. Name it
284
+ to match the adopting application, replace it with a direct static import, or
285
+ use another compiled-only condition. The helper does not inspect or require
286
+ `global.MDCUI_MAIN`; that is jsmdcui's own convention. When using a Bun
287
+ `--define`, use the same expression at the call site, for example
288
+ `--define global.MY_EMBEDDED_APP=...`.
289
+
290
+ `buildHtmlBundleImageMap(homepage, sourceAttribute)` reads the compiled HTML
291
+ once and returns a `Map<string, string>` from canonical original image
292
+ references to Bun compiled virtual paths on either platform. The second
293
+ argument is the custom attribute name. It defaults to `"data-mdcui-src"` only
294
+ for jsmdcui's convenience:
295
+
296
+ ```js
297
+ const images = await buildHtmlBundleImageMap(homepage);
298
+ ```
299
+
300
+ Adopting projects can choose any valid HTML attribute name and pass it
301
+ explicitly:
302
+
303
+ ```html
304
+ <img src="./photo.jpg" data-original-image="./photo.jpg">
305
+ ```
306
+
307
+ ```js
308
+ const images = await buildHtmlBundleImageMap(
309
+ homepage,
310
+ "data-original-image",
311
+ );
312
+ ```
313
+
314
+ The helper decodes HTML attribute entities and percent encoding so the HTML
315
+ reference can match the equivalent original caller reference. Image bytes
316
+ remain lazy and are read only when the caller uses the returned path.
317
+
318
+ For lower-level lookup, `findHtmlBundleAsset(homepage, publicPath, options)`
319
+ matches a rewritten public path such as `/photo-abcd1234.jpg` to its
320
+ `homepage.files` entry. `findHtmlBundleImageAsset()` restricts the lookup to
321
+ `image/*`, and `htmlBundleImageAssetPath()` returns only the corresponding
322
+ Bun compiled virtual path.
323
+
212
324
  ### 5. Add the optional build commands to the regular CLI
213
325
 
214
326
  Before normal argument parsing, call `buildEarlyExit` from the regular main
@@ -1,3 +1,5 @@
1
+ import { posix } from "node:path";
2
+
1
3
  const textDecoder = new TextDecoder();
2
4
  const textEncoder = new TextEncoder();
3
5
 
@@ -12,6 +14,87 @@ export function assetPath(...parts) {
12
14
  .join("/");
13
15
  }
14
16
 
17
+ export function decodeHtmlAttribute(value) {
18
+ return String(value ?? "").replace(
19
+ /&(?:amp|quot|apos|lt|gt|#39|#x27|#\d+|#x[\da-f]+);/gi,
20
+ (entity) => {
21
+ const named = {
22
+ "&amp;": "&",
23
+ "&quot;": "\"",
24
+ "&apos;": "'",
25
+ "&lt;": "<",
26
+ "&gt;": ">",
27
+ "&#39;": "'",
28
+ "&#x27;": "'",
29
+ }[entity.toLowerCase()];
30
+ if (named != null) return named;
31
+ const hex = /^&#x([\da-f]+);$/i.exec(entity);
32
+ const decimal = /^&#(\d+);$/.exec(entity);
33
+ const codePoint = Number.parseInt(hex?.[1] ?? decimal?.[1] ?? "", hex ? 16 : 10);
34
+ try {
35
+ return Number.isInteger(codePoint) ? String.fromCodePoint(codePoint) : entity;
36
+ } catch {
37
+ return entity;
38
+ }
39
+ },
40
+ );
41
+ }
42
+
43
+ export function canonicalHtmlBundleImageHref(input, { htmlAttribute = false } = {}) {
44
+ let value = String(input ?? "");
45
+ if (htmlAttribute) value = decodeHtmlAttribute(value);
46
+ try {
47
+ return decodeURIComponent(value);
48
+ } catch {
49
+ return value;
50
+ }
51
+ }
52
+
53
+ export function findHtmlBundleAsset(homepage, publicPath, {
54
+ contentTypePrefix = "",
55
+ } = {}) {
56
+ if (!Array.isArray(homepage?.files)) return null;
57
+ const name = posix.basename(String(publicPath ?? "").replace(/[?#].*$/, ""));
58
+ for (const file of homepage.files) {
59
+ if (file?.loader !== "file") continue;
60
+ const contentType = String(file.headers?.["content-type"] ?? "");
61
+ if (contentTypePrefix && !contentType.startsWith(contentTypePrefix)) continue;
62
+ if (posix.basename(String(file.path ?? "")) === name) return file;
63
+ }
64
+ return null;
65
+ }
66
+
67
+ export function findHtmlBundleImageAsset(homepage, publicPath) {
68
+ return findHtmlBundleAsset(homepage, publicPath, {
69
+ contentTypePrefix: "image/",
70
+ });
71
+ }
72
+
73
+ export function htmlBundleImageAssetPath(homepage, publicPath) {
74
+ return findHtmlBundleImageAsset(homepage, publicPath)?.path ?? null;
75
+ }
76
+
77
+ export async function buildHtmlBundleImageMap(
78
+ homepage,
79
+ sourceAttribute = "data-mdcui-src",
80
+ ) {
81
+ const images = new Map();
82
+ if (!homepage?.index || !Array.isArray(homepage.files)) return images;
83
+ const html = await Bun.file(homepage.index).text();
84
+ for (const tag of html.match(/<img\b[^>]*>/gi) ?? []) {
85
+ const rawHref = htmlTagAttribute(tag, sourceAttribute);
86
+ const publicPath = htmlTagAttribute(tag, "src");
87
+ if (rawHref == null || publicPath == null) continue;
88
+ const bundledPath = htmlBundleImageAssetPath(homepage, decodeHtmlAttribute(publicPath));
89
+ if (!bundledPath) continue;
90
+ images.set(
91
+ canonicalHtmlBundleImageHref(rawHref, { htmlAttribute: true }),
92
+ bundledPath,
93
+ );
94
+ }
95
+ return images;
96
+ }
97
+
15
98
  export function listInternalAssetPaths(prefix = "") {
16
99
  const store = getAssetStore();
17
100
  if (!store) return [];
@@ -88,3 +171,9 @@ function iterateAssetKeys(store) {
88
171
  if (store instanceof Map) return [...store.keys()].map(String);
89
172
  return Object.keys(store);
90
173
  }
174
+
175
+ function htmlTagAttribute(tag, name) {
176
+ const escapedName = String(name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
177
+ const match = String(tag).match(new RegExp(`\\b${escapedName}\\s*=\\s*([\"'])(.*?)\\1`, "i"));
178
+ return match?.[2] ?? null;
179
+ }
@@ -2,6 +2,7 @@ import { dirname, resolve } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { logKittyPlacement } from "./kitty-debug.mjs";
4
4
  import { fetchHttpBytes as defaultFetchHttpBytes } from "../platform/commands.js";
5
+ import { canonicalHtmlBundleImageHref } from "../../single-exe/assetsHelper.js";
5
6
 
6
7
  const PNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
7
8
 
@@ -63,8 +64,8 @@ function imageSize(buffer) {
63
64
  }
64
65
  const svg = buffer.subarray(0, Math.min(buffer.length, 8192)).toString("utf8");
65
66
  if (svg.includes("<svg")) {
66
- const width = svg.match(/\bwidth=["']([0-9.]+)(?:px)?["']/i);
67
- const height = svg.match(/\bheight=["']([0-9.]+)(?:px)?["']/i);
67
+ const width = svg.match(/\bwidth=["']([0-9.]+)(?:px)?["']/i); //'
68
+ const height = svg.match(/\bheight=["']([0-9.]+)(?:px)?["']/i); //'
68
69
  if (width && height) {
69
70
  return { mime: "image/svg+xml", width: Math.round(Number(width[1])), height: Math.round(Number(height[1])) };
70
71
  }
@@ -136,11 +137,17 @@ export async function prepareKittyImages(ansiText, markdownPath, terminalCols =
136
137
  const images = [];
137
138
  const maxCols = Math.max(1, Math.trunc(Number(terminalCols) || 80));
138
139
  const oscImage = /\x1b\]8;;([^\x1b]*)\x1b\\(?=[^\n]*📷)/;
140
+ const bundledImages = await options.getBundledImageMap?.() ?? null;
139
141
 
140
142
  for (let sourceLine = 0; sourceLine < inputLines.length; sourceLine++) {
141
143
  const line = inputLines[sourceLine];
142
144
  const match = line.match(oscImage);
143
- const source = match ? imageSource(match[1], markdownPath, options.allowUrl === true) : null;
145
+ const bundledPath = match
146
+ ? bundledImages?.get(canonicalHtmlBundleImageHref(match[1]))
147
+ : null;
148
+ const source = bundledPath
149
+ ? { kind: "bundled", value: bundledPath }
150
+ : match ? imageSource(match[1], markdownPath, options.allowUrl === true) : null;
144
151
  if (!source) {
145
152
  outputLines.push(line);
146
153
  continue;
@@ -0,0 +1,6 @@
1
+ const KITTY_MODES = new Set(["off", "compat", "extended"]);
2
+
3
+ export function kittyModeFromEnvironment(input) {
4
+ const value = String(input ?? "").trim().toLowerCase();
5
+ return KITTY_MODES.has(value) ? value : "off";
6
+ }
@@ -9,6 +9,7 @@ const mda = Bun.markdown.ansi
9
9
  import homepage from "./testapp.md.html"
10
10
  import * as backmod from "./testapp.md.back.js";
11
11
 
12
+ export { homepage };
12
13
 
13
14
  /*
14
15
  // Wait until Bun fixes dynamic html import bundle
package/src/index.js CHANGED
@@ -94,17 +94,17 @@ import { accessSync, closeSync, constants, existsSync, openSync, readSync, readd
94
94
  import { mkdir } from "node:fs/promises";
95
95
  import { dirname, basename, join, resolve, sep } from "node:path";
96
96
  import { fileURLToPath, pathToFileURL } from "node:url";
97
- import process from "node:process";
98
97
  import { toggleTaskCheckboxBeforeColumn, updateAnsiTaskCheckbox } from "./cui/task-checkbox.mjs";
99
98
  import { fenceEventMap, inlineFenceEventCode } from "./cui/fence-events.mjs";
100
99
  import { checkMarkdownIdCollisions, formatMarkdownIdCheckAnsi } from "./cui/id-collision.mjs";
101
100
  import { fitKittyImageToWidth, prepareKittyImages } from "./cui/kitty-images.mjs";
101
+ import { kittyModeFromEnvironment } from "./cui/kitty-mode.mjs";
102
102
  import { logKittyPlacement } from "./cui/kitty-debug.mjs";
103
103
  import { Config } from "./config/config.js";
104
104
  import { defaultAllSettings, OPTION_CHOICES, LOCAL_SETTINGS } from "./config/defaults.js";
105
105
  import { cleanConfig } from "./config/clean.js";
106
106
  import { RuntimeRegistry, RTColorscheme, RTHelp } from "./runtime/registry.js";
107
- import { assetPath, hasInternalAssets, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetText } from "./runtime/assets.js";
107
+ import { assetPath, buildHtmlBundleImageMap, hasInternalAssets, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetText } from "../single-exe/assetsHelper.js";
108
108
  //import { PluginManager } from "./plugins/manager.js";
109
109
  import { JsPluginManager, buildMicroGlobal, buildTuiBlockIndex, findTuiBlockInIndex, insertTuiTextareaNewline, mergeTuiTextareaBackward, mergeTuiTextareaForward, runAction, listActions } from "./plugins/js-bridge.js";
110
110
  import { Colorscheme } from "./config/colorscheme.js";
@@ -124,6 +124,7 @@ import { writeBackup, removeBackup, applyBackup } from "./buffer/backup.js";
124
124
  let kittyImageMode = "off";
125
125
  let allowRemoteKittyImages = false;
126
126
  const remoteMarkdownSources = new Map();
127
+ let bundledImageMapPromise = null;
127
128
  import { isHex3Encoding, isMdcuiEncoding } from "./runtime/encodings.js";
128
129
  import { createInterface } from "node:readline/promises";
129
130
 
@@ -135,6 +136,13 @@ import { expandBuildMdAliases } from "./build-args.js";
135
136
  const __filename = fileURLToPath(import.meta.url);
136
137
  const __dirname = dirname(__filename);
137
138
 
139
+ function getBundledImageMap() {
140
+ if (!IS_COMPILED || !global.MDCUI_MAIN) return null;
141
+ bundledImageMapPromise ??= import(global.MDCUI_MAIN + "-server.js")
142
+ .then((module) => buildHtmlBundleImageMap(module.homepage));
143
+ return bundledImageMapPromise;
144
+ }
145
+
138
146
 
139
147
  if(!globalThis.Bun)
140
148
  {
@@ -380,6 +388,7 @@ async function renderMdcui(markdown, width = process.stdout.columns || 80, mdpat
380
388
  : await prepareKittyImages(tui, resolvedImageBasePath, width, {
381
389
  allowUrl: allowRemoteKittyImages,
382
390
  kittyMode: kittyImageMode,
391
+ getBundledImageMap,
383
392
  });
384
393
  return {
385
394
  rendered: prepared.rendered,
@@ -1119,7 +1128,7 @@ function parseArgs(argv) {
1119
1128
  cdpMaze: false,
1120
1129
  cdpPort: 0,
1121
1130
  cdpAddress: "",
1122
- kittyMode: "off",
1131
+ kittyMode: kittyModeFromEnvironment(process.env.JSMDCUI_KITTY_MODE),
1123
1132
  settings: new Map(),
1124
1133
  };
1125
1134
  const files = [];
@@ -1269,6 +1278,9 @@ Modes:
1269
1278
  Display Markdown images with Kitty graphics and the jsgotty MIME extension
1270
1279
  --kitty-compat
1271
1280
  Display Markdown images with Kitty graphics without the non-standard MIME U field
1281
+
1282
+ JSMDCUI_KITTY_MODE=off|compat|extended
1283
+ Set the Kitty image mode without command-line flags; explicit Kitty flags override it
1272
1284
 
1273
1285
  --edit
1274
1286
  Open files as editable UTF-8 text
@@ -8265,6 +8277,7 @@ async function main() {
8265
8277
  addCheckpoint("Argument Parsing");
8266
8278
 
8267
8279
  expandBuildMdAliases(process.argv);
8280
+ stringifyNonPrimitiveDefineValues(process.argv, "process.env.JSMDCUI_KITTY_MODE");
8268
8281
  stringifyNonPrimitiveDefineValues(process.argv, "global.MDCUI_MAIN");
8269
8282
  const argvMdcuiMain = stringDefineFromArgv(
8270
8283
  process.argv,
package/src/lua/engine.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
- import { readInternalAssetBytes } from "../runtime/assets.js";
2
+ import { readInternalAssetBytes } from "../../single-exe/assetsHelper.js";
3
3
  import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import { REPO_ROOT } from "../../single-exe/compiled.js";
@@ -3,7 +3,7 @@ import { readdir } from "node:fs/promises";
3
3
  import { dirname, join, basename, extname } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { tmpdir } from "node:os";
6
- import { assetPath, hasInternalAssets, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetBytes } from "../runtime/assets.js";
6
+ import { assetPath, hasInternalAssets, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetBytes } from "../../single-exe/assetsHelper.js";
7
7
  import { isMdcuiEncoding } from "../runtime/encodings.js";
8
8
  import { newMessage, newMessageAtLine, MTError, MTWarning, MTInfo } from "../buffer/message.js";
9
9
  import { Loc } from "../buffer/loc.js";
@@ -4,7 +4,7 @@ import { basename, dirname, extname, join, sep } from "node:path";
4
4
  import { fetchHttp, downloadFile } from "../platform/commands.js";
5
5
  import { extractAndStrip } from "../platform/archive.js";
6
6
  import { createLuaEngine } from "../lua/engine.js";
7
- import { assetPath, hasInternalAssets, internalAssetSource, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetText } from "../runtime/assets.js";
7
+ import { assetPath, hasInternalAssets, internalAssetSource, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetText } from "../../single-exe/assetsHelper.js";
8
8
  import { execCommand, runBackgroundShell, runCommand } from "../shell/shell.js";
9
9
  import { Loc } from "../buffer/loc.js";
10
10
  import { BTDefault, BTHelp, BTInfo, BTLog, BTRaw, BTScratch, byteOffset, BufferCore } from "../buffer/buffer.js";
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { readdir, readFile } from "node:fs/promises";
3
3
  import { basename, extname, join } from "node:path";
4
- import { assetPath, hasInternalAssets, listInternalAssetPaths, readInternalAssetBytes } from "./assets.js";
4
+ import { assetPath, hasInternalAssets, listInternalAssetPaths, readInternalAssetBytes } from "../../single-exe/assetsHelper.js";
5
5
 
6
6
  export const RTColorscheme = 0;
7
7
  export const RTSyntax = 1;