alchemy 0.3.0 → 0.3.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.
Files changed (107) hide show
  1. package/lib/ai/approve.d.ts +99 -0
  2. package/lib/ai/approve.js +76 -0
  3. package/lib/ai/astro-file.js +7 -24
  4. package/lib/ai/client.d.ts +7 -0
  5. package/lib/ai/client.js +45 -0
  6. package/lib/ai/css-file.js +7 -24
  7. package/lib/ai/data.d.ts +26 -21
  8. package/lib/ai/data.js +33 -22
  9. package/lib/ai/document.d.ts +64 -4
  10. package/lib/ai/document.js +102 -55
  11. package/lib/ai/html-file.js +7 -24
  12. package/lib/ai/index.d.ts +2 -0
  13. package/lib/ai/index.js +2 -0
  14. package/lib/ai/json-file.js +11 -32
  15. package/lib/ai/review.d.ts +122 -0
  16. package/lib/ai/review.js +101 -0
  17. package/lib/ai/typescript-file.d.ts +1 -2
  18. package/lib/ai/typescript-file.js +8 -39
  19. package/lib/ai/vue-file.js +7 -24
  20. package/lib/ai/yaml-file.js +12 -48
  21. package/lib/alchemy.js +17 -2
  22. package/lib/apply.js +1 -1
  23. package/lib/cloudflare/generate-asset-manifest.js +1 -1
  24. package/lib/cloudflare/static-site-router.js +16 -7
  25. package/lib/cloudflare/static-site.js +3 -0
  26. package/lib/cloudflare/upload-asset-manifest.js +4 -2
  27. package/lib/fs/copy-file.d.ts +54 -0
  28. package/lib/fs/copy-file.js +63 -0
  29. package/lib/fs/file.d.ts +13 -0
  30. package/lib/fs/file.js +24 -5
  31. package/lib/fs/index.d.ts +6 -0
  32. package/lib/fs/index.js +6 -0
  33. package/lib/fs/static-astro-file.d.ts +34 -0
  34. package/lib/fs/static-astro-file.js +39 -0
  35. package/lib/fs/static-css-file.d.ts +24 -0
  36. package/lib/fs/static-css-file.js +29 -0
  37. package/lib/fs/static-html-file.d.ts +31 -0
  38. package/lib/fs/static-html-file.js +36 -0
  39. package/lib/fs/static-json-file.d.ts +2 -2
  40. package/lib/fs/static-json-file.js +3 -2
  41. package/lib/fs/static-text-file.d.ts +1 -1
  42. package/lib/fs/static-text-file.js +3 -2
  43. package/lib/fs/static-typescript-file.d.ts +2 -2
  44. package/lib/fs/static-typescript-file.js +3 -2
  45. package/lib/fs/static-vue-file.d.ts +28 -0
  46. package/lib/fs/static-vue-file.js +33 -0
  47. package/lib/fs/static-yaml-file.d.ts +11 -8
  48. package/lib/fs/static-yaml-file.js +3 -2
  49. package/lib/internal/getting-started.d.ts +15 -4
  50. package/lib/internal/getting-started.js +34 -41
  51. package/lib/internal/index.d.ts +3 -0
  52. package/lib/internal/index.js +3 -0
  53. package/lib/internal/providers.d.ts +7 -3
  54. package/lib/internal/providers.js +42 -18
  55. package/lib/internal/tutorial.d.ts +104 -0
  56. package/lib/internal/tutorial.js +251 -0
  57. package/lib/web/vitepress/config.d.ts +10 -0
  58. package/lib/web/vitepress/config.js +31 -0
  59. package/lib/web/vitepress/home-page.d.ts +5 -3
  60. package/lib/web/vitepress/home-page.js +48 -35
  61. package/lib/web/vitepress/index.d.ts +1 -0
  62. package/lib/web/vitepress/index.js +1 -0
  63. package/lib/web/vitepress/vitepress.d.ts +5 -4
  64. package/lib/web/vitepress/vitepress.js +17 -34
  65. package/package.json +1 -1
  66. package/src/ai/approve.ts +163 -0
  67. package/src/ai/astro-file.ts +11 -30
  68. package/src/ai/client.ts +59 -0
  69. package/src/ai/css-file.ts +11 -30
  70. package/src/ai/data.ts +50 -25
  71. package/src/ai/document.ts +146 -65
  72. package/src/ai/html-file.ts +11 -30
  73. package/src/ai/index.ts +2 -0
  74. package/src/ai/json-file.ts +13 -37
  75. package/src/ai/review.ts +213 -0
  76. package/src/ai/typescript-file.ts +14 -48
  77. package/src/ai/vue-file.ts +11 -30
  78. package/src/ai/yaml-file.ts +13 -53
  79. package/src/alchemy.ts +18 -7
  80. package/src/apply.ts +8 -8
  81. package/src/cloudflare/generate-asset-manifest.ts +4 -4
  82. package/src/cloudflare/static-site-router.ts +18 -8
  83. package/src/cloudflare/static-site.ts +11 -7
  84. package/src/cloudflare/upload-asset-manifest.ts +6 -4
  85. package/src/cloudflare/worker.ts +44 -43
  86. package/src/fs/copy-file.ts +115 -0
  87. package/src/fs/file.ts +35 -9
  88. package/src/fs/index.ts +6 -0
  89. package/src/fs/static-astro-file.ts +45 -0
  90. package/src/fs/static-css-file.ts +35 -0
  91. package/src/fs/static-html-file.ts +42 -0
  92. package/src/fs/static-json-file.ts +4 -3
  93. package/src/fs/static-text-file.ts +5 -2
  94. package/src/fs/static-typescript-file.ts +4 -3
  95. package/src/fs/static-vue-file.ts +39 -0
  96. package/src/fs/static-yaml-file.ts +13 -9
  97. package/src/internal/getting-started.ts +51 -43
  98. package/src/internal/index.ts +3 -0
  99. package/src/internal/providers.ts +59 -27
  100. package/src/internal/tutorial.ts +392 -0
  101. package/src/web/vitepress/config.ts +48 -0
  102. package/src/web/vitepress/home-page.ts +54 -42
  103. package/src/web/vitepress/index.ts +1 -0
  104. package/src/web/vitepress/vitepress.ts +31 -48
  105. package/lib/internal/project.d.ts +0 -13
  106. package/lib/internal/project.js +0 -101
  107. package/src/internal/project.ts +0 -119
@@ -0,0 +1,392 @@
1
+ import type { CoreMessage } from "ai";
2
+ import { Approve, Document, Review } from "../ai";
3
+ import type { ModelConfig } from "../ai/client";
4
+ import { alchemy } from "../alchemy";
5
+ import type { Context } from "../context";
6
+ import type { Folder } from "../fs";
7
+ import { Resource } from "../resource";
8
+
9
+ /**
10
+ * Properties for creating or updating a Tutorial
11
+ */
12
+ export interface TutorialProps {
13
+ /**
14
+ * The output directory for the tutorial document.
15
+ */
16
+ path: string | Folder;
17
+
18
+ /**
19
+ * The title of the tutorial.
20
+ */
21
+ title: string;
22
+
23
+ /**
24
+ * The prompt to use for generating the tutorial.
25
+ * This should include specific details about the tool or framework.
26
+ */
27
+ prompt: string;
28
+
29
+ /**
30
+ * Optional difficulty level for the tutorial.
31
+ * Defaults to "beginner".
32
+ */
33
+ difficulty?: "beginner" | "intermediate" | "advanced";
34
+
35
+ /**
36
+ * Optional estimated time to complete the tutorial in minutes.
37
+ * Defaults to 30.
38
+ */
39
+ estimatedTime?: number;
40
+
41
+ /**
42
+ * Optional model configuration for generating the tutorial.
43
+ * Defaults to Claude 3.5 Sonnet.
44
+ */
45
+ model?: ModelConfig;
46
+
47
+ /**
48
+ * Maximum number of review iterations.
49
+ * Defaults to 3.
50
+ */
51
+ maxIterations?: number;
52
+
53
+ /**
54
+ * Initial message history for the conversation.
55
+ * If not provided, a new conversation will be started.
56
+ */
57
+ messages?: CoreMessage[];
58
+ }
59
+
60
+ /**
61
+ * Output returned after Tutorial creation/update
62
+ */
63
+ export interface Tutorial extends TutorialProps, Resource<"docs::Tutorial"> {
64
+ /**
65
+ * The Document resource
66
+ */
67
+ document: Document;
68
+
69
+ /**
70
+ * The content of the tutorial
71
+ */
72
+ content: string;
73
+
74
+ /**
75
+ * Message history from the conversation.
76
+ */
77
+ messages: CoreMessage[];
78
+
79
+ /**
80
+ * Time at which the tutorial was created
81
+ */
82
+ createdAt: number;
83
+
84
+ /**
85
+ * Time at which the tutorial was last updated
86
+ */
87
+ updatedAt: number;
88
+ }
89
+
90
+ /**
91
+ * Creates a tutorial document with iterative review and improvement
92
+ *
93
+ * @example
94
+ * // Create a basic tutorial
95
+ * const tutorial = await Tutorial("getting-started", {
96
+ * path: "docs/tutorials/getting-started",
97
+ * title: "Getting Started with Alchemy",
98
+ * prompt: "Create a tutorial for getting started with the Alchemy framework",
99
+ * difficulty: "beginner",
100
+ * estimatedTime: 30
101
+ * });
102
+ *
103
+ * @example
104
+ * // Create an advanced tutorial with custom model and continue from existing messages
105
+ * const advancedTutorial = await Tutorial("advanced-features", {
106
+ * path: "docs/tutorials/advanced-features",
107
+ * title: "Advanced Alchemy Features",
108
+ * prompt: "Create a tutorial covering advanced features of the Alchemy framework",
109
+ * difficulty: "advanced",
110
+ * estimatedTime: 60,
111
+ * model: {
112
+ * id: "claude-3-7-sonnet-latest",
113
+ * provider: "anthropic"
114
+ * },
115
+ * maxIterations: 5,
116
+ * messages: basicTutorial.messages
117
+ * });
118
+ */
119
+ export const Tutorial = Resource(
120
+ "docs::Tutorial",
121
+ async function (
122
+ this: Context<Tutorial>,
123
+ id: string,
124
+ props: TutorialProps
125
+ ): Promise<Tutorial> {
126
+ const {
127
+ path: outFile,
128
+ title,
129
+ prompt,
130
+ difficulty = "beginner",
131
+ estimatedTime = 30,
132
+ model = {
133
+ id: "claude-3-5-sonnet-latest",
134
+ provider: "anthropic",
135
+ },
136
+ maxIterations = 3,
137
+ messages: initialMessages = [],
138
+ } = props;
139
+
140
+ console.log(`Tutorial: Starting creation of "${title}" (ID: ${id})`);
141
+
142
+ // Handle deletion phase
143
+ if (this.phase === "delete") {
144
+ console.log(`Tutorial: Deleting tutorial "${title}" (ID: ${id})`);
145
+ return this.destroy();
146
+ }
147
+
148
+ // System prompts
149
+ const docSystemPrompt = `You are a technical writer creating a comprehensive tutorial.
150
+
151
+ Your task is to create a detailed tutorial about ${title} with difficulty level: ${difficulty} and estimated time to complete: ${estimatedTime} minutes.
152
+
153
+ The tutorial should take users from zero knowledge to a working understanding of the tool or framework.
154
+
155
+ The tutorial should be structured as follows:
156
+
157
+ # ${title}
158
+
159
+ ## Overview
160
+
161
+ (Provide a brief introduction to the tool/framework, its purpose, and what users will learn in this tutorial)
162
+
163
+ ## Prerequisites
164
+
165
+ (List any prerequisites, tools, or knowledge required before starting the tutorial)
166
+
167
+ ## Setup
168
+
169
+ ### Installation
170
+
171
+ \`\`\`bash
172
+ # Installation commands
173
+ \`\`\`
174
+
175
+ ### Configuration
176
+
177
+ (Explain any necessary configuration steps)
178
+
179
+ \`\`\`bash
180
+ # Configuration commands or code
181
+ \`\`\`
182
+
183
+ ## Step 1: [First Step Title]
184
+
185
+ (Explain the first step in detail)
186
+
187
+ \`\`\`bash
188
+ # Commands or code for the first step
189
+ \`\`\`
190
+
191
+ (Explain what the code does and why it's important)
192
+
193
+ ## Step 2: [Second Step Title]
194
+
195
+ (Explain the second step in detail)
196
+
197
+ \`\`\`bash
198
+ # Commands or code for the second step
199
+ \`\`\`
200
+
201
+ (Explain what the code does and why it's important)
202
+
203
+ ## Step 3: [Third Step Title]
204
+
205
+ (Explain the third step in detail)
206
+
207
+ \`\`\`bash
208
+ # Commands or code for the third step
209
+ \`\`\`
210
+
211
+ (Explain what the code does and why it's important)
212
+
213
+ ## Step 4: [Fourth Step Title]
214
+
215
+ (Explain the fourth step in detail)
216
+
217
+ \`\`\`bash
218
+ # Commands or code for the fourth step
219
+ \`\`\`
220
+
221
+ (Explain what the code does and why it's important)
222
+
223
+ ## Step 5: [Fifth Step Title]
224
+
225
+ (Explain the fifth step in detail)
226
+
227
+ \`\`\`bash
228
+ # Commands or code for the fifth step
229
+ \`\`\`
230
+
231
+ (Explain what the code does and why it's important)
232
+
233
+ ## Testing Your Work
234
+
235
+ (Explain how to verify that everything is working correctly)
236
+
237
+ \`\`\`bash
238
+ # Testing commands or code
239
+ \`\`\`
240
+
241
+ ## Troubleshooting
242
+
243
+ (Common issues users might encounter and how to resolve them)
244
+
245
+ ## Next Steps
246
+
247
+ (Suggest additional resources, advanced topics, or projects to try next)
248
+
249
+ ## Additional Resources
250
+
251
+ (Links to documentation, community resources, or related tutorials)`;
252
+
253
+ // Initial message if none provided
254
+ const startingMessages =
255
+ initialMessages.length > 0
256
+ ? initialMessages
257
+ : [
258
+ {
259
+ role: "user" as const,
260
+ content: `Create a comprehensive tutorial about ${title}.\n\n${prompt}\n\nDifficulty level: ${difficulty}\nEstimated time to complete: ${estimatedTime} minutes`,
261
+ },
262
+ ];
263
+
264
+ // Generate the initial tutorial
265
+ console.log(`Tutorial: Generating initial tutorial for "${title}"`);
266
+ let tutorial = await Document(`document`, {
267
+ title: title,
268
+ path: typeof outFile === "string" ? outFile : outFile.path,
269
+ model,
270
+ messages: startingMessages,
271
+ system: docSystemPrompt,
272
+ });
273
+ console.log(
274
+ `Tutorial: Initial tutorial generated for "${title}" (${tutorial.content.length} chars)`
275
+ );
276
+
277
+ // Review and improve the tutorial in a loop
278
+ let iteration = 0;
279
+ let approved = false;
280
+ let finalMessages = tutorial.messages;
281
+
282
+ while (!approved && iteration < maxIterations) {
283
+ iteration++;
284
+ console.log(
285
+ `Tutorial: Starting review iteration ${iteration}/${maxIterations} for "${title}"`
286
+ );
287
+
288
+ // Review the tutorial using system prompt
289
+ console.log(`Tutorial: Requesting review for iteration ${iteration}`);
290
+ const review = await Review(`review-${iteration}`, {
291
+ messages: finalMessages,
292
+ system:
293
+ await alchemy`Please review this tutorial for correctness, conciseness, logical flow, and accurateness.
294
+
295
+ The tutorial should:
296
+ 1. Be technically accurate and free of errors
297
+ 2. Be concise without over-explaining
298
+ 3. Have a logical flow from basic to advanced concepts
299
+ 4. Be accurate in its descriptions and instructions
300
+ 5. Be appropriate for the ${difficulty} difficulty level
301
+ 6. Be completable within approximately ${estimatedTime} minutes
302
+
303
+ Provide specific feedback on areas that need improvement.`,
304
+ model,
305
+ });
306
+
307
+ // Extract the actual review content from the last assistant message
308
+ const reviewContent =
309
+ review.messages[review.messages.length - 1]?.content || "";
310
+ console.log(
311
+ `Tutorial: Review received for iteration ${iteration} (${reviewContent.length} chars)`
312
+ );
313
+
314
+ // Check if the tutorial is approved using system prompt
315
+ console.log(`Tutorial: Evaluating approval for iteration ${iteration}`);
316
+ const approvalResult = await Approve(`approval-${iteration}`, {
317
+ messages: review.messages,
318
+ system:
319
+ await alchemy`Based on the review above, determine if the tutorial meets the quality standards.
320
+ The tutorial should be approved if:
321
+ 1. It is technically accurate and free of errors
322
+ 2. It is concise without over-explaining
323
+ 3. It has a logical flow from basic to advanced concepts
324
+ 4. It is accurate in its descriptions and instructions
325
+ 5. It is appropriate for the ${difficulty} difficulty level
326
+ 6. It is completable within approximately ${estimatedTime} minutes
327
+
328
+ Respond with APPROVED or DENIED, followed by your explanation.`,
329
+ });
330
+ console.log(
331
+ `Tutorial: Approval result for iteration ${iteration}: ${approvalResult.approved ? "APPROVED" : "DENIED"}`
332
+ );
333
+
334
+ // Log approval status
335
+ if (approvalResult.approved) {
336
+ console.log(
337
+ `Tutorial: Final tutorial approved: ${approvalResult.explanation}`
338
+ );
339
+ approved = true;
340
+ finalMessages = approvalResult.messages;
341
+ } else {
342
+ console.log(
343
+ `Tutorial: Tutorial needs improvement: ${approvalResult.explanation}`
344
+ );
345
+
346
+ // Add improvement request and generate an improved tutorial
347
+ const improvementMessages = [
348
+ ...approvalResult.messages,
349
+ {
350
+ role: "user" as const,
351
+ content: `Please create an improved version of the tutorial that addresses the issues identified in the review: ${approvalResult.explanation}`,
352
+ },
353
+ ];
354
+
355
+ console.log(
356
+ `Tutorial: Regenerating tutorial based on feedback for iteration ${iteration}`
357
+ );
358
+
359
+ tutorial = await Document(`tutorial-${iteration}`, {
360
+ title: title,
361
+ path: typeof outFile === "string" ? outFile : outFile.path,
362
+ model,
363
+ messages: improvementMessages,
364
+ system: docSystemPrompt,
365
+ });
366
+ console.log(
367
+ `Tutorial: Improved tutorial generated for iteration ${iteration} (${tutorial.content.length} chars)`
368
+ );
369
+
370
+ finalMessages = tutorial.messages;
371
+ }
372
+ }
373
+
374
+ if (!approved) {
375
+ console.log(
376
+ `Tutorial: Tutorial not approved after ${maxIterations} iterations. Using the best version available.`
377
+ );
378
+ }
379
+
380
+ console.log(`Tutorial: Completed creation of "${title}" (ID: ${id})`);
381
+
382
+ // Return the tutorial resource
383
+ return this({
384
+ ...props,
385
+ document: tutorial,
386
+ content: tutorial.content,
387
+ messages: finalMessages,
388
+ createdAt: Date.now(),
389
+ updatedAt: Date.now(),
390
+ });
391
+ }
392
+ );
@@ -0,0 +1,48 @@
1
+ import path from "path";
2
+ import type { DefaultTheme, ThemeOptions } from "vitepress";
3
+ import { StaticTypeScriptFile } from "../../fs/static-typescript-file";
4
+
5
+ export type VitePressConfigProps = {
6
+ cwd: string;
7
+ title?: string;
8
+ description?: string;
9
+ theme?: ThemeOptions;
10
+ themeConfig: DefaultTheme.Config;
11
+ };
12
+
13
+ export type VitePressConfig = Awaited<ReturnType<typeof VitePressConfig>>;
14
+
15
+ export function VitePressConfig(props: VitePressConfigProps) {
16
+ return StaticTypeScriptFile(
17
+ path.join(props.cwd, ".vitepress", "config.mts"),
18
+ `import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
19
+ import footnotePlugin from "markdown-it-footnote";
20
+ import { defineConfig } from "vitepress";
21
+
22
+ // https://vitepress.dev/reference/site-config
23
+ export default defineConfig({
24
+ title: ${JSON.stringify(props.title || "Alchemy")},
25
+ description: ${JSON.stringify(props.description || "Alchemy Docs")},
26
+ markdown: {
27
+ // @ts-ignore
28
+ codeTransformers: [transformerTwoslash()],
29
+ theme: ${JSON.stringify(
30
+ props.theme ?? {
31
+ light: "light-plus",
32
+ dark: "dark-plus",
33
+ }
34
+ )},
35
+ config: (md) => md.use(footnotePlugin),
36
+ },
37
+ // https://vitepress.dev/reference/default-theme-config
38
+ themeConfig: ${JSON.stringify({
39
+ ...props.themeConfig,
40
+ search: props.themeConfig.search ?? { provider: "local" },
41
+ nav: props.themeConfig.nav ?? [{ text: "Home", link: "/" }],
42
+ sidebar: props.themeConfig.sidebar ?? [],
43
+ socialLinks: props.themeConfig.socialLinks ?? [],
44
+ })}
45
+ });
46
+ `
47
+ );
48
+ }
@@ -1,6 +1,7 @@
1
- import alchemy from "alchemy";
2
1
  import yaml from "yaml";
