zixulu 1.80.1 → 1.80.3
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/dist/index.js +179 -92
- package/dist/index.js.map +1 -1
- package/dist/src/utils/getEditorExtensions.d.ts +6 -15
- package/dist/src/utils/syncVscode.d.ts +10 -5
- package/package.json +1 -1
- package/src/utils/downloadVscodeExts.ts +2 -5
- package/src/utils/getEditorExtensions.ts +6 -45
- package/src/utils/syncVscode.ts +190 -78
package/dist/index.js
CHANGED
|
@@ -4865,23 +4865,10 @@ description:
|
|
|
4865
4865
|
throw error;
|
|
4866
4866
|
}
|
|
4867
4867
|
}
|
|
4868
|
-
const
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
win32Command: "code.cmd",
|
|
4873
|
-
win32Path: join(getEditorExtensions_userDir, "AppData/Local/Programs/Microsoft VS Code/bin/code.cmd")
|
|
4874
|
-
},
|
|
4875
|
-
Cursor: {
|
|
4876
|
-
command: "cursor",
|
|
4877
|
-
win32Command: "cursor.cmd",
|
|
4878
|
-
win32Path: join(getEditorExtensions_userDir, "AppData/Local/Programs/cursor/resources/app/bin/cursor.cmd")
|
|
4879
|
-
},
|
|
4880
|
-
Antigravity: {
|
|
4881
|
-
command: "antigravity",
|
|
4882
|
-
win32Command: "antigravity.cmd",
|
|
4883
|
-
win32Path: join(getEditorExtensions_userDir, "AppData/Local/Programs/Antigravity/bin/antigravity.cmd")
|
|
4884
|
-
}
|
|
4868
|
+
const EditorExtensionCommandMap = {
|
|
4869
|
+
Code: "code",
|
|
4870
|
+
Cursor: "cursor",
|
|
4871
|
+
Antigravity: "antigravity"
|
|
4885
4872
|
};
|
|
4886
4873
|
async function canGetEditorExtensions({ editor }) {
|
|
4887
4874
|
const command = getEditorExtensionCommand({
|
|
@@ -4895,11 +4882,7 @@ async function canGetEditorExtensions({ editor }) {
|
|
|
4895
4882
|
}
|
|
4896
4883
|
}
|
|
4897
4884
|
function getEditorExtensionCommand({ editor }) {
|
|
4898
|
-
|
|
4899
|
-
if ("win32" !== process.platform) return item.command;
|
|
4900
|
-
if (item.win32Path && existsSync(item.win32Path)) return `"${item.win32Path}"`;
|
|
4901
|
-
if (item.win32Command) return item.win32Command;
|
|
4902
|
-
return item.command;
|
|
4885
|
+
return EditorExtensionCommandMap[editor];
|
|
4903
4886
|
}
|
|
4904
4887
|
async function getEditorExtensions({ source }) {
|
|
4905
4888
|
let data = [];
|
|
@@ -5258,13 +5241,10 @@ async function getVscodeExtInfo(ext) {
|
|
|
5258
5241
|
const reg = /^(.+?)\.(.+?)$/;
|
|
5259
5242
|
const [, author, name] = ext.match(reg);
|
|
5260
5243
|
let version;
|
|
5261
|
-
const codeCommand = getEditorExtensionCommand({
|
|
5262
|
-
editor: "Code"
|
|
5263
|
-
});
|
|
5264
5244
|
if ("ms-ceintl.vscode-language-pack-zh-hans" === ext) {
|
|
5265
5245
|
const reg2 = /"Versions":(\[\{".+?\])/;
|
|
5266
5246
|
const versions = JSON.parse(html.match(reg2)[1]);
|
|
5267
|
-
const output = await execAsync(
|
|
5247
|
+
const output = await execAsync("code --version");
|
|
5268
5248
|
const codeVersions = output.split("\n")[0].split(".").map(Number);
|
|
5269
5249
|
const item = versions.find(({ version })=>version.split(".").map(Number).every((item, index)=>index >= 2 || item <= codeVersions[index])) ?? versions[0];
|
|
5270
5250
|
version = item.version;
|
|
@@ -5287,10 +5267,7 @@ async function downloadVscodeExts(dir) {
|
|
|
5287
5267
|
recursive: true
|
|
5288
5268
|
});
|
|
5289
5269
|
consola.start("正在获取 VS Code 扩展列表");
|
|
5290
|
-
const
|
|
5291
|
-
editor: "Code"
|
|
5292
|
-
});
|
|
5293
|
-
const extList = await execAsync(`${codeCommand} --list-extensions`);
|
|
5270
|
+
const extList = await execAsync("code --list-extensions");
|
|
5294
5271
|
const exts = await Promise.all(extList.split(/[\n\r]/).filter(Boolean).filter((item)=>!item.startsWith("anysphere.")).map((ext)=>getVscodeExtInfo(ext)));
|
|
5295
5272
|
const setting = await readZixuluSetting();
|
|
5296
5273
|
const vscodeDownloadHistory = setting?.vscodeDownloadHistory;
|
|
@@ -5308,37 +5285,189 @@ async function downloadVscodeExts(dir) {
|
|
|
5308
5285
|
await writeZixuluSetting(setting);
|
|
5309
5286
|
await Promise.all(exts.filter((ext)=>exts2.exts.includes(ext.id)).map((ext)=>retry(()=>download_download(ext.url, dir, `${ext.id}-${ext.version}.vsix`), 4)));
|
|
5310
5287
|
}
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5288
|
+
const VscodeSyncOption = {
|
|
5289
|
+
配置: "SETTING",
|
|
5290
|
+
插件: "EXTENSION",
|
|
5291
|
+
软件: "SOFTWARE",
|
|
5292
|
+
PowerShell: "POWERSHELL"
|
|
5293
|
+
};
|
|
5294
|
+
function createSyncVscodeScript(options) {
|
|
5295
|
+
const needUserDir = options.includes(VscodeSyncOption.配置) || options.includes(VscodeSyncOption.PowerShell);
|
|
5296
|
+
return `// @ts-check
|
|
5297
|
+
|
|
5298
|
+
import { spawn } from "node:child_process"
|
|
5299
|
+
import { access, copyFile, mkdir, readdir, rm } from "node:fs/promises"
|
|
5300
|
+
import { homedir } from "node:os"
|
|
5301
|
+
import { delimiter, join } from "node:path"
|
|
5302
|
+
|
|
5303
|
+
/**
|
|
5304
|
+
* @param {string} path
|
|
5305
|
+
*/
|
|
5306
|
+
async function pathExists(path) {
|
|
5307
|
+
try {
|
|
5308
|
+
await access(path)
|
|
5309
|
+
return true
|
|
5310
|
+
} catch {
|
|
5311
|
+
return false
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
|
|
5315
|
+
// Windows 上优先查找 code.cmd,避免直接调用 Code.exe 打开编辑器窗口
|
|
5316
|
+
async function resolveCodeCli() {
|
|
5317
|
+
if (process.platform !== "win32") return "code"
|
|
5318
|
+
|
|
5319
|
+
const candidates = new Set()
|
|
5320
|
+
const localAppData = process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local")
|
|
5321
|
+
const programFiles = process.env.ProgramFiles ?? "C:/Program Files"
|
|
5322
|
+
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:/Program Files (x86)"
|
|
5323
|
+
|
|
5324
|
+
candidates.add(join(localAppData, "Programs", "Microsoft VS Code", "bin", "code.cmd"))
|
|
5325
|
+
candidates.add(join(programFiles, "Microsoft VS Code", "bin", "code.cmd"))
|
|
5326
|
+
candidates.add(join(programFilesX86, "Microsoft VS Code", "bin", "code.cmd"))
|
|
5327
|
+
|
|
5328
|
+
const pathDirs = process.env.PATH?.split(delimiter).filter(Boolean) ?? []
|
|
5329
|
+
for (const dir of pathDirs) {
|
|
5330
|
+
candidates.add(join(dir, "code.cmd"))
|
|
5331
|
+
candidates.add(join(dir, "code"))
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
for (const candidate of candidates) {
|
|
5335
|
+
if (await pathExists(candidate)) return candidate
|
|
5336
|
+
}
|
|
5337
|
+
|
|
5338
|
+
throw new Error("未找到 VS Code 命令行工具,请先安装 VS Code,并确认安装时勾选了“添加到 PATH”")
|
|
5339
|
+
}
|
|
5340
|
+
|
|
5341
|
+
/**
|
|
5342
|
+
* @param {string} value
|
|
5343
|
+
*/
|
|
5344
|
+
function quoteWindowsArg(value) {
|
|
5345
|
+
return "\\"" + value.replace(/"/g, "\\"\\"") + "\\""
|
|
5346
|
+
}
|
|
5347
|
+
|
|
5348
|
+
/**
|
|
5349
|
+
* @param {string[]} args
|
|
5350
|
+
* @param {string} output
|
|
5351
|
+
*/
|
|
5352
|
+
function isCliCommandSuccessful(args, output) {
|
|
5353
|
+
if (args.includes("--install-extension")) return output.includes("was successfully installed.") || output.includes("is already installed.")
|
|
5354
|
+
if (args.includes("--uninstall-extension")) return output.includes("was successfully uninstalled.") || output.includes("is not installed.")
|
|
5355
|
+
return false
|
|
5356
|
+
}
|
|
5357
|
+
|
|
5358
|
+
/**
|
|
5359
|
+
* @param {Buffer | string} data
|
|
5360
|
+
* @param {string[]} chunks
|
|
5361
|
+
* @param {NodeJS.WriteStream} stream
|
|
5362
|
+
*/
|
|
5363
|
+
function writeChildOutput(data, chunks, stream) {
|
|
5364
|
+
const text = data.toString()
|
|
5365
|
+
chunks.push(text)
|
|
5366
|
+
stream.write(text)
|
|
5367
|
+
}
|
|
5368
|
+
|
|
5369
|
+
/**
|
|
5370
|
+
* @param {string} command
|
|
5371
|
+
* @param {string[]} args
|
|
5372
|
+
*/
|
|
5373
|
+
function spawnAsync(command, args) {
|
|
5374
|
+
return new Promise((resolve, reject) => {
|
|
5375
|
+
// Windows 不能直接 spawn .cmd 或 .bat 文件,需要交给 cmd.exe 执行
|
|
5376
|
+
const needCmdShell = process.platform === "win32" && /\\.(cmd|bat)$/i.test(command)
|
|
5377
|
+
const chunks = []
|
|
5378
|
+
const child = needCmdShell
|
|
5379
|
+
? spawn(
|
|
5380
|
+
process.env.ComSpec ?? "cmd.exe",
|
|
5381
|
+
["/d", "/s", "/c", "\\"" + quoteWindowsArg(command) + " " + args.map(quoteWindowsArg).join(" ") + "\\""],
|
|
5382
|
+
{
|
|
5383
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5384
|
+
windowsVerbatimArguments: true,
|
|
5385
|
+
},
|
|
5386
|
+
)
|
|
5387
|
+
: spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] })
|
|
5388
|
+
|
|
5389
|
+
child.stdout?.on("data", data => writeChildOutput(data, chunks, process.stdout))
|
|
5390
|
+
child.stderr?.on("data", data => writeChildOutput(data, chunks, process.stderr))
|
|
5391
|
+
child.on("error", reject)
|
|
5392
|
+
child.on("exit", code => {
|
|
5393
|
+
const output = chunks.join("")
|
|
5394
|
+
|
|
5395
|
+
if (code !== 0) {
|
|
5396
|
+
if (isCliCommandSuccessful(args, output)) {
|
|
5397
|
+
console.warn(\`VS Code 命令退出码为 \${code},但操作已完成,继续执行后续步骤\`)
|
|
5398
|
+
return resolve(0)
|
|
5399
|
+
}
|
|
5400
|
+
|
|
5401
|
+
return reject(new Error(\`Command failed with code \${code}: \${command} \${args.join(" ")}\`))
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5404
|
+
resolve(0)
|
|
5405
|
+
})
|
|
5406
|
+
})
|
|
5407
|
+
}
|
|
5408
|
+
|
|
5409
|
+
async function main() {
|
|
5410
|
+
const workspaceDir = process.cwd()
|
|
5411
|
+
${needUserDir ? ` const userDir = homedir()
|
|
5412
|
+
` : ""}${options.includes(VscodeSyncOption.插件) ? ` const extensionsDir = join(workspaceDir, "extensions")
|
|
5413
|
+
const codeCli = await resolveCodeCli()
|
|
5414
|
+
const dir = await readdir(extensionsDir)
|
|
5415
|
+
const extensionErrors = []
|
|
5416
|
+
for (const ext of dir) {
|
|
5417
|
+
try {
|
|
5418
|
+
await spawnAsync(codeCli, ["--install-extension", join(extensionsDir, ext), "--force"])
|
|
5419
|
+
} catch (error) {
|
|
5420
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
5421
|
+
extensionErrors.push(\`\${ext}: \${message}\`)
|
|
5422
|
+
console.error(\`扩展同步失败:\${ext}\`)
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
if (extensionErrors.length > 0) {
|
|
5426
|
+
throw new Error(\`以下扩展同步失败:\\n\${extensionErrors.join("\\n")}\`)
|
|
5427
|
+
}
|
|
5428
|
+
` : ""}${options.includes(VscodeSyncOption.配置) ? ` const codeUserDir = join(userDir, "AppData", "Roaming", "Code", "User")
|
|
5429
|
+
await mkdir(codeUserDir, { recursive: true })
|
|
5430
|
+
const setting = join(codeUserDir, "settings.json")
|
|
5431
|
+
await rm(setting, { force: true })
|
|
5432
|
+
await copyFile(join(workspaceDir, "settings.json"), setting)
|
|
5433
|
+
const snippetTarget = join(codeUserDir, "snippets")
|
|
5434
|
+
await mkdir(snippetTarget, { recursive: true })
|
|
5435
|
+
const dir2 = await readdir(join(workspaceDir, "snippets"))
|
|
5436
|
+
for (const file of dir2) {
|
|
5437
|
+
await rm(join(snippetTarget, file), { force: true })
|
|
5438
|
+
await copyFile(join(workspaceDir, "snippets", file), join(snippetTarget, file))
|
|
5439
|
+
}` : ""}${options.includes(VscodeSyncOption.PowerShell) ? `
|
|
5440
|
+
const profileDir = join(userDir, "Documents", "PowerShell")
|
|
5441
|
+
await mkdir(profileDir, { recursive: true })
|
|
5442
|
+
const profile = join(profileDir, "Microsoft.PowerShell_profile.ps1")
|
|
5443
|
+
await copyFile(join(workspaceDir, "Microsoft.PowerShell_profile.ps1"), profile)` : ""}
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
main()
|
|
5447
|
+
`;
|
|
5448
|
+
}
|
|
5318
5449
|
async function syncVscode() {
|
|
5319
|
-
const codeCommand = getEditorExtensionCommand({
|
|
5320
|
-
editor: "Code"
|
|
5321
|
-
});
|
|
5322
5450
|
const options = (await inquirer_0.prompt({
|
|
5323
5451
|
type: "checkbox",
|
|
5324
5452
|
name: "options",
|
|
5325
5453
|
message: "请选择要同步的内容",
|
|
5326
|
-
choices: getEnumEntries(
|
|
5454
|
+
choices: getEnumEntries(VscodeSyncOption).map(([name, value])=>({
|
|
5327
5455
|
name,
|
|
5328
5456
|
value
|
|
5329
5457
|
})),
|
|
5330
|
-
default: getEnumValues(
|
|
5458
|
+
default: getEnumValues(VscodeSyncOption)
|
|
5331
5459
|
})).options;
|
|
5332
5460
|
if (0 === options.length) return;
|
|
5333
5461
|
const userDir = homedir();
|
|
5334
|
-
const
|
|
5335
|
-
const
|
|
5462
|
+
const codeUserDir = join(userDir, "AppData", "Roaming", "Code", "User");
|
|
5463
|
+
const snippetSource = join(codeUserDir, "snippets");
|
|
5464
|
+
const setting = (await readFile(join(codeUserDir, "settings.json"), "utf-8")).replace(/}[ \n\r]*$/, ` "chat.disableAIFeatures": true,\n}`);
|
|
5336
5465
|
const dir = `vscode-${dayjs().format("YYYYMMDDHHmmss")}`;
|
|
5337
5466
|
try {
|
|
5338
5467
|
await mkdir(dir, {
|
|
5339
5468
|
recursive: true
|
|
5340
5469
|
});
|
|
5341
|
-
if (options.includes(
|
|
5470
|
+
if (options.includes(VscodeSyncOption.配置)) {
|
|
5342
5471
|
const snippetTarget = join(dir, "snippets");
|
|
5343
5472
|
await mkdir(snippetTarget, {
|
|
5344
5473
|
recursive: true
|
|
@@ -5349,62 +5478,20 @@ async function syncVscode() {
|
|
|
5349
5478
|
for (const file of files)await copyFile(join(snippetSource, file), join(snippetTarget, file));
|
|
5350
5479
|
consola.success("下载最新 VSCode 配置完成");
|
|
5351
5480
|
}
|
|
5352
|
-
if (options.includes(
|
|
5481
|
+
if (options.includes(VscodeSyncOption.插件)) {
|
|
5353
5482
|
await downloadVscodeExts(join(dir, "extensions"));
|
|
5354
5483
|
consola.success("下载最新 VSCode 插件完成");
|
|
5355
5484
|
}
|
|
5356
|
-
if (options.includes(
|
|
5357
|
-
const script =
|
|
5358
|
-
|
|
5359
|
-
import { spawn } from "node:child_process"
|
|
5360
|
-
import { readdir, copyFile, rm } from "node:fs/promises"
|
|
5361
|
-
import { homedir } from "node:os"
|
|
5362
|
-
import { join } from "node:path"
|
|
5363
|
-
|
|
5364
|
-
const codeCommand = ${JSON.stringify(codeCommand)}
|
|
5365
|
-
|
|
5366
|
-
/**
|
|
5367
|
-
* @param {string} command
|
|
5368
|
-
*/
|
|
5369
|
-
function spawnAsync(command) {
|
|
5370
|
-
return new Promise((resolve, reject) => {
|
|
5371
|
-
const child = spawn(command, { shell: true, stdio: "inherit" })
|
|
5372
|
-
child.on("exit", code => {
|
|
5373
|
-
if (code !== 0) return reject(new Error(\`Command failed with code \${code}\`))
|
|
5374
|
-
resolve(0)
|
|
5375
|
-
})
|
|
5376
|
-
})
|
|
5377
|
-
}
|
|
5378
|
-
|
|
5379
|
-
async function main() {
|
|
5380
|
-
${options.includes("EXTENSION") ? ` const dir = await readdir("./extensions")
|
|
5381
|
-
for (const ext of dir) {
|
|
5382
|
-
await spawnAsync(\`\${codeCommand} --install-extension "./extensions/\${ext}"\`)
|
|
5383
|
-
}
|
|
5384
|
-
` : ""}${options.includes("SETTING") ? ` const userDir = homedir()
|
|
5385
|
-
const setting = join(userDir, "AppData/Roaming/Code/User/settings.json")
|
|
5386
|
-
await rm(setting, { force: true })
|
|
5387
|
-
await copyFile("./settings.json", setting)
|
|
5388
|
-
const snippetTarget = join(userDir, "AppData/Roaming/Code/User/snippets")
|
|
5389
|
-
const dir2 = await readdir("./snippets")
|
|
5390
|
-
for (const file of dir2) {
|
|
5391
|
-
await rm(join(snippetTarget, file), { force: true })
|
|
5392
|
-
await copyFile(join("./snippets", file), join(snippetTarget, file))
|
|
5393
|
-
}` : ""}${options.includes("POWERSHELL") ? `
|
|
5394
|
-
${options.includes("SETTING") ? "" : `const userDir = homedir()
|
|
5395
|
-
`}const profile = join(userDir, "Documents/PowerShell/Microsoft.PowerShell_profile.ps1")
|
|
5396
|
-
await copyFile("./Microsoft.PowerShell_profile.ps1", profile)` : ""}
|
|
5397
|
-
}
|
|
5398
|
-
|
|
5399
|
-
main()`;
|
|
5485
|
+
if (options.includes(VscodeSyncOption.配置) || options.includes(VscodeSyncOption.插件) || options.includes(VscodeSyncOption.PowerShell)) {
|
|
5486
|
+
const script = createSyncVscodeScript(options);
|
|
5400
5487
|
await writeFile(join(dir, "syncVscode.mjs"), script, "utf-8");
|
|
5401
5488
|
}
|
|
5402
|
-
if (options.includes(
|
|
5489
|
+
if (options.includes(VscodeSyncOption.软件)) {
|
|
5403
5490
|
consola.start("开始下载最新 VSCode");
|
|
5404
5491
|
await download_download("https://code.visualstudio.com/sha/download?build=stable&os=win32-x64", dir);
|
|
5405
5492
|
consola.success("下载最新 VSCode 完成");
|
|
5406
5493
|
}
|
|
5407
|
-
if (options.includes(
|
|
5494
|
+
if (options.includes(VscodeSyncOption.PowerShell)) {
|
|
5408
5495
|
consola.start("开始同步 PowerShell 配置");
|
|
5409
5496
|
const userDir = homedir();
|
|
5410
5497
|
const profile = join(userDir, "Documents/PowerShell/Microsoft.PowerShell_profile.ps1");
|