@portel/photon 1.18.0 → 1.19.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.
Files changed (172) hide show
  1. package/dist/auto-ui/beam.d.ts.map +1 -1
  2. package/dist/auto-ui/beam.js +14 -4
  3. package/dist/auto-ui/beam.js.map +1 -1
  4. package/dist/beam-form.bundle.js +5 -3
  5. package/dist/beam-form.bundle.js.map +2 -2
  6. package/dist/beam.bundle.js +686 -30
  7. package/dist/beam.bundle.js.map +3 -3
  8. package/dist/claude-code-plugin.js +1 -1
  9. package/dist/cli/commands/beam.d.ts.map +1 -1
  10. package/dist/cli/commands/beam.js +8 -2
  11. package/dist/cli/commands/beam.js.map +1 -1
  12. package/dist/cli/commands/changelog.d.ts +9 -0
  13. package/dist/cli/commands/changelog.d.ts.map +1 -0
  14. package/dist/cli/commands/changelog.js +133 -0
  15. package/dist/cli/commands/changelog.js.map +1 -0
  16. package/dist/cli/commands/maker.d.ts.map +1 -1
  17. package/dist/cli/commands/maker.js +23 -2
  18. package/dist/cli/commands/maker.js.map +1 -1
  19. package/dist/cli/commands/mcp.d.ts.map +1 -1
  20. package/dist/cli/commands/mcp.js +53 -0
  21. package/dist/cli/commands/mcp.js.map +1 -1
  22. package/dist/cli/commands/package.d.ts.map +1 -1
  23. package/dist/cli/commands/package.js +18 -2
  24. package/dist/cli/commands/package.js.map +1 -1
  25. package/dist/cli/commands/run.d.ts.map +1 -1
  26. package/dist/cli/commands/run.js +1 -0
  27. package/dist/cli/commands/run.js.map +1 -1
  28. package/dist/cli/commands/update.d.ts +3 -2
  29. package/dist/cli/commands/update.d.ts.map +1 -1
  30. package/dist/cli/commands/update.js +50 -43
  31. package/dist/cli/commands/update.js.map +1 -1
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +16 -2
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/cli-alias.js +1 -1
  36. package/dist/cli-alias.js.map +1 -1
  37. package/dist/context-store.d.ts +23 -33
  38. package/dist/context-store.d.ts.map +1 -1
  39. package/dist/context-store.js +147 -97
  40. package/dist/context-store.js.map +1 -1
  41. package/dist/context.d.ts +15 -10
  42. package/dist/context.d.ts.map +1 -1
  43. package/dist/context.js +37 -13
  44. package/dist/context.js.map +1 -1
  45. package/dist/daemon/server.js +4 -2
  46. package/dist/daemon/server.js.map +1 -1
  47. package/dist/data-migration.d.ts +27 -0
  48. package/dist/data-migration.d.ts.map +1 -0
  49. package/dist/data-migration.js +307 -0
  50. package/dist/data-migration.js.map +1 -0
  51. package/dist/editor-support/docblock-tag-catalog.d.ts.map +1 -1
  52. package/dist/editor-support/docblock-tag-catalog.js +6 -0
  53. package/dist/editor-support/docblock-tag-catalog.js.map +1 -1
  54. package/dist/loader.d.ts +10 -0
  55. package/dist/loader.d.ts.map +1 -1
  56. package/dist/loader.js +97 -12
  57. package/dist/loader.js.map +1 -1
  58. package/dist/marketplace-manager.d.ts.map +1 -1
  59. package/dist/marketplace-manager.js +25 -5
  60. package/dist/marketplace-manager.js.map +1 -1
  61. package/dist/photon-cli-runner.d.ts.map +1 -1
  62. package/dist/photon-cli-runner.js +47 -21
  63. package/dist/photon-cli-runner.js.map +1 -1
  64. package/dist/photon-doc-extractor.d.ts +1 -0
  65. package/dist/photon-doc-extractor.d.ts.map +1 -1
  66. package/dist/photon-doc-extractor.js +6 -0
  67. package/dist/photon-doc-extractor.js.map +1 -1
  68. package/dist/readme-syncer.d.ts.map +1 -1
  69. package/dist/readme-syncer.js +6 -1
  70. package/dist/readme-syncer.js.map +1 -1
  71. package/dist/server.d.ts +40 -0
  72. package/dist/server.d.ts.map +1 -1
  73. package/dist/server.js +143 -28
  74. package/dist/server.js.map +1 -1
  75. package/dist/shared/audit.js +4 -4
  76. package/dist/shared/audit.js.map +1 -1
  77. package/dist/tasks/store.d.ts.map +1 -1
  78. package/dist/tasks/store.js +6 -2
  79. package/dist/tasks/store.js.map +1 -1
  80. package/dist/version-notify.d.ts +27 -0
  81. package/dist/version-notify.d.ts.map +1 -0
  82. package/dist/version-notify.js +142 -0
  83. package/dist/version-notify.js.map +1 -0
  84. package/package.json +2 -2
  85. package/dist/auto-ui/bridge/openai-shim.d.ts +0 -20
  86. package/dist/auto-ui/bridge/openai-shim.d.ts.map +0 -1
  87. package/dist/auto-ui/bridge/openai-shim.js +0 -231
  88. package/dist/auto-ui/bridge/openai-shim.js.map +0 -1
  89. package/dist/auto-ui/bridge/photon-app.d.ts +0 -162
  90. package/dist/auto-ui/bridge/photon-app.d.ts.map +0 -1
  91. package/dist/auto-ui/bridge/photon-app.js +0 -460
  92. package/dist/auto-ui/bridge/photon-app.js.map +0 -1
  93. package/dist/auto-ui/daemon-tools.d.ts +0 -45
  94. package/dist/auto-ui/daemon-tools.d.ts.map +0 -1
  95. package/dist/auto-ui/daemon-tools.js +0 -581
  96. package/dist/auto-ui/daemon-tools.js.map +0 -1
  97. package/dist/auto-ui/design-system/index.d.ts +0 -21
  98. package/dist/auto-ui/design-system/index.d.ts.map +0 -1
  99. package/dist/auto-ui/design-system/index.js +0 -27
  100. package/dist/auto-ui/design-system/index.js.map +0 -1
  101. package/dist/auto-ui/design-system/transaction-ui.d.ts +0 -70
  102. package/dist/auto-ui/design-system/transaction-ui.d.ts.map +0 -1
  103. package/dist/auto-ui/design-system/transaction-ui.js +0 -982
  104. package/dist/auto-ui/design-system/transaction-ui.js.map +0 -1
  105. package/dist/auto-ui/playground-server.d.ts +0 -7
  106. package/dist/auto-ui/playground-server.d.ts.map +0 -1
  107. package/dist/auto-ui/playground-server.js +0 -840
  108. package/dist/auto-ui/playground-server.js.map +0 -1
  109. package/dist/auto-ui/rendering/components.d.ts +0 -29
  110. package/dist/auto-ui/rendering/components.d.ts.map +0 -1
  111. package/dist/auto-ui/rendering/components.js +0 -1341
  112. package/dist/auto-ui/rendering/components.js.map +0 -1
  113. package/dist/auto-ui/rendering/field-analyzer.d.ts +0 -104
  114. package/dist/auto-ui/rendering/field-analyzer.d.ts.map +0 -1
  115. package/dist/auto-ui/rendering/field-analyzer.js +0 -447
  116. package/dist/auto-ui/rendering/field-analyzer.js.map +0 -1
  117. package/dist/auto-ui/rendering/field-renderers.d.ts +0 -64
  118. package/dist/auto-ui/rendering/field-renderers.d.ts.map +0 -1
  119. package/dist/auto-ui/rendering/field-renderers.js +0 -317
  120. package/dist/auto-ui/rendering/field-renderers.js.map +0 -1
  121. package/dist/auto-ui/rendering/index.d.ts +0 -28
  122. package/dist/auto-ui/rendering/index.d.ts.map +0 -1
  123. package/dist/auto-ui/rendering/index.js +0 -60
  124. package/dist/auto-ui/rendering/index.js.map +0 -1
  125. package/dist/auto-ui/rendering/layout-selector.d.ts +0 -60
  126. package/dist/auto-ui/rendering/layout-selector.d.ts.map +0 -1
  127. package/dist/auto-ui/rendering/layout-selector.js +0 -476
  128. package/dist/auto-ui/rendering/layout-selector.js.map +0 -1
  129. package/dist/markdown-utils.d.ts +0 -8
  130. package/dist/markdown-utils.d.ts.map +0 -1
  131. package/dist/markdown-utils.js +0 -64
  132. package/dist/markdown-utils.js.map +0 -1
  133. package/dist/mcp-client.d.ts +0 -9
  134. package/dist/mcp-client.d.ts.map +0 -1
  135. package/dist/mcp-client.js +0 -11
  136. package/dist/mcp-client.js.map +0 -1
  137. package/dist/mcp-elicitation.d.ts +0 -32
  138. package/dist/mcp-elicitation.d.ts.map +0 -1
  139. package/dist/mcp-elicitation.js +0 -26
  140. package/dist/mcp-elicitation.js.map +0 -1
  141. package/dist/photons/builder-compass.photon.d.ts +0 -167
  142. package/dist/photons/builder-compass.photon.d.ts.map +0 -1
  143. package/dist/photons/builder-compass.photon.js +0 -816
  144. package/dist/photons/builder-compass.photon.js.map +0 -1
  145. package/dist/photons/builder-compass.photon.ts +0 -1129
  146. package/dist/photons/docs/ui/docs.html +0 -441
  147. package/dist/photons/docs.photon.d.ts +0 -237
  148. package/dist/photons/docs.photon.d.ts.map +0 -1
  149. package/dist/photons/docs.photon.js +0 -483
  150. package/dist/photons/docs.photon.js.map +0 -1
  151. package/dist/photons/docs.photon.ts +0 -536
  152. package/dist/photons/slides.photon.d.ts +0 -212
  153. package/dist/photons/slides.photon.d.ts.map +0 -1
  154. package/dist/photons/slides.photon.js +0 -355
  155. package/dist/photons/slides.photon.js.map +0 -1
  156. package/dist/photons/slides.photon.ts +0 -370
  157. package/dist/photons/spreadsheet/ui/spreadsheet.html +0 -779
  158. package/dist/photons/spreadsheet.photon.d.ts +0 -554
  159. package/dist/photons/spreadsheet.photon.d.ts.map +0 -1
  160. package/dist/photons/spreadsheet.photon.js +0 -1050
  161. package/dist/photons/spreadsheet.photon.js.map +0 -1
  162. package/dist/photons/spreadsheet.photon.ts +0 -1239
  163. package/dist/photons/ui/builder-compass.html +0 -1199
  164. package/dist/photons/ui/builder-compass.photon.html +0 -380
  165. package/dist/security-scanner.d.ts +0 -52
  166. package/dist/security-scanner.d.ts.map +0 -1
  167. package/dist/security-scanner.js +0 -181
  168. package/dist/security-scanner.js.map +0 -1
  169. package/dist/shared/performance.d.ts +0 -65
  170. package/dist/shared/performance.d.ts.map +0 -1
  171. package/dist/shared/performance.js +0 -136
  172. package/dist/shared/performance.js.map +0 -1
@@ -1,370 +0,0 @@
1
- /**
2
- * Slides — AI-Native Presentation Tool
3
- *
4
- * Each instance is a deck: `_use('quarterly-review')` → `quarterly-review.md`.
5
- * Pass a full path to open any markdown file: `_use('/path/to/deck.md')`.
6
- *
7
- * Slides are Marp-compatible markdown rendered natively by Beam's
8
- * `@format slides` viewer — no custom UI, no external dependencies.
9
- *
10
- * @version 2.0.0
11
- * @runtime ^1.14.0
12
- * @tags presentation, slides, markdown, marp, ai-control
13
- * @icon 📽️
14
- * @stateful
15
- */
16
- import * as fs from 'fs/promises';
17
- import { existsSync, mkdirSync } from 'fs';
18
- import * as path from 'path';
19
- import * as os from 'os';
20
-
21
- const DEFAULT_DECK = `---
22
- marp: true
23
- theme: default
24
- paginate: true
25
- transition: fade
26
- ---
27
- # AI-Native Slides
28
- ### Powered by Marp & Photon
29
-
30
- ---
31
-
32
- # How it works
33
-
34
- 1. **AI generates Marp markdown**
35
- 2. **Beam renders high-fidelity slides**
36
- 3. **Navigate with keyboard or buttons**
37
-
38
- ---
39
-
40
- # Try it!
41
-
42
- Ask me to:
43
- - "Add a slide about the benefits of AI"
44
- - "Change the theme to gaia"
45
- - "Edit slide 2 with new content"
46
- `;
47
-
48
- export default class Slides {
49
- protected settings = {
50
- /** @property Directory where slide markdown files are stored */
51
- folder: path.join(os.homedir(), 'Documents', 'slides'),
52
- };
53
-
54
- declare memory: {
55
- get<T>(key: string): Promise<T | null>;
56
- set(key: string, value: unknown): Promise<void>;
57
- };
58
- declare emit: (payload: { event: string; data: unknown }) => void;
59
- declare instanceName: string;
60
-
61
- // ── File Resolution ──────────────────────────────────────────
62
-
63
- private get defaultFolder(): string {
64
- return this.settings?.folder || path.join(os.homedir(), 'Documents', 'slides');
65
- }
66
-
67
- private get deckPath(): string {
68
- const name = this.instanceName || 'slides';
69
- if (path.isAbsolute(name)) return name.endsWith('.md') ? name : name + '.md';
70
- if (name.includes('/') || name.includes('\\')) {
71
- const resolved = path.resolve(name);
72
- return resolved.endsWith('.md') ? resolved : resolved + '.md';
73
- }
74
- const dir = this.defaultFolder;
75
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
76
- return path.join(dir, name.endsWith('.md') ? name : name + '.md');
77
- }
78
-
79
- async onInitialize() {
80
- const dir = this.defaultFolder;
81
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
82
-
83
- if (!existsSync(this.deckPath)) {
84
- await fs.writeFile(this.deckPath, DEFAULT_DECK, 'utf8');
85
- }
86
- }
87
-
88
- // ── Presentation ─────────────────────────────────────────────
89
-
90
- /**
91
- * Open the presentation
92
- * @format slides
93
- * @autorun
94
- * @readOnly
95
- */
96
- async main() {
97
- return await this.readDeck();
98
- }
99
-
100
- /**
101
- * Move to the next slide
102
- */
103
- async next() {
104
- const md = await this.readDeck();
105
- const total = this.countSlides(md);
106
- const state = await this.getState();
107
- if (state.currentSlide < total - 1) {
108
- state.currentSlide++;
109
- await this.memory.set('state', state);
110
- }
111
- this.emit({ event: 'slideChanged', data: { index: state.currentSlide } });
112
- return `Slide ${state.currentSlide + 1} of ${total}`;
113
- }
114
-
115
- /**
116
- * Move to the previous slide
117
- */
118
- async previous() {
119
- const state = await this.getState();
120
- if (state.currentSlide > 0) {
121
- state.currentSlide--;
122
- await this.memory.set('state', state);
123
- }
124
- this.emit({ event: 'slideChanged', data: { index: state.currentSlide } });
125
- return `Slide ${state.currentSlide + 1}`;
126
- }
127
-
128
- /**
129
- * Jump to a specific slide
130
- * @param index 0-based slide index
131
- */
132
- async go({ index }: { index: number }) {
133
- const md = await this.readDeck();
134
- const total = this.countSlides(md);
135
- const state = await this.getState();
136
- state.currentSlide = clamp(Math.trunc(index), 0, Math.max(total - 1, 0));
137
- await this.memory.set('state', state);
138
- this.emit({ event: 'slideChanged', data: { index: state.currentSlide } });
139
- return `Slide ${state.currentSlide + 1} of ${total}`;
140
- }
141
-
142
- // ── Deck Management ──────────────────────────────────────────
143
-
144
- /**
145
- * List saved decks in the slides folder
146
- * @format table
147
- * @readOnly
148
- */
149
- async list() {
150
- const dir = this.defaultFolder;
151
- if (!existsSync(dir)) return [];
152
- const entries = await fs.readdir(dir, { withFileTypes: true });
153
- const decks = await Promise.all(
154
- entries
155
- .filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.md'))
156
- .map(async (e) => {
157
- const stat = await fs.stat(path.join(dir, e.name));
158
- const md = await fs.readFile(path.join(dir, e.name), 'utf8');
159
- return {
160
- file: e.name,
161
- title: firstHeading(md) || e.name.replace(/\.md$/i, ''),
162
- slides: countSeparators(md),
163
- updated: stat.mtime.toISOString().slice(0, 16).replace('T', ' '),
164
- };
165
- })
166
- );
167
- return decks.sort((a, b) => b.updated.localeCompare(a.updated));
168
- }
169
-
170
- /**
171
- * Read the current deck's raw markdown
172
- * @format markdown
173
- * @readOnly
174
- */
175
- async read() {
176
- return await this.readDeck();
177
- }
178
-
179
- /**
180
- * Save markdown to the current deck and show result
181
- * @param markdown Full Marp markdown content
182
- * @format slides
183
- */
184
- async save({ markdown }: { markdown: string }) {
185
- await fs.writeFile(this.deckPath, markdown, 'utf8');
186
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
187
- return markdown;
188
- }
189
-
190
- /**
191
- * Update the full markdown and re-render
192
- * @param markdown New Marp markdown content
193
- * @format slides
194
- */
195
- async update({ markdown }: { markdown: string }) {
196
- return this.save({ markdown });
197
- }
198
-
199
- // ── Slide-Level Operations ───────────────────────────────────
200
-
201
- /**
202
- * Insert a new slide at a position
203
- * @param markdown Slide content (without --- separators)
204
- * @param index Position to insert (appends if omitted)
205
- * @format slides
206
- */
207
- async add(params?: { markdown?: string; index?: number }) {
208
- const md = await this.readDeck();
209
- const { frontmatter, slides } = splitMarpMarkdown(md);
210
- const content = params?.markdown ?? '# New Slide\n\nAdd your content here';
211
- const index =
212
- params?.index != null ? clamp(Math.trunc(params.index), 0, slides.length) : slides.length;
213
- slides.splice(index, 0, content);
214
- const newMd = joinMarpMarkdown(frontmatter, slides);
215
- await fs.writeFile(this.deckPath, newMd, 'utf8');
216
- await this.memory.set('state', { currentSlide: index });
217
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
218
- return newMd;
219
- }
220
-
221
- /**
222
- * Replace a slide's content
223
- * @param index Slide index
224
- * @param markdown New content for the slide
225
- * @format slides
226
- */
227
- async edit({ index, markdown }: { index: number; markdown: string }) {
228
- const md = await this.readDeck();
229
- const { frontmatter, slides } = splitMarpMarkdown(md);
230
- const i = clamp(Math.trunc(index), 0, Math.max(slides.length - 1, 0));
231
- slides[i] = markdown;
232
- const newMd = joinMarpMarkdown(frontmatter, slides);
233
- await fs.writeFile(this.deckPath, newMd, 'utf8');
234
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
235
- return newMd;
236
- }
237
-
238
- /**
239
- * Reorder a slide
240
- * @param from Source index
241
- * @param to Target index
242
- * @format slides
243
- */
244
- async move({ from, to }: { from: number; to: number }) {
245
- const md = await this.readDeck();
246
- const { frontmatter, slides } = splitMarpMarkdown(md);
247
- const f = clamp(Math.trunc(from), 0, Math.max(slides.length - 1, 0));
248
- const t = clamp(Math.trunc(to), 0, Math.max(slides.length - 1, 0));
249
- if (f === t) return md;
250
- const [slide] = slides.splice(f, 1);
251
- slides.splice(t, 0, slide);
252
- const newMd = joinMarpMarkdown(frontmatter, slides);
253
- await fs.writeFile(this.deckPath, newMd, 'utf8');
254
- await this.memory.set('state', { currentSlide: t });
255
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
256
- return newMd;
257
- }
258
-
259
- /**
260
- * Delete a slide
261
- * @param index Slide index
262
- * @destructive
263
- * @format slides
264
- */
265
- async remove({ index }: { index: number }) {
266
- const md = await this.readDeck();
267
- const { frontmatter, slides } = splitMarpMarkdown(md);
268
- if (slides.length <= 1) return md;
269
- const i = clamp(Math.trunc(index), 0, Math.max(slides.length - 1, 0));
270
- slides.splice(i, 1);
271
- const newMd = joinMarpMarkdown(frontmatter, slides);
272
- await fs.writeFile(this.deckPath, newMd, 'utf8');
273
- const cur = clamp(i, 0, Math.max(slides.length - 1, 0));
274
- await this.memory.set('state', { currentSlide: cur });
275
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
276
- return newMd;
277
- }
278
-
279
- /**
280
- * Duplicate a slide
281
- * @param index Slide index to copy
282
- * @format slides
283
- */
284
- async duplicate({ index }: { index: number }) {
285
- const md = await this.readDeck();
286
- const { frontmatter, slides } = splitMarpMarkdown(md);
287
- const i = clamp(Math.trunc(index), 0, Math.max(slides.length - 1, 0));
288
- slides.splice(i + 1, 0, slides[i]);
289
- const newMd = joinMarpMarkdown(frontmatter, slides);
290
- await fs.writeFile(this.deckPath, newMd, 'utf8');
291
- await this.memory.set('state', { currentSlide: i + 1 });
292
- this.emit({ event: 'deckChanged', data: { file: path.basename(this.deckPath) } });
293
- return newMd;
294
- }
295
-
296
- // ── Context ──────────────────────────────────────────────────
297
-
298
- /**
299
- * Current presentation state for AI context
300
- * @readOnly
301
- */
302
- async status() {
303
- const md = await this.readDeck();
304
- const { slides } = splitMarpMarkdown(md);
305
- const state = await this.getState();
306
- return {
307
- file: path.basename(this.deckPath),
308
- currentSlide: state.currentSlide,
309
- totalSlides: slides.length,
310
- currentContent: slides[state.currentSlide] || '',
311
- nextSlidePreview: slides[state.currentSlide + 1] || null,
312
- };
313
- }
314
-
315
- // ── Private ──────────────────────────────────────────────────
316
-
317
- private async readDeck(): Promise<string> {
318
- try {
319
- return await fs.readFile(this.deckPath, 'utf8');
320
- } catch {
321
- return DEFAULT_DECK;
322
- }
323
- }
324
-
325
- private async getState() {
326
- return (await this.memory.get<any>('state')) || { currentSlide: 0 };
327
- }
328
-
329
- private countSlides(markdown: string): number {
330
- return countSeparators(markdown);
331
- }
332
- }
333
-
334
- // ── Helpers ────────────────────────────────────────────────────
335
-
336
- function clamp(v: number, min: number, max: number) {
337
- return Math.min(Math.max(Number.isFinite(v) ? v : min, min), max);
338
- }
339
-
340
- function firstHeading(md: string) {
341
- return md.match(/^#\s+(.+)$/m)?.[1]?.trim() || '';
342
- }
343
-
344
- function countSeparators(md: string): number {
345
- const fm = md.match(/^---\n[\s\S]*?\n---\n*/);
346
- const body = fm ? md.slice(fm[0].length) : md;
347
- return body.split(/\n---\s*\n/).length;
348
- }
349
-
350
- function splitMarpMarkdown(markdown: string) {
351
- const fm = markdown.match(/^---\n[\s\S]*?\n---\n*/);
352
- const frontmatter = fm ? fm[0].trimEnd() : '---\nmarp: true\n---';
353
- const body = fm ? markdown.slice(fm[0].length) : markdown;
354
- const slides: string[] = [];
355
- let cur: string[] = [];
356
- for (const line of body.split('\n')) {
357
- if (line.trim() === '---') {
358
- slides.push(cur.join('\n').trim());
359
- cur = [];
360
- continue;
361
- }
362
- cur.push(line);
363
- }
364
- slides.push(cur.join('\n').trim());
365
- return { frontmatter, slides: slides.filter((s) => s.length > 0) };
366
- }
367
-
368
- function joinMarpMarkdown(frontmatter: string, slides: string[]): string {
369
- return `${frontmatter}\n\n${slides.join('\n\n---\n\n')}\n`;
370
- }