jsmdcui 0.10.1 → 0.11.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,62 @@
2
2
 
3
3
  All notable user-visible changes to jsmdcui are documented here.
4
4
 
5
+ ## [0.11.1] - 2026-07-26
6
+
7
+ ### Changed
8
+
9
+ - Accept a bare `global.MDCUI_MAIN` path in forwarded build arguments by
10
+ automatically encoding non-primitive define values as JavaScript strings.
11
+
12
+ ## [0.11.0] - 2026-07-26
13
+
14
+ This release adds custom Markdown-app embedding for Bun single-file
15
+ executables, with explicit per-buffer selection between embedded and
16
+ filesystem modules in both TUI and WUI.
17
+
18
+ ### Added
19
+
20
+ - Add the build-time `global.MDCUI_MAIN` string define for embedding a custom
21
+ Markdown app together with its generated front, RPC, back, HTML, and server
22
+ modules. Build preparation resolves and validates the source, copies it into
23
+ the bundled demos, derives `global.MDCUI_MAIN_BASE`, and selects the app on a
24
+ no-argument launch.
25
+ - Add a bundling mode to `extractJs()` and `createWui()`. It emits a
26
+ browser-only `.tmpfs.js` front module and a `.tmpfi.js` installer that exposes
27
+ the front exports on `window`, then makes the bundled HTML load that entry.
28
+ - Add embedded WUI server startup and report whether WUI is starting an
29
+ embedded or external server before launch.
30
+ - Add `micro.CurPane().Buf.MdcuiModuleSource`, returning `embedded` or
31
+ `external`, and show the value in the bundled `showpath` example.
32
+ - Allow Unicode letters and numbers, including Chinese, in custom demo names
33
+ while continuing to reject whitespace and path separators.
34
+ - Show `global.MDCUI_MAIN` and the generated `global.MDCUI_MAIN_BASE` in
35
+ `--version` distribution settings.
36
+
37
+ ### Changed
38
+
39
+ - Track embedded-module selection per buffer. The configured demo uses
40
+ embedded TUI front/RPC and WUI server modules when its local byte length
41
+ matches the bundled Markdown. Missing or overwritten copies are written
42
+ first and then use embedded modules; other files and changed-size demos use
43
+ filesystem companions.
44
+ - Document presence-based `MDCUI_*` defines with `=1`, supported build-flag
45
+ combinations, and commands for switching a TUI-default build to WUI or a
46
+ WUI-default build to TUI.
47
+
48
+ ### Fixed
49
+
50
+ - Bundle and load the configured app's front, RPC, back, server, and dependency
51
+ graph so custom apps with companion imports can run from a single
52
+ executable.
53
+ - Keep unrelated Markdown buffers on external modules instead of reusing the
54
+ embedded main app's front and RPC modules.
55
+ - Use the bundled file's byte length after `MDCUI_OVERWRITE_DEMO` replaces a
56
+ stale local demo, ensuring that the overwritten app selects embedded
57
+ modules.
58
+ - Install WUI front exports on `window` without relying on the generated front
59
+ module's process-dependent or self-import path.
60
+
5
61
  ## [0.10.1] - 2026-07-25
6
62
 
7
63
  ### Fixed
package/README.md CHANGED
@@ -757,54 +757,94 @@ both are equivalent to `-encoding mdcui`.
757
757
 
758
758
  ### Build-time distribution constants
759
759
 
