jsharness 1.10.0 → 1.11.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/lib/index.mjs +77 -19
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -107,7 +107,7 @@ export const SUPPORTED_TOOLS = [
|
|
|
107
107
|
priority: 88,
|
|
108
108
|
ruleFormat: 'markdown',
|
|
109
109
|
skillFormat: 'markdown',
|
|
110
|
-
commandFormat:
|
|
110
|
+
commandFormat: null,
|
|
111
111
|
subagentFormat: 'md',
|
|
112
112
|
},
|
|
113
113
|
];
|
|
@@ -345,6 +345,30 @@ const SKILL_TRANSFORMERS = {
|
|
|
345
345
|
return { format: 'reference', files: outputs };
|
|
346
346
|
},
|
|
347
347
|
|
|
348
|
+
copilot(skillFiles, opts) {
|
|
349
|
+
// Copilot 不支持独立 skills 目录,合并为 Markdown 段落
|
|
350
|
+
let content = '';
|
|
351
|
+
for (const file of skillFiles) {
|
|
352
|
+
const raw = fs.readFileSync(file.path, 'utf-8');
|
|
353
|
+
const skillName = inferSkillName(file);
|
|
354
|
+
const description = parseFrontmatter(raw).description || extractDescription(raw) || skillName;
|
|
355
|
+
content += `### ${skillName}\n\n> ${description}\n\n${extractBody(raw)}\n\n`;
|
|
356
|
+
}
|
|
357
|
+
return { format: 'merged-section', sectionName: 'Skills', content };
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
codex(skillFiles, opts) {
|
|
361
|
+
// Codex CLI 不支持独立 skills 目录,合并为 Markdown 段落
|
|
362
|
+
let content = '';
|
|
363
|
+
for (const file of skillFiles) {
|
|
364
|
+
const raw = fs.readFileSync(file.path, 'utf-8');
|
|
365
|
+
const skillName = inferSkillName(file);
|
|
366
|
+
const description = parseFrontmatter(raw).description || extractDescription(raw) || skillName;
|
|
367
|
+
content += `### ${skillName}\n\n> ${description}\n\n${extractBody(raw)}\n\n`;
|
|
368
|
+
}
|
|
369
|
+
return { format: 'merged-section', sectionName: 'Skills', content };
|
|
370
|
+
},
|
|
371
|
+
|
|
348
372
|
qoder(skillFiles, opts) {
|
|
349
373
|
const outputs = [];
|
|
350
374
|
for (const file of skillFiles) {
|
|
@@ -492,16 +516,15 @@ const COMMAND_TRANSFORMERS = {
|
|
|
492
516
|
},
|
|
493
517
|
|
|
494
518
|
augment(commandFiles, opts) {
|
|
495
|
-
|
|
519
|
+
// Augment 不支持独立 commands 目录,合并为 Markdown 段落
|
|
520
|
+
let content = '';
|
|
496
521
|
for (const file of commandFiles) {
|
|
497
522
|
const raw = fs.readFileSync(file.path, 'utf-8');
|
|
498
523
|
const cmdName = inferCommandName(file);
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
let content = `---\nname: ${cmdName}\ndescription: ${description}\ntrigger_type: manual\n---\n\n${extractBody(raw)}`;
|
|
502
|
-
outputs.push({ relativePath: `.augment/skills/${cmdName}/SKILL.md`, content, source: file.path });
|
|
524
|
+
const description = parseFrontmatter(raw).description || extractDescription(raw) || cmdName;
|
|
525
|
+
content += `### ${cmdName}\n\n> ${description}\n\n${extractBody(raw)}\n\n`;
|
|
503
526
|
}
|
|
504
|
-
return { format: '
|
|
527
|
+
return { format: 'merged-section', sectionName: 'Commands', content };
|
|
505
528
|
},
|
|
506
529
|
|
|
507
530
|
copilot(commandFiles, opts) {
|
|
@@ -928,6 +951,30 @@ function inferAgentName(file) {
|
|
|
928
951
|
return file.name.replace(/\.md$/, '') || 'unknown';
|
|
929
952
|
}
|
|
930
953
|
|
|
954
|
+
/**
|
|
955
|
+
* 将 command 内容转为 skill 格式输出(用于不支持 commands 目录的工具)
|
|
956
|
+
* 根据工具类型决定输出路径和 frontmatter 格式
|
|
957
|
+
*/
|
|
958
|
+
function buildCommandAsSkill(toolId, cmdName, description, body) {
|
|
959
|
+
const skillPaths = {
|
|
960
|
+
'claude-code': `.claude/skills/cmd-${cmdName}/SKILL.md`,
|
|
961
|
+
augment: `.augment/skills/cmd-${cmdName}/SKILL.md`,
|
|
962
|
+
};
|
|
963
|
+
const relativePath = skillPaths[toolId] || `.harness/skills/cmd-${cmdName}/SKILL.md`;
|
|
964
|
+
|
|
965
|
+
// 根据工具类型构建不同的 frontmatter
|
|
966
|
+
let frontmatter;
|
|
967
|
+
if (toolId === 'claude-code') {
|
|
968
|
+
frontmatter = `---\nname: cmd-${cmdName}\ndescription: ${description}\ntrigger_type: manual\n---`;
|
|
969
|
+
} else if (toolId === 'augment') {
|
|
970
|
+
frontmatter = `---\nname: cmd-${cmdName}\ndescription: ${description}\n---`;
|
|
971
|
+
} else {
|
|
972
|
+
frontmatter = `---\nname: cmd-${cmdName}\ndescription: ${description}\nalwaysApply: false\nenabled: true\n---`;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
return { relativePath, content: `${frontmatter}\n\n${body}` };
|
|
976
|
+
}
|
|
977
|
+
|
|
931
978
|
/**
|
|
932
979
|
* 从 frontmatter 和原始内容构建 agent 元数据
|
|
933
980
|
* 统一提取 name/description/tools/model/agentMode/enabled/enabledAutoRun/maxTurns/scope/safetyLevel
|
|
@@ -1683,10 +1730,13 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1683
1730
|
// 不支持独立 skills 的工具:合并到 rules 输出
|
|
1684
1731
|
console.log(`⚡ 合并技能到规则 (${allSkills.length} 个)...`);
|
|
1685
1732
|
const skillMerged = transformSkills(allSkills, tool.id, transformOpts);
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1733
|
+
const rulesOutput = outputs.find(o => o.relativePath === getRulesOutputPath(tool.id));
|
|
1734
|
+
if (rulesOutput) {
|
|
1735
|
+
if (skillMerged.format === 'merged-section') {
|
|
1736
|
+
// merged-section 格式:直接拼接 sectionName + content
|
|
1737
|
+
rulesOutput.content += `\n---\n\n## ${skillMerged.sectionName}\n\n${skillMerged.content}`;
|
|
1738
|
+
} else if (skillMerged.files && skillMerged.files.length > 0) {
|
|
1739
|
+
// directory/reference 格式:逐个拼接 body 内容
|
|
1690
1740
|
rulesOutput.content += '\n---\n\n## Skills\n\n';
|
|
1691
1741
|
for (const sf of skillMerged.files) {
|
|
1692
1742
|
rulesOutput.content += sf.content + '\n\n';
|
|
@@ -1702,21 +1752,29 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1702
1752
|
console.log(`🔧 注入命令 (${allCommandFiles.length} 个)...`);
|
|
1703
1753
|
outputs.push(...transformCommands(allCommandFiles, tool.id, transformOpts).files);
|
|
1704
1754
|
} else {
|
|
1705
|
-
// 不支持独立 commands
|
|
1706
|
-
console.log(`🔧
|
|
1755
|
+
// 不支持独立 commands 的工具
|
|
1756
|
+
console.log(`🔧 合并命令 (${allCommandFiles.length} 个)...`);
|
|
1707
1757
|
const cmdResult = transformCommands(allCommandFiles, tool.id, transformOpts);
|
|
1708
1758
|
if (cmdResult.format === 'merged-section') {
|
|
1759
|
+
// merged-section:尝试合并到 rules 单文件
|
|
1709
1760
|
const rulesOutput = outputs.find(o => o.relativePath === getRulesOutputPath(tool.id));
|
|
1710
1761
|
if (rulesOutput) {
|
|
1711
1762
|
rulesOutput.content += `\n---\n\n## ${cmdResult.sectionName}\n\n${cmdResult.content}`;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1763
|
+
} else {
|
|
1764
|
+
// rules 是 directory 格式,无法合并到单文件 → 转为独立 skill 文件输出
|
|
1765
|
+
console.log(` 📎 命令转存为技能文件...`);
|
|
1766
|
+
for (const file of allCommandFiles) {
|
|
1767
|
+
const raw = fs.readFileSync(file.path, 'utf-8');
|
|
1768
|
+
const cmdName = inferCommandName(file);
|
|
1769
|
+
const description = parseFrontmatter(raw).description || extractDescription(raw) || cmdName;
|
|
1770
|
+
const body = extractBody(raw);
|
|
1771
|
+
const cmdAsSkill = buildCommandAsSkill(tool.id, cmdName, description, body);
|
|
1772
|
+
outputs.push(cmdAsSkill);
|
|
1718
1773
|
}
|
|
1719
1774
|
}
|
|
1775
|
+
} else if (cmdResult.files && cmdResult.files.length > 0) {
|
|
1776
|
+
// directory 格式:直接作为独立文件输出
|
|
1777
|
+
outputs.push(...cmdResult.files);
|
|
1720
1778
|
}
|
|
1721
1779
|
}
|
|
1722
1780
|
}
|
package/package.json
CHANGED