cloving 0.3.4 → 0.3.6
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/README.md +8 -2
- package/dist/cloving_gpt/adapters/claude.js +7 -5
- package/dist/cloving_gpt/adapters/gemini.js +14 -9
- package/dist/cloving_gpt/adapters/mistral.js +9 -7
- package/dist/cloving_gpt/adapters/ollama.js +7 -7
- package/dist/cloving_gpt/adapters/openai.js +9 -7
- package/dist/cloving_gpt/index.js +13 -8
- package/dist/commands/config.js +9 -9
- package/dist/commands/generate/context.js +13 -6
- package/dist/commands/generate/unit_tests.js +3 -261
- package/dist/commands/init.js +3 -218
- package/dist/commands/tokens.js +14 -6
- package/dist/index.js +5 -8
- package/dist/managers/BlockManager.js +121 -0
- package/dist/managers/ChatManager.js +202 -42
- package/dist/managers/ChunkManager.js +12 -0
- package/dist/managers/CodeManager.js +24 -10
- package/dist/managers/CommitManager.js +6 -3
- package/dist/managers/InitManager.js +216 -0
- package/dist/managers/ProxyManager.js +33 -10
- package/dist/managers/ReviewManager.js +40 -12
- package/dist/managers/ShellManager.js +7 -4
- package/dist/managers/UnitTestManager.js +243 -0
- package/dist/package.json +13 -8
- package/dist/utils/command_utils.js +86 -34
- package/dist/utils/config_utils.js +15 -5
- package/dist/utils/git_utils.js +7 -4
- package/dist/utils/prompt_utils.js +515 -0
- package/dist/utils/string_utils.js +119 -12
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
# Cloving
|
|
1
|
+
# Cloving
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An AI pair-programmer for the command line.
|
|
4
|
+
|
|
5
|
+
LLM-powered shell commands, code generation, commit messages, code reviews, unit test generation, and more. Works with most popular LLMs including OpenAI, Claude, Gemini, Ollama, and more.
|
|
6
|
+
|
|
7
|
+
[](https://asciinema.org/a/SCcxw4B2XFQaTD0GeDTk0xbuq)
|
|
8
|
+
|
|
9
|
+
Cloving CLI is a command line utility which integrates AI into your development workflow.
|
|
4
10
|
|
|
5
11
|
What makes the Cloving CLI different from other AI tools is that it builds sophisticated context-aware prompts to generate code, commit messages, and more.
|
|
6
12
|
|
|
@@ -7,7 +7,7 @@ class ClaudeAdapter {
|
|
|
7
7
|
this.anthropicVersion = '2023-06-01';
|
|
8
8
|
}
|
|
9
9
|
static listSupportedModels() {
|
|
10
|
-
ClaudeAdapter.supportedModels.forEach(model => {
|
|
10
|
+
ClaudeAdapter.supportedModels.forEach((model) => {
|
|
11
11
|
console.log(model);
|
|
12
12
|
});
|
|
13
13
|
}
|
|
@@ -18,7 +18,7 @@ class ClaudeAdapter {
|
|
|
18
18
|
return {
|
|
19
19
|
'x-api-key': apiKey,
|
|
20
20
|
'Content-Type': 'application/json',
|
|
21
|
-
'anthropic-version': this.anthropicVersion
|
|
21
|
+
'anthropic-version': this.anthropicVersion,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
getPayload(request, stream = false) {
|
|
@@ -30,10 +30,12 @@ class ClaudeAdapter {
|
|
|
30
30
|
return {
|
|
31
31
|
model: this.model.replace(':', '-'),
|
|
32
32
|
system,
|
|
33
|
-
messages: request.messages && request.messages.length > 0
|
|
33
|
+
messages: request.messages && request.messages.length > 0
|
|
34
|
+
? request.messages
|
|
35
|
+
: [{ role: 'user', content: request.prompt }],
|
|
34
36
|
max_tokens: request.maxTokens || 4096,
|
|
35
37
|
temperature: request.temperature || 0.2,
|
|
36
|
-
stream
|
|
38
|
+
stream,
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
extractResponse(data) {
|
|
@@ -67,7 +69,7 @@ class ClaudeAdapter {
|
|
|
67
69
|
const output = parsedObject?.delta?.text || '';
|
|
68
70
|
return {
|
|
69
71
|
output,
|
|
70
|
-
lastChar
|
|
72
|
+
lastChar,
|
|
71
73
|
};
|
|
72
74
|
}
|
|
73
75
|
catch (error) {
|
|
@@ -6,7 +6,7 @@ class GeminiAdapter {
|
|
|
6
6
|
this.model = model;
|
|
7
7
|
}
|
|
8
8
|
static async listSupportedModels() {
|
|
9
|
-
GeminiAdapter.supportedModels.forEach(model => {
|
|
9
|
+
GeminiAdapter.supportedModels.forEach((model) => {
|
|
10
10
|
console.log(model);
|
|
11
11
|
});
|
|
12
12
|
}
|
|
@@ -21,7 +21,7 @@ class GeminiAdapter {
|
|
|
21
21
|
getHeaders(apiKey) {
|
|
22
22
|
return {
|
|
23
23
|
'Content-Type': 'application/json',
|
|
24
|
-
'x-goog-api-key': apiKey
|
|
24
|
+
'x-goog-api-key': apiKey,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
getPayload(request, stream = false) {
|
|
@@ -31,22 +31,27 @@ class GeminiAdapter {
|
|
|
31
31
|
role: 'user', // or 'model' if generated from the model
|
|
32
32
|
parts: [
|
|
33
33
|
{
|
|
34
|
-
text: request.prompt
|
|
35
|
-
}
|
|
36
|
-
]
|
|
34
|
+
text: request.prompt,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
39
|
generationConfig: {
|
|
40
40
|
temperature: request.temperature || 0.2,
|
|
41
41
|
topK: 40,
|
|
42
42
|
topP: 0.95,
|
|
43
|
-
maxOutputTokens: 1024
|
|
44
|
-
}
|
|
43
|
+
maxOutputTokens: 1024,
|
|
44
|
+
},
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
extractResponse(data) {
|
|
48
48
|
try {
|
|
49
|
-
if (data &&
|
|
49
|
+
if (data &&
|
|
50
|
+
data.candidates &&
|
|
51
|
+
data.candidates[0] &&
|
|
52
|
+
data.candidates[0].content &&
|
|
53
|
+
data.candidates[0].content.parts &&
|
|
54
|
+
data.candidates[0].content.parts[0]) {
|
|
50
55
|
return data.candidates[0].content.parts[0].text;
|
|
51
56
|
}
|
|
52
57
|
else {
|
|
@@ -74,7 +79,7 @@ class GeminiAdapter {
|
|
|
74
79
|
const output = parsedObject?.candidates[0]?.content?.parts[0]?.text || '';
|
|
75
80
|
return {
|
|
76
81
|
output,
|
|
77
|
-
lastChar
|
|
82
|
+
lastChar,
|
|
78
83
|
};
|
|
79
84
|
}
|
|
80
85
|
catch (error) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MistralAdapter = void 0;
|
|
4
4
|
class MistralAdapter {
|
|
5
5
|
static listSupportedModels() {
|
|
6
|
-
MistralAdapter.supportedModels.forEach(model => {
|
|
6
|
+
MistralAdapter.supportedModels.forEach((model) => {
|
|
7
7
|
console.log(model);
|
|
8
8
|
});
|
|
9
9
|
}
|
|
@@ -15,23 +15,25 @@ class MistralAdapter {
|
|
|
15
15
|
}
|
|
16
16
|
getHeaders(apiKey) {
|
|
17
17
|
return {
|
|
18
|
-
|
|
19
|
-
'Content-Type': 'application/json'
|
|
18
|
+
Authorization: `Bearer ${apiKey}`,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
getPayload(request, stream = false) {
|
|
23
23
|
return {
|
|
24
24
|
model: this.model.replace(':', '-'),
|
|
25
|
-
messages: request.messages && request.messages.length > 0
|
|
25
|
+
messages: request.messages && request.messages.length > 0
|
|
26
|
+
? request.messages
|
|
27
|
+
: [{ role: 'user', content: request.prompt }],
|
|
26
28
|
max_tokens: request.maxTokens,
|
|
27
29
|
temperature: request.temperature || 0.2,
|
|
28
|
-
stream
|
|
30
|
+
stream,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
extractResponse(data) {
|
|
32
34
|
return data.choices[0].message.content;
|
|
33
35
|
}
|
|
34
|
-
// data example:
|
|
36
|
+
// data example:
|
|
35
37
|
// {
|
|
36
38
|
// id: 'chatcmpl-9tL477A98d54qvVQqJT010bm8BLJl',
|
|
37
39
|
// object: 'chat.completion.chunk',
|
|
@@ -64,7 +66,7 @@ class MistralAdapter {
|
|
|
64
66
|
const output = parsedObject?.choices[0]?.delta?.content || '';
|
|
65
67
|
return {
|
|
66
68
|
output,
|
|
67
|
-
lastChar
|
|
69
|
+
lastChar,
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
catch (error) {
|
|
@@ -13,13 +13,13 @@ class OllamaAdapter {
|
|
|
13
13
|
try {
|
|
14
14
|
const endpoint = 'http://localhost:11434/api/tags';
|
|
15
15
|
const headers = {
|
|
16
|
-
'Content-Type': 'application/json'
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
17
|
};
|
|
18
18
|
const response = await axios_1.default.get(endpoint, { headers });
|
|
19
19
|
const data = response.data;
|
|
20
20
|
if (data && Array.isArray(data.models)) {
|
|
21
21
|
OllamaAdapter.supportedModels = data.models.map((model) => `ollama:${model.name}`);
|
|
22
|
-
OllamaAdapter.supportedModels.forEach(model => {
|
|
22
|
+
OllamaAdapter.supportedModels.forEach((model) => {
|
|
23
23
|
console.log(model);
|
|
24
24
|
});
|
|
25
25
|
}
|
|
@@ -36,15 +36,15 @@ class OllamaAdapter {
|
|
|
36
36
|
}
|
|
37
37
|
getHeaders(apiKey) {
|
|
38
38
|
return {
|
|
39
|
-
|
|
40
|
-
'Content-Type': 'application/json'
|
|
39
|
+
Authorization: `Bearer ${apiKey}`,
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
getPayload(request, stream = false) {
|
|
44
44
|
return {
|
|
45
45
|
model: this.model,
|
|
46
46
|
prompt: request.prompt,
|
|
47
|
-
stream
|
|
47
|
+
stream,
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
extractResponse(data) {
|
|
@@ -62,7 +62,7 @@ class OllamaAdapter {
|
|
|
62
62
|
throw error;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
// data example:
|
|
65
|
+
// data example:
|
|
66
66
|
// {
|
|
67
67
|
// model: 'dolphin-llama3:latest',
|
|
68
68
|
// created_at: '2024-08-06T21:04:34.616355Z',
|
|
@@ -84,7 +84,7 @@ class OllamaAdapter {
|
|
|
84
84
|
const output = parsedObject?.response || '';
|
|
85
85
|
return {
|
|
86
86
|
output,
|
|
87
|
-
lastChar
|
|
87
|
+
lastChar,
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
catch (error) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.OpenAIAdapter = void 0;
|
|
4
4
|
class OpenAIAdapter {
|
|
5
5
|
static listSupportedModels() {
|
|
6
|
-
OpenAIAdapter.supportedModels.forEach(model => {
|
|
6
|
+
OpenAIAdapter.supportedModels.forEach((model) => {
|
|
7
7
|
console.log(model);
|
|
8
8
|
});
|
|
9
9
|
}
|
|
@@ -15,23 +15,25 @@ class OpenAIAdapter {
|
|
|
15
15
|
}
|
|
16
16
|
getHeaders(apiKey) {
|
|
17
17
|
return {
|
|
18
|
-
|
|
19
|
-
'Content-Type': 'application/json'
|
|
18
|
+
Authorization: `Bearer ${apiKey}`,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
getPayload(request, stream = false) {
|
|
23
23
|
return {
|
|
24
24
|
model: this.model.replace(':', '-'),
|
|
25
|
-
messages: request.messages && request.messages.length > 0
|
|
25
|
+
messages: request.messages && request.messages.length > 0
|
|
26
|
+
? request.messages
|
|
27
|
+
: [{ role: 'user', content: request.prompt }],
|
|
26
28
|
max_tokens: request.maxTokens,
|
|
27
29
|
temperature: request.temperature || 0.2,
|
|
28
|
-
stream
|
|
30
|
+
stream,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
extractResponse(data) {
|
|
32
34
|
return data.choices[0].message.content;
|
|
33
35
|
}
|
|
34
|
-
// data example:
|
|
36
|
+
// data example:
|
|
35
37
|
// {
|
|
36
38
|
// id: 'chatcmpl-9tL477A98d54qvVQqJT010bm8BLJl',
|
|
37
39
|
// object: 'chat.completion.chunk',
|
|
@@ -64,7 +66,7 @@ class OpenAIAdapter {
|
|
|
64
66
|
const output = parsedObject?.choices[0]?.delta?.content || '';
|
|
65
67
|
return {
|
|
66
68
|
output,
|
|
67
|
-
lastChar
|
|
69
|
+
lastChar,
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
catch (error) {
|
|
@@ -10,6 +10,7 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
10
10
|
const child_process_1 = require("child_process");
|
|
11
11
|
const process_1 = __importDefault(require("process"));
|
|
12
12
|
const prompts_1 = require("@inquirer/prompts");
|
|
13
|
+
const colors_1 = __importDefault(require("colors"));
|
|
13
14
|
const claude_1 = require("./adapters/claude");
|
|
14
15
|
const openai_1 = require("./adapters/openai");
|
|
15
16
|
const mistral_1 = require("./adapters/mistral");
|
|
@@ -58,11 +59,13 @@ class ClovingGPT {
|
|
|
58
59
|
async reviewPrompt(prompt, messages, endpoint) {
|
|
59
60
|
if (this.silent)
|
|
60
61
|
return prompt;
|
|
61
|
-
const fullPrompt = messages
|
|
62
|
+
const fullPrompt = messages
|
|
63
|
+
.map((m) => (m.role === 'user' ? `# Task\n\n${m.content}` : m.content))
|
|
64
|
+
.join('\n\n');
|
|
62
65
|
const tokenCount = Math.ceil(fullPrompt.length / 4).toLocaleString();
|
|
63
66
|
const reviewPrompt = await (0, prompts_1.confirm)({
|
|
64
67
|
message: `Do you want to review the ~${tokenCount} token prompt before sending it to ${endpoint}?`,
|
|
65
|
-
default: true
|
|
68
|
+
default: true,
|
|
66
69
|
});
|
|
67
70
|
if (reviewPrompt) {
|
|
68
71
|
const tempFile = path_1.default.join(os_1.default.tmpdir(), `cloving_prompt_${Date.now()}.txt`);
|
|
@@ -86,7 +89,7 @@ class ClovingGPT {
|
|
|
86
89
|
}
|
|
87
90
|
const confirmPrompt = await (0, prompts_1.confirm)({
|
|
88
91
|
message: `Are you sure you want to continue?`,
|
|
89
|
-
default: true
|
|
92
|
+
default: true,
|
|
90
93
|
});
|
|
91
94
|
if (!confirmPrompt) {
|
|
92
95
|
resolve(null);
|
|
@@ -125,16 +128,18 @@ class ClovingGPT {
|
|
|
125
128
|
data: payload,
|
|
126
129
|
headers: headers,
|
|
127
130
|
responseType: 'stream',
|
|
128
|
-
timeout: this.timeout
|
|
131
|
+
timeout: this.timeout,
|
|
129
132
|
});
|
|
130
133
|
}
|
|
131
134
|
catch (err) {
|
|
132
135
|
const error = err;
|
|
133
136
|
if (error.response && error.response.status === 429) {
|
|
134
137
|
attempt++;
|
|
135
|
-
const tokenCount = payload.messages
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
const tokenCount = payload.messages
|
|
139
|
+
.reduce((acc, message) => acc + Math.ceil(message.content.length / 4), 0)
|
|
140
|
+
.toLocaleString();
|
|
141
|
+
console.warn(`${colors_1.default.red.bold('ERROR')} Rate limit error for this ${tokenCount} token prompt. Possibly past the token limit for this AI API. Try including fewer code files. Retrying in ${delay / 1000} seconds... (Attempt ${attempt} of ${maxRetries})`);
|
|
142
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
138
143
|
delay *= 2; // Exponential backoff
|
|
139
144
|
}
|
|
140
145
|
else {
|
|
@@ -164,7 +169,7 @@ class ClovingGPT {
|
|
|
164
169
|
if (errorMessage === '') {
|
|
165
170
|
errorMessage = 'connection error';
|
|
166
171
|
}
|
|
167
|
-
console.error(`Error communicating with the GPT server (${this.adapter.getEndpoint(this.stream)})\n\n${JSON.stringify(error.response?.data || "''", null, 2)}\n`);
|
|
172
|
+
console.error(`Error communicating with the GPT server (${this.adapter.getEndpoint(this.stream)})\n\n${colors_1.default.red.bold(JSON.stringify(error.response?.data || "''", null, 2))}\n`);
|
|
168
173
|
throw error;
|
|
169
174
|
}
|
|
170
175
|
}
|
package/dist/commands/config.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.config = void 0;
|
|
4
4
|
const config_utils_1 = require("../utils/config_utils");
|
|
5
|
-
const
|
|
5
|
+
const prompt_utils_1 = require("../utils/prompt_utils");
|
|
6
6
|
const prompts_1 = require("@inquirer/prompts");
|
|
7
7
|
const config = async () => {
|
|
8
8
|
let currentConfig = (0, config_utils_1.getConfig)({});
|
|
@@ -10,27 +10,27 @@ const config = async () => {
|
|
|
10
10
|
if (!currentConfig.models) {
|
|
11
11
|
currentConfig.models = {};
|
|
12
12
|
}
|
|
13
|
-
const models = await (0,
|
|
13
|
+
const models = await (0, prompt_utils_1.fetchModels)();
|
|
14
14
|
if (models.length === 0) {
|
|
15
15
|
console.error('No models available.');
|
|
16
16
|
throw new Error('No models available');
|
|
17
17
|
}
|
|
18
18
|
let continueConfig = true;
|
|
19
19
|
while (continueConfig) {
|
|
20
|
-
const providers = [...new Set(models.map(model => model.split(':')[0]))];
|
|
20
|
+
const providers = [...new Set(models.map((model) => model.split(':')[0]))];
|
|
21
21
|
const selectedProvider = await (0, prompts_1.select)({
|
|
22
22
|
message: 'Select a provider:',
|
|
23
|
-
choices: providers.map(provider => ({ name: provider, value: provider })),
|
|
23
|
+
choices: providers.map((provider) => ({ name: provider, value: provider })),
|
|
24
24
|
});
|
|
25
|
-
const providerModels = models.filter(model => model.startsWith(selectedProvider));
|
|
26
|
-
const modelCategories = [...new Set(providerModels.map(model => model.split(':')[1]))];
|
|
25
|
+
const providerModels = models.filter((model) => model.startsWith(selectedProvider));
|
|
26
|
+
const modelCategories = [...new Set(providerModels.map((model) => model.split(':')[1]))];
|
|
27
27
|
const selectedCategory = await (0, prompts_1.select)({
|
|
28
28
|
message: 'Select a category:',
|
|
29
|
-
choices: modelCategories.map(category => ({ name: category, value: category })),
|
|
29
|
+
choices: modelCategories.map((category) => ({ name: category, value: category })),
|
|
30
30
|
});
|
|
31
|
-
const specificModels = providerModels.filter(model => model.split(':')[1] === selectedCategory);
|
|
31
|
+
const specificModels = providerModels.filter((model) => model.split(':')[1] === selectedCategory);
|
|
32
32
|
const modelIndex = await (0, prompts_1.select)({
|
|
33
|
-
message:
|
|
33
|
+
message: "Select an AI model you'd like to use:",
|
|
34
34
|
choices: specificModels.map((model, index) => ({ name: model, value: index })),
|
|
35
35
|
pageSize: specificModels.length,
|
|
36
36
|
});
|
|
@@ -8,12 +8,16 @@ const copy_paste_1 = __importDefault(require("copy-paste"));
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const prompts_1 = require("@inquirer/prompts");
|
|
11
|
-
const
|
|
11
|
+
const prompt_utils_1 = require("../../utils/prompt_utils");
|
|
12
12
|
const config_utils_1 = require("../../utils/config_utils");
|
|
13
13
|
const generateContextPrompt = (files, contextFiles) => {
|
|
14
|
-
const specialFileContents = (0,
|
|
15
|
-
const specialFiles = Object.keys(specialFileContents)
|
|
16
|
-
|
|
14
|
+
const specialFileContents = (0, prompt_utils_1.collectSpecialFileContents)();
|
|
15
|
+
const specialFiles = Object.keys(specialFileContents)
|
|
16
|
+
.map((file) => `### Contents of ${file}\n\n${JSON.stringify(specialFileContents[file], null, 2)}\n\n`)
|
|
17
|
+
.join('\n');
|
|
18
|
+
const contextFileContents = Object.keys(contextFiles)
|
|
19
|
+
.map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`)
|
|
20
|
+
.join('\n');
|
|
17
21
|
return `### Description of App
|
|
18
22
|
|
|
19
23
|
${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
|
|
@@ -35,7 +39,10 @@ const context = async (options) => {
|
|
|
35
39
|
if (files) {
|
|
36
40
|
for (const file of files) {
|
|
37
41
|
const filePath = path_1.default.resolve(file);
|
|
38
|
-
if (await fs_1.default.promises
|
|
42
|
+
if (await fs_1.default.promises
|
|
43
|
+
.stat(filePath)
|
|
44
|
+
.then((stat) => stat.isFile())
|
|
45
|
+
.catch(() => false)) {
|
|
39
46
|
const content = await fs_1.default.promises.readFile(filePath, 'utf-8');
|
|
40
47
|
contextFiles[file] = content;
|
|
41
48
|
}
|
|
@@ -48,7 +55,7 @@ const context = async (options) => {
|
|
|
48
55
|
message: 'Enter the relative path of a file or directory you would like to include as context (or press enter to continue):',
|
|
49
56
|
});
|
|
50
57
|
if (contextFile) {
|
|
51
|
-
contextFiles = await (0,
|
|
58
|
+
contextFiles = await (0, prompt_utils_1.addFileOrDirectoryToContext)(contextFile, contextFiles, options);
|
|
52
59
|
}
|
|
53
60
|
else {
|
|
54
61
|
includeMoreFiles = false;
|