760
- Single-file distributions can define one of these default modes:
760
+ The following switch defines are presence-based: the program checks whether
761
+ they were passed, not whether their values are true. Consequently, `=0` and
762
+ `=false` still enable a switch. Omit a define entirely to disable it. Examples
763
+ use `=1` to make this explicit.
764
+
765
+ - `MDCUI_DEFAULT_EDIT=1`: open files as editable text by default.
766
+ - `MDCUI_DEFAULT_DEMO=1`: add `--demo` when launched without arguments.
767
+ - `MDCUI_DEFAULT_DEMO_WUI=1`: add `--wui` when launched without arguments.
768
+ - `MDCUI_OVERWRITE_DEMO=1`: add `--overwrite-demo`; this modifies a selected
769
+ demo but does not select one by itself.
770
+ - `global.MDCUI_MAIN=<path>.md`: embed a custom Markdown application and its
771
+ generated front, RPC, back, HTML, and server modules. When this define is
772
+ forwarded after `--build-exe` or `--build-for`, a non-primitive value such as
773
+ a bare path is automatically encoded as a JavaScript string. An explicitly
774
+ quoted string remains supported.
775
+ - `global.MDCUI_MAIN_BASE`: internal define generated automatically from
776
+ `global.MDCUI_MAIN`; do not pass it manually.
777
+
778
+ Place every build define after `--build-exe`, or after the target argument of
779
+ `--build-for`. Choose at most one of `MDCUI_DEFAULT_EDIT`,
780
+ `MDCUI_DEFAULT_DEMO`, and `MDCUI_DEFAULT_DEMO_WUI`.
781
+
782
+ | Build defines | No-argument launch | Open the same app in the other UI |
783
+ | --- | --- | --- |
784
+ | none | normal CLI/TUI | `./mdcui --wui app.md` |
785
+ | `MDCUI_DEFAULT_EDIT=1` | text editor | `./mdcui --tui app.md` |
786
+ | `MDCUI_DEFAULT_DEMO=1` | `testapp.md` TUI | `./mdcui --wui --demo` |
787
+ | `MDCUI_DEFAULT_DEMO_WUI=1` | `testapp.md` WUI | `./mdcui --tui --demo` |
788
+ | `global.MDCUI_MAIN=../中文工具.md` | embedded custom TUI | `./mdcui --wui --demo-中文工具` |
789
+ | MAIN plus `MDCUI_DEFAULT_DEMO_WUI=1` | embedded custom WUI | `./mdcui --tui --demo-中文工具` |
761
790
 
762
- - `MDCUI_DEFAULT_EDIT`: open files as editable text by default.
763
- - `MDCUI_DEFAULT_DEMO`: add `--demo` when launched without arguments.
764
- - `MDCUI_DEFAULT_DEMO_WUI`: add `--wui` when launched without arguments.
791
+ Any explicit runtime argument suppresses the no-argument demo/WUI injection.
792
+ That is why the commands in the last column repeat `--demo` or
793
+ `--demo-中文工具`; `./mdcui --wui` by itself does not implicitly select a custom
794
+ main application.
765
795
 
766
- Choose only one of the three default-mode constants for a distribution.
767
- `MDCUI_OVERWRITE_DEMO` is an optional modifier for the demo or WUI mode.
768
- These are presence-based constants, so their build values do not require
769
- shell-quoted strings:
796
+ To package `../中文工具.md` as a TUI by default:
770
797
 
771
798
  ```sh
772
- bun src/index.js --build-exe --define MDCUI_DEFAULT_EDIT=true
773
- ```
799
+ bun src/index.js --build-exe \
800
+ --define global.MDCUI_MAIN=../中文工具.md
774
801
 
775
- ### Ship `testapp.md` as a standalone application
802
+ ./mdcui
803
+ ./mdcui --wui --demo-中文工具
804
+ ```
776
805
 
777
- To turn your finished Markdown UI into a standalone executable, save it as the
778
- repository-root `testapp.md`, then build with both demo constants:
806
+ To package the same application as a WUI by default and explicitly switch back
807
+ to its TUI:
779
808
 
780
809
  ```sh
781
810
  bun src/index.js --build-exe \
782
- --define MDCUI_DEFAULT_DEMO=true \
783
- --define MDCUI_OVERWRITE_DEMO=true
811
+ --define global.MDCUI_MAIN=../中文工具.md \
812
+ --define MDCUI_DEFAULT_DEMO_WUI=1
813
+
814
+ ./mdcui
815
+ ./mdcui --tui --demo-中文工具
784
816
  ```
785
817
 
786
- The build first packs `testapp.md` into the executable and writes the resulting
787
- `mdcui` binary in the current directory. In that binary,
788
- `MDCUI_DEFAULT_DEMO` adds `--demo` when the user launches it without arguments,
789
- and `MDCUI_OVERWRITE_DEMO` adds `--overwrite-demo`. Consequently, running
790
- `./mdcui` writes the bundled application to `./testapp.md`, replacing an older
791
- copy, and starts it as the terminal UI.
818
+ The `MDCUI_MAIN` basename must end with lowercase `.md`. Its demo-name portion
819
+ must start with a Unicode letter or number and may contain Unicode
820
+ letters/numbers (including Chinese), combining marks, dots, underscores, and
821
+ hyphens. Whitespace and path separators are not allowed.
822
+
823
+ When the configured custom demo is selected and its local Markdown byte length
824
+ matches the embedded copy, TUI uses the embedded front/RPC modules and WUI uses
825
+ the embedded server. A missing demo, or one selected with
826
+ `MDCUI_OVERWRITE_DEMO=1`, is first written from the embedded copy and then uses
827
+ embedded modules. A different byte length prints a warning and uses filesystem
828
+ companion modules. Directly opening `./mdcui app.md` or
829
+ `./mdcui --wui app.md` has no demo provenance and therefore uses filesystem
830
+ modules even if the basename matches `MDCUI_MAIN`.
792
831
 
793
- To make a no-argument launch start the browser UI instead, build with
794
- `MDCUI_DEFAULT_DEMO_WUI`:
832
+ To retain the older repository-root `testapp.md` distribution instead, build a
833
+ TUI with:
795
834
 
796
835
  ```sh
