@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.
Files changed (89) hide show
  1. package/dist/block-utils.d.ts +11 -0
  2. package/dist/block-utils.d.ts.map +1 -0
  3. package/dist/block-utils.js +13 -0
  4. package/dist/block-utils.js.map +1 -0
  5. package/dist/formats/agent-md.d.ts +35 -0
  6. package/dist/formats/agent-md.d.ts.map +1 -0
  7. package/dist/formats/agent-md.js +241 -0
  8. package/dist/formats/agent-md.js.map +1 -0
  9. package/dist/formats/markdown.d.ts +35 -0
  10. package/dist/formats/markdown.d.ts.map +1 -0
  11. package/dist/formats/markdown.js +241 -0
  12. package/dist/formats/markdown.js.map +1 -0
  13. package/dist/formats/mcp-json.d.ts +25 -0
  14. package/dist/formats/mcp-json.d.ts.map +1 -0
  15. package/dist/formats/mcp-json.js +132 -0
  16. package/dist/formats/mcp-json.js.map +1 -0
  17. package/dist/formats/shared.d.ts +4 -0
  18. package/dist/formats/shared.d.ts.map +1 -0
  19. package/dist/formats/shared.js +24 -0
  20. package/dist/formats/shared.js.map +1 -0
  21. package/dist/formats/skill-dir.d.ts +17 -0
  22. package/dist/formats/skill-dir.d.ts.map +1 -0
  23. package/dist/formats/skill-dir.js +72 -0
  24. package/dist/formats/skill-dir.js.map +1 -0
  25. package/dist/gitignore.d.ts +12 -0
  26. package/dist/gitignore.d.ts.map +1 -0
  27. package/dist/gitignore.js +32 -0
  28. package/dist/gitignore.js.map +1 -0
  29. package/dist/index.d.ts +18 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +358 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/injection.d.ts +26 -0
  34. package/dist/injection.d.ts.map +1 -0
  35. package/dist/injection.js +169 -0
  36. package/dist/injection.js.map +1 -0
  37. package/dist/mcp-writer.d.ts +23 -0
  38. package/dist/mcp-writer.d.ts.map +1 -0
  39. package/dist/mcp-writer.js +131 -0
  40. package/dist/mcp-writer.js.map +1 -0
  41. package/dist/merge.d.ts +14 -0
  42. package/dist/merge.d.ts.map +1 -0
  43. package/dist/merge.js +35 -0
  44. package/dist/merge.js.map +1 -0
  45. package/dist/pipeline.d.ts +16 -0
  46. package/dist/pipeline.d.ts.map +1 -0
  47. package/dist/pipeline.js +165 -0
  48. package/dist/pipeline.js.map +1 -0
  49. package/dist/pipeline.new.d.ts +11 -0
  50. package/dist/pipeline.new.d.ts.map +1 -0
  51. package/dist/pipeline.new.js +11 -0
  52. package/dist/pipeline.new.js.map +1 -0
  53. package/dist/repo-cache.d.ts +24 -0
  54. package/dist/repo-cache.d.ts.map +1 -0
  55. package/dist/repo-cache.js +51 -0
  56. package/dist/repo-cache.js.map +1 -0
  57. package/dist/scanner.d.ts +12 -0
  58. package/dist/scanner.d.ts.map +1 -0
  59. package/dist/scanner.js +119 -0
  60. package/dist/scanner.js.map +1 -0
  61. package/dist/sync.d.ts +26 -0
  62. package/dist/sync.d.ts.map +1 -0
  63. package/dist/sync.js +172 -0
  64. package/dist/sync.js.map +1 -0
  65. package/dist/targets.d.ts +28 -0
  66. package/dist/targets.d.ts.map +1 -0
  67. package/dist/targets.js +90 -0
  68. package/dist/targets.js.map +1 -0
  69. package/dist/types.d.ts +112 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +53 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/writers/index.d.ts +15 -0
  74. package/dist/writers/index.d.ts.map +1 -0
  75. package/dist/writers/index.js +23 -0
  76. package/dist/writers/index.js.map +1 -0
  77. package/dist/writers/markdown-writer.d.ts +15 -0
  78. package/dist/writers/markdown-writer.d.ts.map +1 -0
  79. package/dist/writers/markdown-writer.js +249 -0
  80. package/dist/writers/markdown-writer.js.map +1 -0
  81. package/dist/writers/mcp-json-writer.d.ts +11 -0
  82. package/dist/writers/mcp-json-writer.d.ts.map +1 -0
  83. package/dist/writers/mcp-json-writer.js +185 -0
  84. package/dist/writers/mcp-json-writer.js.map +1 -0
  85. package/dist/writers/types.d.ts +29 -0
  86. package/dist/writers/types.d.ts.map +1 -0
  87. package/dist/writers/types.js +8 -0
  88. package/dist/writers/types.js.map +1 -0
  89. package/package.json +27 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - MCP 配置写入
3
+ *
4
+ * 将 MCP 服务器配置写入各 IDE 的 MCP 配置文件
5
+ * 支持 VS Code (.vscode/mcp.json)、Cursor (.cursor/mcp.json)、Claude Code (.mcp.json)
6
+ *
7
+ * xfe 管理的 server key 使用 `xfe--` 前缀,与用户手动配置隔离
8
+ */
9
+ import { existsSync } from 'node:fs';
10
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ import { getTarget } from './targets.js';
13
+ // ─── Constants ──────
14
+ const XFE_SERVER_PREFIX = 'xfe--';
15
+ // ─── Public ──────
16
+ /**
17
+ * 将静态 + 动态 MCP 服务器配置写入各 IDE 的 MCP 配置文件
18
+ *
19
+ * - 静态条目:源仓库 mcp.json 中用户选中的 servers
20
+ * - 动态注入:其他插件通过 mcpInjections 注册的 servers(如 xfe-cli-mcp)
21
+ * - 保留用户手动添加的 servers(无 xfe-- 前缀的 key)
22
+ */
23
+ export async function applyMcpConfigs(ctx, config, staticEntries, mcpInjections) {
24
+ const xfeServers = buildXfeServerMap(staticEntries, mcpInjections);
25
+ const targets = collectMcpTargets(config);
26
+ let written = 0;
27
+ for (const target of targets) {
28
+ const didWrite = await writeTargetMcpConfig(ctx.projectRoot, target, xfeServers);
29
+ if (didWrite)
30
+ written++;
31
+ }
32
+ return { written, removed: 0 };
33
+ }
34
+ /**
35
+ * 清理所有 IDE MCP 配置文件中 xfe 管理的条目
36
+ */
37
+ export async function cleanMcpConfigs(ctx, config) {
38
+ const targets = collectMcpTargets(config);
39
+ let removed = 0;
40
+ for (const target of targets) {
41
+ const didClean = await cleanTargetMcpConfig(ctx.projectRoot, target);
42
+ if (didClean)
43
+ removed++;
44
+ }
45
+ return { written: 0, removed };
46
+ }
47
+ // ─── Target 写入 ──────
48
+ async function writeTargetMcpConfig(projectRoot, target, xfeServers) {
49
+ if (!target.mcpConfigPath)
50
+ return false;
51
+ const absPath = path.join(projectRoot, target.mcpConfigPath);
52
+ const existing = await readMcpConfigFile(absPath);
53
+ const serverKey = target.mcpServerKey;
54
+ const currentServers = (existing[serverKey] ?? {});
55
+ const userServers = filterUserServers(currentServers);
56
+ const merged = { ...userServers, ...xfeServers };
57
+ if (Object.keys(merged).length === 0 && !existsSync(absPath))
58
+ return false;
59
+ const output = { ...existing, [serverKey]: merged };
60
+ await mkdir(path.dirname(absPath), { recursive: true });
61
+ await writeFile(absPath, JSON.stringify(output, null, 2) + '\n', 'utf-8');
62
+ return true;
63
+ }
64
+ async function cleanTargetMcpConfig(projectRoot, target) {
65
+ if (!target.mcpConfigPath)
66
+ return false;
67
+ const absPath = path.join(projectRoot, target.mcpConfigPath);
68
+ if (!existsSync(absPath))
69
+ return false;
70
+ const existing = await readMcpConfigFile(absPath);
71
+ const serverKey = target.mcpServerKey;
72
+ const currentServers = (existing[serverKey] ?? {});
73
+ const userServers = filterUserServers(currentServers);
74
+ if (Object.keys(userServers).length === 0) {
75
+ const { [serverKey]: _, ...rest } = existing;
76
+ if (Object.keys(rest).length === 0) {
77
+ const { unlink } = await import('node:fs/promises');
78
+ await unlink(absPath);
79
+ }
80
+ else {
81
+ await writeFile(absPath, JSON.stringify(rest, null, 2) + '\n', 'utf-8');
82
+ }
83
+ }
84
+ else {
85
+ await writeFile(absPath, JSON.stringify({ ...existing, [serverKey]: userServers }, null, 2) + '\n', 'utf-8');
86
+ }
87
+ return true;
88
+ }
89
+ // ─── Helpers ──────
90
+ function buildXfeServerMap(staticEntries, mcpInjections) {
91
+ const result = {};
92
+ for (const entry of staticEntries) {
93
+ result[`${XFE_SERVER_PREFIX}${entry.id}`] = entry.config;
94
+ }
95
+ for (const entries of mcpInjections.values()) {
96
+ for (const entry of entries) {
97
+ result[`${XFE_SERVER_PREFIX}${entry.id}`] = entry.config;
98
+ }
99
+ }
100
+ return result;
101
+ }
102
+ function collectMcpTargets(config) {
103
+ const targets = [];
104
+ for (const targetId of config.targets) {
105
+ const target = getTarget(targetId);
106
+ if (target?.mcpConfigPath)
107
+ targets.push(target);
108
+ }
109
+ return targets;
110
+ }
111
+ function filterUserServers(servers) {
112
+ const result = {};
113
+ for (const [key, value] of Object.entries(servers)) {
114
+ if (!key.startsWith(XFE_SERVER_PREFIX)) {
115
+ result[key] = value;
116
+ }
117
+ }
118
+ return result;
119
+ }
120
+ async function readMcpConfigFile(absPath) {
121
+ if (!existsSync(absPath))
122
+ return {};
123
+ try {
124
+ const raw = await readFile(absPath, 'utf-8');
125
+ return JSON.parse(raw);
126
+ }
127
+ catch {
128
+ return {};
129
+ }
130
+ }
131
+ //# sourceMappingURL=mcp-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-writer.js","sourceRoot":"","sources":["../src/mcp-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 标记段落合并
3
+ *
4
+ * 管理共享文件中的标记区域,保留用户手写内容
5
+ */
6
+ import type { SyncItem } from './types.js';
7
+ /**
8
+ * 将多个 SyncItem 合并到文件内容中
9
+ *
10
+ * - 标记块外的用户内容完全保留
11
+ * - 标记块内按 section 替换
12
+ */
13
+ export declare function mergeMarkedSections(existingContent: string, items: SyncItem[]): string;
14
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAY1C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAQtF"}
package/dist/merge.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 标记段落合并
3
+ *
4
+ * 管理共享文件中的标记区域,保留用户手写内容
5
+ */
6
+ import { spliceMarkerBlock } from './injection.js';
7
+ // ─── Constants ──────
8
+ const MARKER_BEGIN = '<!-- xfe:ai-rules:begin -->';
9
+ const MARKER_END = '<!-- xfe:ai-rules:end -->';
10
+ const SECTION_PREFIX = '<!-- xfe:section:';
11
+ const SECTION_SUFFIX = ' -->';
12
+ // ─── Public ──────
13
+ /**
14
+ * 将多个 SyncItem 合并到文件内容中
15
+ *
16
+ * - 标记块外的用户内容完全保留
17
+ * - 标记块内按 section 替换
18
+ */
19
+ export function mergeMarkedSections(existingContent, items) {
20
+ if (items.length === 0)
21
+ return existingContent;
22
+ const managedBlock = buildManagedBlock(items);
23
+ if (!existingContent.trim())
24
+ return managedBlock + '\n';
25
+ return spliceMarkerBlock(existingContent, MARKER_BEGIN, MARKER_END, managedBlock);
26
+ }
27
+ // ─── Helpers ──────
28
+ function buildManagedBlock(items) {
29
+ const sections = items.map((item) => {
30
+ const sectionMarker = `${SECTION_PREFIX}${item.id}${SECTION_SUFFIX}`;
31
+ return `${sectionMarker}\n## ${item.name}\n\n${item.content}`;
32
+ });
33
+ return [MARKER_BEGIN, '', ...sections, '', MARKER_END].join('\n');
34
+ }
35
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,uBAAuB;AAEvB,MAAM,YAAY,GAAG,6BAA6B,CAAA;AAClD,MAAM,UAAU,GAAG,2BAA2B,CAAA;AAC9C,MAAM,cAAc,GAAG,mBAAmB,CAAA;AAC1C,MAAM,cAAc,GAAG,MAAM,CAAA;AAE7B,oBAAoB;AAEpB;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,eAAuB,EAAE,KAAiB;IAC5E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,eAAe,CAAA;IAE9C,MAAM,YAAY,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA;IAE7C,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE;QAAE,OAAO,YAAY,GAAG,IAAI,CAAA;IAEvD,OAAO,iBAAiB,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC,CAAA;AACnF,CAAC;AAED,qBAAqB;AAErB,SAAS,iBAAiB,CAAC,KAAiB;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,aAAa,GAAG,GAAG,cAAc,GAAG,IAAI,CAAC,EAAE,GAAG,cAAc,EAAE,CAAA;QAEpE,OAAO,GAAG,aAAa,QAAQ,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACnE,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 同步管道
3
+ *
4
+ * 四步管道: planSync → detectConflicts → resolveConflicts → executePlan
5
+ * 前两步为纯函数 / 只读 IO,后两步为交互 + 写 IO
6
+ * applyInjections 为独立路径,供外部插件即时注入使用
7
+ */
8
+ import type { PluginContext } from '@xfe-repo/cli-core';
9
+ import type { AiConfig, ApplyResult, InjectionRegistry, SyncPlan, SyncResult, SyncEntry } from './types.js';
10
+ export declare function planSync(config: AiConfig, items: SyncEntry[], injections?: InjectionRegistry): SyncPlan;
11
+ export declare function detectConflicts(plan: SyncPlan, projectRoot: string, lastHashes: Record<string, string>): Promise<SyncPlan>;
12
+ export declare function resolveConflicts(plan: SyncPlan, ctx: PluginContext): Promise<SyncPlan>;
13
+ export declare function executePlan(plan: SyncPlan, projectRoot: string): Promise<SyncResult>;
14
+ export declare function checkSyncStatus(ctx: PluginContext, config: AiConfig): Promise<boolean>;
15
+ export declare function applyInjections(ctx: PluginContext, config: AiConfig, injections: InjectionRegistry): Promise<ApplyResult>;
16
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD,OAAO,KAAK,EACV,QAAQ,EAER,WAAW,EACX,iBAAiB,EAGjB,QAAQ,EACR,UAAU,EACV,SAAS,EACV,MAAM,YAAY,CAAA;AAuBnB,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,EAAE,iBAAiB,GAAG,QAAQ,CAmBvG;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmBhI;AAID,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgC5F;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAiC1F;AAID,wBAAsB,eAAe,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B5F;AAID,wBAAsB,eAAe,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAkB/H"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 同步管道
3
+ *
4
+ * 四步管道: planSync → detectConflicts → resolveConflicts → executePlan
5
+ * 前两步为纯函数 / 只读 IO,后两步为交互 + 写 IO
6
+ * applyInjections 为独立路径,供外部插件即时注入使用
7
+ */
8
+ import { existsSync } from 'node:fs';
9
+ import { readFile, writeFile } from 'node:fs/promises';
10
+ import path from 'node:path';
11
+ import { getTarget } from './targets.js';
12
+ import { getCachePath, hasCachedRepo } from './repo-cache.js';
13
+ import { computeHash, spliceMarkerBlock } from './formats/shared.js';
14
+ import { planMarkdownFiles, detectMarkdownConflict, writeMarkdownFile, patchMarkdownInjections, getMarkdownGitignore, stripInjectedSections, removeStaleInjectedFiles, } from './formats/agent-md.js';
15
+ import { planMcpJsonFiles, writeMcpJsonFile, patchMcpJsonInjections, getMcpJsonGitignore } from './formats/mcp-json.js';
16
+ import { planSkillDirs, writeSkillDir, patchSkillDirInjections } from './formats/skill-dir.js';
17
+ // ─── Constants ──────
18
+ const GITIGNORE_BLOCK_START = '# xfe-ai-rules (auto-generated, do not edit)';
19
+ const GITIGNORE_BLOCK_END = '# end xfe-ai-rules';
20
+ // ─── Pipeline Step 1: Plan ──────
21
+ export function planSync(config, items, injections) {
22
+ const files = [];
23
+ const skillDirs = [];
24
+ const gitignoreEntries = new Set();
25
+ for (const targetId of config.targets) {
26
+ const target = getTarget(targetId);
27
+ if (!target)
28
+ continue;
29
+ files.push(...planMarkdownFiles(target, items, injections));
30
+ files.push(...planMcpJsonFiles(target, items, injections));
31
+ skillDirs.push(...planSkillDirs(target, items));
32
+ getMarkdownGitignore(target).forEach((e) => gitignoreEntries.add(e));
33
+ getMcpJsonGitignore(target).forEach((e) => gitignoreEntries.add(e));
34
+ }
35
+ return { files, skillDirs, gitignoreEntries: [...gitignoreEntries] };
36
+ }
37
+ // ─── Pipeline Step 2: Detect Conflicts ──────
38
+ export async function detectConflicts(plan, projectRoot, lastHashes) {
39
+ const updatedFiles = [];
40
+ for (const file of plan.files) {
41
+ if (file.source !== 'sync') {
42
+ updatedFiles.push(file);
43
+ continue;
44
+ }
45
+ // MCP JSON 使用前缀隔离,不做冲突检测
46
+ if (file.format === 'mcp-json') {
47
+ updatedFiles.push(file);
48
+ continue;
49
+ }
50
+ updatedFiles.push(await detectMarkdownConflict(file, projectRoot, lastHashes));
51
+ }
52
+ return { ...plan, files: updatedFiles };
53
+ }
54
+ // ─── Pipeline Step 3: Resolve Conflicts ──────
55
+ export async function resolveConflicts(plan, ctx) {
56
+ const updatedFiles = [];
57
+ for (const file of plan.files) {
58
+ if (file.action !== 'conflict') {
59
+ updatedFiles.push(file);
60
+ continue;
61
+ }
62
+ const prefilledAction = ctx.prefilled?.conflictAction;
63
+ let action;
64
+ if (prefilledAction === 'overwrite' || prefilledAction === 'skip') {
65
+ action = prefilledAction === 'overwrite' ? 'write' : 'skip';
66
+ }
67
+ else {
68
+ const { conflictAction } = await ctx.prompt.ask({
69
+ type: 'list',
70
+ name: 'conflictAction',
71
+ message: `文件 ${file.relativePath} 已被本地修改,如何处理?`,
72
+ choices: [
73
+ { name: '覆盖(使用远程版本)', value: 'overwrite' },
74
+ { name: '跳过(保留本地版本)', value: 'skip' },
75
+ ],
76
+ });
77
+ action = conflictAction === 'overwrite' ? 'write' : 'skip';
78
+ }
79
+ updatedFiles.push({ ...file, action });
80
+ }
81
+ return { ...plan, files: updatedFiles };
82
+ }
83
+ // ─── Pipeline Step 4: Execute ──────
84
+ export async function executePlan(plan, projectRoot) {
85
+ let written = 0;
86
+ let skipped = 0;
87
+ const fileHashes = {};
88
+ const injectedHashes = {};
89
+ const skillDirPaths = [];
90
+ for (const file of plan.files) {
91
+ if (file.action === 'skip') {
92
+ skipped++;
93
+ continue;
94
+ }
95
+ const hash = file.format === 'mcp-json' ? await writeMcpJsonFile(file, projectRoot) : await writeMarkdownFile(file, projectRoot);
96
+ written++;
97
+ if (file.source === 'sync') {
98
+ fileHashes[file.relativePath] = hash;
99
+ }
100
+ else {
101
+ injectedHashes[file.relativePath] = hash;
102
+ }
103
+ }
104
+ for (const skillDir of plan.skillDirs) {
105
+ await writeSkillDir(skillDir, projectRoot);
106
+ skillDirPaths.push(skillDir.targetDir);
107
+ written++;
108
+ }
109
+ await updateGitignore(projectRoot, plan.gitignoreEntries);
110
+ return { written, skipped, fileHashes, injectedHashes, skillDirPaths };
111
+ }
112
+ // ─── Sync Status Check ──────
113
+ export async function checkSyncStatus(ctx, config) {
114
+ const storeState = (ctx.store.getState()['ai-rules'] ?? {});
115
+ if (!storeState.lastSyncTime)
116
+ return false;
117
+ if (!hasCachedRepo(config.source))
118
+ return false;
119
+ const git = ctx.inject('git');
120
+ const cachePath = getCachePath(config.source);
121
+ await git.pull(ctx, { cwd: cachePath });
122
+ if ((await git.latestHash({ cwd: cachePath })) !== storeState.lastRemoteHash)
123
+ return false;
124
+ const lastHashes = storeState.lastSyncHash ?? {};
125
+ for (const [relativePath, expectedHash] of Object.entries(lastHashes)) {
126
+ const absPath = path.join(ctx.projectRoot, relativePath);
127
+ if (!existsSync(absPath))
128
+ return false;
129
+ const content = await readFile(absPath, 'utf-8');
130
+ if (computeHash(stripInjectedSections(content)) !== expectedHash)
131
+ return false;
132
+ }
133
+ return true;
134
+ }
135
+ // ─── Standalone Injection ──────
136
+ export async function applyInjections(ctx, config, injections) {
137
+ const mdResult = await patchMarkdownInjections(config, ctx.projectRoot, injections);
138
+ const mcpResult = await patchMcpJsonInjections(config, ctx.projectRoot, injections);
139
+ const skillResult = await patchSkillDirInjections(config, ctx.projectRoot, injections);
140
+ const written = mdResult.written + mcpResult.written + skillResult.written;
141
+ const removed = mdResult.removed + mcpResult.removed;
142
+ const allHashes = { ...mdResult.hashes, ...mcpResult.hashes };
143
+ // 删除历史注入独立文件
144
+ const storeState = (ctx.store.getState()['ai-rules'] ?? {});
145
+ const prevPaths = new Set(Object.keys(storeState.lastInjectedHash ?? {}));
146
+ const currentPaths = new Set(Object.keys(allHashes));
147
+ const staleRemoved = await removeStaleInjectedFiles(ctx.projectRoot, prevPaths, currentPaths);
148
+ ctx.store.setPluginState('ai-rules', { ...storeState, lastInjectedHash: allHashes });
149
+ return { written, removed: removed + staleRemoved };
150
+ }
151
+ // ─── .gitignore ──────
152
+ async function updateGitignore(projectRoot, entries) {
153
+ if (entries.length === 0)
154
+ return;
155
+ const gitignorePath = path.join(projectRoot, '.gitignore');
156
+ const newBlock = [GITIGNORE_BLOCK_START, ...entries, GITIGNORE_BLOCK_END].join('\n');
157
+ if (!existsSync(gitignorePath)) {
158
+ await writeFile(gitignorePath, newBlock + '\n', 'utf-8');
159
+ return;
160
+ }
161
+ const content = await readFile(gitignorePath, 'utf-8');
162
+ const updated = spliceMarkerBlock(content, GITIGNORE_BLOCK_START, GITIGNORE_BLOCK_END, newBlock);
163
+ await writeFile(gitignorePath, updated, 'utf-8');
164
+ }
165
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 同步管道
3
+ *
4
+ * 声明式四步管道: planSync → detectConflicts → resolveConflicts → executePlan
5
+ * 前两步为纯函数 / 只读 IO,后两步为交互 + 写 IO
6
+ *
7
+ * 管道为纯编排层,格式相关逻辑委派给 Writer 实现(MarkdownWriter / McpJsonWriter)
8
+ * applyInjections 为独立路径,供外部插件即时注入使用
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=pipeline.new.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.new.d.ts","sourceRoot":"","sources":["../src/pipeline.new.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 同步管道
3
+ *
4
+ * 声明式四步管道: planSync → detectConflicts → resolveConflicts → executePlan
5
+ * 前两步为纯函数 / 只读 IO,后两步为交互 + 写 IO
6
+ *
7
+ * 管道为纯编排层,格式相关逻辑委派给 Writer 实现(MarkdownWriter / McpJsonWriter)
8
+ * applyInjections 为独立路径,供外部插件即时注入使用
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=pipeline.new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.new.js","sourceRoot":"","sources":["../src/pipeline.new.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 仓库缓存管理
3
+ *
4
+ * 管理远程 Git 仓库的本地缓存
5
+ * 缓存在 ~/.xfe/ai-rules-cache/<url-hash>/ 下,全局共享
6
+ */
7
+ import type { PluginContext } from '@xfe-repo/cli-core';
8
+ import type { GitCapability } from '@xfe-repo/cli-plugin-git';
9
+ import type { AiConfig } from './types.js';
10
+ /**
11
+ * 获取或更新远程仓库的本地缓存,返回缓存目录路径
12
+ *
13
+ * 首次访问时 clone,后续访问时 pull 更新
14
+ */
15
+ export declare function fetchCachedRepo(ctx: PluginContext, git: GitCapability, config: AiConfig): Promise<string>;
16
+ /**
17
+ * 获取缓存路径(不触发 clone/pull)
18
+ */
19
+ export declare function getCachePath(source: string): string;
20
+ /**
21
+ * 检查缓存是否已存在
22
+ */
23
+ export declare function hasCachedRepo(source: string): boolean;
24
+ //# sourceMappingURL=repo-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-cache.d.ts","sourceRoot":"","sources":["../src/repo-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAM1C;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB/G;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAInD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIrD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 仓库缓存管理
3
+ *
4
+ * 管理远程 Git 仓库的本地缓存
5
+ * 缓存在 ~/.xfe/ai-rules-cache/<url-hash>/ 下,全局共享
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ import { existsSync } from 'node:fs';
9
+ import { mkdir } from 'node:fs/promises';
10
+ import { homedir } from 'node:os';
11
+ import path from 'node:path';
12
+ const CACHE_ROOT = path.join(homedir(), '.xfe', 'ai-rules-cache');
13
+ // ─── Public ──────
14
+ /**
15
+ * 获取或更新远程仓库的本地缓存,返回缓存目录路径
16
+ *
17
+ * 首次访问时 clone,后续访问时 pull 更新
18
+ */
19
+ export async function fetchCachedRepo(ctx, git, config) {
20
+ const cachePath = getCachePath(config.source);
21
+ await mkdir(CACHE_ROOT, { recursive: true });
22
+ const isCloned = existsSync(path.join(cachePath, '.git'));
23
+ if (!isCloned) {
24
+ ctx.logger.log(`首次拉取规则仓库: ${config.source}`);
25
+ const success = await git.clone(ctx, { url: config.source, destination: cachePath });
26
+ if (!success) {
27
+ throw new Error(`无法克隆仓库: ${config.source}`);
28
+ }
29
+ return cachePath;
30
+ }
31
+ const success = await git.pull(ctx, { cwd: cachePath });
32
+ if (!success) {
33
+ ctx.logger.warn('远程更新失败,将使用本地缓存');
34
+ }
35
+ return cachePath;
36
+ }
37
+ /**
38
+ * 获取缓存路径(不触发 clone/pull)
39
+ */
40
+ export function getCachePath(source) {
41
+ const hash = createHash('sha256').update(source).digest('hex').slice(0, 12);
42
+ return path.join(CACHE_ROOT, hash);
43
+ }
44
+ /**
45
+ * 检查缓存是否已存在
46
+ */
47
+ export function hasCachedRepo(source) {
48
+ const cachePath = getCachePath(source);
49
+ return existsSync(path.join(cachePath, '.git'));
50
+ }
51
+ //# sourceMappingURL=repo-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-cache.js","sourceRoot":"","sources":["../src/repo-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAO5B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAEjE,oBAAoB;AAEpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAkB,EAAE,GAAkB,EAAE,MAAgB;IAC5F,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAE7C,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE5C,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAEzD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAA;QAEpF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;QAC7C,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAA;IAEvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACnC,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAE3E,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IAEtC,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;AACjD,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @xfe-repo/cli-plugin-ai-rules - 远程仓库扫描
3
+ *
4
+ * 扫描 rules/ agents/ skills/ 目录下的 MD 文件和 mcp.json,
5
+ * 从 YAML frontmatter 中读取元数据
6
+ */
7
+ import type { AiConfig, SyncEntry } from './types.js';
8
+ /** 扫描缓存目录,返回所有可用条目(MD 文件 + MCP servers) */
9
+ export declare function scanRemoteEntries(cachePath: string): Promise<SyncEntry[]>;
10
+ /** 根据选中 ID 列表加载内容,返回可写入的 SyncItem */
11
+ export declare function loadSelectedItems(cachePath: string, entries: SyncEntry[], selectedIds: Set<string>, config?: AiConfig): Promise<SyncEntry[]>;
12
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAWrD,2CAA2C;AAC3C,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA6C/E;AAED,qCAAqC;AACrC,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,EAAE,EACpB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,MAAM,CAAC,EAAE,QAAQ,GAChB,OAAO,CAAC,SAAS,EAAE,CAAC,CAmCtB"}