@futurebrand/dev-tools 2.5.4 → 2.6.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.
- package/dist/commands/ai/modules/figma/api.d.ts +0 -1
- package/dist/commands/ai/modules/figma/api.js +0 -4
- package/dist/commands/ai/modules/figma/index.js +1 -5
- package/dist/commands/ai/modules/figma/types.d.ts +0 -3
- package/dist/commands/ai/modules/file-manager/index.d.ts +8 -1
- package/dist/commands/ai/modules/file-manager/index.js +145 -5
- package/dist/commands/ai/modules/file-manager/types.d.ts +8 -0
- package/dist/commands/ai/modules/generator/index.d.ts +1 -1
- package/dist/commands/ai/modules/generator/index.js +43 -26
- package/dist/commands/ai/modules/generator/types.d.ts +12 -0
- package/dist/commands/ai/modules/state/index.d.ts +2 -1
- package/dist/commands/ai/modules/state/index.js +4 -7
- package/dist/commands/ai/modules/state/types.d.ts +0 -1
- package/dist/modules/ai-server-module/index.js +17 -1
- package/dist/utils/files.d.ts +1 -1
- package/dist/utils/files.js +5 -3
- package/package.json +3 -2
|
@@ -3,6 +3,5 @@ export declare class FigmaAPI {
|
|
|
3
3
|
private state;
|
|
4
4
|
constructor(state: AIState);
|
|
5
5
|
getBlockCanvas(pageId: string): Promise<string>;
|
|
6
|
-
getVariables(pageId: string): Promise<Record<string, any>>;
|
|
7
6
|
getBlocks(pageId: string, canvasId: string): Promise<Record<string, import("./types").IFigmaNode[]>>;
|
|
8
7
|
}
|
|
@@ -10,10 +10,6 @@ class FigmaAPI {
|
|
|
10
10
|
const { id } = await this.state.fetchApi(`/figma/${pageId}/blocks`);
|
|
11
11
|
return id;
|
|
12
12
|
}
|
|
13
|
-
async getVariables(pageId) {
|
|
14
|
-
const { variables } = await this.state.fetchApi(`/figma/${pageId}/variables`);
|
|
15
|
-
return variables;
|
|
16
|
-
}
|
|
17
13
|
async getBlocks(pageId, canvasId) {
|
|
18
14
|
const { blocks } = await this.state.fetchApi(`/figma/${pageId}/blocks/${canvasId}`);
|
|
19
15
|
return blocks;
|
|
@@ -47,10 +47,7 @@ class FigmaModule {
|
|
|
47
47
|
const canvas = await this.api.getBlockCanvas(figmaPageID);
|
|
48
48
|
console.log('- Loading pages blocks');
|
|
49
49
|
const blocksData = [];
|
|
50
|
-
const
|
|
51
|
-
this.api.getBlocks(figmaPageID, canvas),
|
|
52
|
-
this.api.getVariables(figmaPageID),
|
|
53
|
-
]);
|
|
50
|
+
const blocks = await this.api.getBlocks(figmaPageID, canvas);
|
|
54
51
|
Object.keys(blocks).forEach((blockName) => {
|
|
55
52
|
let block = blocksData.find((block) => block.name === blockName);
|
|
56
53
|
if (!block) {
|
|
@@ -86,7 +83,6 @@ class FigmaModule {
|
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
this.state.setBlocks(blocksData);
|
|
89
|
-
this.state.setVariables(variables);
|
|
90
86
|
console.log('- Figma blocks loaded successfully');
|
|
91
87
|
}
|
|
92
88
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { IProject } from '../../../../types/project';
|
|
2
|
+
import type { INextjsGenerateResponse, IStrapiGenerateResponse } from '../generator/types';
|
|
2
3
|
import type { IBlockData } from '../state/types';
|
|
4
|
+
import type { IProjectFile, IProjectFileSegment } from './types';
|
|
3
5
|
export declare const GENERATOR_FOLDER_NAME = "generated-blocks";
|
|
4
6
|
export declare const GENERATOR_STRAPI_FILE_NAME = "strapi.json";
|
|
5
7
|
export declare const GENERATOR_NEXTJS_FILE_NAME = "nextjs.tsx";
|
|
8
|
+
export declare const GENERATOR_NEXTJS_EXTRA_FILES = "nextjs-extra-files.json";
|
|
6
9
|
declare class FileManager {
|
|
7
10
|
private getBlockTempPath;
|
|
8
11
|
private getBlockTempFilePath;
|
|
@@ -14,9 +17,13 @@ declare class FileManager {
|
|
|
14
17
|
getAvailableBlocksToGenerate(blocks: IBlockData[], project: IProject): Promise<IBlockData[]>;
|
|
15
18
|
getAvailableBlocksToAdd(blocks: IBlockData[], project: IProject): Promise<IBlockData[]>;
|
|
16
19
|
createBlockTempFolder(blockName: string): Promise<void>;
|
|
17
|
-
saveGeneratedBlock(blockName: string, project: IProject, content:
|
|
20
|
+
saveGeneratedBlock(blockName: string, project: IProject, content: IStrapiGenerateResponse | INextjsGenerateResponse): Promise<void>;
|
|
18
21
|
loadGeneratedBlock(blockName: string, project: IProject): Promise<string>;
|
|
19
22
|
addNextBlockToProject(blockName: string, project: IProject): Promise<void>;
|
|
20
23
|
addStrapiBlockToProject(blockName: string, project: IProject): Promise<void>;
|
|
24
|
+
loadFilesInPath(rootPath: string, relativeTo?: string, includeSubFolders?: boolean): Promise<IProjectFile[]>;
|
|
25
|
+
loadProjectFiles(project: IProject | null, subDir: string): Promise<IProjectFileSegment[]>;
|
|
26
|
+
loadCustomPrompts(blockName: string): Promise<string>;
|
|
27
|
+
loadProjectCSS(nextProject?: IProject): Promise<string | null>;
|
|
21
28
|
}
|
|
22
29
|
export default FileManager;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GENERATOR_NEXTJS_FILE_NAME = exports.GENERATOR_STRAPI_FILE_NAME = exports.GENERATOR_FOLDER_NAME = void 0;
|
|
3
|
+
exports.GENERATOR_NEXTJS_EXTRA_FILES = exports.GENERATOR_NEXTJS_FILE_NAME = exports.GENERATOR_STRAPI_FILE_NAME = exports.GENERATOR_FOLDER_NAME = void 0;
|
|
4
4
|
const fs = require("node:fs/promises");
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
const files_1 = require("../../../../utils/files");
|
|
7
7
|
exports.GENERATOR_FOLDER_NAME = 'generated-blocks';
|
|
8
8
|
exports.GENERATOR_STRAPI_FILE_NAME = 'strapi.json';
|
|
9
9
|
exports.GENERATOR_NEXTJS_FILE_NAME = 'nextjs.tsx';
|
|
10
|
+
exports.GENERATOR_NEXTJS_EXTRA_FILES = 'nextjs-extra-files.json';
|
|
10
11
|
class FileManager {
|
|
11
12
|
async getBlockTempPath(blockName) {
|
|
12
13
|
const tempFolder = await (0, files_1.getTempFilePath)(exports.GENERATOR_FOLDER_NAME, blockName);
|
|
@@ -98,9 +99,23 @@ class FileManager {
|
|
|
98
99
|
await (0, files_1.verifyAndCreateFolder)(tempFolder);
|
|
99
100
|
}
|
|
100
101
|
async saveGeneratedBlock(blockName, project, content) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (project.type === 'next.js') {
|
|
103
|
+
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
104
|
+
await fs.writeFile(blockPath, content.block);
|
|
105
|
+
const blockDir = path.dirname(blockPath);
|
|
106
|
+
const definitionPath = path.join(blockDir, 'nextjs-definition.json');
|
|
107
|
+
await fs.writeFile(definitionPath, JSON.stringify(content.definition, null, 2));
|
|
108
|
+
const extraFiles = content.extraFiles || [];
|
|
109
|
+
if (extraFiles.length > 0) {
|
|
110
|
+
const extraFilesPath = path.join(blockDir, exports.GENERATOR_NEXTJS_EXTRA_FILES);
|
|
111
|
+
await fs.writeFile(extraFilesPath, JSON.stringify(extraFiles, null, 2));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (project.type === 'strapi') {
|
|
115
|
+
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
116
|
+
const stringContent = JSON.stringify(content, null, 2);
|
|
117
|
+
await fs.writeFile(blockPath, stringContent);
|
|
118
|
+
}
|
|
104
119
|
}
|
|
105
120
|
async loadGeneratedBlock(blockName, project) {
|
|
106
121
|
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
@@ -113,13 +128,34 @@ class FileManager {
|
|
|
113
128
|
if (project.type !== 'next.js') {
|
|
114
129
|
throw new Error('Project is not a Next.js project');
|
|
115
130
|
}
|
|
131
|
+
const tempFolder = await this.getBlockTempPath(blockName);
|
|
132
|
+
// Verify generated block
|
|
116
133
|
const generatedPath = await this.getBlockTempFilePath(project, blockName);
|
|
117
134
|
if (!(await (0, files_1.verifyPath)(generatedPath))) {
|
|
118
135
|
throw new Error(`Generated block not found: ${generatedPath}`);
|
|
119
136
|
}
|
|
120
|
-
|
|
137
|
+
// Create block folder
|
|
121
138
|
const blockFolder = this.getNextjsBlockFolder(project, blockName);
|
|
122
139
|
await (0, files_1.verifyAndCreateFolder)(blockFolder);
|
|
140
|
+
// Add Extra files
|
|
141
|
+
try {
|
|
142
|
+
const extraFilesPath = path.join(tempFolder, exports.GENERATOR_NEXTJS_EXTRA_FILES);
|
|
143
|
+
const hasExtraFiles = await (0, files_1.verifyPath)(extraFilesPath);
|
|
144
|
+
if (hasExtraFiles) {
|
|
145
|
+
const extraFilesContent = await (0, files_1.loadFile)(extraFilesPath);
|
|
146
|
+
const extraFiles = JSON.parse(extraFilesContent);
|
|
147
|
+
if (extraFiles && extraFiles.length > 0) {
|
|
148
|
+
for (const extraFile of extraFiles) {
|
|
149
|
+
const extraFilePath = path.join(blockFolder, extraFile.name);
|
|
150
|
+
await fs.writeFile(extraFilePath, extraFile.content);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error('Failed to add extra files to Next.js block:', error);
|
|
157
|
+
}
|
|
158
|
+
const content = await (0, files_1.loadFile)(generatedPath);
|
|
123
159
|
const mainFilePath = path.join(blockFolder, `${blockName}.tsx`);
|
|
124
160
|
const indexFilePath = path.join(blockFolder, 'index.ts');
|
|
125
161
|
const indexContent = `export { default } from './${blockName}'
|
|
@@ -152,5 +188,109 @@ class FileManager {
|
|
|
152
188
|
await fs.writeFile(assetFilePath, JSON.stringify(asset, null, 2));
|
|
153
189
|
}
|
|
154
190
|
}
|
|
191
|
+
async loadFilesInPath(rootPath, relativeTo, includeSubFolders = true) {
|
|
192
|
+
const allFilesPath = await (0, files_1.getFilesInPath)(rootPath, includeSubFolders);
|
|
193
|
+
const files = [];
|
|
194
|
+
for (const filePath of allFilesPath) {
|
|
195
|
+
const content = await (0, files_1.loadFile)(filePath);
|
|
196
|
+
const relativePath = relativeTo
|
|
197
|
+
? path.relative(relativeTo, filePath)
|
|
198
|
+
: filePath;
|
|
199
|
+
files.push({ path: relativePath, content });
|
|
200
|
+
}
|
|
201
|
+
return files;
|
|
202
|
+
}
|
|
203
|
+
async loadProjectFiles(project, subDir) {
|
|
204
|
+
if (!project) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const rootFolder = path.join(project.srcPath, subDir);
|
|
208
|
+
const segments = [];
|
|
209
|
+
try {
|
|
210
|
+
if (!(await (0, files_1.verifyPath)(rootFolder))) {
|
|
211
|
+
throw new Error('Components folder does not exist');
|
|
212
|
+
}
|
|
213
|
+
const files = await this.loadFilesInPath(rootFolder, project.srcPath, false);
|
|
214
|
+
if (files.length > 0) {
|
|
215
|
+
for (const file of files) {
|
|
216
|
+
const name = path.basename(file.path, path.extname(file.path));
|
|
217
|
+
const segment = {
|
|
218
|
+
name,
|
|
219
|
+
files: [
|
|
220
|
+
{
|
|
221
|
+
...file,
|
|
222
|
+
path: `@/${file.path}`.replace(/\/index.ts|\/index.tsx/g, ''),
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
};
|
|
226
|
+
segments.push(segment);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const dirs = await (0, files_1.getDirectoriesInPath)(rootFolder);
|
|
230
|
+
for (const dir of dirs) {
|
|
231
|
+
const dirPath = path.join(rootFolder, dir);
|
|
232
|
+
const dirFiles = (await this.loadFilesInPath(dirPath, project.srcPath)).map((file) => ({
|
|
233
|
+
...file,
|
|
234
|
+
path: `@/${file.path}`.replace(/\/index.ts|\/index.tsx/g, ''),
|
|
235
|
+
}));
|
|
236
|
+
const dirName = path.basename(dir);
|
|
237
|
+
const segment = {
|
|
238
|
+
name: dirName,
|
|
239
|
+
files: dirFiles,
|
|
240
|
+
};
|
|
241
|
+
segments.push(segment);
|
|
242
|
+
}
|
|
243
|
+
return segments;
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
console.error(error);
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async loadCustomPrompts(blockName) {
|
|
251
|
+
try {
|
|
252
|
+
const prompts = [];
|
|
253
|
+
const globalPromptPath = await (0, files_1.getTempFilePath)('prompts.md');
|
|
254
|
+
if (await (0, files_1.verifyPath)(globalPromptPath)) {
|
|
255
|
+
const globalPrompt = await (0, files_1.loadFile)(globalPromptPath);
|
|
256
|
+
if (globalPrompt) {
|
|
257
|
+
prompts.push(globalPrompt);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
await (0, files_1.writeFile)(globalPromptPath, '');
|
|
262
|
+
}
|
|
263
|
+
const blockFolder = await this.getBlockTempPath(blockName);
|
|
264
|
+
const blockPromptsPath = path.join(blockFolder, 'prompts.md');
|
|
265
|
+
if (await (0, files_1.verifyPath)(blockPromptsPath)) {
|
|
266
|
+
const blockPrompt = await (0, files_1.loadFile)(blockPromptsPath);
|
|
267
|
+
if (blockPrompt) {
|
|
268
|
+
prompts.push(blockPrompt);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return prompts.join('\n\n');
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
console.error(error);
|
|
275
|
+
return '';
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
async loadProjectCSS(nextProject) {
|
|
279
|
+
if (!nextProject) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
const cssFile = path.join(nextProject.srcPath, 'styles', 'index.css');
|
|
283
|
+
try {
|
|
284
|
+
const css = await fs.readFile(cssFile, 'utf-8');
|
|
285
|
+
if (!css) {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
return css;
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
console.error(error);
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
155
295
|
}
|
|
156
296
|
exports.default = FileManager;
|
|
@@ -10,8 +10,8 @@ export declare class Generator {
|
|
|
10
10
|
private get data();
|
|
11
11
|
private fetchNextBlock;
|
|
12
12
|
private fetchStrapiBlock;
|
|
13
|
-
loadProjectCSS(nextProject?: IProject): Promise<string | null>;
|
|
14
13
|
private generateStrapiBlock;
|
|
14
|
+
private getNextjsProjectFiles;
|
|
15
15
|
private generateNextBlock;
|
|
16
16
|
generateBlock(blockName: string, project: IProject): Promise<IStrapiGenerateResponse | undefined>;
|
|
17
17
|
generateBlocks(blockNames: string[], project: IProject): Promise<void>;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Generator = exports.GENERATOR_NEXTJS_FILE_NAME = exports.GENERATOR_STRAPI_FILE_NAME = exports.GENERATOR_FOLDER_NAME = void 0;
|
|
4
4
|
const fs = require("node:fs/promises");
|
|
5
|
-
const path = require("node:path");
|
|
6
5
|
const files_1 = require("../../../../utils/files");
|
|
7
6
|
const cliProgress = require("cli-progress");
|
|
8
7
|
exports.GENERATOR_FOLDER_NAME = 'generated-blocks';
|
|
@@ -16,13 +15,14 @@ class Generator {
|
|
|
16
15
|
get data() {
|
|
17
16
|
return this.state.getData();
|
|
18
17
|
}
|
|
19
|
-
async fetchNextBlock(blockName, blockVariants,
|
|
18
|
+
async fetchNextBlock(blockName, blockVariants, files, strapiComponent, customPrompt) {
|
|
20
19
|
const requestBody = {
|
|
21
20
|
name: blockName.replace('block-', ''),
|
|
22
21
|
variants: blockVariants,
|
|
23
|
-
|
|
24
|
-
styles,
|
|
22
|
+
files,
|
|
25
23
|
strapiComponent,
|
|
24
|
+
customPrompt,
|
|
25
|
+
figma: this.data.configs.figma,
|
|
26
26
|
};
|
|
27
27
|
const data = await this.state.fetchApi('/generate/nextjs/block', {
|
|
28
28
|
method: 'POST',
|
|
@@ -34,12 +34,13 @@ class Generator {
|
|
|
34
34
|
if (!data.result?.block) {
|
|
35
35
|
throw new Error('Next.js block generation failed');
|
|
36
36
|
}
|
|
37
|
-
return data.result
|
|
37
|
+
return data.result;
|
|
38
38
|
}
|
|
39
39
|
async fetchStrapiBlock(blockName, blockVariants) {
|
|
40
40
|
const requestBody = {
|
|
41
41
|
name: blockName.replace('block-', ''),
|
|
42
42
|
variants: blockVariants,
|
|
43
|
+
figma: this.data.configs.figma,
|
|
43
44
|
};
|
|
44
45
|
const data = await this.state.fetchApi('/generate/strapi/block', {
|
|
45
46
|
method: 'POST',
|
|
@@ -53,23 +54,6 @@ class Generator {
|
|
|
53
54
|
}
|
|
54
55
|
return data.result;
|
|
55
56
|
}
|
|
56
|
-
async loadProjectCSS(nextProject) {
|
|
57
|
-
if (!nextProject) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
const cssFile = path.join(nextProject.srcPath, 'styles', 'index.css');
|
|
61
|
-
try {
|
|
62
|
-
const css = await fs.readFile(cssFile, 'utf-8');
|
|
63
|
-
if (!css) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
return css;
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
console.error(error);
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
57
|
async generateStrapiBlock(blockName, project, blockVariants) {
|
|
74
58
|
const isAlreadyGenerated = await this.state.file.verifyBlockAlreadyGenerated(blockName, project);
|
|
75
59
|
if (isAlreadyGenerated) {
|
|
@@ -80,13 +64,26 @@ class Generator {
|
|
|
80
64
|
await this.state.file.saveGeneratedBlock(blockName, project, response);
|
|
81
65
|
return response;
|
|
82
66
|
}
|
|
67
|
+
async getNextjsProjectFiles(project) {
|
|
68
|
+
const styles = await this.state.file.loadProjectFiles(project, 'styles');
|
|
69
|
+
const components = await this.state.file.loadProjectFiles(project, 'components');
|
|
70
|
+
const types = await this.state.file.loadProjectFiles(project, 'types');
|
|
71
|
+
const layouts = await this.state.file.loadProjectFiles(project, 'layouts/shared');
|
|
72
|
+
return {
|
|
73
|
+
styles,
|
|
74
|
+
components,
|
|
75
|
+
types,
|
|
76
|
+
layouts,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
83
79
|
async generateNextBlock(blockName, project, blockVariants) {
|
|
84
80
|
const strapiProject = this.data.projects.find((p) => p.type === 'strapi');
|
|
85
81
|
const strapiBlock = strapiProject
|
|
86
82
|
? await this.generateStrapiBlock(blockName, strapiProject, blockVariants)
|
|
87
83
|
: undefined;
|
|
88
|
-
const
|
|
89
|
-
const
|
|
84
|
+
const customPrompt = await this.state.file.loadCustomPrompts(blockName);
|
|
85
|
+
const files = await this.getNextjsProjectFiles(project);
|
|
86
|
+
const nextResponse = await this.fetchNextBlock(blockName, blockVariants, files, strapiBlock, customPrompt);
|
|
90
87
|
await this.state.file.saveGeneratedBlock(blockName, project, nextResponse);
|
|
91
88
|
}
|
|
92
89
|
async generateBlock(blockName, project) {
|
|
@@ -101,7 +98,12 @@ class Generator {
|
|
|
101
98
|
}
|
|
102
99
|
}
|
|
103
100
|
catch (error) {
|
|
101
|
+
console.log('------------------------------------');
|
|
102
|
+
console.log('------------------------------------');
|
|
103
|
+
console.log(`Error generating block: ${blockName}`);
|
|
104
104
|
console.error(error);
|
|
105
|
+
console.log('------------------------------------');
|
|
106
|
+
console.log('------------------------------------');
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
async generateBlocks(blockNames, project) {
|
|
@@ -124,7 +126,8 @@ class Generator {
|
|
|
124
126
|
}
|
|
125
127
|
async generateStyles() {
|
|
126
128
|
console.log('- Generating Styles... Please wait');
|
|
127
|
-
|
|
129
|
+
// TODO: get variables from blocks
|
|
130
|
+
const variables = {}; // this.data.variables
|
|
128
131
|
const data = await this.state.fetchApi('/generate/styles', {
|
|
129
132
|
method: 'POST',
|
|
130
133
|
headers: {
|
|
@@ -150,13 +153,27 @@ class Generator {
|
|
|
150
153
|
console.log('- Generating Checklist... Please wait');
|
|
151
154
|
const lines = ['# Checklist', ''];
|
|
152
155
|
const blocks = this.state.getData().blocks;
|
|
156
|
+
let project = this.state.getProjectByType('next.js');
|
|
157
|
+
if (!project) {
|
|
158
|
+
project = this.state.getProjectByType('strapi');
|
|
159
|
+
if (!project) {
|
|
160
|
+
throw new Error('No suitable project found for checklist generation');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
153
163
|
for (const block of blocks) {
|
|
164
|
+
const isChecked = block.hidden ||
|
|
165
|
+
(await this.state.file.verifyBlockAlreadyExists(project, block.name));
|
|
154
166
|
const name = block.name
|
|
155
167
|
.replace('block-', '')
|
|
156
168
|
.split('-')
|
|
157
169
|
.map((word) => word.length > 1 ? word.charAt(0).toUpperCase() + word.slice(1) : word)
|
|
158
170
|
.join(' ');
|
|
159
|
-
|
|
171
|
+
let nameContent = `Block | ${name} (\`${block.name}\`)`;
|
|
172
|
+
if (block.hidden) {
|
|
173
|
+
nameContent = `~~${nameContent}~~ <sup>hidden</sup>`;
|
|
174
|
+
}
|
|
175
|
+
const checkContent = isChecked ? 'x' : ' ';
|
|
176
|
+
lines.push(`- [${checkContent}] ${nameContent}`);
|
|
160
177
|
}
|
|
161
178
|
const listText = lines.join('\n');
|
|
162
179
|
const tempPath = await (0, files_1.getTempFilePath)('checklist.md');
|
|
@@ -12,6 +12,18 @@ export interface IStrapiGenerateResponse {
|
|
|
12
12
|
block: IStrapiComponent;
|
|
13
13
|
assets: IStrapiComponent[];
|
|
14
14
|
}
|
|
15
|
+
export interface IGenerationExtraFile {
|
|
16
|
+
name: string;
|
|
17
|
+
content: string;
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
15
21
|
export interface INextjsGenerateResponse {
|
|
16
22
|
block: string;
|
|
23
|
+
extraFiles: IGenerationExtraFile[];
|
|
24
|
+
definition: {
|
|
25
|
+
architecture: string[];
|
|
26
|
+
decisions: string[];
|
|
27
|
+
note: string;
|
|
28
|
+
};
|
|
17
29
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IProject, ProjectType } from '../../../../types/project';
|
|
1
2
|
import FileManager from '../file-manager';
|
|
2
3
|
import type { IAIFileState, IAvailableFilters } from './types';
|
|
3
4
|
declare class AIState {
|
|
@@ -13,10 +14,10 @@ declare class AIState {
|
|
|
13
14
|
save(): Promise<void>;
|
|
14
15
|
get isReady(): boolean;
|
|
15
16
|
getData(): IAIFileState;
|
|
17
|
+
getProjectByType(type: ProjectType): IProject | null;
|
|
16
18
|
getAvailableBlocks({ generated, hidden }?: IAvailableFilters): import("./types").IBlockData[];
|
|
17
19
|
getAvailableBlocksNames(filters?: IAvailableFilters): string[];
|
|
18
20
|
setBlocks(blocks: IAIFileState['blocks']): void;
|
|
19
|
-
setVariables(variables: IAIFileState['variables']): void;
|
|
20
21
|
setColors(colors: IAIFileState['colors']): void;
|
|
21
22
|
setBlockGenerated(blockName: string, generated?: boolean): void;
|
|
22
23
|
getBlockVariants(blockName: string): any[];
|
|
@@ -42,7 +42,6 @@ class AIState {
|
|
|
42
42
|
},
|
|
43
43
|
projects,
|
|
44
44
|
blocks: [],
|
|
45
|
-
variables: {},
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
async create() {
|
|
@@ -74,6 +73,10 @@ class AIState {
|
|
|
74
73
|
}
|
|
75
74
|
return this.data;
|
|
76
75
|
}
|
|
76
|
+
getProjectByType(type) {
|
|
77
|
+
const projects = this.getData().projects;
|
|
78
|
+
return projects.find((project) => project.type === type) || null;
|
|
79
|
+
}
|
|
77
80
|
getAvailableBlocks({ generated, hidden } = {}) {
|
|
78
81
|
let blocks = this.getData().blocks;
|
|
79
82
|
if (hidden != null || generated != null) {
|
|
@@ -96,12 +99,6 @@ class AIState {
|
|
|
96
99
|
setBlocks(blocks) {
|
|
97
100
|
this.data.blocks = blocks;
|
|
98
101
|
}
|
|
99
|
-
setVariables(variables) {
|
|
100
|
-
if (!this.data) {
|
|
101
|
-
throw new Error('AI State not initialized');
|
|
102
|
-
}
|
|
103
|
-
this.data.variables = variables;
|
|
104
|
-
}
|
|
105
102
|
setColors(colors) {
|
|
106
103
|
if (!this.data) {
|
|
107
104
|
throw new Error('AI State not initialized');
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_net_1 = require("node:net");
|
|
3
4
|
const inquirer_1 = require("inquirer");
|
|
5
|
+
const undici_1 = require("undici");
|
|
4
6
|
const files_1 = require("../../utils/files");
|
|
5
7
|
const FILE_NAME = 'ai-server.json';
|
|
8
|
+
const TIMEOUT_LIMIT_TIME = 1000 * 60 * 60; // 60 minutes
|
|
9
|
+
const longTimeoutAgent = new undici_1.Agent({
|
|
10
|
+
connect: {
|
|
11
|
+
timeout: TIMEOUT_LIMIT_TIME,
|
|
12
|
+
},
|
|
13
|
+
headersTimeout: TIMEOUT_LIMIT_TIME,
|
|
14
|
+
bodyTimeout: TIMEOUT_LIMIT_TIME,
|
|
15
|
+
});
|
|
6
16
|
class AIServerModule {
|
|
7
17
|
filePath = '';
|
|
8
18
|
api = '';
|
|
9
19
|
token = '';
|
|
10
|
-
constructor() {
|
|
20
|
+
constructor() {
|
|
21
|
+
(0, node_net_1.setDefaultAutoSelectFamilyAttemptTimeout)(TIMEOUT_LIMIT_TIME);
|
|
22
|
+
}
|
|
11
23
|
async createConfigs() {
|
|
12
24
|
const query = await inquirer_1.default.prompt([
|
|
13
25
|
{
|
|
@@ -46,6 +58,10 @@ class AIServerModule {
|
|
|
46
58
|
Authorization: `Bearer ${this.token}`,
|
|
47
59
|
...init?.headers,
|
|
48
60
|
},
|
|
61
|
+
signal: AbortSignal.timeout(TIMEOUT_LIMIT_TIME),
|
|
62
|
+
...{
|
|
63
|
+
dispatcher: longTimeoutAgent,
|
|
64
|
+
},
|
|
49
65
|
});
|
|
50
66
|
if (!response.ok) {
|
|
51
67
|
throw new Error(`Failed to fetch ${path}`);
|
package/dist/utils/files.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export declare function writeRootFile(fileName: string, content: string): Promis
|
|
|
9
9
|
export declare function writeFile(filePath: string, content: string): Promise<void>;
|
|
10
10
|
export declare function loadFile(filePath: string): Promise<string>;
|
|
11
11
|
export declare function getDirectoriesInPath(rootPath: string): Promise<string[]>;
|
|
12
|
-
export declare function getFilesInPath(rootPath: string): Promise<string[]>;
|
|
12
|
+
export declare function getFilesInPath(rootPath: string, includeSubFolders?: boolean): Promise<string[]>;
|
package/dist/utils/files.js
CHANGED
|
@@ -102,7 +102,7 @@ async function getDirectoriesInPath(rootPath) {
|
|
|
102
102
|
return directories;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
async function getFilesInPath(rootPath) {
|
|
105
|
+
async function getFilesInPath(rootPath, includeSubFolders = true) {
|
|
106
106
|
const files = [];
|
|
107
107
|
try {
|
|
108
108
|
const allContent = await fs.readdir(rootPath);
|
|
@@ -113,8 +113,10 @@ async function getFilesInPath(rootPath) {
|
|
|
113
113
|
files.push(contentPath);
|
|
114
114
|
}
|
|
115
115
|
else if (stats.isDirectory()) {
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
if (includeSubFolders) {
|
|
117
|
+
const subFiles = await getFilesInPath(contentPath);
|
|
118
|
+
files.push(...subFiles);
|
|
119
|
+
}
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
return files;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futurebrand/dev-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "FutureBrand Dev Tools",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc && tsc-alias",
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"inquirer": "^12.6.3",
|
|
65
65
|
"prettier": "^3.6.0",
|
|
66
66
|
"prettier-plugin-tailwindcss": "^0.6.13",
|
|
67
|
-
"typescript-eslint": "^8.35.0"
|
|
67
|
+
"typescript-eslint": "^8.35.0",
|
|
68
|
+
"undici": "^7.18.2"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
70
71
|
"@types/cli-progress": "^3.11.6",
|