797
836
  bun src/index.js --build-exe \
798
- --define MDCUI_DEFAULT_DEMO_WUI=true \
799
- --define MDCUI_OVERWRITE_DEMO=true
837
+ --define MDCUI_DEFAULT_DEMO=1 \
838
+ --define MDCUI_OVERWRITE_DEMO=1
800
839
  ```
801
840
 
802
- This adds `--wui` when the executable is launched without arguments.
841
+ For a default WUI, replace `MDCUI_DEFAULT_DEMO` with
842
+ `MDCUI_DEFAULT_DEMO_WUI`.
803
843
 
804
844
  You can rename and distribute the resulting binary. It contains the Bun
805
- runtime, jsmdcui, the packed runtime assets, and your `testapp.md`; the target
806
- directory must remain writable because launching the application creates
807
- `testapp.md` and its generated companion files there.
845
+ runtime, jsmdcui, the packed runtime assets, and the configured demo or custom
846
+ main application. The target directory must remain writable because launching
847
+ an application creates its Markdown file and generated companion files there.
808
848
 
809
849
  ## Development
810
850
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsmdcui",
3
- "version": "0.10.1",
3
+ "version": "0.11.1",
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
@@ -54,6 +54,7 @@ export async function main(tuiWidth=30, {
54
54
  mdpath: requestedMdpath = null,
55
55
  overwriteDemo = process.argv.includes("--overwrite-demo"),
56
56
  printUi = process.argv.includes("--print-ui"),
57
+ useBundledMdcuiServer = false,
57
58
  } = {})
58
59
  {
59
60
  const explicitMdpath = process.argv.find(i=>i.endsWith('.md'))
@@ -99,7 +100,20 @@ export async function main(tuiWidth=30, {
99
100
 
100
101
 
101
102
  const serverPath = mdpath + "-server.js"
102
- const svmod = await import(pathToFileURL(path.resolve(serverPath)).href)
103
+ const useEmbeddedMdcuiServer = Boolean(
104
+ global.MDCUI_MAIN && useBundledMdcuiServer
105
+ )
106
+ cse(
107
+ `[mdcui] Starting ${useEmbeddedMdcuiServer ? "embedded" : "external"} `
108
+ + `WUI server: ${
109
+ useEmbeddedMdcuiServer
110
+ ? String(global.MDCUI_MAIN)
111
+ : path.resolve(serverPath)
112
+ }`
113
+ )
114
+ const svmod = useEmbeddedMdcuiServer
115
+ ? await import(global.MDCUI_MAIN + "-server.js")
116
+ : await import(pathToFileURL(path.resolve(serverPath)).href)
103
117
 
104
118
  cse("\n\n"+mda('# Server'))
105
119
  svmod.main();
@@ -109,7 +123,7 @@ export async function main(tuiWidth=30, {
109
123
  // Exports
110
124
 
111
125
 
112
- export async function extractJs(md,mdpath)
126
+ export async function extractJs(md,mdpath,{ bundling = false } = {})
113
127
  {
114
128
  const mdb = path.basename(mdpath)
115
129
 
@@ -128,16 +142,23 @@ export async function extractJs(md,mdpath)
128
142
  }
129
143
  )
130
144
 
145
+ const frontSource = sctags
131
146
  sctags = "#!/usr/bin/env bun" + `
132
147
 
133
148
  import { rpc as wuiRpcClient } from "./${mdb}-rpc.js";
134
- let rpc = "${mdb}"
149
+ let rpc = null
135
150
  if(globalThis.process)
