@adversity/coding-tool-x 2.2.0 → 2.3.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/CHANGELOG.md +20 -0
- package/README.md +4 -14
- package/dist/web/assets/index-dhun1bYQ.js +3555 -0
- package/dist/web/assets/index-hHb7DAda.css +41 -0
- package/dist/web/index.html +2 -2
- package/package.json +5 -4
- package/src/index.js +2 -2
- package/src/server/api/agents.js +188 -0
- package/src/server/api/commands.js +261 -0
- package/src/server/api/config-templates.js +20 -5
- package/src/server/api/permissions.js +347 -0
- package/src/server/api/rules.js +188 -0
- package/src/server/api/skills.js +66 -14
- package/src/server/api/workspaces.js +30 -55
- package/src/server/index.js +3 -0
- package/src/server/services/agents-service.js +179 -1
- package/src/server/services/commands-service.js +231 -47
- package/src/server/services/config-templates-service.js +457 -106
- package/src/server/services/format-converter.js +506 -0
- package/src/server/services/repo-scanner-base.js +678 -0
- package/src/server/services/rules-service.js +179 -1
- package/src/server/services/skill-service.js +114 -61
- package/src/server/services/workspace-service.js +110 -1
- package/dist/web/assets/index-D1AYlFLZ.js +0 -3220
- package/dist/web/assets/index-aL3cKxSK.css +0 -41
- package/docs/CHANGELOG.md +0 -582
- package/docs/DIRECTORY_MIGRATION.md +0 -112
- package/docs/PROJECT_STRUCTURE.md +0 -396
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式转换服务
|
|
3
|
+
*
|
|
4
|
+
* 支持 Claude Code ↔ Codex CLI 格式互转
|
|
5
|
+
* - Skills: SKILL.md 格式转换
|
|
6
|
+
* - Commands/Prompts: 命令/提示格式转换
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Codex CLI 限制
|
|
10
|
+
const CODEX_LIMITS = {
|
|
11
|
+
skillName: 100,
|
|
12
|
+
skillDescription: 500
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 解析 YAML frontmatter
|
|
17
|
+
* 支持基本的 YAML 解析和嵌套 metadata 对象
|
|
18
|
+
*/
|
|
19
|
+
function parseFrontmatter(content) {
|
|
20
|
+
const result = {
|
|
21
|
+
frontmatter: {},
|
|
22
|
+
body: content
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// 移除 BOM
|
|
26
|
+
content = content.trim().replace(/^\uFEFF/, '');
|
|
27
|
+
|
|
28
|
+
// 解析 YAML frontmatter
|
|
29
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/);
|
|
30
|
+
if (!match) {
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const frontmatterText = match[1];
|
|
35
|
+
result.body = match[2].trim();
|
|
36
|
+
|
|
37
|
+
// 解析 YAML(支持嵌套 metadata)
|
|
38
|
+
const lines = frontmatterText.split('\n');
|
|
39
|
+
let currentParent = null;
|
|
40
|
+
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
// 检测缩进(嵌套对象)
|
|
43
|
+
const indentMatch = line.match(/^(\s*)/);
|
|
44
|
+
const indent = indentMatch ? indentMatch[1].length : 0;
|
|
45
|
+
|
|
46
|
+
// 跳过空行
|
|
47
|
+
if (!line.trim()) continue;
|
|
48
|
+
|
|
49
|
+
const colonIndex = line.indexOf(':');
|
|
50
|
+
if (colonIndex === -1) continue;
|
|
51
|
+
|
|
52
|
+
const key = line.slice(0, colonIndex).trim();
|
|
53
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
54
|
+
|
|
55
|
+
// 检测是否是嵌套对象开始(值为空)
|
|
56
|
+
if (!value && indent === 0) {
|
|
57
|
+
currentParent = key;
|
|
58
|
+
result.frontmatter[key] = {};
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 处理嵌套属性
|
|
63
|
+
if (indent > 0 && currentParent && typeof result.frontmatter[currentParent] === 'object') {
|
|
64
|
+
// 去除引号
|
|
65
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
66
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
67
|
+
value = value.slice(1, -1);
|
|
68
|
+
}
|
|
69
|
+
result.frontmatter[currentParent][key] = value;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 重置当前父级
|
|
74
|
+
currentParent = null;
|
|
75
|
+
|
|
76
|
+
// 去除引号
|
|
77
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
78
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
79
|
+
value = value.slice(1, -1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
result.frontmatter[key] = value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 生成 YAML frontmatter 字符串
|
|
90
|
+
*/
|
|
91
|
+
function generateFrontmatter(data, format = 'claude') {
|
|
92
|
+
const lines = ['---'];
|
|
93
|
+
|
|
94
|
+
if (format === 'codex') {
|
|
95
|
+
// Codex 格式: name, description 必须,metadata 可选
|
|
96
|
+
if (data.name) {
|
|
97
|
+
lines.push(`name: "${escapeYamlString(data.name)}"`);
|
|
98
|
+
}
|
|
99
|
+
if (data.description) {
|
|
100
|
+
lines.push(`description: "${escapeYamlString(data.description)}"`);
|
|
101
|
+
}
|
|
102
|
+
if (data.metadata && Object.keys(data.metadata).length > 0) {
|
|
103
|
+
lines.push('metadata:');
|
|
104
|
+
for (const [key, value] of Object.entries(data.metadata)) {
|
|
105
|
+
lines.push(` ${key}: "${escapeYamlString(value)}"`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Codex commands/prompts 特有字段
|
|
109
|
+
if (data['argument-hint']) {
|
|
110
|
+
lines.push(`argument-hint: ${data['argument-hint']}`);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
// Claude Code 格式
|
|
114
|
+
if (data.name) {
|
|
115
|
+
lines.push(`name: "${escapeYamlString(data.name)}"`);
|
|
116
|
+
}
|
|
117
|
+
if (data.description) {
|
|
118
|
+
lines.push(`description: "${escapeYamlString(data.description)}"`);
|
|
119
|
+
}
|
|
120
|
+
if (data.license) {
|
|
121
|
+
lines.push(`license: "${escapeYamlString(data.license)}"`);
|
|
122
|
+
}
|
|
123
|
+
// Claude Code commands 特有字段
|
|
124
|
+
if (data['allowed-tools']) {
|
|
125
|
+
lines.push(`allowed-tools: ${data['allowed-tools']}`);
|
|
126
|
+
}
|
|
127
|
+
if (data['argument-hint']) {
|
|
128
|
+
lines.push(`argument-hint: ${data['argument-hint']}`);
|
|
129
|
+
}
|
|
130
|
+
if (data.model) {
|
|
131
|
+
lines.push(`model: ${data.model}`);
|
|
132
|
+
}
|
|
133
|
+
if (data.context) {
|
|
134
|
+
lines.push(`context: ${data.context}`);
|
|
135
|
+
}
|
|
136
|
+
if (data.agent) {
|
|
137
|
+
lines.push(`agent: ${data.agent}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
lines.push('---');
|
|
142
|
+
return lines.join('\n');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 转义 YAML 字符串中的特殊字符
|
|
147
|
+
*/
|
|
148
|
+
function escapeYamlString(str) {
|
|
149
|
+
if (!str) return '';
|
|
150
|
+
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 检测 Skill 格式
|
|
155
|
+
* @returns {'claude' | 'codex' | 'unknown'}
|
|
156
|
+
*/
|
|
157
|
+
function detectSkillFormat(content) {
|
|
158
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
159
|
+
|
|
160
|
+
// Codex 特征: 有 metadata 对象
|
|
161
|
+
if (frontmatter.metadata && typeof frontmatter.metadata === 'object') {
|
|
162
|
+
return 'codex';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Claude Code 特征: 有 allowed-tools 或 license
|
|
166
|
+
if (frontmatter['allowed-tools'] || frontmatter.license) {
|
|
167
|
+
return 'claude';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 两者都有 name 和 description,无法区分时默认 claude
|
|
171
|
+
if (frontmatter.name && frontmatter.description) {
|
|
172
|
+
return 'claude';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return 'unknown';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 检测 Command/Prompt 格式
|
|
180
|
+
* @returns {'claude' | 'codex' | 'unknown'}
|
|
181
|
+
*/
|
|
182
|
+
function detectCommandFormat(content) {
|
|
183
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
184
|
+
|
|
185
|
+
// Claude Code 特征: allowed-tools, model, context, agent, hooks
|
|
186
|
+
if (frontmatter['allowed-tools'] || frontmatter.model ||
|
|
187
|
+
frontmatter.context || frontmatter.agent || frontmatter.hooks) {
|
|
188
|
+
return 'claude';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Codex 特征: 只有 description 和 argument-hint
|
|
192
|
+
if (frontmatter.description && !frontmatter['allowed-tools']) {
|
|
193
|
+
return 'codex';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return 'unknown';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 转换 Skill: Claude Code → Codex CLI
|
|
201
|
+
*/
|
|
202
|
+
function convertSkillToCodex(claudeContent, options = {}) {
|
|
203
|
+
const { frontmatter, body } = parseFrontmatter(claudeContent);
|
|
204
|
+
const warnings = [];
|
|
205
|
+
|
|
206
|
+
// 处理字段
|
|
207
|
+
const codexData = {
|
|
208
|
+
name: frontmatter.name || '',
|
|
209
|
+
description: frontmatter.description || '',
|
|
210
|
+
metadata: {}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// 检查并截断 name
|
|
214
|
+
if (codexData.name.length > CODEX_LIMITS.skillName) {
|
|
215
|
+
warnings.push(`name 超过 ${CODEX_LIMITS.skillName} 字符,已截断`);
|
|
216
|
+
codexData.name = codexData.name.slice(0, CODEX_LIMITS.skillName);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 检查并截断 description
|
|
220
|
+
if (codexData.description.length > CODEX_LIMITS.skillDescription) {
|
|
221
|
+
warnings.push(`description 超过 ${CODEX_LIMITS.skillDescription} 字符,已截断`);
|
|
222
|
+
codexData.description = codexData.description.slice(0, CODEX_LIMITS.skillDescription);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 不支持的字段警告
|
|
226
|
+
if (frontmatter['allowed-tools']) {
|
|
227
|
+
warnings.push('allowed-tools 字段在 Codex 中不支持,已忽略');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 生成 Codex 格式内容
|
|
231
|
+
const codexFrontmatter = generateFrontmatter(codexData, 'codex');
|
|
232
|
+
const codexContent = codexFrontmatter + '\n\n' + body;
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
content: codexContent,
|
|
236
|
+
warnings,
|
|
237
|
+
format: 'codex'
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* 转换 Skill: Codex CLI → Claude Code
|
|
243
|
+
*/
|
|
244
|
+
function convertSkillToClaude(codexContent, options = {}) {
|
|
245
|
+
const { frontmatter, body } = parseFrontmatter(codexContent);
|
|
246
|
+
const warnings = [];
|
|
247
|
+
|
|
248
|
+
// 处理字段
|
|
249
|
+
const claudeData = {
|
|
250
|
+
name: frontmatter.name || '',
|
|
251
|
+
description: frontmatter.description || ''
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// 保留 metadata.short-description(如果有)作为注释
|
|
255
|
+
if (frontmatter.metadata && frontmatter.metadata['short-description']) {
|
|
256
|
+
// 可以选择将其添加到 description 或作为单独字段
|
|
257
|
+
warnings.push(`metadata.short-description 已保留: "${frontmatter.metadata['short-description']}"`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 生成 Claude Code 格式内容
|
|
261
|
+
const claudeFrontmatter = generateFrontmatter(claudeData, 'claude');
|
|
262
|
+
const claudeContent = claudeFrontmatter + '\n\n' + body;
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
content: claudeContent,
|
|
266
|
+
warnings,
|
|
267
|
+
format: 'claude'
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 转换 Command: Claude Code → Codex CLI (Custom Prompt)
|
|
273
|
+
*/
|
|
274
|
+
function convertCommandToCodex(claudeContent, options = {}) {
|
|
275
|
+
const { frontmatter, body } = parseFrontmatter(claudeContent);
|
|
276
|
+
const warnings = [];
|
|
277
|
+
|
|
278
|
+
// 处理字段
|
|
279
|
+
const codexData = {
|
|
280
|
+
description: frontmatter.description || ''
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// argument-hint 两者都支持
|
|
284
|
+
if (frontmatter['argument-hint']) {
|
|
285
|
+
codexData['argument-hint'] = frontmatter['argument-hint'];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 不支持的字段警告
|
|
289
|
+
const unsupportedFields = ['allowed-tools', 'model', 'context', 'agent', 'hooks'];
|
|
290
|
+
for (const field of unsupportedFields) {
|
|
291
|
+
if (frontmatter[field]) {
|
|
292
|
+
warnings.push(`${field} 字段在 Codex 中不支持,已忽略`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 检查 body 中的 Claude Code 特有语法
|
|
297
|
+
let processedBody = body;
|
|
298
|
+
|
|
299
|
+
// 检测 Bash 执行语法 !`command`
|
|
300
|
+
if (/!\`[^`]+\`/.test(body)) {
|
|
301
|
+
warnings.push('Bash 执行语法 !`command` 在 Codex 中不支持,请手动替换');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// 检测文件引用语法 @filepath
|
|
305
|
+
if (/@[^\s]+/.test(body)) {
|
|
306
|
+
warnings.push('文件引用语法 @filepath 在 Codex 中不支持,请手动替换');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 生成 Codex 格式内容
|
|
310
|
+
let codexContent = '';
|
|
311
|
+
if (codexData.description || codexData['argument-hint']) {
|
|
312
|
+
codexContent = generateFrontmatter(codexData, 'codex') + '\n\n';
|
|
313
|
+
}
|
|
314
|
+
codexContent += processedBody;
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
content: codexContent,
|
|
318
|
+
warnings,
|
|
319
|
+
format: 'codex'
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 转换 Command: Codex CLI (Custom Prompt) → Claude Code
|
|
325
|
+
*/
|
|
326
|
+
function convertCommandToClaude(codexContent, options = {}) {
|
|
327
|
+
const { frontmatter, body } = parseFrontmatter(codexContent);
|
|
328
|
+
const warnings = [];
|
|
329
|
+
|
|
330
|
+
// 处理字段
|
|
331
|
+
const claudeData = {
|
|
332
|
+
description: frontmatter.description || ''
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// argument-hint 两者都支持
|
|
336
|
+
if (frontmatter['argument-hint']) {
|
|
337
|
+
claudeData['argument-hint'] = frontmatter['argument-hint'];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Codex 命名参数 $KEY 在 Claude Code 中也支持,无需转换
|
|
341
|
+
|
|
342
|
+
// 生成 Claude Code 格式内容
|
|
343
|
+
let claudeContent = '';
|
|
344
|
+
if (claudeData.description || claudeData['argument-hint']) {
|
|
345
|
+
claudeContent = generateFrontmatter(claudeData, 'claude') + '\n\n';
|
|
346
|
+
}
|
|
347
|
+
claudeContent += body;
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
content: claudeContent,
|
|
351
|
+
warnings,
|
|
352
|
+
format: 'claude'
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* 批量转换 Skills
|
|
358
|
+
*/
|
|
359
|
+
function convertSkillsBatch(skills, targetFormat) {
|
|
360
|
+
const results = [];
|
|
361
|
+
|
|
362
|
+
for (const skill of skills) {
|
|
363
|
+
try {
|
|
364
|
+
const converted = targetFormat === 'codex'
|
|
365
|
+
? convertSkillToCodex(skill.content)
|
|
366
|
+
: convertSkillToClaude(skill.content);
|
|
367
|
+
|
|
368
|
+
results.push({
|
|
369
|
+
name: skill.name,
|
|
370
|
+
success: true,
|
|
371
|
+
...converted
|
|
372
|
+
});
|
|
373
|
+
} catch (err) {
|
|
374
|
+
results.push({
|
|
375
|
+
name: skill.name,
|
|
376
|
+
success: false,
|
|
377
|
+
error: err.message
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return results;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* 批量转换 Commands
|
|
387
|
+
*/
|
|
388
|
+
function convertCommandsBatch(commands, targetFormat) {
|
|
389
|
+
const results = [];
|
|
390
|
+
|
|
391
|
+
for (const command of commands) {
|
|
392
|
+
try {
|
|
393
|
+
const converted = targetFormat === 'codex'
|
|
394
|
+
? convertCommandToCodex(command.content)
|
|
395
|
+
: convertCommandToClaude(command.content);
|
|
396
|
+
|
|
397
|
+
results.push({
|
|
398
|
+
name: command.name,
|
|
399
|
+
success: true,
|
|
400
|
+
...converted
|
|
401
|
+
});
|
|
402
|
+
} catch (err) {
|
|
403
|
+
results.push({
|
|
404
|
+
name: command.name,
|
|
405
|
+
success: false,
|
|
406
|
+
error: err.message
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return results;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* 解析 Skill 内容(支持双格式)
|
|
416
|
+
*/
|
|
417
|
+
function parseSkillContent(content) {
|
|
418
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
419
|
+
const format = detectSkillFormat(content);
|
|
420
|
+
|
|
421
|
+
const result = {
|
|
422
|
+
name: frontmatter.name || '',
|
|
423
|
+
description: frontmatter.description || '',
|
|
424
|
+
body,
|
|
425
|
+
fullContent: content,
|
|
426
|
+
format
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// 处理 Codex 特有字段
|
|
430
|
+
if (frontmatter.metadata) {
|
|
431
|
+
result.metadata = frontmatter.metadata;
|
|
432
|
+
if (frontmatter.metadata['short-description']) {
|
|
433
|
+
result.shortDescription = frontmatter.metadata['short-description'];
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 处理 Claude Code 特有字段
|
|
438
|
+
if (frontmatter['allowed-tools']) {
|
|
439
|
+
result.allowedTools = frontmatter['allowed-tools'];
|
|
440
|
+
}
|
|
441
|
+
if (frontmatter.license) {
|
|
442
|
+
result.license = frontmatter.license;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* 解析 Command 内容(支持双格式)
|
|
450
|
+
*/
|
|
451
|
+
function parseCommandContent(content) {
|
|
452
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
453
|
+
const format = detectCommandFormat(content);
|
|
454
|
+
|
|
455
|
+
const result = {
|
|
456
|
+
description: frontmatter.description || '',
|
|
457
|
+
argumentHint: frontmatter['argument-hint'] || '',
|
|
458
|
+
body,
|
|
459
|
+
fullContent: content,
|
|
460
|
+
format
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// 处理 Claude Code 特有字段
|
|
464
|
+
if (frontmatter['allowed-tools']) {
|
|
465
|
+
result.allowedTools = frontmatter['allowed-tools'];
|
|
466
|
+
}
|
|
467
|
+
if (frontmatter.model) {
|
|
468
|
+
result.model = frontmatter.model;
|
|
469
|
+
}
|
|
470
|
+
if (frontmatter.context) {
|
|
471
|
+
result.context = frontmatter.context;
|
|
472
|
+
}
|
|
473
|
+
if (frontmatter.agent) {
|
|
474
|
+
result.agent = frontmatter.agent;
|
|
475
|
+
}
|
|
476
|
+
if (frontmatter.hooks) {
|
|
477
|
+
result.hooks = frontmatter.hooks;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
module.exports = {
|
|
484
|
+
// 格式检测
|
|
485
|
+
detectSkillFormat,
|
|
486
|
+
detectCommandFormat,
|
|
487
|
+
|
|
488
|
+
// Skills 转换
|
|
489
|
+
convertSkillToCodex,
|
|
490
|
+
convertSkillToClaude,
|
|
491
|
+
convertSkillsBatch,
|
|
492
|
+
|
|
493
|
+
// Commands 转换
|
|
494
|
+
convertCommandToCodex,
|
|
495
|
+
convertCommandToClaude,
|
|
496
|
+
convertCommandsBatch,
|
|
497
|
+
|
|
498
|
+
// 通用解析(支持双格式)
|
|
499
|
+
parseSkillContent,
|
|
500
|
+
parseCommandContent,
|
|
501
|
+
parseFrontmatter,
|
|
502
|
+
generateFrontmatter,
|
|
503
|
+
|
|
504
|
+
// 常量
|
|
505
|
+
CODEX_LIMITS
|
|
506
|
+
};
|