重构配置模块以移除ini依赖,增强baseURL支持并汉化AI提示词
Some checks failed
Test / Test (ubuntu-latest) (push) Has been cancelled
Test / Test (windows-latest) (push) Has been cancelled

This commit is contained in:
史悦
2025-08-27 16:52:04 +08:00
parent e7f26efc71
commit d23dfecbcd
4 changed files with 67 additions and 37 deletions

View File

@@ -25,7 +25,12 @@ export default command(
if (mode === 'set') {
await setConfigs(
keyValues.map((keyValue) => keyValue.split('=') as [string, string])
keyValues.map((keyValue) => {
const separatorIndex = keyValue.indexOf('=');
const key = keyValue.slice(0, separatorIndex);
const value = keyValue.slice(separatorIndex + 1);
return [key, value] as [string, string];
})
);
return;
}

View File

@@ -1,7 +1,6 @@
import fs from 'fs/promises';
import path from 'path';
import os from 'os';
import ini from 'ini';
import type { TiktokenModel } from '@dqbd/tiktoken';
import { fileExists } from './fs.js';
import { KnownError } from './error.js';
@@ -117,18 +116,12 @@ const configParsers = {
},
baseURL(url?: string) {
if (!url || url.length === 0) {
return 'api.openai.com';
return undefined;
}
parseAssert('baseURL', /^https?:\/\/.+/.test(url), 'Must be a valid URL');
parseAssert('baseURL', /^https?:\/\//.test(url), 'Must be a valid URL');
// 如果用户输入完整URL提取域名部分
try {
const urlObj = new URL(url);
return urlObj.hostname;
} catch {
return url;
}
return url;
},
} as const;
@@ -151,7 +144,16 @@ const readConfigFile = async (): Promise<RawConfig> => {
}
const configString = await fs.readFile(configPath, 'utf8');
return ini.parse(configString);
const config = Object.create(null);
for (const line of configString.split(/\r?\n/)) {
const separatorIndex = line.indexOf('=');
if (separatorIndex !== -1) {
const key = line.slice(0, separatorIndex);
const value = line.slice(separatorIndex + 1);
config[key.trim()] = value.trim();
}
}
return config;
};
export const getConfig = async (
@@ -189,5 +191,9 @@ export const setConfigs = async (keyValues: [key: string, value: string][]) => {
config[key as ConfigKeys] = parsed as any;
}
await fs.writeFile(configPath, ini.stringify(config), 'utf8');
const configString = Object.entries(config)
.filter(([, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${key}=${value}`)
.join(os.EOL);
await fs.writeFile(configPath, configString, 'utf8');
};

View File

@@ -39,7 +39,7 @@ const httpsPost = async (
'Content-Length': Buffer.byteLength(postContent),
},
timeout,
agent: proxy ? createHttpsProxyAgent(proxy) : undefined,
agent: (proxy && proxy.trim() !== '') ? createHttpsProxyAgent(proxy) : undefined as any,
},
(response) => {
const body: Buffer[] = [];
@@ -74,10 +74,14 @@ const createChatCompletion = async (
proxy?: string,
baseURL?: string
) => {
const hostname = baseURL || 'api.openai.com';
const url = baseURL ? new URL(baseURL) : new URL('https://api.openai.com/v1/chat/completions');
if (url.pathname === '/') {
url.pathname = '/v1/chat/completions';
}
const { response, data } = await httpsPost(
hostname,
'/v1/chat/completions',
url.hostname,
url.pathname,
{
Authorization: `Bearer ${apiKey}`,
},
@@ -104,7 +108,19 @@ const createChatCompletion = async (
throw new KnownError(errorMessage);
}
return JSON.parse(data) as CreateChatCompletionResponse;
try {
const json = JSON.parse(data);
if (json.error) {
throw new KnownError(json.error.message);
}
return json as CreateChatCompletionResponse;
} catch (error) {
throw new KnownError(
`Error parsing response: ${error}\n\n${data}`
);
}
};
const sanitizeMessage = (message: string) =>

View File

@@ -5,7 +5,7 @@ const commitTypeFormats: Record<CommitType, string> = {
conventional: '<type>(<optional scope>): <commit message>',
};
const specifyCommitFormat = (type: CommitType) =>
`The output response must be in format:\n${commitTypeFormats[type]}`;
`输出响应必须使用以下格式:\n${commitTypeFormats[type]}`;
const commitTypes: Record<CommitType, string> = {
'': '',
@@ -18,20 +18,20 @@ const commitTypes: Record<CommitType, string> = {
* Conventional Changelog:
* https://github.com/conventional-changelog/conventional-changelog/blob/d0e5d5926c8addba74bc962553dd8bcfba90e228/packages/conventional-changelog-conventionalcommits/writer-opts.js#L182-L193
*/
conventional: `Choose a type from the type-to-description JSON below that best describes the git diff:\n${JSON.stringify(
conventional: `从下面的类型到描述的JSON中选择最能描述git差异的类型\n${JSON.stringify(
{
docs: 'Documentation only changes',
docs: '仅文档更改',
style:
'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
refactor: 'A code change that neither fixes a bug nor adds a feature',
perf: 'A code change that improves performance',
test: 'Adding missing tests or correcting existing tests',
build: 'Changes that affect the build system or external dependencies',
ci: 'Changes to our CI configuration files and scripts',
chore: "Other changes that don't modify src or test files",
revert: 'Reverts a previous commit',
feat: 'A new feature',
fix: 'A bug fix',
'不影响代码含义的更改(空格、格式、缺少分号等)',
refactor: '既不修复错误也不添加功能的代码更改',
perf: '提高性能的代码更改',
test: '添加缺失的测试或更正现有测试',
build: '影响构建系统或外部依赖的更改',
ci: '对我们的CI配置文件和脚本的更改',
chore: '不修改src或测试文件的其他更改',
revert: '恢复之前的提交',
feat: '新功能',
fix: '错误修复',
},
null,
2
@@ -44,10 +44,13 @@ export const generatePrompt = (
type: CommitType
) =>
[
'Generate a concise git commit message written in present tense for the following code diff with the given specifications below:',
`Message language: ${locale}`,
`Commit message must be a maximum of ${maxLength} characters.`,
'Exclude anything unnecessary such as translation. Your entire response will be passed directly into git commit.',
'为以下代码差异生成一个简洁的、使用现在时态的中文git提交消息并遵循以下规范',
`提交消息使用中文编写。`,
`提交消息最多${maxLength}个字符。`,
'提交消息包含具体的类名、方法名或其他关键信息,不能过于笼统。',
'对于功能添加,应该指明具体的类或模块,如"在UserController中添加了用户权限验证功能"。',
'对于代码重构,应该指明重构的具体类或方法,如"重构了PaymentProcessor类的金额计算逻辑"。',
'排除任何不必要的内容如翻译。您的整个响应将直接传递到git提交中。',
commitTypes[type],
specifyCommitFormat(type),
]