code-frontmatter 0.1.0 → 0.2.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/index.js +83 -7
- package/dist/index.js.map +1 -1
- package/dist/tools/write.d.ts +32 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +130 -0
- package/dist/tools/write.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/*---
|
|
3
|
-
intent: "MCP Server 入口:注册
|
|
3
|
+
intent: "MCP Server 入口:注册 cfm_read、cfm_write、cfm_search、cfm_register_language 四个工具,通过 stdio 与 AI IDE 通信"
|
|
4
4
|
role: entry
|
|
5
5
|
exports:
|
|
6
6
|
- "main: MCP Server 启动函数"
|
|
@@ -10,6 +10,7 @@ depends_on:
|
|
|
10
10
|
- "./tools/scan.ts"
|
|
11
11
|
- "./tools/search.ts"
|
|
12
12
|
- "./tools/register.ts"
|
|
13
|
+
- "./tools/write.ts"
|
|
13
14
|
when_to_load: "修改 MCP 工具注册、Server 配置或启动流程时加载"
|
|
14
15
|
ai_notes: "使用 stdio transport,兼容所有 MCP 客户端(Cursor、Claude Desktop 等)"
|
|
15
16
|
---*/
|
|
@@ -20,6 +21,7 @@ import { loadRegistry } from "./registry.js";
|
|
|
20
21
|
import { scanDirectory } from "./tools/scan.js";
|
|
21
22
|
import { searchFrontmatter } from "./tools/search.js";
|
|
22
23
|
import { registerNewLanguage } from "./tools/register.js";
|
|
24
|
+
import { writeFrontmatter } from "./tools/write.js";
|
|
23
25
|
/**
|
|
24
26
|
* 创建并配置 MCP Server
|
|
25
27
|
*/
|
|
@@ -29,10 +31,10 @@ async function main() {
|
|
|
29
31
|
// 创建 MCP Server 实例
|
|
30
32
|
const server = new McpServer({
|
|
31
33
|
name: "code-frontmatter",
|
|
32
|
-
version: "0.
|
|
34
|
+
version: "0.2.0",
|
|
33
35
|
});
|
|
34
|
-
// ─── 工具 1:
|
|
35
|
-
server.tool("
|
|
36
|
+
// ─── 工具 1: cfm_read ───────────────────────────────────
|
|
37
|
+
server.tool("cfm_read", "扫描项目目录中所有代码文件的 CFM 表头,返回结构化索引。这是 AI 建立项目全局认知的第一步:用极低 Token 消耗获取整个项目的文件身份信息。", {
|
|
36
38
|
directory: z
|
|
37
39
|
.string()
|
|
38
40
|
.describe("要扫描的项目根目录的绝对路径"),
|
|
@@ -72,7 +74,81 @@ async function main() {
|
|
|
72
74
|
};
|
|
73
75
|
}
|
|
74
76
|
});
|
|
75
|
-
// ─── 工具 2:
|
|
77
|
+
// ─── 工具 2: cfm_write ──────────────────────────────────
|
|
78
|
+
server.tool("cfm_write", "将标准 CFM 表头写入指定代码文件。AI 在完成编码任务后调用此工具补充/更新表头,确保字段名和注释格式严格合规。工具会自动根据文件类型选择正确的注释语法。", {
|
|
79
|
+
file: z
|
|
80
|
+
.string()
|
|
81
|
+
.describe("目标文件的绝对路径"),
|
|
82
|
+
intent: z
|
|
83
|
+
.string()
|
|
84
|
+
.max(200)
|
|
85
|
+
.describe("文件的核心用途,简洁明了(必填)"),
|
|
86
|
+
role: z
|
|
87
|
+
.string()
|
|
88
|
+
.describe("文件角色(如 service, component, util, config, page, model, entry, example)"),
|
|
89
|
+
exports: z
|
|
90
|
+
.array(z.string())
|
|
91
|
+
.describe("导出的关键 API / 函数 / 组件(格式: \"名称: 简述\")"),
|
|
92
|
+
depends_on: z
|
|
93
|
+
.array(z.string())
|
|
94
|
+
.optional()
|
|
95
|
+
.describe("关键依赖的文件路径列表"),
|
|
96
|
+
when_to_load: z
|
|
97
|
+
.string()
|
|
98
|
+
.optional()
|
|
99
|
+
.describe("什么场景下 AI 才需要读取此文件全文"),
|
|
100
|
+
mutates_state: z
|
|
101
|
+
.boolean()
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("是否修改外部状态(数据库、全局变量等)"),
|
|
104
|
+
side_effects: z
|
|
105
|
+
.array(z.string())
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("副作用描述列表"),
|
|
108
|
+
domain: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe("业务领域标签(如 payment, auth, map)"),
|
|
112
|
+
ai_notes: z
|
|
113
|
+
.string()
|
|
114
|
+
.optional()
|
|
115
|
+
.describe("给 AI 的特殊注意事项"),
|
|
116
|
+
}, async ({ file, intent, role, exports, depends_on, when_to_load, mutates_state, side_effects, domain, ai_notes }) => {
|
|
117
|
+
try {
|
|
118
|
+
const result = await writeFrontmatter(file, {
|
|
119
|
+
intent,
|
|
120
|
+
role,
|
|
121
|
+
exports,
|
|
122
|
+
depends_on,
|
|
123
|
+
when_to_load,
|
|
124
|
+
mutates_state,
|
|
125
|
+
side_effects,
|
|
126
|
+
domain,
|
|
127
|
+
ai_notes,
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: JSON.stringify(result, null, 2),
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
isError: !result.success,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `写入失败: ${error.message}`,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
isError: true,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// ─── 工具 3: cfm_search ─────────────────────────────────
|
|
76
152
|
server.tool("cfm_search", "在项目中搜索匹配条件的 CFM 表头。支持按关键字(在 intent, exports 等字段中全文搜索)、按角色(role)和按业务领域(domain)过滤,用于精准定位目标文件。", {
|
|
77
153
|
directory: z
|
|
78
154
|
.string()
|
|
@@ -129,8 +205,8 @@ async function main() {
|
|
|
129
205
|
};
|
|
130
206
|
}
|
|
131
207
|
});
|
|
132
|
-
// ─── 工具
|
|
133
|
-
server.tool("cfm_register_language", "注册新的编程语言注释规则。当遇到 CFM 尚不支持的语言时,通过此工具添加该语言的注释语法,使
|
|
208
|
+
// ─── 工具 4: cfm_register_language ──────────────────────
|
|
209
|
+
server.tool("cfm_register_language", "注册新的编程语言注释规则。当遇到 CFM 尚不支持的语言时,通过此工具添加该语言的注释语法,使 cfm_read 能正确提取其表头。注册仅在当前会话有效。", {
|
|
134
210
|
name: z
|
|
135
211
|
.string()
|
|
136
212
|
.describe("语言名称(如 elixir, dart, haskell)"),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CFM 表头数据(写入时的输入)
|
|
3
|
+
*/
|
|
4
|
+
export interface CfmWriteInput {
|
|
5
|
+
intent: string;
|
|
6
|
+
role: string;
|
|
7
|
+
exports: string[];
|
|
8
|
+
depends_on?: string[];
|
|
9
|
+
when_to_load?: string;
|
|
10
|
+
mutates_state?: boolean;
|
|
11
|
+
side_effects?: string[];
|
|
12
|
+
domain?: string;
|
|
13
|
+
ai_notes?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 将 CFM 表头写入指定文件
|
|
17
|
+
*
|
|
18
|
+
* 流程:
|
|
19
|
+
* 1. 根据扩展名查找语言注释规则
|
|
20
|
+
* 2. 构建标准 YAML 内容
|
|
21
|
+
* 3. 用正确的注释语法包裹
|
|
22
|
+
* 4. 替换旧表头或插入到文件顶部
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - 文件绝对路径
|
|
25
|
+
* @param data - CFM 表头数据
|
|
26
|
+
* @returns 操作结果
|
|
27
|
+
*/
|
|
28
|
+
export declare function writeFrontmatter(filePath: string, data: CfmWriteInput): Promise<{
|
|
29
|
+
success: boolean;
|
|
30
|
+
message: string;
|
|
31
|
+
}>;
|
|
32
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAeA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuEhD"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/*---
|
|
2
|
+
intent: "实现 cfm_write 工具:将标准 CFM 表头写入指定代码文件,确保字段名和注释格式严格合规"
|
|
3
|
+
role: service
|
|
4
|
+
exports:
|
|
5
|
+
- "writeFrontmatter: 将 CFM 表头写入指定文件"
|
|
6
|
+
depends_on: ["../registry.ts", "../schema.ts"]
|
|
7
|
+
when_to_load: "修改表头写入逻辑、格式生成或替换策略时加载"
|
|
8
|
+
ai_notes: "此工具是 CFM 规范的唯一写入入口,从根源杜绝字段名不统一的问题"
|
|
9
|
+
---*/
|
|
10
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
11
|
+
import { extname } from "node:path";
|
|
12
|
+
import { stringify as stringifyYaml } from "yaml";
|
|
13
|
+
import { getLanguageByExtension } from "../registry.js";
|
|
14
|
+
/**
|
|
15
|
+
* 将 CFM 表头写入指定文件
|
|
16
|
+
*
|
|
17
|
+
* 流程:
|
|
18
|
+
* 1. 根据扩展名查找语言注释规则
|
|
19
|
+
* 2. 构建标准 YAML 内容
|
|
20
|
+
* 3. 用正确的注释语法包裹
|
|
21
|
+
* 4. 替换旧表头或插入到文件顶部
|
|
22
|
+
*
|
|
23
|
+
* @param filePath - 文件绝对路径
|
|
24
|
+
* @param data - CFM 表头数据
|
|
25
|
+
* @returns 操作结果
|
|
26
|
+
*/
|
|
27
|
+
export async function writeFrontmatter(filePath, data) {
|
|
28
|
+
const ext = extname(filePath);
|
|
29
|
+
const lang = getLanguageByExtension(ext);
|
|
30
|
+
if (!lang) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
message: `不支持的文件类型 "${ext}",请先用 cfm_register_language 注册该语言。`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const { comment_start, comment_end, line_prefix } = lang.rule;
|
|
37
|
+
// ── 构建 YAML 内容 ──
|
|
38
|
+
// 按照标准字段顺序构建对象,只包含有值的字段
|
|
39
|
+
const orderedData = {};
|
|
40
|
+
orderedData.intent = data.intent;
|
|
41
|
+
orderedData.role = data.role;
|
|
42
|
+
orderedData.exports = data.exports;
|
|
43
|
+
if (data.depends_on && data.depends_on.length > 0)
|
|
44
|
+
orderedData.depends_on = data.depends_on;
|
|
45
|
+
if (data.when_to_load)
|
|
46
|
+
orderedData.when_to_load = data.when_to_load;
|
|
47
|
+
if (data.mutates_state !== undefined)
|
|
48
|
+
orderedData.mutates_state = data.mutates_state;
|
|
49
|
+
if (data.side_effects && data.side_effects.length > 0)
|
|
50
|
+
orderedData.side_effects = data.side_effects;
|
|
51
|
+
if (data.domain)
|
|
52
|
+
orderedData.domain = data.domain;
|
|
53
|
+
if (data.ai_notes)
|
|
54
|
+
orderedData.ai_notes = data.ai_notes;
|
|
55
|
+
const yamlStr = stringifyYaml(orderedData, { lineWidth: 0 }).trim();
|
|
56
|
+
// ── 生成注释块 ──
|
|
57
|
+
let header;
|
|
58
|
+
if (line_prefix) {
|
|
59
|
+
// 脚本语言(Python, Ruby 等):每行加前缀
|
|
60
|
+
const yamlLines = yamlStr.split("\n");
|
|
61
|
+
const prefixedLines = yamlLines.map((line) => line ? `${line_prefix}${line}` : line_prefix.trim());
|
|
62
|
+
header = `${comment_start}\n${prefixedLines.join("\n")}\n${comment_end}`;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// C 家族语言(JS, TS, Java 等):块注释
|
|
66
|
+
header = `${comment_start}\n${yamlStr}\n${comment_end}`;
|
|
67
|
+
}
|
|
68
|
+
// ── 读取原文件 ──
|
|
69
|
+
let content;
|
|
70
|
+
try {
|
|
71
|
+
content = await readFile(filePath, "utf-8");
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
message: `无法读取文件: ${filePath}`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// 统一换行符
|
|
80
|
+
const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
81
|
+
// ── 检测是否已有表头,如果有则替换 ──
|
|
82
|
+
const newContent = replaceOrInsertHeader(normalized, comment_start, comment_end, header);
|
|
83
|
+
// ── 写入文件 ──
|
|
84
|
+
try {
|
|
85
|
+
await writeFile(filePath, newContent, "utf-8");
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
message: `无法写入文件: ${filePath}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
message: `CFM 表头已写入 ${filePath}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 替换已有表头或在文件顶部插入新表头
|
|
100
|
+
*/
|
|
101
|
+
function replaceOrInsertHeader(content, commentStart, commentEnd, newHeader) {
|
|
102
|
+
const trimmed = content.trimStart();
|
|
103
|
+
const leadingWhitespace = content.slice(0, content.length - trimmed.length);
|
|
104
|
+
// 检查是否以 shebang (#!) 开头
|
|
105
|
+
let shebangLine = "";
|
|
106
|
+
let restContent = trimmed;
|
|
107
|
+
if (trimmed.startsWith("#!")) {
|
|
108
|
+
const newlineIdx = trimmed.indexOf("\n");
|
|
109
|
+
if (newlineIdx !== -1) {
|
|
110
|
+
shebangLine = trimmed.slice(0, newlineIdx + 1);
|
|
111
|
+
restContent = trimmed.slice(newlineIdx + 1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const restTrimmed = restContent.trimStart();
|
|
115
|
+
// 检查是否已有 CFM 表头
|
|
116
|
+
if (restTrimmed.startsWith(commentStart)) {
|
|
117
|
+
const afterStart = restTrimmed.slice(commentStart.length);
|
|
118
|
+
const endIdx = afterStart.indexOf(commentEnd);
|
|
119
|
+
if (endIdx !== -1) {
|
|
120
|
+
// 找到旧表头,替换
|
|
121
|
+
const afterOldHeader = afterStart.slice(endIdx + commentEnd.length);
|
|
122
|
+
// 保留旧表头后的空行
|
|
123
|
+
const cleaned = afterOldHeader.replace(/^\n{0,2}/, "\n");
|
|
124
|
+
return shebangLine + newHeader + cleaned;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// 没有旧表头,插入到文件顶部
|
|
128
|
+
return shebangLine + newHeader + "\n\n" + restContent;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-frontmatter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "让每一个代码文件拥有自己的身份证,让 AI 不读全文就能理解你的整个项目。An MCP Server that gives every code file a self-describing frontmatter header for AI assistants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|