@xfe-repo/cli-plugin-ai-rules 2.0.0
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/block-utils.d.ts +11 -0
- package/dist/block-utils.d.ts.map +1 -0
- package/dist/block-utils.js +13 -0
- package/dist/block-utils.js.map +1 -0
- package/dist/formats/agent-md.d.ts +35 -0
- package/dist/formats/agent-md.d.ts.map +1 -0
- package/dist/formats/agent-md.js +241 -0
- package/dist/formats/agent-md.js.map +1 -0
- package/dist/formats/markdown.d.ts +35 -0
- package/dist/formats/markdown.d.ts.map +1 -0
- package/dist/formats/markdown.js +241 -0
- package/dist/formats/markdown.js.map +1 -0
- package/dist/formats/mcp-json.d.ts +25 -0
- package/dist/formats/mcp-json.d.ts.map +1 -0
- package/dist/formats/mcp-json.js +132 -0
- package/dist/formats/mcp-json.js.map +1 -0
- package/dist/formats/shared.d.ts +4 -0
- package/dist/formats/shared.d.ts.map +1 -0
- package/dist/formats/shared.js +24 -0
- package/dist/formats/shared.js.map +1 -0
- package/dist/formats/skill-dir.d.ts +17 -0
- package/dist/formats/skill-dir.d.ts.map +1 -0
- package/dist/formats/skill-dir.js +72 -0
- package/dist/formats/skill-dir.js.map +1 -0
- package/dist/gitignore.d.ts +12 -0
- package/dist/gitignore.d.ts.map +1 -0
- package/dist/gitignore.js +32 -0
- package/dist/gitignore.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +358 -0
- package/dist/index.js.map +1 -0
- package/dist/injection.d.ts +26 -0
- package/dist/injection.d.ts.map +1 -0
- package/dist/injection.js +169 -0
- package/dist/injection.js.map +1 -0
- package/dist/mcp-writer.d.ts +23 -0
- package/dist/mcp-writer.d.ts.map +1 -0
- package/dist/mcp-writer.js +131 -0
- package/dist/mcp-writer.js.map +1 -0
- package/dist/merge.d.ts +14 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +35 -0
- package/dist/merge.js.map +1 -0
- package/dist/pipeline.d.ts +16 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +165 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/pipeline.new.d.ts +11 -0
- package/dist/pipeline.new.d.ts.map +1 -0
- package/dist/pipeline.new.js +11 -0
- package/dist/pipeline.new.js.map +1 -0
- package/dist/repo-cache.d.ts +24 -0
- package/dist/repo-cache.d.ts.map +1 -0
- package/dist/repo-cache.js +51 -0
- package/dist/repo-cache.js.map +1 -0
- package/dist/scanner.d.ts +12 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +119 -0
- package/dist/scanner.js.map +1 -0
- package/dist/sync.d.ts +26 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +172 -0
- package/dist/sync.js.map +1 -0
- package/dist/targets.d.ts +28 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +90 -0
- package/dist/targets.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +53 -0
- package/dist/types.js.map +1 -0
- package/dist/writers/index.d.ts +15 -0
- package/dist/writers/index.d.ts.map +1 -0
- package/dist/writers/index.js +23 -0
- package/dist/writers/index.js.map +1 -0
- package/dist/writers/markdown-writer.d.ts +15 -0
- package/dist/writers/markdown-writer.d.ts.map +1 -0
- package/dist/writers/markdown-writer.js +249 -0
- package/dist/writers/markdown-writer.js.map +1 -0
- package/dist/writers/mcp-json-writer.d.ts +11 -0
- package/dist/writers/mcp-json-writer.d.ts.map +1 -0
- package/dist/writers/mcp-json-writer.js +185 -0
- package/dist/writers/mcp-json-writer.js.map +1 -0
- package/dist/writers/types.d.ts +29 -0
- package/dist/writers/types.d.ts.map +1 -0
- package/dist/writers/types.js +8 -0
- package/dist/writers/types.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - Writer barrel 导出
|
|
3
|
+
*
|
|
4
|
+
* 统一管理 Writer 实例注册与获取
|
|
5
|
+
*/
|
|
6
|
+
import type { WriterType } from '../types.js';
|
|
7
|
+
import type { Writer } from './types.js';
|
|
8
|
+
export type { Writer, ApplyInjectionResult } from './types.js';
|
|
9
|
+
export { markdownWriter } from './markdown-writer.js';
|
|
10
|
+
export { mcpJsonWriter } from './mcp-json-writer.js';
|
|
11
|
+
export { stripInjectedSections, computeHash, removeStaleInjectedFiles } from './markdown-writer.js';
|
|
12
|
+
export declare function getWriter(type: WriterType): Writer;
|
|
13
|
+
/** 所有已注册的 Writer 实例 */
|
|
14
|
+
export declare function getAllWriters(): Writer[];
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/writers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAIxC,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AASnG,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,uBAAuB;AACvB,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAExC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - Writer barrel 导出
|
|
3
|
+
*
|
|
4
|
+
* 统一管理 Writer 实例注册与获取
|
|
5
|
+
*/
|
|
6
|
+
import { markdownWriter } from './markdown-writer.js';
|
|
7
|
+
import { mcpJsonWriter } from './mcp-json-writer.js';
|
|
8
|
+
export { markdownWriter } from './markdown-writer.js';
|
|
9
|
+
export { mcpJsonWriter } from './mcp-json-writer.js';
|
|
10
|
+
export { stripInjectedSections, computeHash, removeStaleInjectedFiles } from './markdown-writer.js';
|
|
11
|
+
// ─── Writer Registry ──────
|
|
12
|
+
const WRITER_REGISTRY = {
|
|
13
|
+
markdown: markdownWriter,
|
|
14
|
+
'mcp-json': mcpJsonWriter,
|
|
15
|
+
};
|
|
16
|
+
export function getWriter(type) {
|
|
17
|
+
return WRITER_REGISTRY[type];
|
|
18
|
+
}
|
|
19
|
+
/** 所有已注册的 Writer 实例 */
|
|
20
|
+
export function getAllWriters() {
|
|
21
|
+
return Object.values(WRITER_REGISTRY);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/writers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAEnG,6BAA6B;AAE7B,MAAM,eAAe,GAA+B;IAClD,QAAQ,EAAE,cAAc;IACxB,UAAU,EAAE,aAAa;CAC1B,CAAA;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB;IACxC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - Markdown Writer
|
|
3
|
+
*
|
|
4
|
+
* 处理 Markdown 系列文件的同步写入:
|
|
5
|
+
* - 合并文件(AGENTS.md / CLAUDE.md):多 item 拼接到同一文件
|
|
6
|
+
* - 独立文件(.mdc / .instructions.md):每 item 一个文件
|
|
7
|
+
* - 注入标记块:动态注入内容用 HTML 注释标记包裹
|
|
8
|
+
*/
|
|
9
|
+
import type { Writer } from './types.js';
|
|
10
|
+
export declare const markdownWriter: Writer;
|
|
11
|
+
export declare function stripInjectedSections(content: string): string;
|
|
12
|
+
export declare function computeHash(content: string): string;
|
|
13
|
+
/** 清理历史注入独立文件(不在当前列表中的旧文件) */
|
|
14
|
+
export declare function removeStaleInjectedFiles(projectRoot: string, prevPaths: Set<string>, currentPaths: Set<string>): Promise<number>;
|
|
15
|
+
//# sourceMappingURL=markdown-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-writer.d.ts","sourceRoot":"","sources":["../../src/writers/markdown-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,KAAK,EAAwB,MAAM,EAAE,MAAM,YAAY,CAAA;AAY9D,eAAO,MAAM,cAAc,EAAE,MAmH5B,CAAA;AAiJD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAa7D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,8BAA8B;AAC9B,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBtI"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - Markdown Writer
|
|
3
|
+
*
|
|
4
|
+
* 处理 Markdown 系列文件的同步写入:
|
|
5
|
+
* - 合并文件(AGENTS.md / CLAUDE.md):多 item 拼接到同一文件
|
|
6
|
+
* - 独立文件(.mdc / .instructions.md):每 item 一个文件
|
|
7
|
+
* - 注入标记块:动态注入内容用 HTML 注释标记包裹
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { SyncItemType } from '../types.js';
|
|
14
|
+
import { getTarget, isIndividualSlot, resolvePathTemplate, formatOutputFile } from '../targets.js';
|
|
15
|
+
// ─── Constants ──────
|
|
16
|
+
const INJECTED_BEGIN = '<!-- xfe:injected:begin -->';
|
|
17
|
+
const INJECTED_END = '<!-- xfe:injected:end -->';
|
|
18
|
+
const INJECTED_SOURCE_BEGIN = (source) => `<!-- xfe:injected:${source}:begin -->`;
|
|
19
|
+
const INJECTED_SOURCE_END = (source) => `<!-- xfe:injected:${source}:end -->`;
|
|
20
|
+
const AUTO_GENERATED_HEADER = '<!-- Auto-generated by xfe rules sync — do not edit manually -->';
|
|
21
|
+
// ─── Markdown Writer ──────
|
|
22
|
+
export const markdownWriter = {
|
|
23
|
+
plan(target, items) {
|
|
24
|
+
const mergeMap = new Map();
|
|
25
|
+
const individualFiles = [];
|
|
26
|
+
distributeItems(target, items, mergeMap, individualFiles);
|
|
27
|
+
const files = buildMergeFiles(mergeMap);
|
|
28
|
+
files.push(...individualFiles);
|
|
29
|
+
return files;
|
|
30
|
+
},
|
|
31
|
+
appendInjections(config, files, injections) {
|
|
32
|
+
if (injections.size === 0)
|
|
33
|
+
return;
|
|
34
|
+
const mdInjections = filterMarkdownInjections(injections);
|
|
35
|
+
if (mdInjections.size === 0)
|
|
36
|
+
return;
|
|
37
|
+
const injectedBlock = buildInjectedBlock(mdInjections);
|
|
38
|
+
if (!injectedBlock)
|
|
39
|
+
return;
|
|
40
|
+
const mergeFilePaths = collectMergeFilePaths(config);
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
if (file.writerType !== 'markdown')
|
|
43
|
+
continue;
|
|
44
|
+
if (!mergeFilePaths.has(file.relativePath))
|
|
45
|
+
continue;
|
|
46
|
+
file.content = file.content.trimEnd() + '\n\n' + injectedBlock + '\n';
|
|
47
|
+
}
|
|
48
|
+
const injectedIndividualFiles = generateInjectedIndividualFiles(config, mdInjections);
|
|
49
|
+
files.push(...injectedIndividualFiles.map((f) => ({
|
|
50
|
+
...f,
|
|
51
|
+
action: 'write',
|
|
52
|
+
source: 'injection',
|
|
53
|
+
writerType: 'markdown',
|
|
54
|
+
})));
|
|
55
|
+
},
|
|
56
|
+
async detectConflict(file, projectRoot, lastHashes) {
|
|
57
|
+
const absPath = path.join(projectRoot, file.relativePath);
|
|
58
|
+
if (!existsSync(absPath))
|
|
59
|
+
return file;
|
|
60
|
+
const localContent = await readFile(absPath, 'utf-8');
|
|
61
|
+
const localHash = computeHash(stripInjectedSections(localContent));
|
|
62
|
+
const knownHash = lastHashes[file.relativePath];
|
|
63
|
+
const hasLocalChanges = !knownHash || localHash !== knownHash;
|
|
64
|
+
return hasLocalChanges ? { ...file, action: 'conflict' } : file;
|
|
65
|
+
},
|
|
66
|
+
async write(file, projectRoot) {
|
|
67
|
+
const absPath = path.join(projectRoot, file.relativePath);
|
|
68
|
+
await mkdir(path.dirname(absPath), { recursive: true });
|
|
69
|
+
await writeFile(absPath, file.content, 'utf-8');
|
|
70
|
+
return computeHash(stripInjectedSections(file.content));
|
|
71
|
+
},
|
|
72
|
+
async applyInjections(config, projectRoot, injections) {
|
|
73
|
+
const mdInjections = filterMarkdownInjections(injections);
|
|
74
|
+
const injectedBlock = buildInjectedBlock(mdInjections);
|
|
75
|
+
const mergeFilePaths = collectMergeFilePaths(config);
|
|
76
|
+
let written = 0;
|
|
77
|
+
let removed = 0;
|
|
78
|
+
for (const relativePath of mergeFilePaths) {
|
|
79
|
+
const absPath = path.join(projectRoot, relativePath);
|
|
80
|
+
if (!existsSync(absPath))
|
|
81
|
+
continue;
|
|
82
|
+
const content = await readFile(absPath, 'utf-8');
|
|
83
|
+
const stripped = stripInjectedSections(content);
|
|
84
|
+
if (injectedBlock) {
|
|
85
|
+
await writeFile(absPath, stripped.trimEnd() + '\n\n' + injectedBlock + '\n', 'utf-8');
|
|
86
|
+
written++;
|
|
87
|
+
}
|
|
88
|
+
else if (content !== stripped) {
|
|
89
|
+
await writeFile(absPath, stripped, 'utf-8');
|
|
90
|
+
removed++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const individualFiles = generateInjectedIndividualFiles(config, mdInjections);
|
|
94
|
+
for (const file of individualFiles) {
|
|
95
|
+
const absPath = path.join(projectRoot, file.relativePath);
|
|
96
|
+
await mkdir(path.dirname(absPath), { recursive: true });
|
|
97
|
+
await writeFile(absPath, file.content, 'utf-8');
|
|
98
|
+
written++;
|
|
99
|
+
}
|
|
100
|
+
const hashes = {};
|
|
101
|
+
for (const file of individualFiles) {
|
|
102
|
+
hashes[file.relativePath] = computeHash(file.content);
|
|
103
|
+
}
|
|
104
|
+
return { written, removed, hashes };
|
|
105
|
+
},
|
|
106
|
+
gitignoreEntries(target) {
|
|
107
|
+
return [...target.gitignoreEntries];
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
// ─── Plan Helpers ──────
|
|
111
|
+
function distributeItems(target, items, mergeMap, individualFiles) {
|
|
112
|
+
const byType = groupByType(items);
|
|
113
|
+
for (const [type, typeItems] of byType) {
|
|
114
|
+
if (type === SyncItemType.McpServer)
|
|
115
|
+
continue;
|
|
116
|
+
const pathTemplate = resolvePathTemplate(target, type);
|
|
117
|
+
if (isIndividualSlot(pathTemplate)) {
|
|
118
|
+
for (const item of typeItems) {
|
|
119
|
+
const filePath = pathTemplate.replace('{id}', item.id);
|
|
120
|
+
individualFiles.push({
|
|
121
|
+
relativePath: filePath,
|
|
122
|
+
content: formatOutputFile(filePath, item),
|
|
123
|
+
action: 'write',
|
|
124
|
+
source: 'sync',
|
|
125
|
+
writerType: 'markdown',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const content = typeItems.map((r) => `# ${r.name}\n\n${r.content}`).join('\n\n---\n\n');
|
|
131
|
+
const existing = mergeMap.get(pathTemplate);
|
|
132
|
+
mergeMap.set(pathTemplate, existing ? existing + '\n\n---\n\n' + content : content);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function buildMergeFiles(mergeMap) {
|
|
137
|
+
const files = [];
|
|
138
|
+
for (const [relativePath, content] of mergeMap) {
|
|
139
|
+
files.push({
|
|
140
|
+
relativePath,
|
|
141
|
+
content: AUTO_GENERATED_HEADER + '\n\n' + content + '\n',
|
|
142
|
+
action: 'write',
|
|
143
|
+
source: 'sync',
|
|
144
|
+
writerType: 'markdown',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return files;
|
|
148
|
+
}
|
|
149
|
+
function groupByType(items) {
|
|
150
|
+
const map = new Map();
|
|
151
|
+
for (const item of items) {
|
|
152
|
+
const list = map.get(item.type) ?? [];
|
|
153
|
+
list.push(item);
|
|
154
|
+
map.set(item.type, list);
|
|
155
|
+
}
|
|
156
|
+
return map;
|
|
157
|
+
}
|
|
158
|
+
// ─── Injection Helpers ──────
|
|
159
|
+
function filterMarkdownInjections(injections) {
|
|
160
|
+
const filtered = new Map();
|
|
161
|
+
for (const [source, items] of injections) {
|
|
162
|
+
const mdItems = items.filter((item) => item.type !== SyncItemType.McpServer);
|
|
163
|
+
if (mdItems.length > 0) {
|
|
164
|
+
filtered.set(source, mdItems);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return filtered;
|
|
168
|
+
}
|
|
169
|
+
function buildInjectedBlock(injections) {
|
|
170
|
+
const sections = [];
|
|
171
|
+
for (const [source, items] of injections) {
|
|
172
|
+
if (items.length === 0)
|
|
173
|
+
continue;
|
|
174
|
+
const itemsContent = items.map((item) => `## ${item.name}\n\n${item.content}`).join('\n\n---\n\n');
|
|
175
|
+
sections.push([INJECTED_SOURCE_BEGIN(source), '', itemsContent, '', INJECTED_SOURCE_END(source)].join('\n'));
|
|
176
|
+
}
|
|
177
|
+
if (sections.length === 0)
|
|
178
|
+
return '';
|
|
179
|
+
return [INJECTED_BEGIN, '', ...sections, '', INJECTED_END].join('\n');
|
|
180
|
+
}
|
|
181
|
+
function collectMergeFilePaths(config) {
|
|
182
|
+
const paths = new Set();
|
|
183
|
+
for (const targetId of config.targets) {
|
|
184
|
+
const target = getTarget(targetId);
|
|
185
|
+
if (!target)
|
|
186
|
+
continue;
|
|
187
|
+
for (const template of [target.agent, target.rules, target.subagents, target.skills]) {
|
|
188
|
+
if (!isIndividualSlot(template)) {
|
|
189
|
+
paths.add(template);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return paths;
|
|
194
|
+
}
|
|
195
|
+
function generateInjectedIndividualFiles(config, injections) {
|
|
196
|
+
const allItems = [...injections.values()].flat();
|
|
197
|
+
if (allItems.length === 0)
|
|
198
|
+
return [];
|
|
199
|
+
const files = [];
|
|
200
|
+
for (const targetId of config.targets) {
|
|
201
|
+
const target = getTarget(targetId);
|
|
202
|
+
if (!target)
|
|
203
|
+
continue;
|
|
204
|
+
for (const item of allItems) {
|
|
205
|
+
const template = resolvePathTemplate(target, item.type);
|
|
206
|
+
if (!isIndividualSlot(template))
|
|
207
|
+
continue;
|
|
208
|
+
const filePath = template.replace('{id}', item.id);
|
|
209
|
+
files.push({ relativePath: filePath, content: formatOutputFile(filePath, item) });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return files;
|
|
213
|
+
}
|
|
214
|
+
// ─── Marker Block Utilities ──────
|
|
215
|
+
export function stripInjectedSections(content) {
|
|
216
|
+
const beginIdx = content.indexOf(INJECTED_BEGIN);
|
|
217
|
+
const endIdx = content.indexOf(INJECTED_END);
|
|
218
|
+
const found = beginIdx !== -1 && endIdx !== -1;
|
|
219
|
+
if (!found)
|
|
220
|
+
return content;
|
|
221
|
+
const before = content.slice(0, beginIdx).trimEnd();
|
|
222
|
+
const after = content.slice(endIdx + INJECTED_END.length).trimStart();
|
|
223
|
+
if (!after)
|
|
224
|
+
return before ? before + '\n' : '';
|
|
225
|
+
return before + '\n\n' + after;
|
|
226
|
+
}
|
|
227
|
+
export function computeHash(content) {
|
|
228
|
+
return createHash('sha256').update(content).digest('hex');
|
|
229
|
+
}
|
|
230
|
+
/** 清理历史注入独立文件(不在当前列表中的旧文件) */
|
|
231
|
+
export async function removeStaleInjectedFiles(projectRoot, prevPaths, currentPaths) {
|
|
232
|
+
let removed = 0;
|
|
233
|
+
for (const stalePath of prevPaths) {
|
|
234
|
+
if (currentPaths.has(stalePath))
|
|
235
|
+
continue;
|
|
236
|
+
const absPath = path.join(projectRoot, stalePath);
|
|
237
|
+
if (!existsSync(absPath))
|
|
238
|
+
continue;
|
|
239
|
+
try {
|
|
240
|
+
await unlink(absPath);
|
|
241
|
+
removed++;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// 删除失败时静默跳过
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return removed;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=markdown-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-writer.js","sourceRoot":"","sources":["../../src/writers/markdown-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - MCP JSON Writer
|
|
3
|
+
*
|
|
4
|
+
* 处理 MCP 配置文件(.vscode/mcp.json、.cursor/mcp.json、.mcp.json)的同步写入:
|
|
5
|
+
* - 使用 `xfe:` 前缀隔离 xfe 管理的 server 条目与用户自定义条目
|
|
6
|
+
* - 写入时保留非 xfe 前缀的用户条目,仅覆盖 xfe 前缀条目
|
|
7
|
+
* - 不做冲突检测(前缀隔离已足够)
|
|
8
|
+
*/
|
|
9
|
+
import type { Writer } from './types.js';
|
|
10
|
+
export declare const mcpJsonWriter: Writer;
|
|
11
|
+
//# sourceMappingURL=mcp-json-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-json-writer.d.ts","sourceRoot":"","sources":["../../src/writers/mcp-json-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,KAAK,EAAwB,MAAM,EAAE,MAAM,YAAY,CAAA;AAQ9D,eAAO,MAAM,aAAa,EAAE,MAsI3B,CAAA"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - MCP JSON Writer
|
|
3
|
+
*
|
|
4
|
+
* 处理 MCP 配置文件(.vscode/mcp.json、.cursor/mcp.json、.mcp.json)的同步写入:
|
|
5
|
+
* - 使用 `xfe:` 前缀隔离 xfe 管理的 server 条目与用户自定义条目
|
|
6
|
+
* - 写入时保留非 xfe 前缀的用户条目,仅覆盖 xfe 前缀条目
|
|
7
|
+
* - 不做冲突检测(前缀隔离已足够)
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { SyncItemType } from '../types.js';
|
|
14
|
+
import { getTarget } from '../targets.js';
|
|
15
|
+
// ─── Constants ──────
|
|
16
|
+
const MCP_SERVER_PREFIX = 'xfe:';
|
|
17
|
+
// ─── MCP JSON Writer ──────
|
|
18
|
+
export const mcpJsonWriter = {
|
|
19
|
+
plan(target, items) {
|
|
20
|
+
const mcpItems = items.filter((item) => item.type === SyncItemType.McpServer);
|
|
21
|
+
if (mcpItems.length === 0 || !target.mcp)
|
|
22
|
+
return [];
|
|
23
|
+
const servers = buildServerEntries(mcpItems);
|
|
24
|
+
const content = buildMcpJsonContent(target, servers);
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
relativePath: target.mcp,
|
|
28
|
+
content,
|
|
29
|
+
action: 'write',
|
|
30
|
+
source: 'sync',
|
|
31
|
+
writerType: 'mcp-json',
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
},
|
|
35
|
+
appendInjections(config, files, injections) {
|
|
36
|
+
if (injections.size === 0)
|
|
37
|
+
return;
|
|
38
|
+
const mcpItems = collectMcpInjectionItems(injections);
|
|
39
|
+
if (mcpItems.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const servers = buildServerEntries(mcpItems);
|
|
42
|
+
for (const targetId of config.targets) {
|
|
43
|
+
const target = getTarget(targetId);
|
|
44
|
+
if (!target?.mcp)
|
|
45
|
+
continue;
|
|
46
|
+
const existing = files.find((f) => f.writerType === 'mcp-json' && f.relativePath === target.mcp);
|
|
47
|
+
if (existing) {
|
|
48
|
+
const parsed = JSON.parse(existing.content);
|
|
49
|
+
const rootKey = target.mcpRootKey ?? 'mcpServers';
|
|
50
|
+
Object.assign(parsed[rootKey] ?? {}, servers);
|
|
51
|
+
existing.content = JSON.stringify(parsed, null, 2) + '\n';
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
files.push({
|
|
55
|
+
relativePath: target.mcp,
|
|
56
|
+
content: buildMcpJsonContent(target, servers),
|
|
57
|
+
action: 'write',
|
|
58
|
+
source: 'injection',
|
|
59
|
+
writerType: 'mcp-json',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async detectConflict(file) {
|
|
65
|
+
// MCP JSON 使用前缀隔离,不做冲突检测
|
|
66
|
+
return file;
|
|
67
|
+
},
|
|
68
|
+
async write(file, projectRoot) {
|
|
69
|
+
const absPath = path.join(projectRoot, file.relativePath);
|
|
70
|
+
await mkdir(path.dirname(absPath), { recursive: true });
|
|
71
|
+
const newServers = extractServers(file.content);
|
|
72
|
+
const merged = await mergeWithExisting(absPath, file.content, newServers);
|
|
73
|
+
await writeFile(absPath, merged, 'utf-8');
|
|
74
|
+
return computeHash(merged);
|
|
75
|
+
},
|
|
76
|
+
async applyInjections(config, projectRoot, injections) {
|
|
77
|
+
const mcpItems = collectMcpInjectionItems(injections);
|
|
78
|
+
const servers = buildServerEntries(mcpItems);
|
|
79
|
+
const isEmpty = Object.keys(servers).length === 0;
|
|
80
|
+
let written = 0;
|
|
81
|
+
let removed = 0;
|
|
82
|
+
for (const targetId of config.targets) {
|
|
83
|
+
const target = getTarget(targetId);
|
|
84
|
+
if (!target?.mcp)
|
|
85
|
+
continue;
|
|
86
|
+
const absPath = path.join(projectRoot, target.mcp);
|
|
87
|
+
if (!existsSync(absPath)) {
|
|
88
|
+
if (!isEmpty) {
|
|
89
|
+
await mkdir(path.dirname(absPath), { recursive: true });
|
|
90
|
+
await writeFile(absPath, buildMcpJsonContent(target, servers), 'utf-8');
|
|
91
|
+
written++;
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const content = await readFile(absPath, 'utf-8');
|
|
96
|
+
const rootKey = target.mcpRootKey ?? 'mcpServers';
|
|
97
|
+
const parsed = JSON.parse(content);
|
|
98
|
+
const existingServers = parsed[rootKey] ?? {};
|
|
99
|
+
// 移除旧的 xfe 前缀条目
|
|
100
|
+
const userServers = {};
|
|
101
|
+
for (const [key, value] of Object.entries(existingServers)) {
|
|
102
|
+
if (!key.startsWith(MCP_SERVER_PREFIX)) {
|
|
103
|
+
userServers[key] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (isEmpty) {
|
|
107
|
+
const hadXfeServers = Object.keys(existingServers).some((k) => k.startsWith(MCP_SERVER_PREFIX));
|
|
108
|
+
if (hadXfeServers) {
|
|
109
|
+
parsed[rootKey] = userServers;
|
|
110
|
+
await writeFile(absPath, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
|
|
111
|
+
removed++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
parsed[rootKey] = { ...userServers, ...servers };
|
|
116
|
+
await writeFile(absPath, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
|
|
117
|
+
written++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { written, removed, hashes: {} };
|
|
121
|
+
},
|
|
122
|
+
gitignoreEntries(target) {
|
|
123
|
+
if (!target.mcp)
|
|
124
|
+
return [];
|
|
125
|
+
return [target.mcp];
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
// ─── Helpers ──────
|
|
129
|
+
function buildServerEntries(items) {
|
|
130
|
+
const servers = {};
|
|
131
|
+
for (const item of items) {
|
|
132
|
+
if (!item.serverConfig)
|
|
133
|
+
continue;
|
|
134
|
+
const key = `${MCP_SERVER_PREFIX}${item.id}`;
|
|
135
|
+
servers[key] = item.serverConfig;
|
|
136
|
+
}
|
|
137
|
+
return servers;
|
|
138
|
+
}
|
|
139
|
+
function buildMcpJsonContent(target, servers) {
|
|
140
|
+
const rootKey = target.mcpRootKey ?? 'mcpServers';
|
|
141
|
+
return JSON.stringify({ [rootKey]: servers }, null, 2) + '\n';
|
|
142
|
+
}
|
|
143
|
+
function extractServers(content) {
|
|
144
|
+
const parsed = JSON.parse(content);
|
|
145
|
+
return Object.values(parsed)[0] ?? {};
|
|
146
|
+
}
|
|
147
|
+
async function mergeWithExisting(absPath, newContent, newServers) {
|
|
148
|
+
if (!existsSync(absPath))
|
|
149
|
+
return newContent;
|
|
150
|
+
const existingRaw = await readFile(absPath, 'utf-8');
|
|
151
|
+
let existing;
|
|
152
|
+
try {
|
|
153
|
+
existing = JSON.parse(existingRaw);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return newContent;
|
|
157
|
+
}
|
|
158
|
+
const newParsed = JSON.parse(newContent);
|
|
159
|
+
const rootKey = Object.keys(newParsed)[0];
|
|
160
|
+
const existingServers = existing[rootKey] ?? {};
|
|
161
|
+
// 保留非 xfe 前缀的用户条目
|
|
162
|
+
const userServers = {};
|
|
163
|
+
for (const [key, value] of Object.entries(existingServers)) {
|
|
164
|
+
if (!key.startsWith(MCP_SERVER_PREFIX)) {
|
|
165
|
+
userServers[key] = value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
existing[rootKey] = { ...userServers, ...newServers };
|
|
169
|
+
return JSON.stringify(existing, null, 2) + '\n';
|
|
170
|
+
}
|
|
171
|
+
function collectMcpInjectionItems(injections) {
|
|
172
|
+
const items = [];
|
|
173
|
+
for (const sourceItems of injections.values()) {
|
|
174
|
+
for (const item of sourceItems) {
|
|
175
|
+
if (item.type === SyncItemType.McpServer) {
|
|
176
|
+
items.push(item);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return items;
|
|
181
|
+
}
|
|
182
|
+
function computeHash(content) {
|
|
183
|
+
return createHash('sha256').update(content).digest('hex');
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=mcp-json-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-json-writer.js","sourceRoot":"","sources":["../../src/writers/mcp-json-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xfe-repo/cli-plugin-ai-rules - Writer 接口定义
|
|
3
|
+
*
|
|
4
|
+
* Writer 负责将 SyncItem 转换为具体文件格式并执行读写
|
|
5
|
+
* pipeline 编排层按 WriterType 委派给对应实现
|
|
6
|
+
*/
|
|
7
|
+
import type { AiConfig, InjectionRegistry, PlannedFile, SyncItem } from '../types.js';
|
|
8
|
+
import type { TargetConfig } from '../targets.js';
|
|
9
|
+
export interface Writer {
|
|
10
|
+
/** 将同步项按 target 配置转换为 PlannedFile 列表(纯函数) */
|
|
11
|
+
plan(target: TargetConfig, items: SyncItem[]): PlannedFile[];
|
|
12
|
+
/** 将注入项追加到已有的 PlannedFile 列表中(纯函数,原地修改 files) */
|
|
13
|
+
appendInjections(config: AiConfig, files: PlannedFile[], injections: InjectionRegistry): void;
|
|
14
|
+
/** 检测单个 PlannedFile 是否与本地文件冲突(只读 IO) */
|
|
15
|
+
detectConflict(file: PlannedFile, projectRoot: string, lastHashes: Record<string, string>): Promise<PlannedFile>;
|
|
16
|
+
/** 执行单个 PlannedFile 的写入,返回内容 hash(写 IO) */
|
|
17
|
+
write(file: PlannedFile, projectRoot: string): Promise<string>;
|
|
18
|
+
/** 将注入注册表立即应用到已有文件(独立注入路径,不走完整 sync) */
|
|
19
|
+
applyInjections(config: AiConfig, projectRoot: string, injections: InjectionRegistry): Promise<ApplyInjectionResult>;
|
|
20
|
+
/** 收集该 target 需要加入 .gitignore 的条目 */
|
|
21
|
+
gitignoreEntries(target: TargetConfig): string[];
|
|
22
|
+
}
|
|
23
|
+
export interface ApplyInjectionResult {
|
|
24
|
+
written: number;
|
|
25
|
+
removed: number;
|
|
26
|
+
/** 注入产生的独立文件路径 → hash 映射 */
|
|
27
|
+
hashes: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/writers/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAIjD,MAAM,WAAW,MAAM;IACrB,6CAA6C;IAC7C,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,WAAW,EAAE,CAAA;IAE5D,iDAAiD;IACjD,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAE7F,wCAAwC;IACxC,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAEhH,2CAA2C;IAC3C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAE9D,wCAAwC;IACxC,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAEpH,qCAAqC;IACrC,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAAA;CACjD;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/writers/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xfe-repo/cli-plugin-ai-rules",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "XFE AI Rules plugin - sync AI coding rules from remote repo to IDE configs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"gray-matter": "^4.0.3",
|
|
10
|
+
"zod": "^4.3.6",
|
|
11
|
+
"@xfe-repo/cli-core": "2.0.0",
|
|
12
|
+
"@xfe-repo/cli-plugin-git": "2.0.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^24.3.0",
|
|
16
|
+
"typescript": "^5.9.2"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev": "tsc -p tsconfig.json -w",
|
|
24
|
+
"build": "tsc -p tsconfig.json",
|
|
25
|
+
"clean": "rm -rf dist"
|
|
26
|
+
}
|
|
27
|
+
}
|