cloving 0.1.2 → 0.1.4

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.
@@ -11,20 +11,24 @@ const claude_1 = require("./adapters/claude");
11
11
  const openai_1 = require("./adapters/openai");
12
12
  const gpt4all_1 = require("./adapters/gpt4all");
13
13
  const ollama_1 = require("./adapters/ollama");
14
- const command_utils_1 = require("../utils/command_utils");
14
+ const config_utils_1 = require("../utils/config_utils");
15
15
  class ClovingGPT {
16
16
  constructor(options = { silent: false }) {
17
- const config = (0, command_utils_1.getConfig)(options);
18
- if (!config || !config.primaryModel || !config.models) {
17
+ const { model: partialModel } = options;
18
+ const config = (0, config_utils_1.getConfig)(options);
19
+ if (!config || !config.models) {
19
20
  console.log('No cloving configuration found. Please run: cloving config');
20
21
  process_1.default.exit(1);
21
22
  }
22
- const clovingModel = config.primaryModel;
23
- this.apiKey = config.models[config?.primaryModel || ''].trim();
24
- this.silent = options.silent || false;
25
- const parts = clovingModel.split(':');
26
- const model = parts.slice(1).join(':');
27
- switch (parts[0]) {
23
+ const primaryModel = (0, config_utils_1.getPrimaryModel)(partialModel);
24
+ if (!primaryModel) {
25
+ console.log('No primary model found in the configuration. Please run: cloving config');
26
+ process_1.default.exit(1);
27
+ }
28
+ const { provider, model, config: modelConfig } = primaryModel;
29
+ this.apiKey = modelConfig.apiKey;
30
+ this.silent = options.silent || modelConfig.silent;
31
+ switch (provider) {
28
32
  case 'claude':
29
33
  this.adapter = new claude_1.ClaudeAdapter(model);
30
34
  break;
@@ -38,7 +42,7 @@ class ClovingGPT {
38
42
  this.adapter = new ollama_1.OllamaAdapter(model);
39
43
  break;
40
44
  default:
41
- throw new Error(`Unsupported provider: ${parts[0]}`);
45
+ throw new Error(`Unsupported provider: ${provider}`);
42
46
  }
43
47
  }
44
48
  async askUserToConfirm(prompt, message) {
@@ -8,10 +8,10 @@ const path_1 = __importDefault(require("path"));
8
8
  const child_process_1 = require("child_process");
9
9
  const git_utils_1 = require("../utils/git_utils");
10
10
  const string_utils_1 = require("../utils/string_utils");
11
- const command_utils_1 = require("../utils/command_utils");
11
+ const config_utils_1 = require("../utils/config_utils");
12
12
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
13
13
  const generateAndCommitMessage = async (options) => {
14
- options.silent = (0, command_utils_1.getConfig)(options).silent || false;
14
+ options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
15
15
  const gpt = new cloving_gpt_1.default(options);
16
16
  try {
17
17
  // Generate the prompt for commit message
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.config = void 0;
4
+ const config_utils_1 = require("../utils/config_utils");
4
5
  const command_utils_1 = require("../utils/command_utils");
5
6
  const config = async () => {
6
- let currentConfig = (0, command_utils_1.getConfig)({});
7
+ let currentConfig = (0, config_utils_1.getConfig)({});
7
8
  // Ensure models is initialized properly
8
9
  if (!currentConfig.models) {
9
10
  currentConfig.models = {};
@@ -23,17 +24,43 @@ const config = async () => {
23
24
  }
24
25
  const selectedModel = models[modelIndex];
25
26
  const apiKey = await (0, command_utils_1.promptUser)(`Enter your API key for ${selectedModel}: `);
26
- currentConfig.models[selectedModel] = apiKey;
27
- const setAsPrimary = await (0, command_utils_1.promptUser)('Do you want to set this model as the primary model? [Yn]: ');
28
- if (setAsPrimary.toLowerCase() === 'y' || setAsPrimary === '') {
29
- currentConfig.primaryModel = selectedModel;
27
+ const [provider, ...modelParts] = selectedModel.split(':');
28
+ const model = modelParts.join(':');
29
+ if (!currentConfig.models[provider]) {
30
+ currentConfig.models[provider] = {};
31
+ }
32
+ const setAsPrimary = await (0, command_utils_1.promptUser)('Do you want to use this model as a primary model? [Yn]: ');
33
+ const primary = setAsPrimary.toLowerCase() === 'y' || setAsPrimary === '';
34
+ const priorityNumber = await (0, command_utils_1.promptUser)('Enter the priority for this model (0-100, higher priority will be used as long as the prompt fits the context token limit): [' + (primary ? 100 : 0) + ']');
35
+ const priority = primary ? 100 : parseInt(priorityNumber, 10);
36
+ const silentResponse = await (0, command_utils_1.promptUser)('Do you want to review all prompts before they are sent to this model? [Yn]: ');
37
+ const silent = !(silentResponse.toLowerCase() === 'y' || silentResponse === '');
38
+ const trustResponse = await (0, command_utils_1.promptUser)('Do you trust this model with sensitive information? [Yn]: ');
39
+ const trust = trustResponse.toLowerCase() === 'y' || trustResponse === '';
40
+ const modelConfig = {
41
+ apiKey,
42
+ primary,
43
+ priority,
44
+ silent,
45
+ trust,
46
+ };
47
+ currentConfig.models[provider][model] = modelConfig;
48
+ if (primary) {
49
+ // Ensure only one primary model
50
+ for (const p in currentConfig.models) {
51
+ for (const m in currentConfig.models[p]) {
52
+ if (p !== provider || m !== model) {
53
+ currentConfig.models[p][m].primary = false;
54
+ }
55
+ }
56
+ }
30
57
  }
31
58
  const anotherModel = await (0, command_utils_1.promptUser)('Do you want to configure another model? [Yn]: ');
32
59
  if (anotherModel.toLowerCase() !== 'y' && anotherModel !== '') {
33
60
  continueConfig = false;
34
61
  }
35
62
  }
36
- (0, command_utils_1.saveConfig)(currentConfig);
63
+ (0, config_utils_1.saveConfig)(currentConfig);
37
64
  };
38
65
  exports.config = config;
39
66
  exports.default = exports.config;
@@ -11,10 +11,11 @@ const string_utils_1 = require("../utils/string_utils");
11
11
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
12
12
  const ignore_1 = __importDefault(require("ignore"));
13
13
  const string_utils_2 = require("../utils/string_utils");
14
+ const config_utils_1 = require("../utils/config_utils");
14
15
  const command_utils_1 = require("../utils/command_utils");
15
16
  // Main function for the describe command
16
17
  const init = async (options) => {
17
- options.silent = (0, command_utils_1.getConfig)(options).silent || false;
18
+ options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
18
19
  const gpt = new cloving_gpt_1.default(options);
19
20
  const specialFileContents = (0, command_utils_1.collectSpecialFileContents)();
20
21
  const specialFileNames = Object.keys(specialFileContents).map(file => ' - ' + file);
@@ -22,24 +23,24 @@ const init = async (options) => {
22
23
  if (specialFileNames.length > 0) {
23
24
  console.log(`Cloving will analyze the list of files and the contents of the following files:
24
25
 
25
- ${specialFileNames.join("\n")}
26
+ ${specialFileNames.join("\n")}
26
27
 
27
- Cloving will send AI a request to summarize the technologies used in this project.
28
+ Cloving will send AI a request to summarize the technologies used in this project.
28
29
 
29
- This will provide better context for future Cloving requests.
30
+ This will provide better context for future Cloving requests.
30
31
 
31
- For increased privacy, you can run \`cloving config\` and make sure to configure a local ollama model (llama3:70b-instruct currently works well for this) so that this data is not sent to an AI service provider.
32
+ For increased privacy, you can run \`cloving config\` and make sure to configure a local ollama model (llama3:70b-instruct currently works well for this) so that this data is not sent to an AI service provider.
32
33
  `);
33
34
  }
34
35
  else {
35
36
  console.log(`
36
- This script will analyze the list of files in the current directory using GPT to summarize the
37
- technologies used. This will provide better context for future Cloving requests.
37
+ This script will analyze the list of files in the current directory using GPT to summarize the
38
+ technologies used. This will provide better context for future Cloving requests.
38
39
  `);
39
40
  }
40
41
  }
41
- const config = (0, command_utils_1.getConfig)(options);
42
- if (!config || !config?.primaryModel || !config?.models) {
42
+ const config = (0, config_utils_1.getConfig)(options);
43
+ if (!config || !config?.models) {
43
44
  console.error('No cloving configuration found. Please run `cloving config`');
44
45
  return;
45
46
  }
@@ -80,10 +81,65 @@ const init = async (options) => {
80
81
  ${JSON.stringify(projectDetails, null, 2)}
81
82
 
82
83
  Please return JSON-formatted metadata about the project, including:
84
+
83
85
  - The programming language(s) used
84
86
  - The detected framework(s) (if any)
85
87
  - The version of the language(s)
86
88
 
89
+ Here is a typescript interface for the expected response:
90
+
91
+ interface LanguageConfig {
92
+ name: string
93
+ version?: string
94
+ primary?: boolean
95
+ directory: string
96
+ extension: string
97
+ }
98
+
99
+ interface FrameworkConfig {
100
+ name: string
101
+ type: string
102
+ version?: string
103
+ primary?: boolean
104
+ directory?: string
105
+ extension?: string
106
+ }
107
+
108
+ interface TestingFrameworkConfig {
109
+ name: string
110
+ type: string
111
+ version?: string
112
+ directory?: string
113
+ }
114
+
115
+ interface BuildToolConfig {
116
+ name: string
117
+ type: string
118
+ version?: string
119
+ }
120
+
121
+ interface LinterConfig {
122
+ name: string
123
+ version?: string
124
+ type?: string
125
+ }
126
+
127
+ interface DatabaseConfig {
128
+ name: string
129
+ primary?: boolean
130
+ }
131
+
132
+ export interface ClovingfileConfig {
133
+ languages: LanguageConfig[]
134
+ frameworks: FrameworkConfig[]
135
+ testingFrameworks?: TestingFrameworkConfig[]
136
+ buildTools: BuildToolConfig[]
137
+ packageManager: string
138
+ linters: LinterConfig[]
139
+ databases?: DatabaseConfig[]
140
+ projectType: string
141
+ }
142
+
87
143
  Here is an example response:
88
144
 
89
145
  {
@@ -8,9 +8,9 @@ const child_process_1 = require("child_process");
8
8
  const git_utils_1 = require("../utils/git_utils");
9
9
  const string_utils_1 = require("../utils/string_utils");
10
10
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
11
- const command_utils_1 = require("../utils/command_utils");
11
+ const config_utils_1 = require("../utils/config_utils");
12
12
  const review = async (options) => {
13
- options.silent = (0, command_utils_1.getConfig)(options).silent || false;
13
+ options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
14
14
  const gpt = new cloving_gpt_1.default(options);
15
15
  try {
16
16
  // Define the prompt for analysis
@@ -3,13 +3,11 @@ 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 fs_1 = __importDefault(require("fs"));
7
- const os_1 = __importDefault(require("os"));
8
- const path_1 = __importDefault(require("path"));
6
+ const fs_1 = require("fs");
9
7
  const child_process_1 = require("child_process");
10
8
  const git_utils_1 = require("../utils/git_utils");
11
9
  const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
12
- const command_utils_1 = require("../utils/command_utils");
10
+ const config_utils_1 = require("../utils/config_utils");
13
11
  const extractChangedFiles = (gitDiff) => {
14
12
  const fileRegex = /diff --git a\/(.+?) b\/(.+?)\n/g;
15
13
  const files = new Set();
@@ -19,6 +17,18 @@ const extractChangedFiles = (gitDiff) => {
19
17
  }
20
18
  return Array.from(files);
21
19
  };
20
+ const setupTestingPrompt = async (gpt, config) => {
21
+ const prompt = `I have the following cloving.json configuration file:
22
+
23
+ ==== begin cloving.json ====
24
+ ${JSON.stringify(config, null, 2)}
25
+ ==== end cloving.json ====
26
+
27
+ Please provide instructions on how to set up testing for this project.`;
28
+ const setupInstructions = await gpt.generateText({ prompt });
29
+ console.log(setupInstructions);
30
+ process.exit(0);
31
+ };
22
32
  const generatePrompt = (files, srcFiles, testFiles, gitDiff) => {
23
33
  const filesList = files.length > 0 ? files.join('\n') : 'No files provided';
24
34
  const diffSection = gitDiff ? `Here is my git diff:\n\n==== begin git diff ====\n${gitDiff}\n==== end git diff ====\n` : '';
@@ -62,10 +72,11 @@ const unitTests = async (options) => {
62
72
  const { files } = options;
63
73
  const gpt = new cloving_gpt_1.default(options);
64
74
  // Read the cloving.json file
65
- const config = (0, command_utils_1.readClovingConfig)();
66
- const testingDirectory = config.testingFrameworks.find((framework) => framework.directory)?.directory || 'spec';
67
- // Generate a temporary file path
68
- const tempFilePath = path_1.default.join(os_1.default.tmpdir(), `unit_tests_${Date.now()}.tmp`);
75
+ const config = (0, config_utils_1.readClovingConfig)();
76
+ const testingDirectory = config.testingFrameworks?.find((framework) => framework.directory)?.directory;
77
+ if (!testingDirectory) {
78
+ await setupTestingPrompt(gpt, config);
79
+ }
69
80
  let allSrcFiles = [];
70
81
  // Collect srcFiles for each language with specified directory and extension
71
82
  for (const language of config.languages) {
@@ -76,8 +87,8 @@ const unitTests = async (options) => {
76
87
  }
77
88
  // Ensure allSrcFiles is unique
78
89
  allSrcFiles = Array.from(new Set(allSrcFiles));
79
- if (allSrcFiles.length === 0) {
80
- console.error('Could not find any source files to generate unit tests. Please run: cloving init');
90
+ if (allSrcFiles.length === 0 || !testingDirectory) {
91
+ console.error('Could not find any source files to generate unit tests. Please run: cloving init. Then try again.');
81
92
  process.exit(1);
82
93
  }
83
94
  const testFiles = (0, child_process_1.execFileSync)('find', [testingDirectory, '-type', 'f']).toString().trim();
@@ -96,28 +107,28 @@ const unitTests = async (options) => {
96
107
  const lines = [];
97
108
  const context = [];
98
109
  // Read input from temporary file
99
- contextFiles.split("\n").forEach((line) => {
110
+ contextFiles.split('\n').forEach((line) => {
100
111
  if (line.trim()) {
101
112
  lines.push(line.trim());
102
113
  }
103
114
  });
104
- lines.forEach((codeFile) => {
105
- if (fs_1.default.existsSync(codeFile) && fs_1.default.statSync(codeFile).isFile()) {
106
- const fileContents = fs_1.default.readFileSync(codeFile, 'utf-8');
115
+ for (const codeFile of lines) {
116
+ if (await fs_1.promises?.stat(codeFile).then(stat => stat.isFile()).catch(() => false)) {
117
+ const fileContents = await fs_1.promises.readFile(codeFile, 'utf-8');
107
118
  context.push(`### **Contents of ${codeFile}**\n\n${fileContents}\n\n### **End of ${codeFile}**`);
108
119
  }
109
- });
120
+ }
110
121
  // Generate the message for unit test creation
111
122
  let analysis = '';
112
123
  if ((files || []).length > 0) {
113
124
  const message = `please create unit tests for these files:
114
125
 
115
126
  ## begin list of files
116
- ${(files || []).join("\n")}
127
+ ${(files || []).join('\n')}
117
128
  ## end list of files
118
129
 
119
130
  ## context
120
- ${context.join("\n\n")}`;
131
+ ${context.join('\n\n')}`;
121
132
  // Get the model and analysis using ClovingGPT
122
133
  analysis = await gpt.generateText({ prompt: message });
123
134
  }
@@ -130,7 +141,7 @@ ${await (0, git_utils_1.getGitDiff)()}
130
141
 
131
142
  ## context
132
143
 
133
- ${context.join("\n\n")}`;
144
+ ${context.join('\n\n')}`;
134
145
  // Get the model and analysis using ClovingGPT
135
146
  analysis = await gpt.generateText({ prompt: message });
136
147
  }
package/dist/index.js CHANGED
@@ -20,12 +20,14 @@ program
20
20
  .command('commit')
21
21
  .description('Generate a commit message and commit the changes')
22
22
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
23
+ .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
23
24
  .action(commit_1.default);
24
25
  program
25
26
  .command('unit-tests')
26
- .description('Generate unit tests for the changes')
27
+ .description('Generate unit tests (if you don\'t specify filenames, it will generate tests for commited changes that differ from the main/master branch)')
27
28
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
28
29
  .option('-f, --files <filenames...>', 'Specify filenames for the unit tests')
30
+ .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
29
31
  .action(unit_tests_1.default);
30
32
  program
31
33
  .command('models')
@@ -33,16 +35,18 @@ program
33
35
  .action(models_1.default);
34
36
  program
35
37
  .command('review')
36
- .description('Review the changes and propose ')
38
+ .description('Review the code for commited changes that differ from the main/master branch')
37
39
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
40
+ .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
38
41
  .action(review_1.default);
39
42
  program
40
43
  .command('init')
41
44
  .description('Setup cloving in the current project')
42
45
  .option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
46
+ .option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
43
47
  .action(init_1.default);
44
48
  program
45
49
  .command('config')
46
- .description('Configure cloving with your API key and model')
50
+ .description('Configure cloving with your API key and models to use')
47
51
  .action(config_1.default);
48
52
  program.parse(process.argv);
@@ -3,13 +3,10 @@ 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.readClovingConfig = exports.getConfig = exports.saveConfig = exports.fetchModels = exports.promptUser = exports.runCommand = exports.generateFileList = exports.checkForSpecialFiles = exports.collectSpecialFileContents = exports.SPECIAL_FILES = exports.CONFIG_PATH = void 0;
6
+ exports.fetchModels = exports.promptUser = 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 readline_1 = __importDefault(require("readline"));
9
9
  const fs_1 = __importDefault(require("fs"));
10
- const os_1 = __importDefault(require("os"));
11
- const path_1 = __importDefault(require("path"));
12
- exports.CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.cloving.json');
13
10
  exports.SPECIAL_FILES = [
14
11
  'package.json',
15
12
  'Gemfile',
@@ -122,47 +119,3 @@ const fetchModels = async () => {
122
119
  }
123
120
  };
124
121
  exports.fetchModels = fetchModels;
125
- const saveConfig = (config) => {
126
- fs_1.default.writeFileSync(exports.CONFIG_PATH, JSON.stringify(config, null, 2));
127
- console.log(`Configuration saved to ${exports.CONFIG_PATH}`);
128
- };
129
- exports.saveConfig = saveConfig;
130
- const getConfig = (options) => {
131
- try {
132
- if (fs_1.default.existsSync(exports.CONFIG_PATH)) {
133
- const rawConfig = fs_1.default.readFileSync(exports.CONFIG_PATH, 'utf-8');
134
- const config = JSON.parse(rawConfig);
135
- if (options.silent) {
136
- return { ...config, silent: true };
137
- }
138
- else {
139
- return config;
140
- }
141
- }
142
- }
143
- catch (err) {
144
- console.error('Error reading configuration:', err);
145
- }
146
- if (process.env.CLOVING_MODEL) {
147
- return {
148
- models: { [`${process.env.CLOVING_MODEL}`]: process.env.CLOVING_API_KEY ?? '' },
149
- primaryModel: process.env.CLOVING_MODEL,
150
- silent: options.silent || false
151
- };
152
- }
153
- else {
154
- return { models: {}, primaryModel: null, silent: options.silent || false };
155
- }
156
- };
157
- exports.getConfig = getConfig;
158
- const readClovingConfig = () => {
159
- const configPath = path_1.default.resolve(process.cwd(), 'cloving.json');
160
- if (fs_1.default.existsSync(configPath)) {
161
- const configFile = fs_1.default.readFileSync(configPath, 'utf-8');
162
- return JSON.parse(configFile);
163
- }
164
- else {
165
- throw new Error('cloving.json file not found');
166
- }
167
- };
168
- exports.readClovingConfig = readClovingConfig;
@@ -0,0 +1,89 @@
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
+ exports.getPrimaryModel = exports.saveConfig = exports.readClovingConfig = exports.getConfig = exports.CLOVINGFILE_PATH = exports.CLOVING_CONFIG_PATH = void 0;
7
+ const os_1 = __importDefault(require("os"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const ini_1 = __importDefault(require("ini"));
11
+ exports.CLOVING_CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.clovingconfig');
12
+ exports.CLOVINGFILE_PATH = 'cloving.json';
13
+ const getConfig = (options) => {
14
+ try {
15
+ if (fs_1.default.existsSync(exports.CLOVING_CONFIG_PATH)) {
16
+ const rawConfig = fs_1.default.readFileSync(exports.CLOVING_CONFIG_PATH, 'utf-8');
17
+ const config = ini_1.default.parse(rawConfig);
18
+ if (options.silent) {
19
+ config.globalSilent = true;
20
+ }
21
+ return config;
22
+ }
23
+ }
24
+ catch (err) {
25
+ console.error('Error reading configuration:', err);
26
+ }
27
+ if (process.env.CLOVING_MODEL) {
28
+ const [provider, ...modelParts] = process.env.CLOVING_MODEL.split(':');
29
+ const model = modelParts.join(':');
30
+ return {
31
+ models: {
32
+ [provider]: {
33
+ [model]: {
34
+ apiKey: process.env.CLOVING_API_KEY ?? '',
35
+ primary: true,
36
+ priority: 10,
37
+ silent: options.silent || false,
38
+ trust: false
39
+ }
40
+ }
41
+ },
42
+ globalSilent: options.silent || false
43
+ };
44
+ }
45
+ else {
46
+ return { models: {}, globalSilent: options.silent || false };
47
+ }
48
+ };
49
+ exports.getConfig = getConfig;
50
+ const readClovingConfig = () => {
51
+ if (fs_1.default.existsSync(exports.CLOVINGFILE_PATH)) {
52
+ const configFile = fs_1.default.readFileSync(exports.CLOVINGFILE_PATH, 'utf-8');
53
+ return ini_1.default.parse(configFile);
54
+ }
55
+ else {
56
+ throw new Error('cloving.ini file not found');
57
+ }
58
+ };
59
+ exports.readClovingConfig = readClovingConfig;
60
+ const saveConfig = (config) => {
61
+ const iniString = ini_1.default.stringify(config);
62
+ fs_1.default.writeFileSync(exports.CLOVING_CONFIG_PATH, iniString);
63
+ console.log(`Configuration saved to ${exports.CLOVING_CONFIG_PATH}`);
64
+ };
65
+ exports.saveConfig = saveConfig;
66
+ const getPrimaryModel = (partialModel) => {
67
+ try {
68
+ const config = (0, exports.getConfig)({});
69
+ const models = [];
70
+ for (const provider in config.models) {
71
+ for (const model in config.models[provider]) {
72
+ if (!partialModel || `${provider}:${model}`.startsWith(partialModel)) {
73
+ models.push({
74
+ provider,
75
+ model,
76
+ config: config.models[provider][model],
77
+ });
78
+ }
79
+ }
80
+ }
81
+ models.sort((a, b) => parseInt(`${b.config.priority}`, 10) - parseInt(`${a.config.priority}`, 10));
82
+ return models.length > 0 ? models[0] : null;
83
+ }
84
+ catch (err) {
85
+ console.error('Error reading model from configuration:', err);
86
+ return null;
87
+ }
88
+ };
89
+ exports.getPrimaryModel = getPrimaryModel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -48,11 +48,13 @@
48
48
  "eslint-plugin-n": "^17.9.0",
49
49
  "eslint-plugin-promise": "^6.4.0",
50
50
  "ignore": "^5.3.1",
51
+ "ini": "^4.1.3",
51
52
  "nock": "^13.5.4",
52
53
  "vite": "^5.3.3",
53
54
  "vite-node": "^2.0.1"
54
55
  },
55
56
  "devDependencies": {
57
+ "@types/ini": "^4.1.1",
56
58
  "@types/jest": "^29.5.12",
57
59
  "@types/node": "^20.14.10",
58
60
  "husky": "^9.0.11",