cloving 0.3.11 → 0.3.13

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 (34) hide show
  1. package/dist/cloving_gpt/index.js +32 -39
  2. package/dist/commands/config.js +2 -2
  3. package/dist/commands/generate/commit.js +1 -1
  4. package/dist/commands/generate/docs.js +11 -0
  5. package/dist/commands/generate/review.js +1 -1
  6. package/dist/commands/tokens.js +24 -0
  7. package/dist/index.js +3 -3
  8. package/dist/managers/BlockManager.js +31 -14
  9. package/dist/managers/ChatManager.js +60 -224
  10. package/dist/managers/CodeManager.js +60 -55
  11. package/dist/managers/CommitManager.js +1 -1
  12. package/dist/managers/DocsManager.js +88 -0
  13. package/dist/managers/DocumentationManager.js +2 -1
  14. package/dist/managers/InitManager.js +20 -6
  15. package/dist/managers/ProxyManager.js +19 -2
  16. package/dist/managers/ReviewManager.js +59 -169
  17. package/dist/managers/ShellManager.js +49 -0
  18. package/dist/managers/StreamManager.js +308 -0
  19. package/dist/managers/UnitTestManager.js +3 -3
  20. package/dist/package.json +2 -2
  21. package/dist/utils/config_utils.js +43 -0
  22. package/dist/utils/git_utils.js +29 -0
  23. package/dist/utils/prompt_utils.js +125 -307
  24. package/dist/utils/prompts/CODEGEN_COULDNT_APPLY.md +5 -0
  25. package/dist/utils/prompts/CODEGEN_EXAMPLES.md +82 -0
  26. package/dist/utils/prompts/CODEGEN_INSTRUCTIONS.md +43 -0
  27. package/dist/utils/prompts/DOCS_INSTRUCTIONS.md +9 -0
  28. package/dist/utils/prompts/INIT_INSTRUCTIONS.md +132 -0
  29. package/dist/utils/prompts/REVIEW_INSTRUCTIONS.md +49 -0
  30. package/dist/utils/prompts/SHELL_INSTRUCTIONS.md +15 -0
  31. package/dist/utils/prompts/SPECIAL_FILES.md +66 -0
  32. package/dist/utils/prompts/index.js +27 -0
  33. package/dist/utils/string_utils.js +10 -5
  34. package/package.json +2 -2
