alchemy 0.2.5 → 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 (197) hide show
  1. package/README.md +3 -3
  2. package/lib/ai/approve.d.ts +99 -0
  3. package/lib/ai/approve.js +76 -0
  4. package/lib/ai/astro-file.d.ts +137 -0
  5. package/lib/ai/astro-file.js +156 -0
  6. package/lib/ai/client.d.ts +7 -8
  7. package/lib/ai/client.js +48 -19
  8. package/lib/ai/css-file.d.ts +131 -0
  9. package/lib/ai/css-file.js +141 -0
  10. package/lib/ai/data.d.ts +51 -6
  11. package/lib/ai/data.js +58 -12
  12. package/lib/ai/document.d.ts +108 -24
  13. package/lib/ai/document.js +166 -52
  14. package/lib/ai/html-file.d.ts +128 -0
  15. package/lib/ai/html-file.js +138 -0
  16. package/lib/ai/index.d.ts +9 -0
  17. package/lib/ai/index.js +9 -0
  18. package/lib/ai/json-file.d.ts +160 -0
  19. package/lib/ai/json-file.js +187 -0
  20. package/lib/ai/review.d.ts +122 -0
  21. package/lib/ai/review.js +101 -0
  22. package/lib/ai/typescript-file.d.ts +139 -0
  23. package/lib/ai/typescript-file.js +145 -0
  24. package/lib/ai/vue-file.d.ts +126 -0
  25. package/lib/ai/vue-file.js +136 -0
  26. package/lib/ai/yaml-file.d.ts +169 -0
  27. package/lib/ai/yaml-file.js +200 -0
  28. package/lib/alchemy.js +17 -2
  29. package/lib/apply.js +1 -1
  30. package/lib/cloudflare/dns.d.ts +88 -0
  31. package/lib/cloudflare/dns.js +192 -0
  32. package/lib/cloudflare/generate-asset-manifest.js +1 -1
  33. package/lib/cloudflare/index.d.ts +2 -1
  34. package/lib/cloudflare/index.js +2 -1
  35. package/lib/cloudflare/r2-rest-state-store.d.ts +125 -0
  36. package/lib/cloudflare/r2-rest-state-store.js +254 -0
  37. package/lib/cloudflare/response.d.ts +12 -0
  38. package/lib/cloudflare/response.js +0 -0
  39. package/lib/cloudflare/static-site-router.js +16 -7
  40. package/lib/cloudflare/static-site.js +3 -0
  41. package/lib/cloudflare/upload-asset-manifest.js +4 -2
  42. package/lib/cloudflare/zone.d.ts +18 -0
  43. package/lib/cloudflare/zone.js +17 -4
  44. package/lib/dns/godaddy.d.ts +7 -0
  45. package/lib/dns/godaddy.js +21 -0
  46. package/lib/dns/import-dns.d.ts +82 -0
  47. package/lib/dns/import-dns.js +114 -0
  48. package/lib/dns/index.d.ts +2 -0
  49. package/lib/dns/index.js +2 -0
  50. package/lib/dns/record.d.ts +88 -0
  51. package/lib/dns/record.js +13 -0
  52. package/lib/fs/copy-file.d.ts +54 -0
  53. package/lib/fs/copy-file.js +63 -0
  54. package/lib/fs/file-system-state-store.d.ts +17 -0
  55. package/lib/fs/file-system-state-store.js +87 -0
  56. package/lib/fs/file.d.ts +13 -0
  57. package/lib/fs/file.js +24 -5
  58. package/lib/fs/folder.d.ts +10 -0
  59. package/lib/fs/folder.js +2 -2
  60. package/lib/fs/index.d.ts +10 -4
  61. package/lib/fs/index.js +10 -4
  62. package/lib/fs/static-astro-file.d.ts +34 -0
  63. package/lib/fs/static-astro-file.js +39 -0
  64. package/lib/fs/static-css-file.d.ts +24 -0
  65. package/lib/fs/static-css-file.js +29 -0
  66. package/lib/fs/static-html-file.d.ts +31 -0
  67. package/lib/fs/static-html-file.js +36 -0
  68. package/lib/fs/{json-file.d.ts → static-json-file.d.ts} +3 -3
  69. package/lib/fs/static-json-file.js +15 -0
  70. package/lib/fs/{text-file.d.ts → static-text-file.d.ts} +2 -2
  71. package/lib/fs/static-text-file.js +8 -0
  72. package/lib/fs/{typescript-file.d.ts → static-typescript-file.d.ts} +3 -3
  73. package/lib/fs/{typescript-file.js → static-typescript-file.js} +3 -2
  74. package/lib/fs/static-vue-file.d.ts +28 -0
  75. package/lib/fs/static-vue-file.js +33 -0
  76. package/lib/fs/static-yaml-file.d.ts +22 -0
  77. package/lib/fs/{yaml-file.js → static-yaml-file.js} +3 -2
  78. package/lib/internal/getting-started.d.ts +21 -0
  79. package/lib/internal/getting-started.js +87 -0
  80. package/lib/internal/index.d.ts +3 -0
  81. package/lib/internal/index.js +3 -0
  82. package/lib/internal/providers.d.ts +27 -0
  83. package/lib/internal/providers.js +172 -0
  84. package/lib/internal/tutorial.d.ts +104 -0
  85. package/lib/internal/tutorial.js +251 -0
  86. package/lib/resource.js +8 -1
  87. package/lib/scope.d.ts +1 -1
  88. package/lib/scope.js +4 -2
  89. package/lib/state.d.ts +1 -16
  90. package/lib/state.js +0 -87
  91. package/lib/test/bun.d.ts +11 -0
  92. package/lib/test/bun.js +36 -8
  93. package/lib/web/astro.d.ts +147 -0
  94. package/lib/web/astro.js +414 -0
  95. package/lib/{shadcn/component.js → web/shadcn-component.js} +2 -9
  96. package/lib/web/shadcn.d.ts +97 -0
  97. package/lib/web/shadcn.js +99 -0
  98. package/lib/web/tailwind.d.ts +64 -0
  99. package/lib/web/tailwind.js +97 -0
  100. package/lib/{vite → web}/vite.d.ts +5 -0
  101. package/lib/{vite → web}/vite.js +44 -44
  102. package/lib/web/vitepress/config.d.ts +10 -0
  103. package/lib/web/vitepress/config.js +31 -0
  104. package/lib/web/vitepress/custom-theme.d.ts +173 -0
  105. package/lib/web/vitepress/custom-theme.js +336 -0
  106. package/lib/{vitepress → web/vitepress}/dependencies.d.ts +2 -2
  107. package/lib/{vitepress → web/vitepress}/dependencies.js +1 -1
  108. package/lib/web/vitepress/home-page.d.ts +246 -0
  109. package/lib/web/vitepress/home-page.js +147 -0
  110. package/lib/{vitepress → web/vitepress}/index.d.ts +2 -0
  111. package/lib/{vitepress → web/vitepress}/index.js +2 -0
  112. package/lib/{vitepress → web/vitepress}/vitepress.d.ts +15 -12
  113. package/lib/{vitepress → web/vitepress}/vitepress.js +26 -44
  114. package/package.json +6 -2
  115. package/src/ai/approve.ts +163 -0
  116. package/src/ai/astro-file.ts +269 -0
  117. package/src/ai/client.ts +60 -21
  118. package/src/ai/css-file.ts +247 -0
  119. package/src/ai/data.ts +81 -19
  120. package/src/ai/document.ts +240 -62
  121. package/src/ai/html-file.ts +244 -0
  122. package/src/ai/index.ts +9 -0
  123. package/src/ai/json-file.ts +325 -0
  124. package/src/ai/review.ts +213 -0
  125. package/src/ai/typescript-file.ts +259 -0
  126. package/src/ai/vue-file.ts +242 -0
  127. package/src/ai/yaml-file.ts +328 -0
  128. package/src/alchemy.ts +18 -7
  129. package/src/apply.ts +8 -9
  130. package/src/cloudflare/dns.ts +344 -0
  131. package/src/cloudflare/generate-asset-manifest.ts +4 -4
  132. package/src/cloudflare/index.ts +2 -1
  133. package/src/cloudflare/r2-rest-state-store.ts +353 -0
  134. package/src/cloudflare/response.ts +9 -0
  135. package/src/cloudflare/static-site-router.ts +18 -8
  136. package/src/cloudflare/static-site.ts +11 -7
  137. package/src/cloudflare/upload-asset-manifest.ts +6 -4
  138. package/src/cloudflare/worker.ts +44 -43
  139. package/src/cloudflare/zone.ts +39 -23
  140. package/src/dns/godaddy.ts +29 -0
  141. package/src/dns/import-dns.ts +213 -0
  142. package/src/dns/index.ts +2 -0
  143. package/src/dns/record.ts +121 -0
  144. package/src/fs/copy-file.ts +115 -0
  145. package/src/fs/file-system-state-store.ts +109 -0
  146. package/src/fs/file.ts +35 -9
  147. package/src/fs/folder.ts +14 -2
  148. package/src/fs/index.ts +10 -4
  149. package/src/fs/static-astro-file.ts +45 -0
  150. package/src/fs/static-css-file.ts +35 -0
  151. package/src/fs/static-html-file.ts +42 -0
  152. package/src/fs/static-json-file.ts +34 -0
  153. package/src/fs/{text-file.ts → static-text-file.ts} +9 -3
  154. package/src/fs/{typescript-file.ts → static-typescript-file.ts} +7 -6
  155. package/src/fs/static-vue-file.ts +39 -0
  156. package/src/fs/static-yaml-file.ts +33 -0
  157. package/src/internal/getting-started.ts +115 -0
  158. package/src/internal/index.ts +3 -0
  159. package/src/internal/providers.ts +241 -0
  160. package/src/internal/tutorial.ts +392 -0
  161. package/src/resource.ts +10 -1
  162. package/src/scope.ts +5 -6
  163. package/src/state.ts +1 -111
  164. package/src/test/bun.ts +60 -10
  165. package/src/web/astro.ts +644 -0
  166. package/src/{shadcn/component.ts → web/shadcn-component.ts} +5 -13
  167. package/src/web/shadcn.ts +219 -0
  168. package/src/web/tailwind.ts +167 -0
  169. package/src/{vite → web}/vite.ts +54 -56
  170. package/src/web/vitepress/config.ts +48 -0
  171. package/src/web/vitepress/custom-theme.ts +514 -0
  172. package/src/{vitepress → web/vitepress}/dependencies.ts +2 -2
  173. package/src/web/vitepress/home-page.ts +375 -0
  174. package/src/{vitepress → web/vitepress}/index.ts +2 -0
  175. package/src/{vitepress → web/vitepress}/vitepress.ts +62 -72
  176. package/lib/cloudflare/state.d.ts +0 -82
  177. package/lib/cloudflare/state.js +0 -108
  178. package/lib/fs/json-file.js +0 -7
  179. package/lib/fs/text-file.js +0 -7
  180. package/lib/fs/yaml-file.d.ts +0 -19
  181. package/lib/internal/docs.d.ts +0 -5
  182. package/lib/internal/docs.js +0 -287
  183. package/lib/shadcn/index.d.ts +0 -1
  184. package/lib/shadcn/index.js +0 -1
  185. package/lib/vite/index.d.ts +0 -1
  186. package/lib/vite/index.js +0 -1
  187. package/lib/vitepress/home-page.d.ts +0 -133
  188. package/lib/vitepress/home-page.js +0 -11
  189. package/src/cloudflare/state.ts +0 -138
  190. package/src/fs/json-file.ts +0 -23
  191. package/src/fs/yaml-file.ts +0 -26
  192. package/src/internal/docs.ts +0 -338
  193. package/src/shadcn/index.ts +0 -1
  194. package/src/vite/index.ts +0 -1
  195. package/src/vitepress/home-page.ts +0 -166
  196. /package/lib/{shadcn/component.d.ts → web/shadcn-component.d.ts} +0 -0
  197. /package/src/{vitepress → web/vitepress}/index.md +0 -0