3
2
  import { Document } from "../../ai/document";
3
+ import { alchemy } from "../../alchemy";
4
+ import { StaticTextFile } from "../../fs";
4
5
  import type { Secret } from "../../secret";
5
6
 
6
7
  /**
@@ -184,12 +185,12 @@ export interface HomePageProps {
184
185
  /**
185
186
  * User prompt describing the design of the home page
186
187
  */
187
- prompt: string;
188
+ prompt?: string;
188
189
 
189
190
  /**
190
191
  * Optional extension to the built-in system prompt
191
192
  */
192
- systemPromptExtension?: string;
193
+ system?: string;
193
194
 
194
195
  /**
195
196
  * Base URL for the OpenAI API
@@ -218,7 +219,7 @@ export interface HomePageProps {
218
219
  /**
219
220
  * Output type for the HomePage resource
220
221
  */
221
- export type HomePage = import("../../ai/document").Document;
222
+ export type HomePage = StaticTextFile | Document;
222
223
 
223
224
  /**
224
225
  * Parse YAML frontmatter to home page config
@@ -313,7 +314,7 @@ Follow these guidelines:
313
314
  6. Ensure all links are properly formatted
314
315
  7. Use appropriate markdown formatting for headings, lists, etc.
315
316
 
316
- ${props.systemPromptExtension || ""}
317
+ ${props.system || ""}
317
318
  `;
318
319
 
319
320
  // Convert hero and features to YAML strings if provided
@@ -322,42 +323,53 @@ ${props.systemPromptExtension || ""}
322
323
  ? JSON.stringify(props.features, null, 2)
323
324
  : "";
324
325
 
325
- // Create the document using the AI Document resource
326
- return Document(`${id}`, {
327
- title: props.title,
328
- path: props.outFile,
329
- baseURL: props.baseURL,
330
- apiKey: props.apiKey,
331
- model: props.model ?? {
332
- id: "claude-3-7-sonnet-latest",
333
- provider: "anthropic",
334
- },
335
- temperature: props.temperature ?? 0.7,
336
- prompt: await alchemy`
337
- ${systemPrompt}
338
-
339
- Create a VitePress homepage based on the following description:
340
- ${props.prompt}
341
-
342
- ${
343
- props.hero
344
- ? `Use this hero section configuration:
345
- \`\`\`json
346
- ${heroYaml}
347
- \`\`\``
348
- : ""
349
- }
350
-
351
- ${
352
- props.features
353
- ? `Use these features:
354
- \`\`\`json
355
- ${featuresYaml}
356
- \`\`\``
357
- : ""
358
- }
326
+ if (props.prompt) {
327
+ return Document(id, {
328
+ title: props.title,
329
+ path: props.outFile,
330
+ baseURL: props.baseURL,
331
+ apiKey: props.apiKey,
332
+ model: props.model ?? {
333
+ id: "claude-3-7-sonnet-latest",
334
+ provider: "anthropic",
335
+ },
336
+ temperature: props.temperature ?? 0.7,
337
+ prompt: await alchemy`
338
+ ${systemPrompt}
359
339
 
360
- The output should be a complete index.md file with proper YAML frontmatter and markdown content.
361
- `,
362
- });
340
+ Create a VitePress homepage based on the following description:
341
+ ${props.prompt}
342
+
343
+ ${
344
+ props.hero
345
+ ? `Use this hero section configuration:
346
+ \`\`\`json
347
+ ${heroYaml}
348
+ \`\`\``
349
+ : ""
350
+ }
351
+
352
+ ${
353
+ props.features
354
+ ? `Use these features:
355
+ \`\`\`json
356
+ ${featuresYaml}
357
+ \`\`\``
358
+ : ""
359
+ }
360
+
361
+ The output should be a complete index.md file with proper YAML frontmatter and markdown content.
362
+ `,
363
+ });
364
+ } else {
365
+ return StaticTextFile(id, props.outFile, `---
366
+ ${yaml.stringify({
367
+ layout: "home",
368
+ name: props.title,
369
+ hero: props.hero,
370
+ features: props.features,
371
+ })}
372
+ ---
373
+ `);
374
+ }
363
375
  }
@@ -1,3 +1,4 @@
1
+ export * from "./config";
1
2
  export * from "./custom-theme";
2
3
  export * from "./home-page";
3
4
  export * from "./vitepress";