@@ -0,0 +1,88 @@
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 prompts_1 = require("@inquirer/prompts");
7
+ const colors_1 = __importDefault(require("colors"));
8
+ const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
9
+ const config_utils_1 = require("../utils/config_utils");
10
+ const prompts_2 = require("../utils/prompts");
11
+ const prompt_utils_1 = require("../utils/prompt_utils");
12
+ const string_utils_1 = require("../utils/string_utils");
13
+ const StreamManager_1 = __importDefault(require("./StreamManager"));
14
+ /**
15
+ * Manages the generation of documentation for specified files.
16
+ */
17
+ class DocsManager extends StreamManager_1.default {
18
+ /**
19
+ * Creates a new DocumentationManager instance.
20
+ * @param {ClovingGPTOptions} options - Configuration options for the DocumentationManager.
21
+ */
22
+ constructor(options) {
23
+ super(options);
24
+ options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
25
+ options.stream = true;
26
+ this.gpt = new cloving_gpt_1.default(options);
27
+ }
28
+ /**
29
+ * Generates documentation for the specified files.
30
+ * @returns {Promise<void>}
31
+ */
32
+ async generateDocs(extraPrompt) {
33
+ try {
34
+ this.isProcessing = true;
35
+ if (this.retryCount === 0) {
36
+ await this.checkForLatestVersion();
37
+ }
38
+ await this.loadContextFiles();
39
+ this.addUserPrompt(`${(0, prompt_utils_1.generateDocsPrompt)(this.contextFiles)}\n\n${extraPrompt || ''}`);
40
+ const responseStream = await this.gpt.streamText({
41
+ prompt: this.prompt,
42
+ messages: this.chatHistory,
43
+ });
44
+ this.handleResponseStream(responseStream);
45
+ }
46
+ catch (error) {
47
+ console.error(colors_1.default.red('Error generating documentation:'), error);
48
+ }
49
+ }
50
+ /**
51
+ * Finalizes the response processing.
52
+ * This method should be overridden to provide specific finalization behavior.
53
+ * @protected
54
+ */
55
+ async finalizeResponse() {
56
+ this.addAssistantResponse(this.responseString);
57
+ this.isProcessing = false;
58
+ if (this.responseString !== '') {
59
+ const currentNewBlocks = (0, string_utils_1.extractCurrentNewBlocks)(this.responseString);
60
+ const [canApply, summary] = await (0, string_utils_1.checkBlocksApplicability)(currentNewBlocks);
61
+ if (canApply && currentNewBlocks.length > 0) {
62
+ const shouldSave = await (0, prompts_1.confirm)({
63
+ message: '\n\nDo you want to save the generated documentation?',
64
+ default: true,
65
+ });
66
+ if (shouldSave) {
67
+ await (0, string_utils_1.applyAndSaveCurrentNewBlocks)(currentNewBlocks);
68
+ console.log(colors_1.default.green('\nDocumentation has been saved to the respective files.'));
69
+ }
70
+ }
71
+ else {
72
+ if (this.retryCount < this.maxRetries) {
73
+ console.log(`\n\n${summary}\n\n${colors_1.default.yellow.bold('WARNING')} Some of the provided code blocks could not be automatically applied. Retrying (Attempt ${this.retryCount + 1}/${this.maxRetries})...\n`);
74
+ this.retryCount++;
75
+ this.generateDocs(`\n\n${prompts_2.CODEGEN_COULDNT_APPLY}\n\n${summary}`);
76
+ return;
77
+ }
78
+ else {
79
+ console.log(`\n\n${colors_1.default.red.bold('ERROR')} Failed to generate a diff that could be cleanly applied after ${this.maxRetries} attempts. Please review the changes manually and try again.\n`);
80
+ this.retryCount = 0; // Reset the retry count for future attempts
81
+ }
82
+ }
83
+ }
84
+ // Reset responseString after processing
85
+ this.responseString = '';
86
+ }
87
+ }
88
+ exports.default = DocsManager;
@@ -9,6 +9,7 @@ const cli_highlight_1 = __importDefault(require("cli-highlight"));
9
9
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
10
10
  const config_utils_1 = require("../utils/config_utils");
11
11
  const prompt_utils_1 = require("../utils/prompt_utils");
12
+ const prompts_2 = require("../utils/prompts");
12
13
  const string_utils_1 = require("../utils/string_utils");