@@ -0,0 +1,173 @@
1
+ import type { ModelConfig } from "../../ai/client";
2
+ import type { Context } from "../../context";
3
+ import { Resource } from "../../resource";
4
+ import type { Secret } from "../../secret";
5
+ /**
6
+ * Theme component props for customizing the layout
7
+ */
8
+ export interface ThemeComponentProps {
9
+ /**
10
+ * Name of the component
11
+ */
12
+ name: string;
13
+ /**
14
+ * Description of what the component does
15
+ */
16
+ description: string;
17
+ /**
18
+ * Features or functionality to include in the component
19
+ */
20
+ features?: string[];
21
+ }
22
+ /**
23
+ * Properties for creating or updating a VitePress custom theme
24
+ */
25
+ export interface CustomThemeProps {
26
+ /**
27
+ * Output directory for the theme files
28
+ */
29
+ outDir: string;
30
+ /**
31
+ * Title of the theme
32
+ */
33
+ title: string;
34
+ /**
35
+ * Description of the theme
36
+ */
37
+ description: string;
38
+ /**
39
+ * Components to include in the theme
40
+ */
41
+ components?: ThemeComponentProps[];
42
+ /**
43
+ * Whether to include dark mode support
44
+ * @default true
45
+ */
46
+ darkMode?: boolean;
47
+ /**
48
+ * Custom CSS variables for theming
49
+ */
50
+ customCssVars?: Record<string, string>;
51
+ /**
52
+ * Custom plugins to add to the theme
53
+ */
54
+ plugins?: string[];
55
+ /**
56
+ * User prompt describing the design of the theme
57
+ */
58
+ prompt: string;
59
+ /**
60
+ * Optional extension to the built-in system prompt
61
+ */
62
+ systemPromptExtension?: string;
63
+ /**
64
+ * Base URL for the OpenAI API
65
+ * @default 'https://api.openai.com/v1'
66
+ */
67
+ baseURL?: string;
68
+ /**
69
+ * OpenAI API key to use for generating content
70
+ * If not provided, will use OPENAI_API_KEY environment variable
71
+ */
72
+ apiKey?: Secret;
73
+ /**
74
+ * Model configuration for the AI generator
75
+ */
76
+ model?: ModelConfig;
77
+ /**
78
+ * Temperature for controlling randomness in generation
79
+ * @default 0.7
80
+ */
81
+ temperature?: number;
82
+ }
83
+ /**
84
+ * A generated file in the custom theme
85
+ */
86
+ export interface ThemeFile {
87
+ /**
88
+ * Path to the file
89
+ */
90
+ path: string;
91
+ /**
92
+ * Content of the file
93
+ */
94
+ content: string;
95
+ }
96
+ /**
97
+ * Output for the VitePress custom theme resource
98
+ */
99
+ export interface CustomTheme extends CustomThemeProps, Resource<"vitepress::CustomTheme"> {
100
+ /**
101
+ * Path to the generated theme directory
102
+ */
103
+ themePath: string;
104
+ /**
105
+ * List of generated files
106
+ */
107
+ files: ThemeFile[];
108
+ /**
109
+ * Time at which the theme was created
110
+ */
111
+ createdAt: number;
112
+ /**
113
+ * Time at which the theme was last updated
114
+ */
115
+ updatedAt: number;
116
+ }
117
+ /**
118
+ * Resource for generating a custom VitePress theme using AI.
119
+ *
120
+ * Generates the necessary theme files including:
121
+ * - Theme entry file (index.ts)
122
+ * - Layout component (Layout.vue)
123
+ * - Additional components based on configuration
124
+ * - Style sheets and utilities
125
+ *
126
+ * @example
127
+ * // Create a basic custom theme
128
+ * const theme = await CustomTheme("docs-theme", {
129
+ * outDir: "./.vitepress/theme",
130
+ * title: "My Custom Theme",
131
+ * description: "A clean, minimal theme for documentation",
132
+ * prompt: "Create a clean documentation theme with a sidebar and search"
133
+ * });
134
+ *
135
+ * @example
136
+ * // Create a theme with specific components
137
+ * const complexTheme = await CustomTheme("blog-theme", {
138
+ * outDir: "./.vitepress/theme",
139
+ * title: "Blog Theme",
140
+ * description: "A theme for technical blogs",
141
+ * components: [
142
+ * {
143
+ * name: "PostList",
144
+ * description: "Component that displays a list of blog posts with pagination",
145
+ * features: ["thumbnail images", "post dates", "categories", "excerpts"]
146
+ * },
147
+ * {
148
+ * name: "TableOfContents",
149
+ * description: "Component that displays the current page's table of contents",
150
+ * features: ["sticky positioning", "active link highlighting"]
151
+ * }
152
+ * ],
153
+ * darkMode: true,
154
+ * prompt: "Create a modern blog theme with post listings and detailed article pages"
155
+ * });
156
+ *
157
+ * @example
158
+ * // Create a theme with custom CSS variables
159
+ * const brandedTheme = await CustomTheme("branded-theme", {
160
+ * outDir: "./.vitepress/theme",
161
+ * title: "Branded Docs",
162
+ * description: "A themed documentation site with custom branding",
163
+ * customCssVars: {
164
+ * "--vp-c-brand": "#3a70b0",
165
+ * "--vp-c-brand-light": "#5785bc",
166
+ * "--vp-c-brand-lighter": "#79a1ce",
167
+ * "--vp-c-brand-dark": "#2c5989",
168
+ * "--vp-c-brand-darker": "#1e3d5c"
169
+ * },
170
+ * prompt: "Create a documentation theme with custom branding and color scheme"
171
+ * });
172
+ */
173
+ export declare const CustomTheme: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<CustomTheme>, id: string, props: CustomThemeProps) => Promise<CustomTheme>);
@@ -0,0 +1,336 @@
1
+ import { type } from "arktype";
2
+ import path from "path";
3
+ import { CSSFile } from "../../ai/css-file";
4
+ import { Data } from "../../ai/data";
5
+ import { TypeScriptFile } from "../../ai/typescript-file";
6
+ import { VueFile } from "../../ai/vue-file";
7
+ import { alchemy } from "../../alchemy";
8
+ import { Folder } from "../../fs";
9
+ import { Resource } from "../../resource";
10
+ /**
11
+ * Resource for generating a custom VitePress theme using AI.
12
+ *
13
+ * Generates the necessary theme files including:
14
+ * - Theme entry file (index.ts)
15
+ * - Layout component (Layout.vue)
16
+ * - Additional components based on configuration
17
+ * - Style sheets and utilities
18
+ *
19
+ * @example
20
+ * // Create a basic custom theme
21
+ * const theme = await CustomTheme("docs-theme", {
22
+ * outDir: "./.vitepress/theme",
23
+ * title: "My Custom Theme",
24
+ * description: "A clean, minimal theme for documentation",
25
+ * prompt: "Create a clean documentation theme with a sidebar and search"
26
+ * });
27
+ *
28
+ * @example
29
+ * // Create a theme with specific components
30
+ * const complexTheme = await CustomTheme("blog-theme", {
31
+ * outDir: "./.vitepress/theme",
32
+ * title: "Blog Theme",
33
+ * description: "A theme for technical blogs",
34
+ * components: [
35
+ * {
36
+ * name: "PostList",
37
+ * description: "Component that displays a list of blog posts with pagination",
38
+ * features: ["thumbnail images", "post dates", "categories", "excerpts"]
39
+ * },
40
+ * {
41
+ * name: "TableOfContents",
42
+ * description: "Component that displays the current page's table of contents",
43
+ * features: ["sticky positioning", "active link highlighting"]
44
+ * }
45
+ * ],
46
+ * darkMode: true,
47
+ * prompt: "Create a modern blog theme with post listings and detailed article pages"
48
+ * });
49
+ *
50
+ * @example
51
+ * // Create a theme with custom CSS variables
52
+ * const brandedTheme = await CustomTheme("branded-theme", {
53
+ * outDir: "./.vitepress/theme",
54
+ * title: "Branded Docs",
55
+ * description: "A themed documentation site with custom branding",
56
+ * customCssVars: {
57
+ * "--vp-c-brand": "#3a70b0",
58
+ * "--vp-c-brand-light": "#5785bc",
59
+ * "--vp-c-brand-lighter": "#79a1ce",
60
+ * "--vp-c-brand-dark": "#2c5989",
61
+ * "--vp-c-brand-darker": "#1e3d5c"
62
+ * },
63
+ * prompt: "Create a documentation theme with custom branding and color scheme"
64
+ * });
65
+ */
66
+ export const CustomTheme = Resource("vitepress::CustomTheme", async function (id, props) {
67
+ // Handle deletion
68
+ if (this.phase === "delete") {
69
+ // No need to actually delete files, as they're not critical infrastructure
70
+ // In a real implementation, you might want to clean up files
71
+ return this.destroy();
72
+ }
73
+ // Ensure the output directory exists
74
+ await Folder(props.outDir);
75
+ // Create components directory if it doesn't exist
76
+ await Folder(path.join(props.outDir, "components"));
77
+ // Build the system prompt with optional extension
78
+ const systemPrompt = `
79
+ You are creating a custom VitePress theme.
80
+
81
+ A VitePress custom theme consists of multiple files:
82
+ 1. An entry file (index.ts or index.js) that exports the theme object
83
+ 2. A Layout component (Layout.vue) that handles the overall page structure
84
+ 3. Optional additional Vue components for specific functionality
85
+ 4. Optional style files for theming and customization
86
+
87
+ The theme entry file must export an object with:
88
+ - Layout: The root layout component (required)
89
+ - enhanceApp: Function to enhance the Vue app (optional)
90
+ - extends: Another theme to extend (optional)
91
+
92
+ Follow these guidelines:
93
+ 1. Use Vue 3 Composition API and <script setup> syntax
94
+ 2. Ensure the theme is SSR-compatible
95
+ 3. Use the useData() composable to access page and site data
96
+ 4. Handle different page layouts (home, 404, regular pages)
97
+ 5. Include proper TypeScript types
98
+ 6. Use modern JavaScript/TypeScript features
99
+ 7. Include clear comments explaining key functionality
100
+ 8. Make components reusable and customizable
101
+ 9. Include support for dark mode if requested
102
+
103
+ ${props.systemPromptExtension || ""}
104
+ `;
105
+ // Generate the theme entry file (index.ts)
106
+ const indexFile = await TypeScriptFile(`${id}-index`, {
107
+ path: path.join(props.outDir, "index.ts"),
108
+ prompt: await alchemy `
109
+ Create a VitePress theme entry file (index.ts) for a theme named "${props.title}".
110
+
111
+ The theme should:
112
+ - Export a default theme object with the required properties
113
+ - Import the Layout component
114
+ - Include a proper enhanceApp function
115
+ - Include TypeScript types
116
+ - Have clear comments explaining the code
117
+
118
+ ${props.description ? `Theme description: ${props.description}` : ""}
119
+ ${props.plugins?.length ? `Include these plugins: ${props.plugins.join(", ")}` : ""}
120
+
121
+ The output should be a complete, well-structured TypeScript file.
122
+ `,
123
+ system: `${systemPrompt}
124
+ You are writing a TypeScript entry file for a VitePress theme.`,
125
+ baseURL: props.baseURL,
126
+ apiKey: props.apiKey,
127
+ model: props.model,
128
+ temperature: props.temperature,
129
+ });
130
+ // Generate the Layout component
131
+ const layoutFile = await VueFile(`${id}-layout`, {
132
+ path: path.join(props.outDir, "Layout.vue"),
133
+ prompt: await alchemy `
134
+ Create a Layout.vue component for a VitePress theme named "${props.title}".
135
+
136
+ The layout should:
137
+ - Use <script setup> with the Composition API
138
+ - Import and use the useData() composable
139
+ - Handle different page types (regular pages, home pages, 404 pages)
140
+ - Include a <Content /> component to render the page content
141
+ - Have a clean, modern design
142
+ - Include proper TypeScript types
143
+ - Use Vue's Teleport for elements like modals if needed
144
+
145
+ The layout should use modular components for different parts of the UI, such as:
146
+ - NavBar/Header component for navigation
147
+ - Sidebar component for documentation navigation
148
+ - Footer component
149
+ - Home page specific components (like hero sections)
150
+ - 404 page component
151
+
152
+ These components should be imported from the components directory.
153
+
154
+ ${props.description ? `Theme description: ${props.description}` : ""}
155
+ ${props.darkMode !== false ? "Include support for dark mode" : "Dark mode is not required"}
156
+
157
+ The layout should follow the user's requirements:
158
+ ${props.prompt}
159
+
160
+ The output should be a complete, well-structured Vue component file.
161
+ `,
162
+ system: `${systemPrompt}
163
+ You are writing a Vue component for a VitePress theme Layout.
164
+ Import smaller components from the components directory using relative paths (e.g., import NavBar from './components/NavBar.vue').
165
+ Break down the layout into logical components like NavBar, Sidebar, Footer, etc., which will be generated separately.`,
166
+ baseURL: props.baseURL,
167
+ apiKey: props.apiKey,
168
+ model: props.model,
169
+ temperature: props.temperature,
170
+ });
171
+ // Extract component imports from the Layout.vue file
172
+ const componentImportsData = await Data(`${id}-component-imports`, {
173
+ schema: type({
174
+ components: type({
175
+ name: type("string").describe("Component name as used in the import statement (e.g., NavBar, Footer)"),
176
+ path: type("string").describe("Import path as written in the import statement (e.g., './components/NavBar.vue')"),
177
+ purpose: type("string").describe("A clear description of the component's purpose, functionality, and responsibilities in the layout"),
178
+ }).array(),
179
+ }),
180
+ prompt: await alchemy `
181
+ Analyze the following Layout.vue file and extract information about all the component imports:
182
+
183
+ ${layoutFile.content}
184
+
185
+ For each component import:
186
+ 1. Extract the component name (e.g., NavBar)
187
+ 2. Extract the import path (e.g., ./components/NavBar.vue)
188
+ 3. Infer the purpose of the component based on its name and usage in the file
189
+
190
+ Return a structured list of all component imports found in the file.
191
+ Only include components that are imported from local files (not from VitePress or other libraries).
192
+ Focus on components that are likely Vue components (.vue files).
193
+ `,
194
+ system: "You are a code analyzer tasked with extracting component imports from a Vue file. Be precise and thorough in identifying all local component imports.",
195
+ baseURL: props.baseURL,
196
+ apiKey: props.apiKey,
197
+ model: props.model,
198
+ temperature: props.temperature || 0.2, // Lower temperature for more deterministic extraction
199
+ });
200
+ // Generate the detected components
201
+ const autoComponentFiles = await Promise.all(componentImportsData.object.components.map(async (component) => {
202
+ const componentName = component.name;
203
+ const componentPath = component.path;
204
+ const componentPurpose = component.purpose;
205
+ // Extract the relative path from the import
206
+ const relativePath = componentPath.startsWith("./")
207
+ ? componentPath.slice(2) // Remove './'
208
+ : componentPath.startsWith("/")
209
+ ? componentPath.slice(1) // Remove '/'
210
+ : componentPath;
211
+ // Compute the full file path
212
+ const fullPath = path.join(props.outDir, relativePath);
213
+ return VueFile(`${id}-component-${componentName}`, {
214
+ path: fullPath,
215
+ prompt: await alchemy `
216
+ Create a Vue component named "${componentName}" for a VitePress theme.
217
+
218
+ Component purpose: ${componentPurpose}
219
+
220
+ The component should:
221
+ - Use <script setup> with the Composition API
222
+ - Have a clean, focused design for its specific purpose
223
+ - Include proper TypeScript types
224
+ - Be reusable and customizable
225
+ - Include clear comments explaining key functionality
226
+ - Fit seamlessly with the overall theme design described below
227
+
228
+ This component will be used in the following layout context:
229
+ ${layoutFile.content}
230
+
231
+ ${props.description ? `Theme description: ${props.description}` : ""}
232
+ ${props.darkMode !== false ? "Include support for dark mode" : "Dark mode is not required"}
233
+
234
+ The component should follow the user's theme requirements:
235
+ ${props.prompt}
236
+ `,
237
+ system: `${systemPrompt}
238
+ You are writing a Vue component for a VitePress theme. This component (${componentName}) is intended to ${componentPurpose}.
239
+ Make sure it integrates well with the overall layout and theme style.`,
240
+ baseURL: props.baseURL,
241
+ apiKey: props.apiKey,
242
+ model: props.model,
243
+ temperature: props.temperature,
244
+ });
245
+ }));
246
+ // Generate user-specified components if provided
247
+ const userComponentFiles = await Promise.all((props.components || []).map(async (component) => {
248
+ return VueFile(`${id}-user-component-${component.name}`, {
249
+ path: path.join(props.outDir, "components", `${component.name}.vue`),
250
+ prompt: await alchemy `
251
+ Create a Vue component named "${component.name}" for a VitePress theme.
252
+
253
+ Component description: ${component.description}
254
+
255
+ The component should:
256
+ - Use <script setup> with the Composition API
257
+ - Have a clean, focused design for its specific purpose
258
+ - Include proper TypeScript types
259
+ - Be reusable and customizable
260
+ - Include clear comments
261
+
262
+ ${component.features?.length
263
+ ? `Include these features:
264
+ ${component.features.map((f) => `- ${f}`).join("\n")}`
265
+ : ""}
266
+
267
+ Make sure the component integrates well with the overall theme.
268
+
269
+ The output should be a complete, well-structured Vue component file.
270
+ `,
271
+ system: `${systemPrompt}
272
+ You are writing a Vue component for a VitePress theme.`,
273
+ baseURL: props.baseURL,
274
+ apiKey: props.apiKey,
275
+ model: props.model,
276
+ temperature: props.temperature,
277
+ });
278
+ }));
279
+ // Generate styles file
280
+ const stylesFile = await CSSFile(`${id}-styles`, {
281
+ path: path.join(props.outDir, "styles.css"),
282
+ prompt: await alchemy `
283
+ Create a CSS styles file for a VitePress theme named "${props.title}".
284
+
285
+ The styles should:
286
+ - Define a cohesive set of styles for the theme
287
+ - Include CSS variables for customization
288
+ - Use modern CSS features
289
+ - Be well-organized with clear comments
290
+ ${props.darkMode !== false ? "- Include dark mode variants using :root.dark selectors" : ""}
291
+
292
+ ${props.description ? `Theme description: ${props.description}` : ""}
293
+
294
+ ${props.customCssVars
295
+ ? `Include these custom CSS variables:
296
+ ${Object.entries(props.customCssVars)
297
+ .map(([key, value]) => `${key}: ${value};`)
298
+ .join("\n")}`
299
+ : ""}
300
+
301
+ Style according to the user's requirements:
302
+ ${props.prompt}
303
+
304
+ The output should be a complete, well-structured CSS file.
305
+ `,
306
+ system: `${systemPrompt}
307
+ You are writing CSS styles for a VitePress theme.`,
308
+ baseURL: props.baseURL,
309
+ apiKey: props.apiKey,
310
+ model: props.model,
311
+ temperature: props.temperature,
312
+ });
313
+ // Collect all generated files
314
+ const allFiles = [
315
+ indexFile,
316
+ layoutFile,
317
+ ...autoComponentFiles,
318
+ ...userComponentFiles,
319
+ stylesFile,
320
+ ];
321
+ // Create file objects for resource output
322
+ const files = allFiles.map((file) => ({
323
+ path: file.path,
324
+ content: file.content,
325
+ }));
326
+ // Get the current timestamp
327
+ const now = Date.now();
328
+ // Return the resource using this() to construct output
329
+ return this({
330
+ ...props,
331
+ themePath: props.outDir,
332
+ files,
333
+ createdAt: this.output?.createdAt || now,
334
+ updatedAt: now,
335
+ });
336
+ });
@@ -1,5 +1,5 @@
1
- import type { Context } from "../context";
2
- import { Resource } from "../resource";
1
+ import type { Context } from "../../context";
2
+ import { Resource } from "../../resource";
3
3
  export type InstallDependencies = Resource<"project::InstallDependencies">;
4
4
  export declare const InstallDependencies: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<InstallDependencies>, id: string, { cwd, dependencies, devDependencies, }: {
5
5
  cwd: string;
@@ -1,6 +1,6 @@
1
1
  import { exec } from "child_process";
2
2
  import { promisify } from "util";
3
- import { Resource } from "../resource";
3
+ import { Resource } from "../../resource";
4
4
  const execAsync = promisify(exec);
5
5
  export const InstallDependencies = Resource("project::InstallDependencies", {
6
6
  alwaysUpdate: true,