zixulu 1.80.2 → 1.80.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.
Files changed (39) hide show
  1. package/dist/index.js +182 -63
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/utils/syncAgentRules.d.ts +31 -0
  4. package/package.json +1 -1
  5. package/src/utils/addTailwind.ts +21 -21
  6. package/src/utils/checkTailwind.ts +9 -9
  7. package/src/utils/checkType.ts +9 -9
  8. package/src/utils/clearDockerLog.ts +8 -8
  9. package/src/utils/download7Zip.ts +14 -14
  10. package/src/utils/downloadAnydesk.ts +14 -14
  11. package/src/utils/downloadChrome.ts +14 -14
  12. package/src/utils/downloadFirefox.ts +14 -14
  13. package/src/utils/downloadGit.ts +14 -14
  14. package/src/utils/downloadHoneyview.ts +9 -9
  15. package/src/utils/downloadNodeJS.ts +14 -14
  16. package/src/utils/downloadPeazip.ts +14 -14
  17. package/src/utils/downloadPotPlayer.ts +14 -14
  18. package/src/utils/downloadPowerToys.ts +14 -14
  19. package/src/utils/downloadVscode.ts +14 -14
  20. package/src/utils/getDependcy.ts +16 -16
  21. package/src/utils/getPackageUpgradeVersion.ts +43 -43
  22. package/src/utils/getPackageVersionFromRange.ts +8 -8
  23. package/src/utils/getRelativePath.ts +11 -11
  24. package/src/utils/hasChangeNoCommit.ts +6 -6
  25. package/src/utils/isAsset.ts +26 -26
  26. package/src/utils/isShellProxy.ts +12 -12
  27. package/src/utils/isStableVersion.ts +3 -3
  28. package/src/utils/isUrl.ts +5 -5
  29. package/src/utils/next.ts +12 -12
  30. package/src/utils/replaceCommitAuthor.ts +57 -57
  31. package/src/utils/setBun.ts +10 -10
  32. package/src/utils/setEnv.ts +24 -24
  33. package/src/utils/sleep.ts +3 -3
  34. package/src/utils/sortPackageJson.ts +16 -16
  35. package/src/utils/sudoCommand.ts +17 -17
  36. package/src/utils/syncAgentRules.ts +143 -63
  37. package/src/utils/syncVscode.ts +67 -5
  38. package/src/utils/unique.ts +3 -3
  39. package/src/utils/vite.ts +15 -15
package/dist/index.js CHANGED
@@ -4788,6 +4788,104 @@ async function sortPackageJson() {
4788
4788
  });
4789
4789
  consola.success("排序 package.json 中的依赖成功");
4790
4790
  }
