cloving 0.1.12 → 0.1.14

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.
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const copy_paste_1 = __importDefault(require("copy-paste"));
7
7
  const inquirer_1 = __importDefault(require("inquirer"));
8
8
  const cli_highlight_1 = __importDefault(require("cli-highlight"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
9
11
  const command_utils_1 = require("../../utils/command_utils");
10
12
  const config_utils_1 = require("../../utils/config_utils");
11
13
  const string_utils_1 = require("../../utils/string_utils");
12
14
  const cloving_gpt_1 = __importDefault(require("../../cloving_gpt"));
13
- const fs_1 = __importDefault(require("fs"));
14
- const path_1 = __importDefault(require("path"));
15
15
  const generateCodePrompt = (prompt, files, contextFiles, previousCode) => {
16
16
  const specialFileContents = (0, command_utils_1.collectSpecialFileContents)();
17
17
  const specialFiles = Object.keys(specialFileContents).map((file) => `### Contents of ${file}\n\n${JSON.stringify(specialFileContents[file], null, 2)}\n\n`).join('\n');
@@ -62,29 +62,6 @@ Do not add any commentary or context to the message other than the commit messag
62
62
  An example of the output for this should look like the following:
63
63
  \`\`\`
64
64
 
65
- 2. **src/commands/generate/code.ts**
66
-
67
- \`\`\`typescript
68
- import ncp from 'copy-paste'
69
- import inquirer from 'inquirer'
70
- import highlight from 'cli-highlight'
71
- import { collectSpecialFileContents } from '../../utils/command_utils'
72
- import { getConfig, getClovingConfig, getAllFiles } from '../../utils/config_utils'
73
- import { parseMarkdownInstructions, extractMarkdown } from '../../utils/string_utils'
74
- import ClovingGPT from '../../cloving_gpt'
75
- import type { ClovingGPTOptions } from '../../utils/types'
76
- import fs from 'fs'
77
- import path from 'path'
78
-
79
- const generateCodePrompt = (prompt: string | undefined, files: string[], contextFiles: Record<string, string>, previousCode?: string): string => {
80
- const specialFileContents = collectSpecialFileContents()
81
- const specialFiles = Object.keys(specialFileContents).map((file) => \`### Contents of \${file}\\n\\n\${JSON.stringify(specialFileContents[file], null, 2)}\\n\\n\`).join('\\n')
82
- const contextFileContents = Object.keys(contextFiles).map((file) => \`### Contents of \${file}\\n\\n\${contextFiles[file]}\\n\\n\`).join('\\n')
83
-
84
- return 'Here is a description of my app:'
85
- }
86
- \`\`\`
87
-
88
65
  ### Request
89
66
 
90
67
  Generate code that does the following: ${prompt}
@@ -94,8 +71,10 @@ Do not use any data from the example response structure, only use the structure.
94
71
  };
95
72
  const generateExplainCodePrompt = (prompt) => {
96
73
  return `${prompt}
97
-
98
- Please briefly explain how this code works.`;
74
+
75
+ ## Task
76
+
77
+ Please briefly explain how the code works in this.`;
99
78
  };
100
79
  const generateCode = async (gpt, prompt, allSrcFiles, contextFiles, previousCode) => {
101
80
  const codePrompt = generateCodePrompt(prompt, allSrcFiles, contextFiles, previousCode);
@@ -121,8 +100,33 @@ const displayGeneratedCode = (rawCodeCommand) => {
121
100
  }
122
101
  });
123
102
  };
124
- const handleUserAction = async (gpt, rawCodeCommand, prompt, allSrcFiles, contextFiles) => {
103
+ const saveGeneratedFiles = async (files, fileContents) => {
104
+ for (const file of files) {
105
+ if (fileContents[file]) {
106
+ const filePath = path_1.default.resolve(file);
107
+ await fs_1.default.promises.mkdir(path_1.default.dirname(filePath), { recursive: true });
108
+ await fs_1.default.promises.writeFile(filePath, fileContents[file]);
109
+ console.log(`${file} has been saved.`);
110
+ }
111
+ else {
112
+ console.log(`File content not found for ${file}.`);
113
+ }
114
+ }
115
+ };
116
+ const updateContextFiles = async (contextFiles, files, fileContents) => {
117
+ for (const file of files) {
118
+ if (fileContents[file]) {
119
+ contextFiles[file] = fileContents[file];
120
+ }
121
+ }
122
+ };
123
+ const handleUserAction = async (gpt, rawCodeCommand, prompt, allSrcFiles, contextFiles, options) => {
125
124
  const [files, fileContents] = (0, string_utils_1.extractFilesAndContent)(rawCodeCommand);
125
+ if (options.save) {
126
+ await saveGeneratedFiles(files, fileContents);
127
+ await updateContextFiles(contextFiles, files, fileContents);
128
+ return;
129
+ }
126
130
  const { action } = await inquirer_1.default.prompt([
127
131
  {
128
132
  type: 'list',
@@ -148,9 +152,25 @@ const handleUserAction = async (gpt, rawCodeCommand, prompt, allSrcFiles, contex
148
152
  message: 'How would you like to modify the output:',
149
153
  },
150
154
  ]);
155
+ let includeMoreFiles = true;
156
+ while (includeMoreFiles) {
157
+ const { contextFile } = await inquirer_1.default.prompt([
158
+ {
159
+ type: 'input',
160
+ name: 'contextFile',
161
+ message: 'Enter the relative path of a file or directory you would like to include as context (or press enter to continue):',
162
+ },
163
+ ]);
164
+ if (contextFile) {
165
+ contextFiles = await (0, command_utils_1.addFileOrDirectoryToContext)(contextFile, contextFiles, options);
166
+ }
167
+ else {
168
+ includeMoreFiles = false;
169
+ }
170
+ }
151
171
  const newRawCodeCommand = await generateCode(gpt, newPrompt, allSrcFiles, contextFiles, rawCodeCommand);
152
172
  displayGeneratedCode(newRawCodeCommand);
153
- await handleUserAction(gpt, newRawCodeCommand, newPrompt, allSrcFiles, contextFiles);
173
+ await handleUserAction(gpt, newRawCodeCommand, newPrompt, allSrcFiles, contextFiles, options);
154
174
  break;
155
175
  case 'explain':
156
176
  const explainPrompt = generateExplainCodePrompt(rawCodeCommand);
@@ -205,9 +225,10 @@ const handleUserAction = async (gpt, rawCodeCommand, prompt, allSrcFiles, contex
205
225
  ]);
206
226
  if (fileContents[fileToSave]) {
207
227
  const filePath = path_1.default.resolve(fileToSave);
208
- fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
209
- fs_1.default.writeFileSync(filePath, fileContents[fileToSave]);
228
+ await fs_1.default.promises.mkdir(path_1.default.dirname(filePath), { recursive: true });
229
+ await fs_1.default.promises.writeFile(filePath, fileContents[fileToSave]);
210
230
  console.log(`${fileToSave} has been saved.`);
231
+ await updateContextFiles(contextFiles, [fileToSave], fileContents);
211
232
  }
212
233
  else {
213
234
  console.log('File content not found.');
@@ -224,80 +245,45 @@ const handleUserAction = async (gpt, rawCodeCommand, prompt, allSrcFiles, contex
224
245
  }
225
246
  break;
226
247
  case 'saveAll':
227
- files.forEach(file => {
228
- if (fileContents[file]) {
229
- const filePath = path_1.default.resolve(file);
230
- fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
231
- fs_1.default.writeFileSync(filePath, fileContents[file]);
232
- console.log(`${file} has been saved.`);
233
- }
234
- else {
235
- console.log(`File content not found for ${file}.`);
236
- }
237
- });
248
+ await saveGeneratedFiles(files, fileContents);
249
+ await updateContextFiles(contextFiles, files, fileContents);
238
250
  console.log('All files have been saved.');
239
251
  break;
240
252
  case 'done':
241
253
  break;
242
254
  }
243
255
  };
244
- const addFilesToContext = async (contextFiles, filePath) => {
245
- const stats = fs_1.default.statSync(filePath);
246
- if (stats.isDirectory()) {
247
- const files = fs_1.default.readdirSync(filePath);
248
- for (const file of files) {
249
- await addFilesToContext(contextFiles, path_1.default.join(filePath, file));
250
- }
251
- }
252
- else if (stats.isFile()) {
253
- const content = fs_1.default.readFileSync(filePath, 'utf-8');
254
- contextFiles[filePath] = content;
255
- }
256
- };
257
256
  const code = async (options) => {
258
257
  let { prompt, files } = options;
259
258
  options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
260
259
  const gpt = new cloving_gpt_1.default(options);
261
260
  const allSrcFiles = await (0, config_utils_1.getAllFiles)(options, false);
262
- const contextFiles = {};
261
+ let contextFiles = {};
263
262
  try {
264
263
  if (files) {
265
- files.forEach(async (file) => {
266
- await addFilesToContext(contextFiles, file);
267
- });
264
+ for (const file of files) {
265
+ const filePath = path_1.default.resolve(file);
266
+ if (await fs_1.default.promises.stat(filePath).then(stat => stat.isFile()).catch(() => false)) {
267
+ const content = await fs_1.default.promises.readFile(filePath, 'utf-8');
268
+ contextFiles[file] = content;
269
+ }
270
+ }
268
271
  }
269
272
  else {
270
- let firstFile = true;
271
273
  let includeMoreFiles = true;
272
274
  while (includeMoreFiles) {
273
- const { includeMore } = await inquirer_1.default.prompt([
275
+ const { contextFile } = await inquirer_1.default.prompt([
274
276
  {
275
- type: 'confirm',
276
- name: 'includeMore',
277
- message: `Do you want to include any${firstFile ? '' : ' other'} files or directories as context for the prompt?`,
278
- default: false,
277
+ type: 'input',
278
+ name: 'contextFile',
279
+ message: `Enter the relative path of a file or directory you would like to include as context (or press enter to continue):`,
279
280
  },
280
281
  ]);
281
- firstFile = false;
282
- includeMoreFiles = includeMore;
283
- if (includeMoreFiles) {
284
- const { contextFile } = await inquirer_1.default.prompt([
285
- {
286
- type: 'input',
287
- name: 'contextFile',
288
- message: 'Enter the relative path of a file or directory you would like to include as context:',
289
- },
290
- ]);
291
- if (contextFile) {
292
- const filePath = path_1.default.resolve(contextFile);
293
- if (fs_1.default.existsSync(filePath)) {
294
- await addFilesToContext(contextFiles, filePath);
295
- console.log(`Added ${filePath} to context.`);
296
- }
297
- else {
298
- console.log(`File or directory ${contextFile} does not exist.`);
299
- }
300
- }
282
+ if (contextFile) {
283
+ contextFiles = await (0, command_utils_1.addFileOrDirectoryToContext)(contextFile, contextFiles, options);
284
+ }
285
+ else {
286
+ includeMoreFiles = false;
301
287
  }
302
288
  }
303
289
  }
@@ -311,20 +297,59 @@ const code = async (options) => {
311
297
  ]);
312
298
  prompt = userPrompt;
313
299
  }
314
- if (files && files.length > 0) {
315
- // Check if the files exist
316
- const nonExistentFiles = files.filter(file => !fs_1.default.existsSync(file));
317
- if (nonExistentFiles.length > 0) {
318
- throw new Error(`The following files do not exist: ${nonExistentFiles.join(', ')}`);
319
- }
320
- // Read the content of the provided files
321
- for (const file of files) {
322
- await addFilesToContext(contextFiles, file);
300
+ let rawCodeCommand = await generateCode(gpt, prompt, allSrcFiles, contextFiles);
301
+ displayGeneratedCode(rawCodeCommand);
302
+ if (options.save) {
303
+ const [files, fileContents] = (0, string_utils_1.extractFilesAndContent)(rawCodeCommand);
304
+ await saveGeneratedFiles(files, fileContents);
305
+ await updateContextFiles(contextFiles, files, fileContents);
306
+ }
307
+ else {
308
+ await handleUserAction(gpt, rawCodeCommand, prompt, allSrcFiles, contextFiles, options);
309
+ }
310
+ if (options.interactive) {
311
+ let continueInteractive = true;
312
+ while (continueInteractive) {
313
+ const { newPrompt } = await inquirer_1.default.prompt([
314
+ {
315
+ type: 'input',
316
+ name: 'newPrompt',
317
+ message: 'Revise the code (or press enter to finish):',
318
+ },
319
+ ]);
320
+ if (newPrompt.trim() === '') {
321
+ continueInteractive = false;
322
+ }
323
+ else {
324
+ let includeMoreFiles = true;
325
+ while (includeMoreFiles) {
326
+ const { contextFile } = await inquirer_1.default.prompt([
327
+ {
328
+ type: 'input',
329
+ name: 'contextFile',
330
+ message: 'Enter the relative path of a file or directory you would like to include as context (or press enter to continue):',
331
+ },
332
+ ]);
333
+ if (contextFile) {
334
+ contextFiles = await (0, command_utils_1.addFileOrDirectoryToContext)(contextFile, contextFiles, options);
335
+ }
336
+ else {
337
+ includeMoreFiles = false;
338
+ }
339
+ }
340
+ rawCodeCommand = await generateCode(gpt, newPrompt, allSrcFiles, contextFiles, rawCodeCommand);
341
+ displayGeneratedCode(rawCodeCommand);
342
+ if (options.save || options.interactive) {
343
+ const [files, fileContents] = (0, string_utils_1.extractFilesAndContent)(rawCodeCommand);
344
+ await saveGeneratedFiles(files, fileContents);
345
+ await updateContextFiles(contextFiles, files, fileContents);
346
+ }
347
+ else {
348
+ await handleUserAction(gpt, rawCodeCommand, newPrompt, allSrcFiles, contextFiles, options);
349
+ }
350
+ }
323
351
  }
324
352
  }
325
- const rawCodeCommand = await generateCode(gpt, prompt, allSrcFiles, contextFiles);
326
- displayGeneratedCode(rawCodeCommand);
327
- await handleUserAction(gpt, rawCodeCommand, prompt, allSrcFiles, contextFiles);
328
353
  }
329
354
  catch (error) {
330
355
  console.error('Could not generate code', error);
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const inquirer_1 = __importDefault(require("inquirer"));
7
+ const cli_highlight_1 = __importDefault(require("cli-highlight"));
8
+ const copy_paste_1 = __importDefault(require("copy-paste"));
9
+ const command_utils_1 = require("../../utils/command_utils");
10
+ const config_utils_1 = require("../../utils/config_utils");
11
+ const generateContextPrompt = (files, contextFiles) => {
12
+ const specialFileContents = (0, command_utils_1.collectSpecialFileContents)();
13
+ const specialFiles = Object.keys(specialFileContents).map((file) => `### Contents of ${file}\n\n${JSON.stringify(specialFileContents[file], null, 2)}\n\n`).join('\n');
14
+ const contextFileContents = Object.keys(contextFiles).map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`).join('\n');
15
+ return `### Description of App
16
+
17
+ ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
18
+
19
+ ${specialFiles}
20
+
21
+ ${contextFileContents}
22
+
23
+ ### Directory structure
24
+
25
+ ${files.join('\n')}`;
26
+ };
27
+ const context = async (options) => {
28
+ options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
29
+ const allSrcFiles = await (0, config_utils_1.getAllFiles)(options, false);
30
+ let contextFiles = {};
31
+ try {
32
+ let includeMoreFiles = true;
33
+ while (includeMoreFiles) {
34
+ const { contextFile } = await inquirer_1.default.prompt([
35
+ {
36
+ type: 'input',
37
+ name: 'contextFile',
38
+ message: `Enter the relative path of a file or directory you would like to include as context (or press enter to continue):`,
39
+ },
40
+ ]);
41
+ if (contextFile) {
42
+ contextFiles = await (0, command_utils_1.addFileOrDirectoryToContext)(contextFile, contextFiles, options);
43
+ }
44
+ else {
45
+ includeMoreFiles = false;
46
+ }
47
+ }
48
+ const contextPrompt = generateContextPrompt(allSrcFiles, contextFiles);
49
+ console.log('\nGenerated Context Prompt:');
50
+ console.log((0, cli_highlight_1.default)(contextPrompt, { language: 'markdown' }));
51
+ const { copyToClipboard } = await inquirer_1.default.prompt([
52
+ {
53
+ type: 'confirm',
54
+ name: 'copyToClipboard',
55
+ message: 'Do you want to copy the context prompt to your clipboard?',
56
+ default: true,
57
+ },
58
+ ]);
59
+ if (copyToClipboard) {
60
+ copy_paste_1.default.copy(contextPrompt, () => {
61
+ console.log('Context prompt copied to clipboard');
62
+ });
63
+ }
64
+ }
65
+ catch (error) {
66
+ console.error('Could not generate context', error);
67
+ }
68
+ };
69
+ exports.default = context;
@@ -31,7 +31,9 @@ ${prompt}`;
31
31
  };
32
32
  const generateExplainShellPrompt = (prompt) => {
33
33
  return `${prompt}
34
-
34
+
35
+ ## Task
36
+
35
37
  Please briefly explain how this shell script works.`;
36
38
  };
37
39
  const generateShell = async (gpt, prompt) => {
@@ -42,18 +42,15 @@ technologies used. This will provide better context for future Cloving requests.
42
42
  return;
43
43
  }
44
44
  if (!(0, command_utils_1.checkForSpecialFiles)()) {
45
- const { continueAnswer } = await inquirer_1.default.prompt([
45
+ const { technologies } = await inquirer_1.default.prompt([
46
46
  {
47
- type: 'confirm',
48
- name: 'continueAnswer',
49
- message: 'No special files detected. Are you currently inside a software project\'s main directory? Do you want to continue analyzing this directory for the Cloving setup process?',
50
- default: true,
47
+ type: 'input',
48
+ name: 'technologies',
49
+ message: 'No special files detected. Please describe the main technologies used in your project:',
50
+ validate: (input) => input.trim().length > 0 || 'Please provide a description of the technologies used.',
51
51
  },
52
52
  ]);
53
- if (!continueAnswer) {
54
- console.log('Operation aborted by the user.');
55
- return;
56
- }
53
+ specialFileContents['description'] = technologies;
57
54
  }
58
55
  const tempFilePath = path_1.default.join(os_1.default.tmpdir(), `describe_${Date.now()}.tmp`);
59
56
  try {
@@ -73,10 +70,6 @@ technologies used. This will provide better context for future Cloving requests.
73
70
  }
74
71
  });
75
72
  const limitedFileList = filteredFileList.slice(0, 100);
76
- if (specialFileNames.length === 0) {
77
- console.error('No special files found.');
78
- return;
79
- }
80
73
  const projectDetails = {
81
74
  files: limitedFileList,
82
75
  specialFiles: specialFileContents
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ const models_1 = __importDefault(require("./commands/models"));
13
13
  const shell_1 = __importDefault(require("./commands/generate/shell"));
14
14
  const code_1 = __importDefault(require("./commands/generate/code"));
15
15
  const commit_1 = __importDefault(require("./commands/generate/commit"));
16
+ const context_1 = __importDefault(require("./commands/generate/context"));
16
17
  const unit_tests_1 = __importDefault(require("./commands/generate/unit_tests"));
17
18
  const review_1 = __importDefault(require("./commands/generate/review"));
18
19
  const init_2 = __importDefault(require("./commands/project/init"));
@@ -69,8 +70,10 @@ generate
69
70
  .command('code')
70
71
  .alias('c')
71
72
  .description('Generate code based on a prompt')
73
+ .option('--save', 'Automatically save all files after generating the code')
74
+ .option('-i, --interactive', 'Auto-save generated code and then show a new prompt with existing context to revise the code further')
72
75
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
73
- .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
76
+ .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5:sonnet-20240620)')
74
77
  .option('-p, --prompt <prompt>', 'Specify the prompt to use')
75
78
  .option('-f, --files <filenames...>', 'Specify filenames of files with context to use for generating code')
76
79
  .action(code_1.default);
@@ -80,6 +83,10 @@ generate
80
83
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
81
84
  .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
82
85
  .action(commit_1.default);
86
+ generate
87
+ .command('context')
88
+ .description('Create a context string for generating code')
89
+ .action(context_1.default);
83
90
  generate
84
91
  .command('unit-tests')
85
92
  .alias('u')
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -3,40 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.readFileContent = exports.fetchModels = exports.runCommand = exports.generateFileList = exports.checkForSpecialFiles = exports.collectSpecialFileContents = exports.SPECIAL_FILES = void 0;
6
+ exports.addFileOrDirectoryToContext = exports.readFileContent = exports.fetchModels = exports.runCommand = exports.generateFileList = exports.checkForSpecialFiles = exports.collectSpecialFileContents = exports.SPECIAL_FILES = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const config_utils_1 = require("./config_utils");
9
11
  exports.SPECIAL_FILES = [
10
- 'package.json',
11
- 'Gemfile',
12
- 'requirements.txt',
13
- 'Pipfile',
14
- 'pyproject.toml',
15
- 'pom.xml',
16
- 'build.gradle',
17
- '.csproj',
18
- 'packages.config',
19
- 'composer.json',
20
- 'CMakeLists.txt',
21
- 'conanfile.txt',
22
- 'conanfile.py',
23
- 'go.mod',
24
- 'Cargo.toml',
25
- 'Package.swift',
26
- 'build.gradle.kts',
27
- 'Podfile',
28
- 'Cartfile',
29
- 'cpanfile',
30
- 'DESCRIPTION',
31
- 'mix.exs',
32
- 'build.sbt',
33
- 'pubspec.yaml',
34
- 'stack.yaml',
35
- 'cabal.project',
36
- 'Project.toml',
37
- 'rockspec',
38
- 'rebar.config',
39
- 'project.clj'
12
+ 'package.json', 'Gemfile', 'requirements.txt', 'Pipfile', 'pyproject.toml', 'pom.xml', 'build.gradle',
13
+ '.csproj', 'packages.config', 'composer.json', 'CMakeLists.txt', 'conanfile.txt', 'conanfile.py',
14
+ 'go.mod', 'Cargo.toml', 'Package.swift', 'build.gradle.kts', 'Podfile', 'Cartfile', 'cpanfile',
15
+ 'DESCRIPTION', 'mix.exs', 'build.sbt', 'pubspec.yaml', 'stack.yaml', 'cabal.project', 'Project.toml',
16
+ 'rockspec', 'rebar.config', 'project.clj'
40
17
  ];
41
18
  const collectSpecialFileContents = () => {
42
19
  const specialFileContents = {};
@@ -54,9 +31,7 @@ const collectSpecialFileContents = () => {
54
31
  return specialFileContents;
55
32
  };
56
33
  exports.collectSpecialFileContents = collectSpecialFileContents;
57
- const checkForSpecialFiles = () => {
58
- return exports.SPECIAL_FILES.some(file => fs_1.default.existsSync(file));
59
- };
34
+ const checkForSpecialFiles = () => exports.SPECIAL_FILES.some(file => fs_1.default.existsSync(file));
60
35
  exports.checkForSpecialFiles = checkForSpecialFiles;
61
36
  const generateFileList = async () => {
62
37
  try {
@@ -115,3 +90,28 @@ const readFileContent = (file) => {
115
90
  }
116
91
  };
117
92
  exports.readFileContent = readFileContent;
93
+ const addFileOrDirectoryToContext = async (contextFile, contextFiles, options) => {
94
+ const filePath = path_1.default.resolve(contextFile);
95
+ if (await fs_1.default.promises.stat(filePath).then(stat => stat.isDirectory()).catch(() => false)) {
96
+ // Add all files in the specified directory
97
+ const files = await (0, config_utils_1.getAllFiles)(options, false);
98
+ for (const file of files) {
99
+ // if the file is in the same directory as the context file, add it to the context
100
+ if (path_1.default.dirname(file) === path_1.default.dirname(filePath)) {
101
+ const content = await fs_1.default.promises.readFile(file, 'utf-8');
102
+ contextFiles[path_1.default.relative(process.cwd(), file)] = content;
103
+ }
104
+ }
105
+ console.log(`Added contents of ${contextFile} to context.`);
106
+ }
107
+ else if (await fs_1.default.promises.stat(filePath).then(stat => stat.isFile()).catch(() => false)) {
108
+ const content = await fs_1.default.promises.readFile(filePath, 'utf-8');
109
+ contextFiles[contextFile] = content;
110
+ console.log(`Added ${filePath} to context.`);
111
+ }
112
+ else {
113
+ console.log(`File or directory ${contextFile} does not exist.`);
114
+ }
115
+ return contextFiles;
116
+ };
117
+ exports.addFileOrDirectoryToContext = addFileOrDirectoryToContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {