zixulu 1.80.6 → 1.80.8
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 +160 -102
- package/dist/index.js.map +1 -1
- package/dist/src/utils/getEditorExtensions.d.ts +10 -1
- package/dist/src/utils/syncAgentRules.d.ts +37 -24
- package/package.json +1 -1
- package/src/utils/getEditorExtensions.ts +94 -4
- package/src/utils/syncAgentRules.ts +110 -111
- package/src/utils/syncCursorExtToCode.ts +1 -1
- package/src/utils/syncEditorSetting.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { capitalize, emailReg, getEnumEntries, getEnumKeys, getEnumValues, isNon
|
|
|
6
6
|
import { compress, execAsync, isPathLike, setDefaultOptions, spawnAsync, unzip, zip } from "soda-nodejs";
|
|
7
7
|
import inquirer_0 from "inquirer";
|
|
8
8
|
import { chdir, cwd as external_node_process_cwd, exit } from "node:process";
|
|
9
|
-
import { copyFile, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
10
|
-
import { basename, join, parse as external_node_path_parse, resolve as external_node_path_resolve } from "node:path";
|
|
9
|
+
import { access, copyFile, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
10
|
+
import { basename, delimiter, join, parse as external_node_path_parse, resolve as external_node_path_resolve } from "node:path";
|
|
11
11
|
import node_fetch, { Headers as external_node_fetch_Headers } from "node-fetch";
|
|
12
12
|
import semver from "semver";
|
|
13
13
|
import { checkPort } from "get-port-please";
|
|
@@ -4788,26 +4788,22 @@ async function sortPackageJson() {
|
|
|
4788
4788
|
});
|
|
4789
4789
|
consola.success("排序 package.json 中的依赖成功");
|
|
4790
4790
|
}
|
|
4791
|
-
const
|
|
4792
|
-
|
|
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");
|
|
4791
|
+
const syncAgentRules_source = join(".agent-rules");
|
|
4792
|
+
const agentsMdTarget = "AGENTS.md";
|
|
4799
4793
|
const orders = [
|
|
4800
|
-
"base.
|
|
4801
|
-
"
|
|
4802
|
-
"
|
|
4803
|
-
"
|
|
4794
|
+
"base.md",
|
|
4795
|
+
"style.md",
|
|
4796
|
+
"react.md",
|
|
4797
|
+
"api.md",
|
|
4798
|
+
"next.md"
|
|
4804
4799
|
];
|
|
4805
|
-
function
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4800
|
+
async function pathExists(path) {
|
|
4801
|
+
try {
|
|
4802
|
+
await access(path);
|
|
4803
|
+
return true;
|
|
4804
|
+
} catch {
|
|
4805
|
+
return false;
|
|
4806
|
+
}
|
|
4811
4807
|
}
|
|
4812
4808
|
function sortAgentRuleFiles(files) {
|
|
4813
4809
|
return files.toSorted((a, b)=>{
|
|
@@ -4819,72 +4815,70 @@ function sortAgentRuleFiles(files) {
|
|
|
4819
4815
|
return aIndex - bIndex;
|
|
4820
4816
|
});
|
|
4821
4817
|
}
|
|
4822
|
-
function
|
|
4823
|
-
return
|
|
4824
|
-
trigger: ${"true" === p1 ? "always_on" : "model_decision"}
|
|
4825
|
-
glob:
|
|
4826
|
-
description:
|
|
4827
|
-
---`);
|
|
4818
|
+
function normalizeMarkdownHeading(heading) {
|
|
4819
|
+
return heading.replace(/\s+#+$/, "").trim().toLocaleLowerCase();
|
|
4828
4820
|
}
|
|
4829
|
-
function
|
|
4830
|
-
|
|
4821
|
+
function getMarkdownHeadings(content, level) {
|
|
4822
|
+
const hashes = "#".repeat(level);
|
|
4823
|
+
const regexp = new RegExp(`^${hashes}(?!#)\\s+(.+?)\\s*$`, "gm");
|
|
4824
|
+
return Array.from(content.matchAll(regexp), ([, heading])=>heading.replace(/\s+#+$/, "").trim());
|
|
4831
4825
|
}
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4826
|
+
function getMarkdownFirstHeading(content) {
|
|
4827
|
+
return getMarkdownHeadings(content, 1)[0] ?? "";
|
|
4828
|
+
}
|
|
4829
|
+
function transformMarkdownRuleToAgentsRule(source) {
|
|
4830
|
+
return source.replace(/^(#+ )/gm, "#$1").replace(/\n+$/, "");
|
|
4831
|
+
}
|
|
4832
|
+
async function getMarkdownRuleFilenames() {
|
|
4833
|
+
const entries = await readdir(syncAgentRules_source, {
|
|
4834
|
+
withFileTypes: true
|
|
4835
|
+
});
|
|
4836
|
+
return sortAgentRuleFiles(entries.filter((entry)=>entry.isFile()).map((entry)=>entry.name).filter((filename)=>filename.toLowerCase().endsWith(".md")));
|
|
4837
|
+
}
|
|
4838
|
+
async function readAgentRuleFiles(files) {
|
|
4839
|
+
const rules = [];
|
|
4840
|
+
for (const filename of files){
|
|
4841
|
+
const content = await readFile(join(syncAgentRules_source, filename), "utf-8");
|
|
4842
|
+
const title = getMarkdownFirstHeading(content) || filename;
|
|
4843
|
+
rules.push({
|
|
4844
|
+
filename,
|
|
4845
|
+
title,
|
|
4846
|
+
content
|
|
4847
|
+
});
|
|
4847
4848
|
}
|
|
4848
|
-
return
|
|
4849
|
+
return rules;
|
|
4849
4850
|
}
|
|
4850
|
-
async function
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4851
|
+
async function readOriginalAgentsMd() {
|
|
4852
|
+
if (!await pathExists(agentsMdTarget)) return;
|
|
4853
|
+
return await readFile(agentsMdTarget, "utf-8");
|
|
4854
|
+
}
|
|
4855
|
+
function getDefaultAgentRuleFiles(params) {
|
|
4856
|
+
const { rules, originalContent } = params;
|
|
4857
|
+
if (!originalContent) return rules.map((rule)=>rule.filename);
|
|
4858
|
+
const originalSecondHeadings = new Set(getMarkdownHeadings(originalContent, 2).map(normalizeMarkdownHeading));
|
|
4859
|
+
return rules.filter((rule)=>originalSecondHeadings.has(normalizeMarkdownHeading(rule.title))).map((rule)=>rule.filename);
|
|
4860
|
+
}
|
|
4861
|
+
async function selectAgentRuleFiles(params) {
|
|
4862
|
+
const { rules, defaultFiles } = params;
|
|
4863
|
+
const { files } = await inquirer_0.prompt({
|
|
4855
4864
|
type: "checkbox",
|
|
4856
4865
|
name: "files",
|
|
4857
|
-
message: "
|
|
4858
|
-
choices:
|
|
4859
|
-
name: `${
|
|
4860
|
-
value:
|
|
4866
|
+
message: "请选择要同步到 AGENTS.md 的规则",
|
|
4867
|
+
choices: rules.map((rule)=>({
|
|
4868
|
+
name: `${rule.title} (${rule.filename})`,
|
|
4869
|
+
value: rule.filename
|
|
4861
4870
|
})),
|
|
4862
|
-
default:
|
|
4871
|
+
default: defaultFiles
|
|
4863
4872
|
});
|
|
4864
|
-
|
|
4865
|
-
recursive: true
|
|
4866
|
-
});
|
|
4867
|
-
for (const file of selectedFiles)await copyFile(join(syncAgentRules_source, file), join(cursorRulesTarget, file));
|
|
4873
|
+
return files;
|
|
4868
4874
|
}
|
|
4869
|
-
async function
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
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);
|
|
4875
|
+
async function syncAgentsMdRules(rules) {
|
|
4876
|
+
const sections = rules.map((rule)=>transformMarkdownRuleToAgentsRule(rule.content)).filter(Boolean);
|
|
4877
|
+
const agentsRule = `${[
|
|
4878
|
+
"# Agent Rules",
|
|
4879
|
+
...sections
|
|
4880
|
+
].join("\n\n").replace(/\n+$/, "")}\n`;
|
|
4881
|
+
await writeFile(agentsMdTarget, agentsRule);
|
|
4888
4882
|
}
|
|
4889
4883
|
async function asyncAgentRules() {
|
|
4890
4884
|
try {
|
|
@@ -4893,33 +4887,33 @@ async function asyncAgentRules() {
|
|
|
4893
4887
|
await writePackageJson({
|
|
4894
4888
|
data: packageJson
|
|
4895
4889
|
});
|
|
4896
|
-
} catch
|
|
4897
|
-
await
|
|
4890
|
+
} catch {}
|
|
4891
|
+
await rm(syncAgentRules_source, {
|
|
4892
|
+
recursive: true,
|
|
4893
|
+
force: true
|
|
4894
|
+
});
|
|
4898
4895
|
try {
|
|
4899
|
-
|
|
4900
|
-
const
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4896
|
+
await spawnAsync(`npx gitpick 1adybug/cursor-rule ${syncAgentRules_source}`);
|
|
4897
|
+
const sourceDir = await getMarkdownRuleFilenames();
|
|
4898
|
+
if (0 === sourceDir.length) throw new Error("未找到 Agent 规则文件");
|
|
4899
|
+
const rules = await readAgentRuleFiles(sourceDir);
|
|
4900
|
+
const originalAgentsMd = await readOriginalAgentsMd();
|
|
4901
|
+
const defaultFiles = getDefaultAgentRuleFiles({
|
|
4902
|
+
rules,
|
|
4903
|
+
originalContent: originalAgentsMd
|
|
4907
4904
|
});
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
if (targets.includes(AgentRulesSyncTarget.agentsMd)) await syncAgentsMdRules(sourceDir);
|
|
4912
|
-
await rm(syncAgentRules_source, {
|
|
4913
|
-
recursive: true,
|
|
4914
|
-
force: true
|
|
4905
|
+
const selectedFiles = await selectAgentRuleFiles({
|
|
4906
|
+
rules,
|
|
4907
|
+
defaultFiles
|
|
4915
4908
|
});
|
|
4909
|
+
if (0 === selectedFiles.length) throw new Error("未选择 Agent 规则");
|
|
4910
|
+
await syncAgentsMdRules(rules.filter((rule)=>selectedFiles.includes(rule.filename)));
|
|
4916
4911
|
return getCommitMessage("feature", "同步 Agent 规则");
|
|
4917
|
-
}
|
|
4912
|
+
} finally{
|
|
4918
4913
|
await rm(syncAgentRules_source, {
|
|
4919
4914
|
recursive: true,
|
|
4920
4915
|
force: true
|
|
4921
4916
|
});
|
|
4922
|
-
throw error;
|
|
4923
4917
|
}
|
|
4924
4918
|
}
|
|
4925
4919
|
const EditorExtensionCommandMap = {
|
|
@@ -4927,8 +4921,53 @@ const EditorExtensionCommandMap = {
|
|
|
4927
4921
|
Cursor: "cursor",
|
|
4928
4922
|
Antigravity: "antigravity"
|
|
4929
4923
|
};
|
|
4924
|
+
const editorExtensionCommandCache = new Map();
|
|
4925
|
+
async function getEditorExtensions_pathExists({ path }) {
|
|
4926
|
+
try {
|
|
4927
|
+
await access(path);
|
|
4928
|
+
return true;
|
|
4929
|
+
} catch {
|
|
4930
|
+
return false;
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
function quoteShellCommand({ command }) {
|
|
4934
|
+
if (!/[\s()]/.test(command)) return command;
|
|
4935
|
+
return `"${command.replace(/"/g, '\\"')}"`;
|
|
4936
|
+
}
|
|
4937
|
+
function getEditorWindowsCliCandidates({ editor }) {
|
|
4938
|
+
const command = EditorExtensionCommandMap[editor];
|
|
4939
|
+
const candidates = new Set();
|
|
4940
|
+
const localAppData = process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local");
|
|
4941
|
+
const programFiles = process.env.ProgramFiles ?? "C:/Program Files";
|
|
4942
|
+
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:/Program Files (x86)";
|
|
4943
|
+
if ("Code" === editor) {
|
|
4944
|
+
candidates.add(join(localAppData, "Programs", "Microsoft VS Code", "bin", "code.cmd"));
|
|
4945
|
+
candidates.add(join(programFiles, "Microsoft VS Code", "bin", "code.cmd"));
|
|
4946
|
+
candidates.add(join(programFilesX86, "Microsoft VS Code", "bin", "code.cmd"));
|
|
4947
|
+
}
|
|
4948
|
+
if ("Cursor" === editor) {
|
|
4949
|
+
candidates.add(join(localAppData, "Programs", "Cursor", "resources", "app", "bin", "cursor.cmd"));
|
|
4950
|
+
candidates.add(join(localAppData, "Programs", "cursor", "resources", "app", "bin", "cursor.cmd"));
|
|
4951
|
+
candidates.add(join(programFiles, "Cursor", "resources", "app", "bin", "cursor.cmd"));
|
|
4952
|
+
candidates.add(join(programFilesX86, "Cursor", "resources", "app", "bin", "cursor.cmd"));
|
|
4953
|
+
}
|
|
4954
|
+
if ("Antigravity" === editor) {
|
|
4955
|
+
candidates.add(join(localAppData, "Programs", "Antigravity", "bin", "antigravity.cmd"));
|
|
4956
|
+
candidates.add(join(localAppData, "Programs", "Antigravity", "resources", "app", "bin", "antigravity.cmd"));
|
|
4957
|
+
candidates.add(join(programFiles, "Antigravity", "bin", "antigravity.cmd"));
|
|
4958
|
+
candidates.add(join(programFiles, "Antigravity", "resources", "app", "bin", "antigravity.cmd"));
|
|
4959
|
+
candidates.add(join(programFilesX86, "Antigravity", "bin", "antigravity.cmd"));
|
|
4960
|
+
candidates.add(join(programFilesX86, "Antigravity", "resources", "app", "bin", "antigravity.cmd"));
|
|
4961
|
+
}
|
|
4962
|
+
const pathDirs = process.env.PATH?.split(delimiter).filter(Boolean) ?? [];
|
|
4963
|
+
for (const dir of pathDirs){
|
|
4964
|
+
candidates.add(join(dir, `${command}.cmd`));
|
|
4965
|
+
candidates.add(join(dir, command));
|
|
4966
|
+
}
|
|
4967
|
+
return Array.from(candidates);
|
|
4968
|
+
}
|
|
4930
4969
|
async function canGetEditorExtensions({ editor }) {
|
|
4931
|
-
const command = getEditorExtensionCommand({
|
|
4970
|
+
const command = await getEditorExtensionCommand({
|
|
4932
4971
|
editor
|
|
4933
4972
|
});
|
|
4934
4973
|
try {
|
|
@@ -4938,13 +4977,32 @@ async function canGetEditorExtensions({ editor }) {
|
|
|
4938
4977
|
return false;
|
|
4939
4978
|
}
|
|
4940
4979
|
}
|
|
4941
|
-
function getEditorExtensionCommand({ editor }) {
|
|
4942
|
-
|
|
4980
|
+
async function getEditorExtensionCommand({ editor }) {
|
|
4981
|
+
const cachedCommand = editorExtensionCommandCache.get(editor);
|
|
4982
|
+
if (cachedCommand) return cachedCommand;
|
|
4983
|
+
const fallbackCommand = EditorExtensionCommandMap[editor];
|
|
4984
|
+
if ("win32" !== process.platform) {
|
|
4985
|
+
editorExtensionCommandCache.set(editor, fallbackCommand);
|
|
4986
|
+
return fallbackCommand;
|
|
4987
|
+
}
|
|
4988
|
+
for (const candidate of getEditorWindowsCliCandidates({
|
|
4989
|
+
editor
|
|
4990
|
+
})){
|
|
4991
|
+
if (!await getEditorExtensions_pathExists({
|
|
4992
|
+
path: candidate
|
|
4993
|
+
})) continue;
|
|
4994
|
+
const command = quoteShellCommand({
|
|
4995
|
+
command: candidate
|
|
4996
|
+
});
|
|
4997
|
+
editorExtensionCommandCache.set(editor, command);
|
|
4998
|
+
return command;
|
|
4999
|
+
}
|
|
5000
|
+
throw new Error(`${editor} 命令行工具不可用,请确认已安装并加入 PATH`);
|
|
4943
5001
|
}
|
|
4944
5002
|
async function getEditorExtensions({ source }) {
|
|
4945
5003
|
let data = [];
|
|
4946
5004
|
if ("Online" !== source) {
|
|
4947
|
-
const command = getEditorExtensionCommand({
|
|
5005
|
+
const command = await getEditorExtensionCommand({
|
|
4948
5006
|
editor: source
|
|
4949
5007
|
});
|
|
4950
5008
|
const output = await execAsync(`${command} --list-extensions`);
|
|
@@ -4971,7 +5029,7 @@ async function syncCursorExtToCode() {
|
|
|
4971
5029
|
const vscodeExts = await getEditorExtensions({
|
|
4972
5030
|
source: "Code"
|
|
4973
5031
|
});
|
|
4974
|
-
const codeCommand = getEditorExtensionCommand({
|
|
5032
|
+
const codeCommand = await getEditorExtensionCommand({
|
|
4975
5033
|
editor: "Code"
|
|
4976
5034
|
});
|
|
4977
5035
|
const installExts = cursorExts.difference(vscodeExts);
|
|
@@ -5097,7 +5155,7 @@ async function syncEditorFile({ type, source: { value: sourceValue }, target: {
|
|
|
5097
5155
|
consola.success(`${targetValue} 同步完成`);
|
|
5098
5156
|
}
|
|
5099
5157
|
async function syncEditorExtensions({ editor, sourceExtensions, targetExtensions }) {
|
|
5100
|
-
const command = getEditorExtensionCommand({
|
|
5158
|
+
const command = await getEditorExtensionCommand({
|
|
5101
5159
|
editor
|
|
5102
5160
|
});
|
|
5103
5161
|
const installExtensions = sourceExtensions.difference(targetExtensions);
|