code-frontmatter 0.2.5 → 0.2.7

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.
@@ -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.2.5",
3
+ "version": "0.2.7",
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",
@@ -8,8 +8,8 @@
8
8
  "code-frontmatter": "dist/index.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "tsup",
12
- "dev": "tsup --watch",
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
13
  "start": "node dist/index.js",
14
14
  "prepublishOnly": "npm run build"
15
15
  },
@@ -37,6 +37,10 @@
37
37
  "type": "git",
38
38
  "url": "https://github.com/coobi7/code-frontmatter.git"
39
39
  },
40
+ "bugs": {
41
+ "url": "https://github.com/coobi7/code-frontmatter/issues"
42
+ },
43
+ "homepage": "https://github.com/coobi7/code-frontmatter#readme",
40
44
  "engines": {
41
45
  "node": ">=18.0.0"
42
46
  },
@@ -47,7 +51,6 @@
47
51
  },
48
52
  "devDependencies": {
49
53
  "@types/node": "^22.15.3",
50
- "tsup": "^8.5.1",
51
54
  "typescript": "^5.8.3"
52
55
  }
53
56
  }