136
- rpc = await import("./"+rpc+".back.js") ;
151
+ {
152
+ rpc = await import(
153
+ "./" +
154
+ (global.MDCUI_MAIN_BASE||"${mdb}") +
155
+ ".back.js"
156
+ ) ;
157
+ }
137
158
  else
138
159
  rpc = wuiRpcClient ;
139
160
 
140
- ` + sctags + `
161
+ ` + frontSource + `
141
162
 
142
163
  if (typeof window !== "undefined")
143
164
  {
@@ -152,6 +173,28 @@ export async function extractJs(md,mdpath)
152
173
 
153
174
  await Bun.write(sctagsp,sctags);
154
175
  logWroteFile("front", sctagsp)
176
+
177
+ if (bundling) {
178
+ const bundledFrontSource = "#!/usr/bin/env bun" + `
179
+
180
+ import { rpc as wuiRpcClient } from "./${mdb}-rpc.js";
181
+ const rpc = wuiRpcClient;
182
+
183
+ ` + frontSource
184
+ const bundledFrontPath = mdpath + ".tmpfs.js"
185
+ await Bun.write(bundledFrontPath, bundledFrontSource)
186
+ logWroteFile("bundling front", bundledFrontPath)
187
+
188
+ const bundledImportPath = mdpath + ".tmpfi.js"
189
+ await Bun.write(
190
+ bundledImportPath,
191
+ `import * as frontMod from "./${mdb}.tmpfs.js";
192
+
193
+ Object.assign(window, frontMod);
194
+ `,
195
+ )
196
+ logWroteFile("bundling import", bundledImportPath)
197
+ }
155
198
 
156
199
  sctagsp = mdpath + ".back.js"
157
200
  sctags = "#!/usr/bin/env bun\n\n"
@@ -354,7 +397,7 @@ export function wrapWuiHeadingSections(html)
354
397
  return output;
355
398
  }
356
399
 