13
14
  /**
14
15
  * Manages the generation of documentation for specified files.
@@ -33,7 +34,7 @@ class DocumentationManager {
33
34
  try {
34
35
  await this.loadContextFiles();
35
36
  if (this.chatHistory.length === 0) {
36
- this.chatHistory.push({ role: 'user', content: prompt_utils_1.CODEGEN_INSTRUCTIONS });
37
+ this.chatHistory.push({ role: 'user', content: prompts_2.CODEGEN_INSTRUCTIONS });
37
38
  this.chatHistory.push({ role: 'assistant', content: 'What would you like to do?' });
38
39
  }
39
40
  const prompt = this.generateDocumentationPrompt();
@@ -14,6 +14,7 @@ const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
14
14
  const string_utils_1 = require("../utils/string_utils");
15
15
  const config_utils_1 = require("../utils/config_utils");
16
16
  const prompt_utils_1 = require("../utils/prompt_utils");
17
+ const prompts_2 = require("../utils/prompts");
17
18
  class InitManager {
18
19
  constructor(options) {
19
20
  this.options = options;
@@ -22,7 +23,7 @@ class InitManager {
22
23
  this.gpt = new cloving_gpt_1.default(this.options);
23
24
  this.chatHistory.push({
24
25
  role: 'system',
25
- content: prompt_utils_1.INIT_INSTRUCTIONS,
26
+ content: prompts_2.INIT_INSTRUCTIONS,
26
27
  });
27
28
  }
28
29
  /**
@@ -181,15 +182,28 @@ ${JSON.stringify(projectDetails, null, 2)}`;
181
182
  }
182
183
  const clovingJson = JSON.parse(cleanAiChatResponse);
183
184
  const directoriesToCheck = [
184
- ...clovingJson.languages.map((language) => language.directory),
185
- ...clovingJson.frameworks.map((framework) => framework.directory),
186
- ...clovingJson.testingFrameworks.map((testingFramework) => testingFramework.directory),
185
+ ...clovingJson.languages.map((language) => ({
186
+ type: 'Language',
187
+ name: language.name,
188
+ directory: language.directory,
189
+ })),
190
+ ...clovingJson.frameworks.map((framework) => ({
191
+ type: 'Framework',
192
+ name: framework.name,
193
+ directory: framework.directory,
194
+ })),
195
+ ...clovingJson.testingFrameworks.map((testingFramework) => ({
196
+ type: 'Testing Framework',
197
+ name: testingFramework.name,
198
+ directory: testingFramework.directory,
199
+ })),
187
200
  ];
188
- const missingDirectories = directoriesToCheck.filter((directory) => !fs_1.default.existsSync(directory));
201
+ const missingDirectories = directoriesToCheck.filter((item) => !fs_1.default.existsSync(item.directory));
189
202
  if (missingDirectories.length > 0) {
203
+ const missingDirMessages = missingDirectories.map((item) => `${item.type} ${colors_1.default.bold(item.name)}: ${colors_1.default.red.bold(item.directory)}`);
190
204
  return [
191
205
  false,
192
- `${colors_1.default.red.bold('ERROR:')} The following directories were not found: ${colors_1.default.red.bold(missingDirectories.join(', '))}`,
206
+ `${colors_1.default.red.bold('ERROR:')} The following directories were not found:\n${missingDirMessages.join('\n')}`,
193
207
  ];
194
208
  }
195
209
  return [true, ''];
@@ -73,7 +73,17 @@ class ProxyManager {
73
73
  async handleChatCompletions(req, res) {
74
74
  try {
75
75
  const { messages, stream } = req.body;
76
- const content = messages.map((message) => message.content).join('\n\n');
76
+ if (!Array.isArray(messages)) {
77
+ return res.status(400).json({ error: 'Invalid request body: messages must be an array' });
78
+ }
79
+ const content = messages
80
+ .map((message) => {
81
+ if (typeof message !== 'object' || typeof message.content !== 'string') {
82
+ throw new Error('Invalid message format');
83
+ }
84
+ return message.content;
85
+ })
86
+ .join('\n\n');
77
87
  const contextFileContents = Object.keys(this.contextFiles)
78
88
  .map((file) => `### Contents of ${file}\n\n${this.contextFiles[file]}\n\n`)
79
89
  .join('\n');
@@ -99,7 +109,14 @@ ${content}`;
99
109
  }
100
110
  catch (error) {
101
111
  console.error('Error processing request:', error);
102
- res.status(500).json({ error: 'Internal server error' });
112
+ if (error instanceof Error && error.message === 'Invalid message format') {
113
+ res.status(400).json({
114
+ error: 'Invalid request body: each message must have a content property of type string',
115
+ });
116
+ }
117
+ else {
118
+ res.status(500).json({ error: 'Internal server error' });
119
+ }
103
120
  }
104
121
  }
105
122
  async handleStreamResponse(prompt, res) {
@@ -3,181 +3,31 @@ 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
- const cli_highlight_1 = __importDefault(require("cli-highlight"));
7
- const prompts_1 = require("@inquirer/prompts");
8
6
  const copy_paste_1 = __importDefault(require("copy-paste"));
9
- const fs_1 = __importDefault(require("fs"));
10
- const path_1 = __importDefault(require("path"));
7
+ const colors_1 = __importDefault(require("colors"));
8
+ const prompts_1 = require("@inquirer/prompts");
11
9
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
12
10
  const git_utils_1 = require("../utils/git_utils");
13
- const string_utils_1 = require("../utils/string_utils");
14
11
  const prompt_utils_1 = require("../utils/prompt_utils");
15
12
  const config_utils_1 = require("../utils/config_utils");
16
- class ReviewManager {
13
+ const StreamManager_1 = __importDefault(require("./StreamManager"));
14
+ class ReviewManager extends StreamManager_1.default {
17
15
  constructor(options) {
18
- this.contextFiles = {};
19
- this.chatHistory = [];
16
+ super(options);
20
17
  options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
21
- this.options = options;
18
+ options.stream = true;
22
19
  this.gpt = new cloving_gpt_1.default(options);
23
20
  }
24
- /**
25
- * Loads the context files specified in the options. If directories are provided,
26
- * it expands them to include all files within. The contents of each file are
27
- * stored in the `contextFiles` object for later use.
28
- */
29
- async loadContextFiles() {
30
- if (this.options.files) {
31
- let expandedFiles = [];
32
- for (const file of this.options.files) {
33
- const filePath = path_1.default.resolve(file);
34
- if (await fs_1.default.promises
35
- .stat(filePath)
36
- .then((stat) => stat.isDirectory())
37
- .catch(() => false)) {
38
- const dirFiles = await (0, prompt_utils_1.getAllFilesInDirectory)(filePath);
39
- expandedFiles = expandedFiles.concat(dirFiles.map((f) => path_1.default.relative(process.cwd(), f)));
40
- }
41
- else {
42
- expandedFiles.push(path_1.default.relative(process.cwd(), filePath));
43
- }
44
- }
45
- this.options.files = expandedFiles;
46
- for (const file of this.options.files) {
47
- const filePath = path_1.default.resolve(file);
48
- if (await fs_1.default.promises
49
- .stat(filePath)
50
- .then((stat) => stat.isFile())
51
- .catch(() => false)) {
52
- const content = await fs_1.default.promises.readFile(filePath, 'utf-8');
53
- this.contextFiles[file] = content;
54
- }
55
- }
56
- }
57
- }
58
- /**
59
- * Generates a review prompt based on the current chat history and options.
60
- * If no chat history exists, it initializes it with a system prompt and a request
61
- * for user input. The prompt includes a structured example response for code review.
62
- *
63
- * @returns {string} The generated review prompt.
64
- */
65
- generateReviewPrompt() {
66
- if (this.chatHistory.length === 0) {
67
- let systemPrompt = `### Example of a well-structured response
68
-
69
- # Code Review: Enhanced Code Generation and File Handling
70
-
71
- ## Changes Overview
72
-
73
- These changes primarily focus on improving the code generation process and adding more robust file handling capabilities. The main modifications include:
74
-
75
- 1. Enhancing the code generation prompt with a structured example response.
76
- 2. Implementing a new function to extract file names and contents from the generated code.
77
- 3. Adding a new option to save generated code directly to files.
78
- 4. Improving the copy-to-clipboard functionality to allow copying individual files.
79
- 5. Removing an unused import in the review.ts file.
80
-
81
- ## Reason for Changes
82
-
83
- The changes aim to enhance the usability and flexibility of the code generation tool by providing clearer prompts, better file management, and more control over the generated code.
84
-
85
- ## Detailed Description
86
-
87
- 1. **Enhanced Code Generation Prompt** - The \`generateCodePrompt\` function now includes a structured example of a well-formatted response. This helps guide the AI to produce more consistent and usable output, making it easier to parse and use the generated code.
88
- 2. **File Extraction Function** - A new function \`extractFilesAndContent\` has been added to parse the raw code command and extract individual file names and their contents. This enables more granular control over the generated code, allowing for file-specific operations.
89
- 3. **Save to File Option** - A new 'Save Source Code to Files' option has been added to the user action menu. This feature allows users to save generated code directly to files in the appropriate directory structure.
90
- 4. **Improved Copy to Clipboard** - The 'Copy Source Code to Clipboard' option has been enhanced to allow users to choose specific files to copy, rather than copying all generated code at once.
91
- 5. **Removed Unused Import** - The unused import of \`execFileSync\` from 'child_process' has been removed from the review.ts file, improving code cleanliness.
92
-
93
- ## Potential Bugs and Recommended Fixes
94
-
95
- ### 1. Possible undefined access in \`extractFilesAndContent\`
96
-
97
- \`\`\`typescript
98
- const contentMatch = regex.exec(rawCodeCommand)
99
- if (contentMatch) {
100
- files.push(fileName)
101
- let content = contentMatch[1]
102
- // ...
103
- }
104
- \`\`\`
105
-
106
- There's a potential for \`contentMatch[1]\` to be undefined if the regex doesn't capture any groups. To fix this, add a null check:
107
-
108
- \`\`\`typescript
109
- const contentMatch = regex.exec(rawCodeCommand)
110
- if (contentMatch && contentMatch[1]) {
111
- files.push(fileName)
112
- let content = contentMatch[1]
113
- // ...
114
- }
115
- \`\`\`
116
-
117
- `;
118
- if (this.options.files) {
119
- const contextFileContents = Object.keys(this.contextFiles)
120
- .map((file) => `### Contents of ${file}\n\n${this.contextFiles[file]}\n\n`)
121
- .join('\n');
122
- systemPrompt += `### Description of App
123
-
124
- ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
125
-
126
- ${contextFileContents}
127
-
128
- ### Request
129
-
130
- I would like you to explain the code and document a description of it.
131
- List any bugs in the new code as well as recommended fixes for those bugs with code examples.
132
- Format the output of this code review in Markdown format.`;
133
- }
134
- else {
135
- systemPrompt += `### Request
136
-
137
- Do not use any data from the example response structure, only use the structure.
138
- I would like you to explain why these change are being made and document a description of these changes.
139
- Also list any bugs in the new code as well as recommended fixes for those bugs with code examples.
140
- Format the output of this code review in Markdown format.`;
141
- }
142
- this.chatHistory.push({ role: 'user', content: systemPrompt });
143
- this.chatHistory.push({ role: 'assistant', content: 'What would you like to do?' });
144
- }
145
- this.chatHistory.push({
146
- role: 'user',
147
- content: this.options.prompt || 'Please provide a code review.',
148
- });
149
- return this.options.prompt || 'Please provide a code review.';
150
- }
151
21
  async getGitDiffPrompt() {
152
22
  const gitDiff = await (0, git_utils_1.getGitDiff)();
153
- this.options.prompt = `## Diff Content
23
+ return `${(0, prompt_utils_1.generateReviewPrompt)(this.options, this.contextFiles)}
24
+
25
+ ## Diff Content
154
26
  ${gitDiff}
155
27
 
156
28
  # Task
157
29
 
158
30
  ${this.options.prompt || 'Please provide a code review.'}`;
159
- const prompt = this.generateReviewPrompt();
160
- return prompt;
161
- }
162
- displayAnalysis(analysis) {
163
- (0, string_utils_1.parseMarkdownInstructions)(analysis).map((code) => {
164
- if (code.trim().startsWith('```')) {
165
- const lines = code.split('\n');
166
- const language = code.match(/```(\w+)/)?.[1] || 'plaintext';
167
- console.log(lines[0]);
168
- try {
169
- console.log((0, cli_highlight_1.default)(lines.slice(1, -1).join('\n'), { language }));
170
- }
171
- catch (error) {
172
- // don't highlight if it fails
173
- console.log(lines.slice(1, -1).join('\n'));
174
- }
175
- console.log(lines.slice(-1)[0]);
176
- }
177
- else {
178
- console.log((0, cli_highlight_1.default)(code, { language: 'markdown' }));
179
- }
180
- });
181
31
  }
182
32
  async handleUserAction(analysis) {
183
33
  const extractSection = (section) => {
@@ -215,27 +65,67 @@ ${this.options.prompt || 'Please provide a code review.'}`;
215
65
  if (contentToCopy) {
216
66
  copy_paste_1.default.copy(contentToCopy, (err) => {
217
67
  if (err) {
218
- console.error('Error: Unable to copy to clipboard.', err);
68
+ console.error(colors_1.default.red('Error: Unable to copy to clipboard.'), err);
219
69
  }
220
70
  else {
221
- console.log('Selected content copied to clipboard');
71
+ console.log(colors_1.default.green('Selected content copied to clipboard'));
222
72
  }
223
73
  });
224
74
  }
225
75
  }
226
- async review() {
76
+ async generateReview(extraPrompt) {
227
77
  try {
78
+ await this.checkForLatestVersion();
228
79
  await this.loadContextFiles();
229
- const prompt = this.options.files
230
- ? this.generateReviewPrompt()
231
- : await this.getGitDiffPrompt();
232
- const analysis = await this.gpt.generateText({ prompt, messages: this.chatHistory });
233
- this.displayAnalysis(analysis);
234
- await this.handleUserAction(analysis);
80
+ if (this.options.files) {
81
+ if (this.chatHistory.length === 0) {
82
+ this.addUserPrompt(`${(0, prompt_utils_1.generateReviewPrompt)(this.options, this.contextFiles)}`);
83
+ this.addAssistantResponse('What would you like to do?');
84
+ }
85
+ this.addUserPrompt(`${this.options.prompt || 'Please provide a code review.'}\n\n${extraPrompt || ''}`);
86
+ }
87
+ else {
88
+ if (this.chatHistory.length === 0) {
89
+ this.addUserPrompt(await this.getGitDiffPrompt());
90
+ this.addAssistantResponse('What would you like to do?');
91
+ }
92
+ this.addUserPrompt(`${this.options.prompt || 'Please provide a code review.'}\n\n${extraPrompt || ''}`);
93
+ }
94
+ const responseStream = await this.gpt.streamText({
95
+ prompt: this.prompt,
96
+ messages: this.chatHistory,
97
+ });
98
+ this.handleResponseStream(responseStream);
235
99
  }
236
100
  catch (error) {
237
- console.error('Error during analysis:', error.message);
101
+ this.handleError(error);
238
102
  }
239
103
  }
104
+ handleError(error) {
105
+ let errorMessage = error.message || 'An error occurred.';
106
+ const errorNumber = error.response?.status || 'unknown';
107
+ switch (errorNumber) {
108
+ case 400:
109
+ errorMessage = 'Invalid model or prompt size too large. Try specifying fewer files.';
110
+ break;
111
+ case 403:
112
+ errorMessage = 'Inactive subscription or usage limit reached';
113
+ break;
114
+ case 429:
115
+ errorMessage = 'Rate limit error';
116
+ break;
117
+ case 500:
118
+ errorMessage = 'Internal server error';
119
+ break;
120
+ }
121
+ const statusMessage = error.response?.data?.statusMessage;
122
+ console.error(colors_1.default.red(`\nError (${errorNumber}) while submitting the prompt to the AI API\n\n${statusMessage}\n`));
123
+ this.isProcessing = false;
124
+ }
125
+ async finalizeResponse() {
126
+ this.addAssistantResponse(this.responseString);
127
+ this.isProcessing = false;
128
+ await this.handleUserAction(this.responseString);
129
+ }
240
130
  }
241
131
  exports.default = ReviewManager;
@@ -11,13 +11,26 @@ const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
11
11
  const prompt_utils_1 = require("../utils/prompt_utils");
12
12
  const string_utils_1 = require("../utils/string_utils");
13
13
  const config_utils_1 = require("../utils/config_utils");
14
+ /**
15
+ * ShellManager class for handling shell script generation and execution.
16
+ */
14
17
  class ShellManager {
18
+ /**
19
+ * Creates an instance of ShellManager.
20
+ * @param {ClovingGPTOptions} options - The options for ClovingGPT.
21
+ */
15
22
  constructor(options) {
16
23
  this.options = options;
17
24
  this.chatHistory = [];
18
25
  options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
19
26
  this.gpt = new cloving_gpt_1.default(options);
20
27
  }
28
+ /**
29
+ * Generates a prompt to explain a shell script.
30
+ * @param {string} prompt - The original shell script prompt.
31
+ * @returns {string} The prompt for explaining the shell script.
32
+ * @private
33
+ */
21
34
  generateExplainShellPrompt(prompt) {
22
35
  return `${prompt}
23
36
 
@@ -25,6 +38,12 @@ class ShellManager {
25
38
 
26
39
  Please briefly explain how this shell script works.`;
27
40
  }
41
+ /**
42
+ * Generates a shell script based on the given prompt.
43
+ * @param {string} prompt - The user's prompt for generating a shell script.
44
+ * @returns {Promise<string>} A promise that resolves to the generated shell script.
45
+ * @private
46
+ */
28
47
  async generateShell(prompt) {
29
48
  if (this.chatHistory.length === 0) {
30
49
  const systemPrompt = (0, prompt_utils_1.generateShellPrompt)();
@@ -34,11 +53,23 @@ Please briefly explain how this shell script works.`;
34
53
  this.chatHistory.push({ role: 'user', content: prompt });
35
54
  return await this.gpt.generateText({ prompt, messages: this.chatHistory });
36
55
  }
56
+ /**
57
+ * Displays the generated shell script with syntax highlighting.
58
+ * @param {string} rawShellCommand - The raw shell command to display.
59
+ * @private
60
+ */
37
61
  displayGeneratedShell(rawShellCommand) {
38
62
  const generatedShell = (0, string_utils_1.extractMarkdown)(rawShellCommand);
39
63
  const generatedShellWithoutShebang = generatedShell.replace(/^#!.*?\s/, '');
40
64
  console.log((0, cli_highlight_1.default)(generatedShellWithoutShebang));
41
65
  }
66
+ /**
67
+ * Handles user actions after generating a shell script.
68
+ * @param {string} response - The generated shell script.
69
+ * @param {string} prompt - The original user prompt.
70
+ * @returns {Promise<void>}
71
+ * @private
72
+ */
42
73
  async handleUserAction(response, prompt) {
43
74
  let { exec } = this.options;
44
75
  this.chatHistory.push({ role: 'assistant', content: response });
@@ -94,6 +125,24 @@ Please briefly explain how this shell script works.`;
94
125
  break;
95
126
  }
96
127
  }
128
+ /**
129
+ * Generates a shell script based on user input and handles subsequent user actions.
130
+ *
131
+ * This method is the main entry point for generating and interacting with shell scripts.
132
+ * It performs the following steps:
133
+ * 1. Obtains a user prompt (either from options or by asking the user).
134
+ * 2. Generates a shell script based on the prompt.
135
+ * 3. Displays the generated script with syntax highlighting.
136
+ * 4. Handles user actions (execute, revise, explain, copy, or cancel) for the generated script.
137
+ *
138
+ * @returns {Promise<void>} A promise that resolves when the generation and handling process is complete.
139
+ * @throws {Error} If there's an issue during the shell script generation process.
140
+ * @public
141
+ *
142
+ * @example
143
+ * const shellManager = new ShellManager(options);
144
+ * await shellManager.generateAndHandleShell();
145
+ */
97
146
  async generateAndHandleShell() {
98
147
  let { prompt: userPrompt } = this.options;
99
148
  try {