4791
+ const AgentRulesSyncTarget = {
4792
+ agentsMd: "AGENTS.md",
4793
+ cursor: "Cursor",
4794
+ antiGravity: "AntiGravity"
4795
+ };
4796
+ const syncAgentRules_source = join(".cursor-rules");
4797
+ const cursorRulesTarget = join(".cursor", "rules");
4798
+ const antiGravityRulesTarget = join(".agent", "rules");
4799
+ const orders = [
4800
+ "base.mdc",
4801
+ "react.mdc",
4802
+ "api.mdc",
4803
+ "next.mdc"
4804
+ ];
4805
+ function getDefaultSyncTargets() {
4806
+ const targets = [];
4807
+ if (existsSync("AGENTS.md")) targets.push(AgentRulesSyncTarget.agentsMd);
4808
+ if (existsSync(".cursor")) targets.push(AgentRulesSyncTarget.cursor);
4809
+ if (existsSync(".agent")) targets.push(AgentRulesSyncTarget.antiGravity);
4810
+ return targets;
4811
+ }
4812
+ function sortAgentRuleFiles(files) {
4813
+ return files.toSorted((a, b)=>{
4814
+ const aIndex = orders.indexOf(a);
4815
+ const bIndex = orders.indexOf(b);
4816
+ if (-1 === aIndex && -1 === bIndex) return a.localeCompare(b);
4817
+ if (-1 === aIndex) return 1;
4818
+ if (-1 === bIndex) return -1;
4819
+ return aIndex - bIndex;
4820
+ });
4821
+ }
4822
+ function transformCursorRuleToAntiGravityRule(source) {
4823
+ return source.replace(/^---\nalwaysApply: (true|false)\n---/, (match, p1)=>`---
4824
+ trigger: ${"true" === p1 ? "always_on" : "model_decision"}
4825
+ glob:
4826
+ description:
4827
+ ---`);
4828
+ }
4829
+ function transformCursorRuleToAgentsRule(source) {
4830
+ return source.replace(/^---\nalwaysApply: (true|false)\n---/, "").replace(/^(#+ )/gm, "#$1");
4831
+ }
4832
+ async function getCursorRuleFileStatusMap(files) {
4833
+ const map = {};
4834
+ if (!existsSync(cursorRulesTarget)) return Object.fromEntries(files.map((file)=>[
4835
+ file,
4836
+ "new"
4837
+ ]));
4838
+ const targetDir = await readdir(cursorRulesTarget);
4839
+ for (const file of files){
4840
+ if (!targetDir.includes(file)) {
4841
+ map[file] = "new";
4842
+ continue;
4843
+ }
4844
+ const sourceContent = await readFile(join(syncAgentRules_source, file), "utf-8");
4845
+ const targetContent = await readFile(join(cursorRulesTarget, file), "utf-8");
4846
+ if (sourceContent !== targetContent) map[file] = "modified";
4847
+ }
4848
+ return map;
4849
+ }
4850
+ async function syncCursorRules(files) {
4851
+ const map = await getCursorRuleFileStatusMap(files);
4852
+ const changedFiles = Object.keys(map);
4853
+ if (0 === changedFiles.length) return;
4854
+ const { files: selectedFiles } = await inquirer_0.prompt({
4855
+ type: "checkbox",
4856
+ name: "files",
4857
+ message: "请选择要添加的 Cursor 规则文件",
4858
+ choices: Object.entries(map).map(([key, value])=>({
4859
+ name: `${key} (${value})`,
4860
+ value: key
4861
+ })),
4862
+ default: changedFiles
4863
+ });
4864
+ await mkdir(cursorRulesTarget, {
4865
+ recursive: true
4866
+ });
4867
+ for (const file of selectedFiles)await copyFile(join(syncAgentRules_source, file), join(cursorRulesTarget, file));
4868
+ }
4869
+ async function syncAntiGravityRules(files) {
4870
+ await mkdir(antiGravityRulesTarget, {
4871
+ recursive: true
4872
+ });
4873
+ for (const file of files){
4874
+ const sourceContent = await readFile(join(syncAgentRules_source, file), "utf-8");
4875
+ const content = transformCursorRuleToAntiGravityRule(sourceContent);
4876
+ await writeFile(join(antiGravityRulesTarget, file.replace(/\.mdc$/, ".md")), content);
4877
+ }
4878
+ }
4879
+ async function syncAgentsMdRules(files) {
4880
+ let agentsRule = "# Agent Rules";
4881
+ for (const file of files){
4882
+ const sourceContent = await readFile(join(syncAgentRules_source, file), "utf-8");
4883
+ const content = transformCursorRuleToAgentsRule(sourceContent);
4884
+ agentsRule = `${agentsRule}${content}`.replace(/\n+$/, "");
4885
+ }
4886
+ agentsRule = `${agentsRule}\n`;
4887
+ await writeFile("AGENTS.md", agentsRule);
4888
+ }
4791
4889
  async function asyncAgentRules() {
4792
4890
  try {
4793
4891
  const packageJson = await readPackageJson();
@@ -4797,70 +4895,29 @@ async function asyncAgentRules() {
4797
4895
  });
4798
4896
  } catch (error) {}
4799
4897
  await spawnAsync("npx gitpick 1adybug/cursor-rule/tree/main/.cursor/rules .cursor-rules");
4800
- const source = join(".cursor-rules");
4801
- const target = join(".cursor", "rules");
4802
- let existed = existsSync(target);
4803
- if (!existed) await mkdir(target, {
4804
- recursive: true
4805
- });
4806
4898
  try {
4807
- const sourceDir = await readdir(source);
4808
- const targetDir = await readdir(target);
4809
- const map = {};
4810
- for (const file of sourceDir){
4811
- if (!targetDir.includes(file)) {
4812
- map[file] = "new";
4813
- continue;
4814
- }
4815
- const sourceContent = await readFile(join(source, file), "utf-8");
4816
- const targetContent = await readFile(join(target, file), "utf-8");
4817
- if (sourceContent !== targetContent) map[file] = "modified";
4818
- }
4819
- if (0 === Object.keys(map).length) throw new Error("Cursor 规则已是最新");
4820
- const { files } = await inquirer_0.prompt({
4899
+ const sourceDir = sortAgentRuleFiles(await readdir(syncAgentRules_source));
4900
+ const defaultTargets = getDefaultSyncTargets();
4901
+ const { targets } = await inquirer_0.prompt({
4821
4902
  type: "checkbox",
4822
- name: "files",
4823
- message: "请选择要添加的文件",
4824
- choices: Object.entries(map).map(([key, value])=>({
4825
- name: `${key} (${value})`,
4826
- value: key
4827
- })),
4828
- default: Object.keys(map)
4829
- });
4830
- for (const file of files)await copyFile(join(source, file), join(target, file));
4831
- await rm(source, {
4832
- recursive: true
4903
+ name: "targets",
4904
+ message: "请选择要同步的 Agent 规则",
4905
+ choices: Object.values(AgentRulesSyncTarget),
4906
+ default: defaultTargets
4833
4907
  });
4834
- const dir = await readdir(".cursor/rules");
4835
- await mkdir(".agent/rules", {
4836
- recursive: true
4908
+ if (0 === targets.length) throw new Error("未选择同步目标");
4909
+ if (targets.includes(AgentRulesSyncTarget.cursor)) await syncCursorRules(sourceDir);
4910
+ if (targets.includes(AgentRulesSyncTarget.antiGravity)) await syncAntiGravityRules(sourceDir);
4911
+ if (targets.includes(AgentRulesSyncTarget.agentsMd)) await syncAgentsMdRules(sourceDir);
4912
+ await rm(syncAgentRules_source, {
4913
+ recursive: true,
4914
+ force: true
4837
4915
  });
4838
- const orders = [
4839
- "base.mdc",
4840
- "react.mdc",
4841
- "api.mdc",
4842
- "next.mdc"
4843
- ];
4844
- dir.sort((a, b)=>orders.indexOf(a) - orders.indexOf(b));
4845
- let agentsRule = "# Agent Rules";
4846
- for (const file of dir){
4847
- const source = await readFile(join(".cursor/rules", file), "utf-8");
4848
- const content = source.replace(/^---\nalwaysApply: (true|false)\n---/, (match, p1)=>`---
4849
- trigger: ${"true" === p1 ? "always_on" : "model_decision"}
4850
- glob:
4851
- description:
4852
- ---`);
4853
- const content2 = source.replace(/^---\nalwaysApply: (true|false)\n---/, "").replace(/^(#+ )/gm, "#$1");
4854
- agentsRule += content2;
4855
- agentsRule = agentsRule.replace(/\n+$/, "");
4856
- await writeFile(join(".agent/rules", file.replace(/\.mdc$/, ".md")), content);
4857
- }
4858
- agentsRule += "\n";
4859
- await writeFile("AGENTS.md", agentsRule);
4860
4916
  return getCommitMessage("feature", "同步 Agent 规则");
4861
4917
  } catch (error) {
4862
- await rm(source, {
4863
- recursive: true
4918
+ await rm(syncAgentRules_source, {
4919
+ recursive: true,
4920
+ force: true
4864
4921
  });
4865
4922
  throw error;
4866
4923
  }
@@ -5312,7 +5369,7 @@ async function pathExists(path) {
5312
5369
  }
5313
5370
  }
5314
5371
 
5315
- // Windows 上优先查找真实的 code.cmd,避免 shell 拼命令时的路径问题
5372
+ // Windows 上优先查找 code.cmd,避免直接调用 Code.exe 打开编辑器窗口
5316
5373
  async function resolveCodeCli() {
5317
5374
  if (process.platform !== "win32") return "code"
5318
5375
 
@@ -5328,7 +5385,6 @@ async function resolveCodeCli() {
5328
5385
  const pathDirs = process.env.PATH?.split(delimiter).filter(Boolean) ?? []
5329
5386
  for (const dir of pathDirs) {
5330
5387
  candidates.add(join(dir, "code.cmd"))
5331
- candidates.add(join(dir, "code.exe"))
5332
5388
  candidates.add(join(dir, "code"))
5333
5389
  }
5334
5390
 
@@ -5339,16 +5395,69 @@ async function resolveCodeCli() {
5339
5395
  throw new Error("未找到 VS Code 命令行工具,请先安装 VS Code,并确认安装时勾选了“添加到 PATH”")
5340
5396
  }
5341
5397
 
5398
+ /**
5399
+ * @param {string} value
5400
+ */
5401
+ function quoteWindowsArg(value) {
5402
+ return "\\"" + value.replace(/"/g, "\\"\\"") + "\\""
5403
+ }
5404
+
5405
+ /**
5406
+ * @param {string[]} args
5407
+ * @param {string} output
5408
+ */
5409
+ function isCliCommandSuccessful(args, output) {
5410
+ if (args.includes("--install-extension")) return output.includes("was successfully installed.") || output.includes("is already installed.")
5411
+ if (args.includes("--uninstall-extension")) return output.includes("was successfully uninstalled.") || output.includes("is not installed.")
5412
+ return false
5413
+ }
5414
+
5415
+ /**
5416
+ * @param {Buffer | string} data
5417
+ * @param {string[]} chunks
5418
+ * @param {NodeJS.WriteStream} stream
5419
+ */
5420
+ function writeChildOutput(data, chunks, stream) {
5421
+ const text = data.toString()
5422
+ chunks.push(text)
5423
+ stream.write(text)
5424
+ }
5425
+
5342
5426
  /**
5343
5427
  * @param {string} command
5344
5428
  * @param {string[]} args
5345
5429
  */
5346
5430
  function spawnAsync(command, args) {
5347
5431
  return new Promise((resolve, reject) => {
5348
- const child = spawn(command, args, { stdio: "inherit" })
5432
+ // Windows 不能直接 spawn .cmd .bat 文件,需要交给 cmd.exe 执行
5433
+ const needCmdShell = process.platform === "win32" && /\\.(cmd|bat)$/i.test(command)
5434
+ const chunks = []
5435
+ const child = needCmdShell
5436
+ ? spawn(
5437
+ process.env.ComSpec ?? "cmd.exe",
5438
+ ["/d", "/s", "/c", "\\"" + quoteWindowsArg(command) + " " + args.map(quoteWindowsArg).join(" ") + "\\""],
5439
+ {
5440
+ stdio: ["ignore", "pipe", "pipe"],
5441
+ windowsVerbatimArguments: true,
5442
+ },
5443
+ )
5444
+ : spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] })
5445
+
5446
+ child.stdout?.on("data", data => writeChildOutput(data, chunks, process.stdout))
5447
+ child.stderr?.on("data", data => writeChildOutput(data, chunks, process.stderr))
5349
5448
  child.on("error", reject)
5350
5449
  child.on("exit", code => {
5351
- if (code !== 0) return reject(new Error(\`Command failed with code \${code}: \${command} \${args.join(" ")}\`))
5450
+ const output = chunks.join("")
5451
+
5452
+ if (code !== 0) {
5453
+ if (isCliCommandSuccessful(args, output)) {
5454
+ console.warn(\`VS Code 命令退出码为 \${code},但操作已完成,继续执行后续步骤\`)
5455
+ return resolve(0)
5456
+ }
5457
+
5458
+ return reject(new Error(\`Command failed with code \${code}: \${command} \${args.join(" ")}\`))
5459
+ }
5460
+
5352
5461
  resolve(0)
5353
5462
  })
5354
5463
  })
@@ -5360,8 +5469,18 @@ ${needUserDir ? ` const userDir = homedir()
5360
5469
  ` : ""}${options.includes(VscodeSyncOption.插件) ? ` const extensionsDir = join(workspaceDir, "extensions")
5361
5470
  const codeCli = await resolveCodeCli()
5362
5471
  const dir = await readdir(extensionsDir)
5472
+ const extensionErrors = []
5363
5473
  for (const ext of dir) {
5364
- await spawnAsync(codeCli, ["--install-extension", join(extensionsDir, ext)])
5474
+ try {
5475
+ await spawnAsync(codeCli, ["--install-extension", join(extensionsDir, ext), "--force"])
5476
+ } catch (error) {
5477
+ const message = error instanceof Error ? error.message : String(error)
5478
+ extensionErrors.push(\`\${ext}: \${message}\`)
5479
+ console.error(\`扩展同步失败:\${ext}\`)
5480
+ }
5481
+ }
5482
+ if (extensionErrors.length > 0) {
5483
+ throw new Error(\`以下扩展同步失败:\\n\${extensionErrors.join("\\n")}\`)
5365
5484
  }
5366
5485
  ` : ""}${options.includes(VscodeSyncOption.配置) ? ` const codeUserDir = join(userDir, "AppData", "Roaming", "Code", "User")
5367
5486
  await mkdir(codeUserDir, { recursive: true })