357
- export async function createWui(md,mdpath) // HTML
400
+ export async function createWui(md,mdpath,{ bundling = false } = {}) // HTML
358
401
  {
359
402
  const eventsById = fenceEventMap(md)
360
403
 
@@ -397,7 +440,8 @@ img {
397
440
  height: auto;
398
441
  }
399
442
  </style>`;
400
- const moduleScript = `<scr`+`ipt type="module" src="./${mdb}.front.js"></scr`+`ipt>`;
443
+ const moduleEntry = bundling ? `${mdb}.tmpfi.js` : `${mdb}.front.js`;
444
+ const moduleScript = `<scr`+`ipt type="module" src="./${moduleEntry}"></scr`+`ipt>`;
401
445
  const isFullHtmlDocument = /^\s*<!doctype html>/i.test(md);
402
446
  if (!isFullHtmlDocument) {
403
447
  md = `<!doctype html>
@@ -757,54 +757,94 @@ both are equivalent to `-encoding mdcui`.
757
757
 
758
758
  ### Build-time distribution constants
759
759
 
760
- Single-file distributions can define one of these default modes:
760
+ The following switch defines are presence-based: the program checks whether
761
+ they were passed, not whether their values are true. Consequently, `=0` and
762
+ `=false` still enable a switch. Omit a define entirely to disable it. Examples
763
+ use `=1` to make this explicit.
764
+
765
+ - `MDCUI_DEFAULT_EDIT=1`: open files as editable text by default.
766
+ - `MDCUI_DEFAULT_DEMO=1`: add `--demo` when launched without arguments.
767
+ - `MDCUI_DEFAULT_DEMO_WUI=1`: add `--wui` when launched without arguments.
768
+ - `MDCUI_OVERWRITE_DEMO=1`: add `--overwrite-demo`; this modifies a selected
769
+ demo but does not select one by itself.
770
+ - `global.MDCUI_MAIN=<path>.md`: embed a custom Markdown application and its
771
+ generated front, RPC, back, HTML, and server modules. When this define is
772
+ forwarded after `--build-exe` or `--build-for`, a non-primitive value such as
773
+ a bare path is automatically encoded as a JavaScript string. An explicitly
774
+ quoted string remains supported.
775
+ - `global.MDCUI_MAIN_BASE`: internal define generated automatically from
776
+ `global.MDCUI_MAIN`; do not pass it manually.
777
+
778
+ Place every build define after `--build-exe`, or after the target argument of
779
+ `--build-for`. Choose at most one of `MDCUI_DEFAULT_EDIT`,
780
+ `MDCUI_DEFAULT_DEMO`, and `MDCUI_DEFAULT_DEMO_WUI`.
781
+
782
+ | Build defines | No-argument launch | Open the same app in the other UI |
783
+ | --- | --- | --- |
784
+ | none | normal CLI/TUI | `./mdcui --wui app.md` |
785
+ | `MDCUI_DEFAULT_EDIT=1` | text editor | `./mdcui --tui app.md` |
786
+ | `MDCUI_DEFAULT_DEMO=1` | `testapp.md` TUI | `./mdcui --wui --demo` |
787
+ | `MDCUI_DEFAULT_DEMO_WUI=1` | `testapp.md` WUI | `./mdcui --tui --demo` |
788
+ | `global.MDCUI_MAIN=../中文工具.md` | embedded custom TUI | `./mdcui --wui --demo-中文工具` |
789
+ | MAIN plus `MDCUI_DEFAULT_DEMO_WUI=1` | embedded custom WUI | `./mdcui --tui --demo-中文工具` |
761
790
 
762
- - `MDCUI_DEFAULT_EDIT`: open files as editable text by default.
763
- - `MDCUI_DEFAULT_DEMO`: add `--demo` when launched without arguments.
764
- - `MDCUI_DEFAULT_DEMO_WUI`: add `--wui` when launched without arguments.
791
+ Any explicit runtime argument suppresses the no-argument demo/WUI injection.
792
+ That is why the commands in the last column repeat `--demo` or
793
+ `--demo-中文工具`; `./mdcui --wui` by itself does not implicitly select a custom
794
+ main application.
765
795
 
766
- Choose only one of the three default-mode constants for a distribution.
767
- `MDCUI_OVERWRITE_DEMO` is an optional modifier for the demo or WUI mode.
768
- These are presence-based constants, so their build values do not require
769
- shell-quoted strings:
796
+ To package `../中文工具.md` as a TUI by default:
770
797
 
771
798
  ```sh
772
- bun src/index.js --build-exe --define MDCUI_DEFAULT_EDIT=true
773
- ```
799
+ bun src/index.js --build-exe \
800
+ --define global.MDCUI_MAIN=../中文工具.md
774
801
 
775
- ### Ship `testapp.md` as a standalone application
802
+ ./mdcui
803
+ ./mdcui --wui --demo-中文工具
804
+ ```
776
805
 
777
- To turn your finished Markdown UI into a standalone executable, save it as the
778
- repository-root `testapp.md`, then build with both demo constants:
806
+ To package the same application as a WUI by default and explicitly switch back
807
+ to its TUI:
779
808
 
780
809
  ```sh
781
810
  bun src/index.js --build-exe \
782
- --define MDCUI_DEFAULT_DEMO=true \
783
- --define MDCUI_OVERWRITE_DEMO=true
811
+ --define global.MDCUI_MAIN=../中文工具.md \
812
+ --define MDCUI_DEFAULT_DEMO_WUI=1
813
+
814
+ ./mdcui
815
+ ./mdcui --tui --demo-中文工具
784
816
  ```
785
817
 
786
- The build first packs `testapp.md` into the executable and writes the resulting
787
- `mdcui` binary in the current directory. In that binary,
788
- `MDCUI_DEFAULT_DEMO` adds `--demo` when the user launches it without arguments,
789
- and `MDCUI_OVERWRITE_DEMO` adds `--overwrite-demo`. Consequently, running
790
- `./mdcui` writes the bundled application to `./testapp.md`, replacing an older
791
- copy, and starts it as the terminal UI.
818
+ The `MDCUI_MAIN` basename must end with lowercase `.md`. Its demo-name portion
819
+ must start with a Unicode letter or number and may contain Unicode
820
+ letters/numbers (including Chinese), combining marks, dots, underscores, and
821
+ hyphens. Whitespace and path separators are not allowed.
822
+
823
+ When the configured custom demo is selected and its local Markdown byte length
824
+ matches the embedded copy, TUI uses the embedded front/RPC modules and WUI uses
825
+ the embedded server. A missing demo, or one selected with
826
+ `MDCUI_OVERWRITE_DEMO=1`, is first written from the embedded copy and then uses
827
+ embedded modules. A different byte length prints a warning and uses filesystem
828
+ companion modules. Directly opening `./mdcui app.md` or
829
+ `./mdcui --wui app.md` has no demo provenance and therefore uses filesystem
830
+ modules even if the basename matches `MDCUI_MAIN`.
792
831
 
793
- To make a no-argument launch start the browser UI instead, build with
794
- `MDCUI_DEFAULT_DEMO_WUI`:
832
+ To retain the older repository-root `testapp.md` distribution instead, build a
833
+ TUI with:
795
834
 
796
835
  ```sh
797
836
  bun src/index.js --build-exe \
798
- --define MDCUI_DEFAULT_DEMO_WUI=true \
799
- --define MDCUI_OVERWRITE_DEMO=true
837
+ --define MDCUI_DEFAULT_DEMO=1 \
838
+ --define MDCUI_OVERWRITE_DEMO=1
800
839
  ```
801
840
 
802
- This adds `--wui` when the executable is launched without arguments.
841
+ For a default WUI, replace `MDCUI_DEFAULT_DEMO` with
842
+ `MDCUI_DEFAULT_DEMO_WUI`.
803
843
 
804
844
  You can rename and distribute the resulting binary. It contains the Bun
805
- runtime, jsmdcui, the packed runtime assets, and your `testapp.md`; the target
806
- directory must remain writable because launching the application creates
807
- `testapp.md` and its generated companion files there.
845
+ runtime, jsmdcui, the packed runtime assets, and the configured demo or custom
846
+ main application. The target directory must remain writable because launching
847
+ an application creates its Markdown file and generated companion files there.
808
848
 
809
849
  ## Development
810
850
 
@@ -69,8 +69,10 @@ micro.on("init", () => {
69
69
 
70
70
  //micro.alert(micro.getLine())
71
71
  const path = bp?.Buf?.Path || "(no path)";
72
+ const moduleSource =
73
+ micro.CurPane()?.Buf?.MdcuiModuleSource || "external";
72
74
  const loc = bp?.CursorLocation?.() || "+1.0:1";
73
- micro.alert(`${path}\n${loc}`)
75
+ micro.alert(`${path}\nMdcuiModuleSource: ${moduleSource}\n${loc}`)
74
76
 
75
77
  });
76
78
 
@@ -39,42 +39,58 @@ bun ./src/index.js --build-exe --sourcemap
39
39
  bun ./src/index.js --build-for <target> --sourcemap
40
40
  ```
41
41
 
42
- The following presence-based build constants select distribution defaults:
43
-
44
- - `MDCUI_DEFAULT_EDIT`: open files as editable text by default.
45
- - `MDCUI_DEFAULT_DEMO`: add `--demo` when launched without arguments.
46
- - `MDCUI_DEFAULT_DEMO_WUI`: add `--wui` when launched without arguments.
47
-
48
- Choose only one of these three default-mode constants for each build.
49
- `MDCUI_OVERWRITE_DEMO` is an optional modifier for a demo or WUI build.
50
-
51
- For example, build a default text editor with:
42
+ Bun expects `--define` values to be JSON-style literals, so strings normally
43
+ need quotes. `stringifyNonPrimitiveDefineValues()` converts a bare value with
44
+ `JSON.stringify()` before it reaches Bun. jsmdcui uses it for
45
+ `global.MDCUI_MAIN`.
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`.
49
+
50
+ - `MDCUI_DEFAULT_EDIT=1`: editable-text default.
51
+ - `MDCUI_DEFAULT_DEMO=1`: no-argument `testapp.md` TUI.
52
+ - `MDCUI_DEFAULT_DEMO_WUI=1`: no-argument `testapp.md` WUI.
53
+ - `MDCUI_OVERWRITE_DEMO=1`: overwrite modifier; it does not select a demo.
54
+ - `global.MDCUI_MAIN=<path>.md`: embed a custom Markdown app and its generated
55
+ front, RPC, back, HTML, and server modules.
56
+ - `global.MDCUI_MAIN_BASE`: generated internally from `MDCUI_MAIN`; do not pass
57
+ it manually.
58
+
59
+ Put defines after `--build-exe` (or after the `--build-for` target), and choose
60
+ at most one `MDCUI_DEFAULT_*` mode.
61
+
62
+ | Build defines | No-argument launch | Switch UI |
63
+ | --- | --- | --- |
64
+ | `MDCUI_DEFAULT_EDIT=1` | text editor | `./mdcui --tui app.md` |
65
+ | `MDCUI_DEFAULT_DEMO=1` | `testapp.md` TUI | `./mdcui --wui --demo` |
66
+ | `MDCUI_DEFAULT_DEMO_WUI=1` | `testapp.md` WUI | `./mdcui --tui --demo` |
67
+ | `global.MDCUI_MAIN=../中文工具.md` | custom TUI | `./mdcui --wui --demo-中文工具` |
68
+ | MAIN plus `MDCUI_DEFAULT_DEMO_WUI=1` | custom WUI | `./mdcui --tui --demo-中文工具` |
69
+
70
+ For a custom TUI-default executable:
52
71
 
53
72
  ```shell
54
73
  bun ./src/index.js --build-exe \
55
- --define MDCUI_DEFAULT_EDIT=true
74
+ --define global.MDCUI_MAIN=../中文工具.md
56
75
  ```
57
76
 
58
- To build a bundled terminal demo that replaces its local copy:
77
+ For a custom WUI-default executable:
59
78
 
60
79
  ```shell
61
80
  bun ./src/index.js --build-exe \
62
- --define MDCUI_DEFAULT_DEMO=true \
63
- --define MDCUI_OVERWRITE_DEMO=true
81
+ --define global.MDCUI_MAIN=../中文工具.md \
82
+ --define MDCUI_DEFAULT_DEMO_WUI=1
64
83
  ```
65
84
 
66
- `MDCUI_DEFAULT_DEMO=true` makes an executable launched without arguments behave
67
- as if `--demo` was passed. `MDCUI_OVERWRITE_DEMO=true` makes every selected demo
68
- replace an existing local copy; it does not select a demo by itself.
69
-
70
- For a browser UI that automatically adds `--wui` when launched without
71
- arguments, use `MDCUI_DEFAULT_DEMO_WUI` instead:
85
+ Explicit runtime arguments suppress automatic demo/WUI selection, so switching
86
+ UI must repeat `--demo` or `--demo-中文工具`. The main basename must end in
87
+ lowercase `.md`; its demo name allows Unicode letters/numbers (including
88
+ Chinese), dots, underscores, and hyphens, but no whitespace.
72
89
 
73
- ```shell
74
- bun ./src/index.js --build-exe \
75
- --define MDCUI_DEFAULT_DEMO_WUI=true \
76
- --define MDCUI_OVERWRITE_DEMO=true
77
- ```
90
+ The custom demo uses embedded TUI front/RPC or the embedded WUI server when its
91
+ local Markdown byte length matches the embedded asset. Missing or overwritten
92
+ demos use embedded modules after the asset is written. A differing byte length
93
+ warns and selects filesystem companion modules.
78
94
 
79
95
  To perform the same steps manually, run these commands from `single-exe/`:
80
96
 
@@ -221,6 +237,47 @@ bun ./packAssets.sh
221
237
  bun build --format=esm --compile --minify --bytecode ./entry.mjs --outfile=my-bin
222
238
  ```
223
239
 
240
+ #### Passing --define to bun build
241
+
242
+ `buildEarlyExit()` forwards build arguments to Bun, whose define parser expects
243
+ strings to be quoted literals. To accept a bare value such as a path, call the below
244
+ helper to normalize it before `buildEarlyExit()`:
245
+
246
+ ```js
247
+ import {
248
+ buildEarlyExit,
249
+ stringifyNonPrimitiveDefineValues,
250
+ } from "../single-exe/compiled.js";
251
+
252
+ stringifyNonPrimitiveDefineValues(process.argv, "MY_STRING_DEFINE");
253
+ await buildEarlyExit(process.argv, "my-bin");
254
+ ```
255
+
256
+ ```shell
257
+ # Wrong: Bun parses the define before the helper runs.
258
+ bun --define MY_STRING_DEFINE=../app.md ./src/index.js --build-exe
259
+
260
+ # Correct
261
+ bun ./src/index.js --build-exe --define MY_STRING_DEFINE=../app.md
262
+ ```
263
+
264
+ Before normalization:
265
+
266
+ ```js
267
+ ["--define", "MY_STRING_DEFINE=../app.md"]
268
+ ```
269
+
270
+ After normalization:
271
+
272
+ ```js
273
+ ["--define", 'MY_STRING_DEFINE="../app.md"']
274
+ ```
275
+
276
+ The inline form works too:
277
+ `--define=MY_STRING_DEFINE=../app.md` becomes
278
+ `--define=MY_STRING_DEFINE="../app.md"`.
279
+
280
+
224
281
  ### 6. Verify both execution paths
225
282
 
226
283
  Verify the compiled asset archive and then run the program normally: