- feat(codex): Add “Apply to VS Code/Remove from VS Code” button on current Codex provider card
- feat(tauri): Add commands to read/write VS Code settings.json with cross-variant detection (Code/Insiders/VSCodium/OSS) - fix(vscode): Use top-level keys “chatgpt.apiBase” and “chatgpt.config.preferred_auth_method” - fix(vscode): Handle empty settings.json (skip deletes, direct write) to avoid “Can not delete in empty document” - fix(windows): Make atomic writes robust by removing target before rename - ui(provider-list): Improve error surfacing when applying/removing - chore(types): Extend window.api typings and tauri-api wrappers for VS Code commands - deps: Add jsonc-parser
This commit is contained in:
110
src/utils/vscodeSettings.ts
Normal file
110
src/utils/vscodeSettings.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { applyEdits, modify, parse } from "jsonc-parser";
|
||||
|
||||
const fmt = { insertSpaces: true, tabSize: 2, eol: "\n" } as const;
|
||||
|
||||
export interface AppliedCheck {
|
||||
hasApiBase: boolean;
|
||||
apiBase?: string;
|
||||
hasPreferredAuthMethod: boolean;
|
||||
}
|
||||
|
||||
export function normalizeBaseUrl(url: string): string {
|
||||
return url.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
const isDocEmpty = (s: string) => s.trim().length === 0;
|
||||
|
||||
// 检查 settings.json(JSONC 文本)中是否已经应用了我们的键
|
||||
export function detectApplied(content: string): AppliedCheck {
|
||||
try {
|
||||
// 允许 JSONC 的宽松解析:jsonc-parser 的 parse 可以直接处理注释
|
||||
const data = parse(content) as any;
|
||||
const apiBase = data?.["chatgpt.apiBase"];
|
||||
const method = data?.["chatgpt.config"]?.preferred_auth_method;
|
||||
return {
|
||||
hasApiBase: typeof apiBase === "string",
|
||||
apiBase,
|
||||
hasPreferredAuthMethod: typeof method === "string",
|
||||
};
|
||||
} catch {
|
||||
return { hasApiBase: false, hasPreferredAuthMethod: false };
|
||||
}
|
||||
}
|
||||
|
||||
// 生成“清理我们管理的键”后的文本(仅删除我们写入的两个键)
|
||||
export function removeManagedKeys(content: string): string {
|
||||
if (isDocEmpty(content)) return content; // 空文档无需删除
|
||||
let out = content;
|
||||
// 删除 chatgpt.apiBase
|
||||
try {
|
||||
out = applyEdits(out, modify(out, ["chatgpt.apiBase"], undefined, { formattingOptions: fmt }));
|
||||
} catch {
|
||||
// 忽略删除失败
|
||||
}
|
||||
// 删除 chatgpt.config.preferred_auth_method(注意 chatgpt.config 是顶层带点的键)
|
||||
try {
|
||||
out = applyEdits(
|
||||
out,
|
||||
modify(out, ["chatgpt.config", "preferred_auth_method"], undefined, {
|
||||
formattingOptions: fmt,
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
// 忽略删除失败
|
||||
}
|
||||
|
||||
// 兼容早期错误写入:若曾写成嵌套 chatgpt.config.preferred_auth_method,也一并清理
|
||||
try {
|
||||
out = applyEdits(
|
||||
out,
|
||||
modify(out, ["chatgpt", "config", "preferred_auth_method"], undefined, {
|
||||
formattingOptions: fmt,
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
// 忽略删除失败
|
||||
}
|
||||
|
||||
// 若 chatgpt.config 变为空对象,顺便移除(不影响其他 chatgpt* 键)
|
||||
try {
|
||||
const data = parse(out) as any;
|
||||
const cfg = data?.["chatgpt.config"];
|
||||
if (cfg && typeof cfg === "object" && !Array.isArray(cfg) && Object.keys(cfg).length === 0) {
|
||||
out = applyEdits(out, modify(out, ["chatgpt.config"], undefined, { formattingOptions: fmt }));
|
||||
}
|
||||
} catch {
|
||||
// 忽略解析失败,保持已删除的键
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// 生成“应用供应商到 VS Code”后的文本:
|
||||
// - 先清理我们管理的键
|
||||
// - 再根据是否官方决定写入(官方:不写入;非官方:写入两个键)
|
||||
export function applyProviderToVSCode(
|
||||
content: string,
|
||||
opts: { baseUrl?: string | null; isOfficial?: boolean },
|
||||
): string {
|
||||
let out = removeManagedKeys(content);
|
||||
if (!opts.isOfficial && opts.baseUrl) {
|
||||
const apiBase = normalizeBaseUrl(opts.baseUrl);
|
||||
if (isDocEmpty(out)) {
|
||||
// 简化:空文档直接写入新对象
|
||||
const obj: any = {
|
||||
"chatgpt.apiBase": apiBase,
|
||||
"chatgpt.config": { preferred_auth_method: "apikey" },
|
||||
};
|
||||
out = JSON.stringify(obj, null, 2) + "\n";
|
||||
} else {
|
||||
out = applyEdits(out, modify(out, ["chatgpt.apiBase"], apiBase, { formattingOptions: fmt }));
|
||||
out = applyEdits(
|
||||
out,
|
||||
modify(out, ["chatgpt.config", "preferred_auth_method"], "apikey", {
|
||||
formattingOptions: fmt,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user