@routerhub/agent-rules 1.3.12 → 1.4.1
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/AGENTS.base.md +1 -0
- package/README.md +3 -3
- package/README.zh-CN.md +8 -7
- package/merge.js +144 -99
- package/package.json +1 -1
package/AGENTS.base.md
CHANGED
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
- 不允许写 `class`,统一使用函数式编程。
|
|
56
56
|
- 不要写 `try/catch`。
|
|
57
57
|
- 代码注释统一使用中文编写。
|
|
58
|
+
- 每一行代码都必须有对应的中文注释,明确说明该行代码的作用。
|
|
58
59
|
- 能复用现有函数或配置时,不要复制粘贴出第二份近似实现。
|
|
59
60
|
- 编写 Go 代码时,优先使用值传递与局部变量生命周期控制,避免不必要的内存逃逸(如无必要不要返回局部变量指针、避免在热路径中产生额外堆分配)。
|
|
60
61
|
- 编写代码需遵循 SOLID 原则,并结合场景合理应用设计模式优化可维护性与扩展性,避免过度设计。
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
只做两件事:
|
|
4
4
|
|
|
5
|
-
1. 生成项目可用的 `AGENTS.md`
|
|
5
|
+
1. 生成项目可用的 `AGENTS.md` 和 `.github/copilot-instructions.md`
|
|
6
6
|
2. 自动监听 `AGENTS.private.md` 并同步
|
|
7
7
|
|
|
8
8
|
完整中文说明见 `README.zh-CN.md`。
|
|
@@ -28,6 +28,6 @@ pnpm add -D concurrently @routerhub/agent-rules
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
作用:
|
|
31
|
-
- 监听 `AGENTS.private.md` 变更
|
|
32
|
-
- 变更后自动重新同步 `AGENTS.md`
|
|
33
31
|
|
|
32
|
+
- 监听 `AGENTS.private.md` 变更
|
|
33
|
+
- 变更后自动重新同步 `AGENTS.md` 和 `.github/copilot-instructions.md`
|
package/README.zh-CN.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @routerhub/agent-rules 中文说明
|
|
2
2
|
|
|
3
|
-
`@routerhub/agent-rules`
|
|
3
|
+
`@routerhub/agent-rules` 用来把通用规则和项目私有规则合并成项目中可直接使用的规则文件。
|
|
4
4
|
|
|
5
5
|
它主要提供两类能力:
|
|
6
6
|
|
|
7
|
-
1. 生成项目可用的 `AGENTS.md`
|
|
7
|
+
1. 生成项目可用的 `AGENTS.md` 和 `.github/copilot-instructions.md`
|
|
8
8
|
2. 监听 `AGENTS.private.md` 变更并自动同步
|
|
9
9
|
|
|
10
10
|
## 安装
|
|
@@ -27,7 +27,7 @@ pnpm exec agent-rules init
|
|
|
27
27
|
|
|
28
28
|
## 同步规则
|
|
29
29
|
|
|
30
|
-
将基础规则与项目私有规则合并为 `AGENTS.md`:
|
|
30
|
+
将基础规则与项目私有规则合并为 `AGENTS.md` 和 `.github/copilot-instructions.md`:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
pnpm exec agent-rules sync
|
|
@@ -41,7 +41,7 @@ pnpm exec agent-rules sync
|
|
|
41
41
|
|
|
42
42
|
## 监听模式
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
开发时建议通过监听模式自动保持规则文件最新:
|
|
45
45
|
|
|
46
46
|
```json
|
|
47
47
|
{
|
|
@@ -53,7 +53,7 @@ pnpm exec agent-rules sync
|
|
|
53
53
|
|
|
54
54
|
监听模式会:
|
|
55
55
|
|
|
56
|
-
- 先执行一次同步,生成最新的 `AGENTS.md`
|
|
56
|
+
- 先执行一次同步,生成最新的 `AGENTS.md` 和 `.github/copilot-instructions.md`
|
|
57
57
|
- 持续监听项目根目录下的 `AGENTS.private.md`
|
|
58
58
|
- 在文件变更后自动重新同步
|
|
59
59
|
|
|
@@ -61,7 +61,8 @@ pnpm exec agent-rules sync
|
|
|
61
61
|
|
|
62
62
|
- `AGENTS.base.md`:规则包内置的通用基础规则
|
|
63
63
|
- `AGENTS.private.md`:项目自己的私有规则
|
|
64
|
-
- `AGENTS.md`:最终合并结果,供项目中的
|
|
64
|
+
- `AGENTS.md`:最终合并结果,供项目中的 Agent 使用
|
|
65
|
+
- `.github/copilot-instructions.md`:最终合并结果,供 GitHub Copilot 强制规则使用
|
|
65
66
|
|
|
66
67
|
## 推荐用法
|
|
67
68
|
|
|
@@ -76,4 +77,4 @@ pnpm exec agent-rules sync
|
|
|
76
77
|
|
|
77
78
|
- 私有规则应只写项目特有的限制、接口地址、组件路径和业务规范
|
|
78
79
|
- 通用规范应维护在规则包的 `AGENTS.base.md` 中
|
|
79
|
-
- 若私有规则与基础规则冲突,以项目私有规则为准
|
|
80
|
+
- 若私有规则与基础规则冲突,以项目私有规则为准
|
package/merge.js
CHANGED
|
@@ -12,200 +12,245 @@
|
|
|
12
12
|
* watch 监听 AGENTS.private.md 变化并自动同步
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
const fs = require(
|
|
16
|
-
const path = require(
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
const path = require("path");
|
|
17
17
|
|
|
18
|
-
const packageRoot = __dirname
|
|
19
|
-
const currentRoot = process.cwd()
|
|
18
|
+
const packageRoot = __dirname;
|
|
19
|
+
const currentRoot = process.cwd();
|
|
20
20
|
|
|
21
|
-
let syncTimer = null
|
|
22
|
-
let isSyncing = false
|
|
23
|
-
let pendingSync = false
|
|
21
|
+
let syncTimer = null;
|
|
22
|
+
let isSyncing = false;
|
|
23
|
+
let pendingSync = false;
|
|
24
24
|
|
|
25
25
|
function getDefaultConfig() {
|
|
26
26
|
return {
|
|
27
|
-
output: path.join(currentRoot,
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
output: path.join(currentRoot, "AGENTS.md"),
|
|
28
|
+
copilotOutput: path.join(currentRoot, ".github", "copilot-instructions.md"),
|
|
29
|
+
baseRulesPath: path.join(packageRoot, "AGENTS.base.md"),
|
|
30
|
+
privateRulesPath: path.join(currentRoot, "AGENTS.private.md"),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function ensureParentDir(filePath) {
|
|
35
|
+
const parentDir = path.dirname(filePath);
|
|
36
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveOutputPaths(config) {
|
|
40
|
+
if (Array.isArray(config.outputs) && config.outputs.length > 0) {
|
|
41
|
+
return config.outputs;
|
|
30
42
|
}
|
|
43
|
+
|
|
44
|
+
const defaultConfig = getDefaultConfig();
|
|
45
|
+
const output = config.output || defaultConfig.output;
|
|
46
|
+
const copilotOutput = config.copilotOutput || defaultConfig.copilotOutput;
|
|
47
|
+
return [output, copilotOutput];
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
function readFileIfExists(filePath) {
|
|
34
51
|
try {
|
|
35
52
|
if (fs.existsSync(filePath)) {
|
|
36
|
-
return fs.readFileSync(filePath,
|
|
53
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
37
54
|
}
|
|
38
55
|
} catch (e) {
|
|
39
|
-
console.warn(`无法读取文件 ${filePath}:`, e.message)
|
|
56
|
+
console.warn(`无法读取文件 ${filePath}:`, e.message);
|
|
40
57
|
}
|
|
41
|
-
return null
|
|
58
|
+
return null;
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
function mergeAgents(config) {
|
|
45
62
|
const {
|
|
46
|
-
output = getDefaultConfig().output,
|
|
47
63
|
baseRulesPath = getDefaultConfig().baseRulesPath,
|
|
48
64
|
privateRulesPath = getDefaultConfig().privateRulesPath,
|
|
49
|
-
} = config
|
|
65
|
+
} = config;
|
|
66
|
+
const outputs = resolveOutputPaths(config);
|
|
50
67
|
|
|
51
|
-
console.log(
|
|
52
|
-
console.log(` 基础规则: ${baseRulesPath}`)
|
|
53
|
-
console.log(` 私有规则: ${privateRulesPath}`)
|
|
54
|
-
console.log(` 输出文件: ${
|
|
68
|
+
console.log("📦 开始合并规则文件...");
|
|
69
|
+
console.log(` 基础规则: ${baseRulesPath}`);
|
|
70
|
+
console.log(` 私有规则: ${privateRulesPath}`);
|
|
71
|
+
console.log(` 输出文件: ${outputs.join(", ")}`);
|
|
55
72
|
|
|
56
|
-
const baseRules = readFileIfExists(baseRulesPath)
|
|
73
|
+
const baseRules = readFileIfExists(baseRulesPath);
|
|
57
74
|
if (!baseRules) {
|
|
58
|
-
console.error(`❌ 基础规则文件不存在: ${baseRulesPath}`)
|
|
59
|
-
process.exit(1)
|
|
75
|
+
console.error(`❌ 基础规则文件不存在: ${baseRulesPath}`);
|
|
76
|
+
process.exit(1);
|
|
60
77
|
}
|
|
61
78
|
|
|
62
|
-
const privateRules = readFileIfExists(privateRulesPath)
|
|
79
|
+
const privateRules = readFileIfExists(privateRulesPath);
|
|
63
80
|
|
|
64
|
-
let merged = baseRules
|
|
81
|
+
let merged = baseRules;
|
|
65
82
|
|
|
66
83
|
if (privateRules) {
|
|
67
|
-
merged +=
|
|
68
|
-
merged +=
|
|
69
|
-
merged +=
|
|
70
|
-
merged += privateRules
|
|
84
|
+
merged += "\n\n---\n\n";
|
|
85
|
+
merged += "# 项目私有规则\n\n";
|
|
86
|
+
merged += "以下规则仅适用于本项目,会覆盖基础规则中的相同部分。\n\n";
|
|
87
|
+
merged += privateRules;
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
90
|
+
for (const outputPath of outputs) {
|
|
91
|
+
try {
|
|
92
|
+
ensureParentDir(outputPath);
|
|
93
|
+
fs.writeFileSync(outputPath, merged, "utf-8");
|
|
94
|
+
console.log(`✅ 规则已合并到 ${outputPath}`);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.error(`❌ 写入文件失败 ${outputPath}:`, e.message);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
79
99
|
}
|
|
80
100
|
}
|
|
81
101
|
|
|
82
102
|
function initAgents() {
|
|
83
|
-
const privateTemplatePath = path.join(
|
|
84
|
-
|
|
103
|
+
const privateTemplatePath = path.join(
|
|
104
|
+
packageRoot,
|
|
105
|
+
"AGENTS.private.example.md",
|
|
106
|
+
);
|
|
107
|
+
const privateOutputPath = path.join(currentRoot, "AGENTS.private.md");
|
|
85
108
|
|
|
86
|
-
mergeAgents(getDefaultConfig())
|
|
109
|
+
mergeAgents(getDefaultConfig());
|
|
87
110
|
|
|
88
111
|
if (!fs.existsSync(privateOutputPath) && fs.existsSync(privateTemplatePath)) {
|
|
89
|
-
fs.copyFileSync(privateTemplatePath, privateOutputPath)
|
|
90
|
-
console.log(`✅ 已创建私有规则模板 ${privateOutputPath}`)
|
|
112
|
+
fs.copyFileSync(privateTemplatePath, privateOutputPath);
|
|
113
|
+
console.log(`✅ 已创建私有规则模板 ${privateOutputPath}`);
|
|
91
114
|
}
|
|
92
115
|
|
|
93
|
-
console.log(
|
|
116
|
+
console.log(
|
|
117
|
+
"✅ 初始化完成,后续执行 agent-rules sync 即可刷新 AGENTS.md 和 .github/copilot-instructions.md",
|
|
118
|
+
);
|
|
94
119
|
}
|
|
95
120
|
|
|
96
121
|
function runSync(triggerSource) {
|
|
97
122
|
if (isSyncing) {
|
|
98
|
-
pendingSync = true
|
|
99
|
-
return
|
|
123
|
+
pendingSync = true;
|
|
124
|
+
return;
|
|
100
125
|
}
|
|
101
126
|
|
|
102
|
-
isSyncing = true
|
|
103
|
-
console.log(`[agent-rules:watch] ${triggerSource} -> 执行同步`)
|
|
127
|
+
isSyncing = true;
|
|
128
|
+
console.log(`[agent-rules:watch] ${triggerSource} -> 执行同步`);
|
|
104
129
|
|
|
105
|
-
mergeAgents(getDefaultConfig())
|
|
130
|
+
mergeAgents(getDefaultConfig());
|
|
106
131
|
|
|
107
|
-
isSyncing = false
|
|
132
|
+
isSyncing = false;
|
|
108
133
|
|
|
109
134
|
if (pendingSync) {
|
|
110
|
-
pendingSync = false
|
|
111
|
-
runSync(
|
|
135
|
+
pendingSync = false;
|
|
136
|
+
runSync("检测到等待中的改动");
|
|
112
137
|
}
|
|
113
138
|
}
|
|
114
139
|
|
|
115
140
|
function scheduleSync(triggerSource) {
|
|
116
141
|
if (syncTimer) {
|
|
117
|
-
clearTimeout(syncTimer)
|
|
142
|
+
clearTimeout(syncTimer);
|
|
118
143
|
}
|
|
119
144
|
|
|
120
145
|
syncTimer = setTimeout(() => {
|
|
121
|
-
syncTimer = null
|
|
122
|
-
runSync(triggerSource)
|
|
123
|
-
}, 300)
|
|
146
|
+
syncTimer = null;
|
|
147
|
+
runSync(triggerSource);
|
|
148
|
+
}, 300);
|
|
124
149
|
}
|
|
125
150
|
|
|
126
151
|
function watchAgents() {
|
|
127
|
-
const privateRulesName =
|
|
128
|
-
const privateRulesPath = path.join(currentRoot, privateRulesName)
|
|
129
|
-
const privateTemplatePath = path.join(
|
|
152
|
+
const privateRulesName = "AGENTS.private.md";
|
|
153
|
+
const privateRulesPath = path.join(currentRoot, privateRulesName);
|
|
154
|
+
const privateTemplatePath = path.join(
|
|
155
|
+
packageRoot,
|
|
156
|
+
"AGENTS.private.example.md",
|
|
157
|
+
);
|
|
130
158
|
|
|
131
159
|
// 不存在则从模板创建
|
|
132
160
|
if (!fs.existsSync(privateRulesPath) && fs.existsSync(privateTemplatePath)) {
|
|
133
|
-
fs.copyFileSync(privateTemplatePath, privateRulesPath)
|
|
134
|
-
console.log(
|
|
161
|
+
fs.copyFileSync(privateTemplatePath, privateRulesPath);
|
|
162
|
+
console.log(
|
|
163
|
+
`[agent-rules:watch] 已创建 ${privateRulesPath},请按项目情况修改`,
|
|
164
|
+
);
|
|
135
165
|
}
|
|
136
166
|
|
|
137
|
-
runSync(
|
|
167
|
+
runSync("启动监听");
|
|
138
168
|
|
|
139
169
|
fs.watch(currentRoot, (eventType, fileName) => {
|
|
140
|
-
const normalizedFileName = typeof fileName ===
|
|
170
|
+
const normalizedFileName = typeof fileName === "string" ? fileName : "";
|
|
141
171
|
if (normalizedFileName !== privateRulesName) {
|
|
142
|
-
return
|
|
172
|
+
return;
|
|
143
173
|
}
|
|
144
174
|
|
|
145
|
-
scheduleSync(`${privateRulesName} 已变更`)
|
|
146
|
-
})
|
|
175
|
+
scheduleSync(`${privateRulesName} 已变更`);
|
|
176
|
+
});
|
|
147
177
|
|
|
148
|
-
console.log(`[agent-rules:watch] 正在监听 ${privateRulesPath}`)
|
|
178
|
+
console.log(`[agent-rules:watch] 正在监听 ${privateRulesPath}`);
|
|
149
179
|
|
|
150
|
-
process.on(
|
|
151
|
-
process.exit(0)
|
|
152
|
-
})
|
|
180
|
+
process.on("SIGINT", () => {
|
|
181
|
+
process.exit(0);
|
|
182
|
+
});
|
|
153
183
|
|
|
154
|
-
process.on(
|
|
155
|
-
process.exit(0)
|
|
156
|
-
})
|
|
184
|
+
process.on("SIGTERM", () => {
|
|
185
|
+
process.exit(0);
|
|
186
|
+
});
|
|
157
187
|
}
|
|
158
188
|
|
|
159
189
|
function main() {
|
|
160
|
-
const command = process.argv[2]
|
|
161
|
-
|
|
162
|
-
if (command ===
|
|
163
|
-
console.log(
|
|
164
|
-
console.log(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
console.log(
|
|
168
|
-
|
|
169
|
-
|
|
190
|
+
const command = process.argv[2];
|
|
191
|
+
|
|
192
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
193
|
+
console.log("agent-rules 使用说明:");
|
|
194
|
+
console.log(
|
|
195
|
+
" agent-rules 初始化 AGENTS.md 与 .github/copilot-instructions.md,并在缺失时创建 AGENTS.private.md 模板",
|
|
196
|
+
);
|
|
197
|
+
console.log(
|
|
198
|
+
" agent-rules init 初始化 AGENTS.md 与 .github/copilot-instructions.md,并在缺失时创建 AGENTS.private.md 模板",
|
|
199
|
+
);
|
|
200
|
+
console.log(
|
|
201
|
+
" agent-rules sync 重新生成项目根目录下的 AGENTS.md 与 .github/copilot-instructions.md",
|
|
202
|
+
);
|
|
203
|
+
console.log(
|
|
204
|
+
" agent-rules watch 监听 AGENTS.private.md,变更后自动同步规则文件",
|
|
205
|
+
);
|
|
206
|
+
console.log(" agent-rules help 查看帮助");
|
|
207
|
+
return;
|
|
170
208
|
}
|
|
171
209
|
|
|
172
|
-
if (!command || command ===
|
|
173
|
-
initAgents()
|
|
174
|
-
return
|
|
210
|
+
if (!command || command === "init") {
|
|
211
|
+
initAgents();
|
|
212
|
+
return;
|
|
175
213
|
}
|
|
176
214
|
|
|
177
|
-
if (command ===
|
|
178
|
-
mergeAgents(getDefaultConfig())
|
|
179
|
-
return
|
|
215
|
+
if (command === "sync") {
|
|
216
|
+
mergeAgents(getDefaultConfig());
|
|
217
|
+
return;
|
|
180
218
|
}
|
|
181
219
|
|
|
182
|
-
if (command ===
|
|
183
|
-
watchAgents()
|
|
184
|
-
return
|
|
220
|
+
if (command === "watch") {
|
|
221
|
+
watchAgents();
|
|
222
|
+
return;
|
|
185
223
|
}
|
|
186
224
|
|
|
187
|
-
const configPath = command
|
|
225
|
+
const configPath = command;
|
|
188
226
|
|
|
189
|
-
let config = {}
|
|
227
|
+
let config = {};
|
|
190
228
|
|
|
191
229
|
if (fs.existsSync(configPath)) {
|
|
192
230
|
try {
|
|
193
|
-
const configContent = fs.readFileSync(configPath,
|
|
194
|
-
config = JSON.parse(configContent)
|
|
195
|
-
console.log(`📄 已加载配置文件: ${configPath}`)
|
|
231
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
232
|
+
config = JSON.parse(configContent);
|
|
233
|
+
console.log(`📄 已加载配置文件: ${configPath}`);
|
|
196
234
|
} catch (e) {
|
|
197
|
-
console.error(`❌ 配置文件解析失败 ${configPath}:`, e.message)
|
|
198
|
-
process.exit(1)
|
|
235
|
+
console.error(`❌ 配置文件解析失败 ${configPath}:`, e.message);
|
|
236
|
+
process.exit(1);
|
|
199
237
|
}
|
|
200
238
|
} else {
|
|
201
|
-
console.log(`⚠️ 配置文件不存在 ${configPath},使用默认配置`)
|
|
239
|
+
console.log(`⚠️ 配置文件不存在 ${configPath},使用默认配置`);
|
|
202
240
|
}
|
|
203
241
|
|
|
204
|
-
mergeAgents(config)
|
|
242
|
+
mergeAgents(config);
|
|
205
243
|
}
|
|
206
244
|
|
|
207
245
|
if (require.main === module) {
|
|
208
|
-
main()
|
|
246
|
+
main();
|
|
209
247
|
}
|
|
210
248
|
|
|
211
|
-
module.exports = {
|
|
249
|
+
module.exports = {
|
|
250
|
+
mergeAgents,
|
|
251
|
+
readFileIfExists,
|
|
252
|
+
initAgents,
|
|
253
|
+
getDefaultConfig,
|
|
254
|
+
watchAgents,
|
|
255
|
+
resolveOutputPaths,
|
|
256
|
+
};
|