@futurebrand/dev-tools 2.5.3 → 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.
@@ -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}/blocks`);
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;
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const files_1 = require("../../../../utils/files");
4
3
  const inquirer_1 = require("inquirer");
5
- const generator_1 = require("../generator");
6
4
  const api_1 = require("./api");
7
5
  class FigmaModule {
8
6
  state;
@@ -26,11 +24,11 @@ class FigmaModule {
26
24
  const defaultBlocks = [];
27
25
  const nextProject = data.projects.find((project) => project.type === 'next.js');
28
26
  for (const block of blocks) {
29
- const tempFolder = await (0, files_1.getTempFilePath)(generator_1.GENERATOR_FOLDER_NAME, block.name);
30
- if (await (0, files_1.verifyPath)(tempFolder)) {
31
- continue;
32
- }
33
27
  if (nextProject) {
28
+ const alreadyGenerated = await this.state.file.verifyBlockAlreadyGenerated(block.name, nextProject);
29
+ if (alreadyGenerated) {
30
+ continue;
31
+ }
34
32
  const alreadyExist = await this.state.file.verifyBlockAlreadyExists(nextProject, block.name);
35
33
  if (alreadyExist) {
36
34
  continue;
@@ -49,10 +47,7 @@ class FigmaModule {
49
47
  const canvas = await this.api.getBlockCanvas(figmaPageID);
50
48
  console.log('- Loading pages blocks');
51
49
  const blocksData = [];
52
- const [blocks, variables] = await Promise.all([
53
- this.api.getBlocks(figmaPageID, canvas),
54
- this.api.getVariables(figmaPageID),
55
- ]);
50
+ const blocks = await this.api.getBlocks(figmaPageID, canvas);
56
51
  Object.keys(blocks).forEach((blockName) => {
57
52
  let block = blocksData.find((block) => block.name === blockName);
58
53
  if (!block) {
@@ -88,7 +83,6 @@ class FigmaModule {
88
83
  }
89
84
  }
90
85
  this.state.setBlocks(blocksData);
91
- this.state.setVariables(variables);
92
86
  console.log('- Figma blocks loaded successfully');
93
87
  }
94
88
  }
@@ -1,9 +1,6 @@
1
1
  export interface IDocumentResponse {
2
2
  id: string;
3
3
  }
4
- export interface IVariablesResponse {
5
- variables: Record<string, any>;
6
- }
7
4
  interface IFigmaProperties {
8
5
  value: string;
9
6
  type: string;
@@ -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: any): Promise<void>;
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
- const blockPath = await this.getBlockTempFilePath(project, blockName);
102
- const stringContent = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
103
- await fs.writeFile(blockPath, stringContent);
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
- const content = await (0, files_1.loadFile)(generatedPath);
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;
@@ -2,3 +2,11 @@ export interface IStrapiFolders {
2
2
  blocks: string;
3
3
  assets: string;
4
4
  }
5
+ export interface IProjectFileSegment {
6
+ name: string;
7
+ files: IProjectFile[];
8
+ }
9
+ export interface IProjectFile {
10
+ path: string;
11
+ content: string;
12
+ }
@@ -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, variables, styles, strapiComponent) {
18
+ async fetchNextBlock(blockName, blockVariants, files, strapiComponent, customPrompt) {
20
19
  const requestBody = {
21
20
  name: blockName.replace('block-', ''),
22
21
  variants: blockVariants,
23
- variables,
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.block;
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 styles = await this.loadProjectCSS(project);
89
- const nextResponse = await this.fetchNextBlock(blockName, blockVariants, this.data.variables, styles, strapiBlock);
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) {
@@ -116,6 +118,7 @@ class Generator {
116
118
  progressBar.start(blockNames.length, 0);
117
119
  for (const block of blockNames) {
118
120
  await this.generateBlock(block, project);
121
+ progressBar.increment();
119
122
  }
120
123
  progressBar.stop();
121
124
  await this.state.save();
@@ -123,7 +126,8 @@ class Generator {
123
126
  }
124
127
  async generateStyles() {
125
128
  console.log('- Generating Styles... Please wait');
126
- const variables = this.data.variables;
129
+ // TODO: get variables from blocks
130
+ const variables = {}; // this.data.variables
127
131
  const data = await this.state.fetchApi('/generate/styles', {
128
132
  method: 'POST',
129
133
  headers: {
@@ -149,13 +153,27 @@ class Generator {
149
153
  console.log('- Generating Checklist... Please wait');
150
154
  const lines = ['# Checklist', ''];
151
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
+ }
152
163
  for (const block of blocks) {
164
+ const isChecked = block.hidden ||
165
+ (await this.state.file.verifyBlockAlreadyExists(project, block.name));
153
166
  const name = block.name
154
167
  .replace('block-', '')
155
168
  .split('-')
156
169
  .map((word) => word.length > 1 ? word.charAt(0).toUpperCase() + word.slice(1) : word)
157
170
  .join(' ');
158
- lines.push(`- [${block.generated || block.hidden ? 'x' : ' '}] Block | ${name} (\`${block.name}\`)`);
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}`);
159
177
  }
160
178
  const listText = lines.join('\n');
161
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,10 +99,10 @@ class AIState {
96
99
  setBlocks(blocks) {
97
100
  this.data.blocks = blocks;
98
101
  }
99
- setVariables(variables) {
100
- this.data.variables = variables;
101
- }
102
102
  setColors(colors) {
103
+ if (!this.data) {
104
+ throw new Error('AI State not initialized');
105
+ }
103
106
  this.data.colors = colors;
104
107
  }
105
108
  setBlockGenerated(blockName, generated = true) {
@@ -23,6 +23,5 @@ export interface IAIFileState {
23
23
  configs: IStateConfigs;
24
24
  blocks: IBlockData[];
25
25
  projects: IProject[];
26
- variables: Record<string, any>;
27
26
  colors?: IProjectColor[];
28
27
  }
@@ -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}`);
@@ -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[]>;
@@ -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
- const subFiles = await getFilesInPath(contentPath);
117
- files.push(...subFiles);
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.5.3",
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",