tosijs-ui 1.6.20 → 1.6.21

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.
@@ -2,11 +2,29 @@ import { EditorView } from '@codemirror/view';
2
2
  import { Extension } from '@codemirror/state';
3
3
  /** Map a `<tosi-code mode>` value to a CodeMirror language extension. */
4
4
  export declare function languageForMode(mode: string): Extension;
5
+ /** Runtime-introspection hooks for tjs autocomplete (all optional). */
6
+ export interface TjsAutocompleteConfig {
7
+ getMetadata?: () => Record<string, unknown> | undefined;
8
+ getImports?: () => Record<string, Record<string, unknown>> | undefined;
9
+ getLiveBindings?: () => Record<string, unknown> | undefined;
10
+ getMembers?: (path: string) => Promise<unknown[] | undefined>;
11
+ }
12
+ /**
13
+ * Lazy-load tjs-lang's CodeMirror language + completion bundle. Returns a single
14
+ * CodeMirror `Extension` (tjs language, forbidden-keyword highlighting, theme, and
15
+ * `tjsCompletionSource`-driven autocomplete) suitable for `setLanguageExtension()`,
16
+ * or `null` when tjs-lang (an optional peer) isn't installed or its editor build
17
+ * lacks `tjsEditorExtension`. The dynamic import keeps it out of the bundle until a
18
+ * tjs editor actually mounts.
19
+ */
20
+ export declare function loadTjsExtension(autocomplete?: TjsAutocompleteConfig): Promise<Extension | null>;
5
21
  export interface CmHandle {
6
22
  view: EditorView;
7
23
  getValue(): string;
8
24
  setValue(text: string): void;
9
25
  setMode(mode: string): void;
26
+ /** Swap the language compartment wholesale (e.g. an async-loaded tjs bundle). */
27
+ setLanguageExtension(ext: Extension): void;
10
28
  setReadOnly(readOnly: boolean): void;
11
29
  undo(): void;
12
30
  redo(): void;
@@ -21,6 +21,18 @@ import { javascript } from '@codemirror/lang-javascript';
21
21
  import { css } from '@codemirror/lang-css';
22
22
  import { html } from '@codemirror/lang-html';
23
23
  import { markdown } from '@codemirror/lang-markdown';
24
+ import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
25
+ // The doc-system flips dark mode with a `darkmode` class on <body> (which inverts
26
+ // the luminance of --code-bg / --text-color, so the editor SURFACE adapts for
27
+ // free). Only CM's syntax-token colors need swapping: the light defaultHighlightStyle
28
+ // washes out on a dark surface, so use oneDark's brighter palette in dark mode.
29
+ const isDarkMode = () => typeof document !== 'undefined' &&
30
+ !!document.body &&
31
+ document.body.classList.contains('darkmode');
32
+ const highlightFor = (dark) => dark
33
+ ? syntaxHighlighting(oneDarkHighlightStyle)
34
+ : syntaxHighlighting(defaultHighlightStyle, { fallback: true });
35
+ const isTjsMode = (mode) => mode === 'tjs' || mode === 'ajs';
24
36
  /** Map a `<tosi-code mode>` value to a CodeMirror language extension. */
25
37
  export function languageForMode(mode) {
26
38
  switch (mode) {
@@ -29,8 +41,10 @@ export function languageForMode(mode) {
29
41
  return javascript();
30
42
  case 'ts':
31
43
  case 'typescript':
32
- // tjs highlights fine as TypeScript until the tjs-lang language is wired
33
- // (workstream B); this keeps `mode="tjs"` readable today.
44
+ // tjs highlights as TypeScript here (the sync default). First-class tjs — the
45
+ // tjs-lang language + autocomplete — is layered on asynchronously via
46
+ // `loadTjsExtension()` + `setLanguageExtension()`, since it lazy-loads the
47
+ // (optional) tjs-lang editor build; this keeps `mode="tjs"` readable meanwhile.
34
48
  case 'tjs':
35
49
  case 'ajs':
36
50
  return javascript({ typescript: true });
@@ -45,10 +59,61 @@ export function languageForMode(mode) {
45
59
  return javascript();
46
60
  }
47
61
  }
62
+ // The language compartment carries the language AND its completion source, so
63
+ // exactly ONE `autocompletion()` is ever active: standard modes use CM's built-in
64
+ // (language-provided) completions here, while the tjs bundle brings its own
65
+ // `autocompletion({ override: [tjsCompletionSource] })`. (This is why the base
66
+ // extension set below does NOT include `autocompletion()`.)
67
+ function standardLanguageBundle(mode) {
68
+ return [languageForMode(mode), autocompletion()];
69
+ }
70
+ /**
71
+ * Lazy-load tjs-lang's CodeMirror language + completion bundle. Returns a single
72
+ * CodeMirror `Extension` (tjs language, forbidden-keyword highlighting, theme, and
73
+ * `tjsCompletionSource`-driven autocomplete) suitable for `setLanguageExtension()`,
74
+ * or `null` when tjs-lang (an optional peer) isn't installed or its editor build
75
+ * lacks `tjsEditorExtension`. The dynamic import keeps it out of the bundle until a
76
+ * tjs editor actually mounts.
77
+ */
78
+ export async function loadTjsExtension(autocomplete = {}) {
79
+ try {
80
+ const mod = (await import('tjs-lang/editors/codemirror'));
81
+ if (typeof mod.tjsEditorExtension === 'function') {
82
+ return mod.tjsEditorExtension({ typescript: true, autocomplete });
83
+ }
84
+ }
85
+ catch {
86
+ // tjs-lang absent or editor build unavailable — caller keeps TS highlighting.
87
+ }
88
+ return null;
89
+ }
90
+ // A minimal theme so the editor has a real surface instead of showing whatever is
91
+ // behind it. It's applied as a CodeMirror theme (not shadow-DOM CSS) so it beats
92
+ // CM's injected base styles. Colors come from the doc-system theme vars
93
+ // (`--code-bg` / `--text-color`, which pierce the shadow root and adapt to dark
94
+ // mode) with sensible standalone fallbacks.
95
+ const editorTheme = EditorView.theme({
96
+ '&': {
97
+ height: '100%',
98
+ backgroundColor: 'var(--code-bg, var(--input-bg, #fdfdfd))',
99
+ color: 'var(--text-color, #222)',
100
+ },
101
+ '.cm-scroller': {
102
+ fontFamily: "Menlo, Monaco, Consolas, 'Courier New', monospace",
103
+ },
104
+ '.cm-gutters': {
105
+ backgroundColor: 'var(--code-bg, var(--input-bg, #fdfdfd))',
106
+ color: 'var(--text-color, #888)',
107
+ border: 'none',
108
+ },
109
+ '.cm-activeLine': { backgroundColor: 'transparent' },
110
+ '.cm-activeLineGutter': { backgroundColor: 'transparent' },
111
+ });
48
112
  // A basicSetup-equivalent without a hard-coded color theme, so the host page's CSS
49
113
  // (and dark mode) controls the palette. Line-wrapping mirrors the old ACE `wrap:true`.
50
114
  function baseExtensions() {
51
115
  return [
116
+ editorTheme,
52
117
  lineNumbers(),
53
118
  highlightActiveLineGutter(),
54
119
  highlightSpecialChars(),
@@ -60,10 +125,11 @@ function baseExtensions() {
60
125
  indentOnInput(),
61
126
  indentUnit.of(' '),
62
127
  EditorState.tabSize.of(2),
63
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
128
+ // syntax highlighting is applied per-instance via a compartment (dark-mode aware)
64
129
  bracketMatching(),
65
130
  closeBrackets(),
66
- autocompletion(),
131
+ // NB: autocompletion() lives in the language compartment (see
132
+ // standardLanguageBundle) so tjs's own completion source never doubles up.
67
133
  rectangularSelection(),
68
134
  crosshairCursor(),
69
135
  highlightActiveLine(),
@@ -85,7 +151,8 @@ function baseExtensions() {
85
151
  export function createCmEditor(parent, opts = {}) {
86
152
  const language = new Compartment();
87
153
  const readonly = new Compartment();
88
- const langExt = opts.languageExtension ?? languageForMode(opts.mode ?? 'javascript');
154
+ const highlight = new Compartment();
155
+ const langExt = opts.languageExtension ?? standardLanguageBundle(opts.mode ?? 'javascript');
89
156
  const view = new EditorView({
90
157
  parent,
91
158
  root: opts.root,
@@ -93,6 +160,7 @@ export function createCmEditor(parent, opts = {}) {
93
160
  doc: opts.value ?? '',
94
161
  extensions: [
95
162
  baseExtensions(),
163
+ highlight.of(highlightFor(isDarkMode())),
96
164
  language.of(langExt),
97
165
  readonly.of(EditorState.readOnly.of(!!opts.readOnly)),
98
166
  EditorView.updateListener.of((u) => {
@@ -102,6 +170,19 @@ export function createCmEditor(parent, opts = {}) {
102
170
  ],
103
171
  }),
104
172
  });
173
+ // Re-apply the right highlight palette when the doc-system toggles dark mode
174
+ // (it flips the `darkmode` class on <body>).
175
+ let dark = isDarkMode();
176
+ const darkObserver = typeof MutationObserver !== 'undefined' && typeof document !== 'undefined'
177
+ ? new MutationObserver(() => {
178
+ const nowDark = isDarkMode();
179
+ if (nowDark !== dark) {
180
+ dark = nowDark;
181
+ view.dispatch({ effects: highlight.reconfigure(highlightFor(dark)) });
182
+ }
183
+ })
184
+ : null;
185
+ darkObserver?.observe(document.body, { attributes: true, attributeFilter: ['class'] });
105
186
  const handle = {
106
187
  view,
107
188
  getValue: () => view.state.doc.toString(),
@@ -113,7 +194,10 @@ export function createCmEditor(parent, opts = {}) {
113
194
  });
114
195
  },
115
196
  setMode(mode) {
116
- view.dispatch({ effects: language.reconfigure(languageForMode(mode)) });
197
+ view.dispatch({ effects: language.reconfigure(standardLanguageBundle(mode)) });
198
+ },
199
+ setLanguageExtension(ext) {
200
+ view.dispatch({ effects: language.reconfigure(ext) });
117
201
  },
118
202
  setReadOnly(ro) {
119
203
  view.dispatch({
@@ -126,7 +210,10 @@ export function createCmEditor(parent, opts = {}) {
126
210
  canRedo: () => redoDepth(view.state) > 0,
127
211
  focus: () => view.focus(),
128
212
  refresh: () => view.requestMeasure(),
129
- destroy: () => view.destroy(),
213
+ destroy: () => {
214
+ darkObserver?.disconnect();
215
+ view.destroy();
216
+ },
130
217
  };
131
218
  return handle;
132
219
  }
@@ -50,6 +50,13 @@ export declare class CodeEditor extends WebComponent<CodeEditorParts> {
50
50
  };
51
51
  onResize(): void;
52
52
  connectedCallback(): void;
53
+ private isTjsMode;
54
+ /**
55
+ * When in tjs mode, lazily upgrade the editor to tjs-lang's CodeMirror language +
56
+ * autocomplete. No-op (keeps TS highlighting) if not tjs, if tjs-lang isn't
57
+ * installed, or if the mode/handle changed before the async load resolved.
58
+ */
59
+ private applyTjsExtension;
53
60
  render(): void;
54
61
  }
55
62
  export declare const codeEditor: ElementCreator<CodeEditor>;
@@ -141,10 +141,31 @@ export class CodeEditor extends WebComponent {
141
141
  this._handle = handle;
142
142
  this._appliedMode = this.mode;
143
143
  this._appliedDisabled = this.disabled;
144
+ this.applyTjsExtension();
144
145
  return handle;
145
146
  });
146
147
  }
147
148
  }
149
+ isTjsMode() {
150
+ return this.mode === 'tjs' || this.mode === 'ajs';
151
+ }
152
+ /**
153
+ * When in tjs mode, lazily upgrade the editor to tjs-lang's CodeMirror language +
154
+ * autocomplete. No-op (keeps TS highlighting) if not tjs, if tjs-lang isn't
155
+ * installed, or if the mode/handle changed before the async load resolved.
156
+ */
157
+ applyTjsExtension() {
158
+ const handle = this._handle;
159
+ if (!handle || !this.isTjsMode())
160
+ return;
161
+ import('./code-editor-cm')
162
+ .then(({ loadTjsExtension }) => loadTjsExtension())
163
+ .then((ext) => {
164
+ if (ext && this._handle === handle && this.isTjsMode()) {
165
+ handle.setLanguageExtension(ext);
166
+ }
167
+ });
168
+ }
148
169
  render() {
149
170
  super.render();
150
171
  if (this._handle) {
@@ -155,6 +176,7 @@ export class CodeEditor extends WebComponent {
155
176
  if (this.mode !== this._appliedMode) {
156
177
  this._handle.setMode(this.mode);
157
178
  this._appliedMode = this.mode;
179
+ this.applyTjsExtension();
158
180
  }
159
181
  }
160
182
  }
@@ -472,6 +472,11 @@ export function createDocBrowser(options) {
472
472
  }
473
473
  });
474
474
  }
475
+ // This instance's own sidenav. Captured from its own change event (below), so the
476
+ // header nav toggle drives THIS doc-browser — not `document.querySelector('tosi-
477
+ // sidenav')`, which returns the FIRST sidenav in the document (an OUTER instance
478
+ // when this one is an embedded, memory-routed browser).
479
+ let sidenav = null;
475
480
  const headerContent = [
476
481
  button({
477
482
  class: 'iconic',
@@ -489,8 +494,8 @@ export function createDocBrowser(options) {
489
494
  },
490
495
  },
491
496
  onClick() {
492
- const nav = document.querySelector(TosiSidenav.tagName);
493
- nav.contentVisible = !nav.contentVisible;
497
+ if (sidenav)
498
+ sidenav.contentVisible = !sidenav.contentVisible;
494
499
  },
495
500
  }, icons.menu()),
496
501
  span({ style: { flex: '0 0 10px' } }),
@@ -1027,9 +1032,12 @@ export function createDocBrowser(options) {
1027
1032
  flex: '1 1 auto',
1028
1033
  overflow: 'hidden',
1029
1034
  },
1030
- onChange() {
1031
- const nav = document.querySelector(TosiSidenav.tagName);
1032
- app.compact = nav.compact;
1035
+ onChange(event) {
1036
+ // Scope to the sidenav that fired — and capture it so the header toggle
1037
+ // targets THIS instance, not the first sidenav in the document.
1038
+ sidenav = event.target.closest(TosiSidenav.tagName);
1039
+ if (sidenav)
1040
+ app.compact = sidenav.compact;
1033
1041
  },
1034
1042
  }, searchField, navContent, div({
1035
1043
  style: {
@@ -48,10 +48,10 @@ async function ensureHaltijaChannel(port) {
48
48
  // HTTPS dev page has no mixed-content), while the `hj` CLI drives over its
49
49
  // default HTTP 8700 — one server, both transports, shared state. HTTPS cert
50
50
  // is mkcert-trusted. Output quiet so it doesn't drown the dev log.
51
- // Track the `@beta` tag: in-browser (widget-mode) WebRTC screen capture —
52
- // which makes the Electron app CI-only — landed in the beta channel, ahead
53
- // of the `latest` dist-tag.
54
- spawn(['bunx', 'haltija@beta', '--server', '--both'], {
51
+ // `@latest` (1.3.2+): the widget-mode WebRTC screen capture (which makes the
52
+ // Electron app CI-only) is on the stable channel now, along with the fix for
53
+ // an accidental Electron launch. (Was pinned to `@beta` before 1.3.2.)
54
+ spawn(['bunx', 'haltija@latest', '--server', '--both'], {
55
55
  stdout: 'ignore',
56
56
  stderr: 'ignore',
57
57
  });
@@ -1,5 +1,5 @@
1
1
  export { defineSiteConfig } from './site-config';
2
- export type { SiteConfig, SiteHost } from './site-config';
2
+ export type { SiteConfig, SiteHost, LibraryBuildContext } from './site-config';
3
3
  export { buildSite } from './orchestrator';
4
4
  export { devServer } from './dev-server';
5
5
  export { extractDocs, saveDocsJSON } from './docs';
@@ -102,6 +102,21 @@ export function generateLlmsTxt(outputPath, meta = {}, corpus) {
102
102
  console.warn('llms.txt: no readable package.json — using config values only');
103
103
  }
104
104
  const entries = corpus ? entriesFromCorpus(corpus, meta) : entriesFromSrcScan();
105
+ // Only orient agents about the live-example execution model when the corpus
106
+ // actually has live examples (a book / pure-docs site has none).
107
+ const exampleFence = /```(js|tjs|ts|html|css)\b/;
108
+ const hasLiveExamples = !!corpus && corpus.some((d) => exampleFence.test(d.text ?? ''));
109
+ const liveExampleNote = hasLiveExamples
110
+ ? [
111
+ 'Live examples run inline on the shared page by default (not sandboxed):',
112
+ 'each has its own `preview` element, but they share one tosijs module, so',
113
+ '`tosi()` state singletons are shared across every example on a page. This is',
114
+ 'deliberate (it shows tosi isolation and lets you drive demos via the global',
115
+ 'singleton). Namespace example state with unique top-level keys so examples',
116
+ "don't clobber each other; the `iframe` attribute isolates DOM/CSS, not state.",
117
+ '',
118
+ ]
119
+ : [];
105
120
  const name = meta.name ?? pkg.name ?? '';
106
121
  const description = meta.description ?? pkg.description ?? '';
107
122
  const links = [];
@@ -125,6 +140,7 @@ export function generateLlmsTxt(outputPath, meta = {}, corpus) {
125
140
  '',
126
141
  'Full documentation, with live code examples, is at the links below.',
127
142
  '',
143
+ ...liveExampleNote,
128
144
  '## Pages',
129
145
  '',
130
146
  ];
@@ -25,6 +25,18 @@ import { buildEpub } from './epub';
25
25
  // Module specifiers contain regex metacharacters (`/`, `.`, `@`, …), so escape
26
26
  // before interpolating into the require-shim detector below.
27
27
  const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
+ // Externalize the tjs CodeMirror editor extension ONLY when tjs-lang isn't
29
+ // installed — otherwise it's bundled in so it shares the editor's CodeMirror
30
+ // instance (see the `external` comment in buildSite). Returns [] when present.
31
+ function tjsEditorExternal(root) {
32
+ try {
33
+ Bun.resolveSync('tjs-lang/editors/codemirror', root);
34
+ return [];
35
+ }
36
+ catch {
37
+ return ['tjs-lang/editors/codemirror'];
38
+ }
39
+ }
28
40
  export async function buildSite(config) {
29
41
  const PROJECT_ROOT = './';
30
42
  const PUBLIC = path.resolve(PROJECT_ROOT, config.outputDir ?? 'docs');
@@ -97,7 +109,17 @@ export async function buildSite(config) {
97
109
  console.time('build');
98
110
  // Optionally also build the library (ESM + type declarations) — for repos
99
111
  // whose single build publishes both an npm package and its doc site.
100
- if (config.libraryTsconfig) {
112
+ if (config.libraryBuild) {
113
+ // Full override — the consumer owns emitting dist/*.js + *.d.ts for ALL
114
+ // sources (e.g. tsc for `.ts` + `tjs convert`/`generateDTS` for native `.tjs`
115
+ // that tsc can't compile). See BUILD-TJS-HOOK.md.
116
+ await config.libraryBuild({
117
+ dist: DIST,
118
+ root: path.resolve(PROJECT_ROOT),
119
+ tsconfig: config.libraryTsconfig,
120
+ });
121
+ }
122
+ else if (config.libraryTsconfig) {
101
123
  // Consumer-controlled library build (handles root noEmit, removeComments,
102
124
  // outDir, etc.).
103
125
  try {
@@ -127,12 +149,20 @@ export async function buildSite(config) {
127
149
  format: 'iife',
128
150
  minify: true,
129
151
  naming: scriptName,
130
- // tjs-lang transpiles live examples; it's dynamically import()'d at
131
- // runtime (falling back to CDN), so keep it out of the bundle.
152
+ // tjs-lang's TRANSPILER (browser bundles) is dynamically import()'d at
153
+ // runtime (same-origin `/tjs/` copy, else CDN), so keep it out of the bundle.
154
+ //
155
+ // `tjs-lang/editors/codemirror` (the CodeMirror language + autocomplete) is
156
+ // different: it MUST share the editor's CodeMirror instance, so it has to be
157
+ // bundled IN — a separately loaded copy carries its own `@codemirror/state`
158
+ // and silently no-ops. So we do NOT externalize it *when tjs-lang is
159
+ // installed*. But tjs-lang is an OPTIONAL peer; if it's absent, bundling would
160
+ // fail to resolve, so we externalize it in that case (the runtime import then
161
+ // no-ops to plain TS highlighting — graceful degradation).
132
162
  external: [
133
- 'tjs-lang',
134
163
  'tjs-lang/browser',
135
164
  'tjs-lang/browser/from-ts',
165
+ ...tjsEditorExternal(PROJECT_ROOT),
136
166
  ...(config.bundleExternals ?? []),
137
167
  ],
138
168
  });
@@ -258,7 +288,13 @@ export async function buildSite(config) {
258
288
  const genCss = existsSync(genCssTs)
259
289
  ? genCssTs
260
290
  : `${import.meta.dir}/generate-css.js`;
261
- await $ `bun ${genCss} ${PUBLIC}/doc-system.css ${JSON.stringify(config.theme || {})}`.text();
291
+ // generate-css imports the consumer's library to burn the theme; when that graph
292
+ // reaches non-`.ts` sources (e.g. `.tjs`), `--preload` a module that registers the
293
+ // Bun loader plugin so those modules evaluate. (See BUILD-TJS-HOOK.md.)
294
+ const themeArg = JSON.stringify(config.theme || {});
295
+ await (config.generateCssPreload
296
+ ? $ `bun --preload ${config.generateCssPreload} ${genCss} ${PUBLIC}/doc-system.css ${themeArg}`
297
+ : $ `bun ${genCss} ${PUBLIC}/doc-system.css ${themeArg}`).text();
262
298
  console.log(`generated ${pageCount} static pages`);
263
299
  // ── host preset files ──
264
300
  // Idempotent, and an explicit static file (copied from staticDirs) always wins.
@@ -3,6 +3,15 @@ import type { DocSystemTheme } from '../doc-system-styles';
3
3
  import type { Doc } from './docs';
4
4
  import type { BookManifest } from '../book-manifest';
5
5
  export type SiteHost = 'github-pages' | 'firebase' | 'static';
6
+ /** Resolved paths handed to a `libraryBuild` override (see SiteConfig). */
7
+ export interface LibraryBuildContext {
8
+ /** absolute path to the `dist` output dir the artifacts must land in */
9
+ dist: string;
10
+ /** project root the build runs from */
11
+ root: string;
12
+ /** the configured `libraryTsconfig`, if any (so the override can still run tsc) */
13
+ tsconfig?: string;
14
+ }
6
15
  export interface SiteConfig {
7
16
  /** project / brand name — header, <title> suffix, og:site_name */
8
17
  name: string;
@@ -103,6 +112,25 @@ export interface SiteConfig {
103
112
  * yourself (e.g. keep doc comments in the published JS for AI readers).
104
113
  */
105
114
  libraryTsconfig?: string;
115
+ /**
116
+ * Fully override the library build (the `tsc` step that `libraryTsconfig` /
117
+ * `emitLibrary` run). Receives the resolved paths and is responsible for emitting
118
+ * `dist/*.js` + `*.d.ts` for ALL sources. Use this when some sources aren't `.ts`
119
+ * — e.g. native tjs-lang `.tjs` modules, which `tsc` can't compile: run `tsc` for
120
+ * the `.ts` graph and `tjs convert` + `generateDTS` for the `.tjs` files, into the
121
+ * same `dist`. Takes precedence over `libraryTsconfig` and `emitLibrary`. Pairs
122
+ * with `generateCssPreload` (below) for the CSS-extraction eval. See
123
+ * BUILD-TJS-HOOK.md.
124
+ */
125
+ libraryBuild?: (ctx: LibraryBuildContext) => void | Promise<void>;
126
+ /**
127
+ * A module to `--preload` into the CSS-extraction subprocess (`generate-css`),
128
+ * which imports your library to burn the theme stylesheet. Needed when that import
129
+ * graph reaches non-`.ts` sources (e.g. `.tjs`) that require a Bun loader plugin
130
+ * to evaluate — point this at a module that registers it (via `Bun.plugin({...})`
131
+ * at import time). Without it the subprocess throws `Cannot find module './x.tjs'`.
132
+ */
133
+ generateCssPreload?: string;
106
134
  /**
107
135
  * Emit llms.txt agent-discoverability index. Default true (uses `name` /
108
136
  * `description` / `baseUrl` / `projectLinks`). Set false to skip, or pass a