fix: sanitize colons in skill/agent names for Windows path compatibility (#398)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import path from "path"
|
||||
import type { ClaudeHomeConfig } from "../parsers/claude-home"
|
||||
import type { ClaudePlugin } from "../types/claude"
|
||||
import { backupFile, writeText } from "../utils/files"
|
||||
import { backupFile, resolveCommandPath, sanitizePathName, writeText } from "../utils/files"
|
||||
import { convertClaudeToCodex } from "../converters/claude-to-codex"
|
||||
import { convertClaudeToCopilot } from "../converters/claude-to-copilot"
|
||||
import { convertClaudeToDroid } from "../converters/claude-to-droid"
|
||||
@@ -57,7 +57,7 @@ export async function syncOpenCodeCommands(
|
||||
const bundle = convertClaudeToOpenCode(plugin, DEFAULT_SYNC_OPTIONS)
|
||||
|
||||
for (const commandFile of bundle.commandFiles) {
|
||||
const commandPath = path.join(outputRoot, "commands", `${commandFile.name}.md`)
|
||||
const commandPath = await resolveCommandPath(path.join(outputRoot, "commands"), commandFile.name, ".md")
|
||||
const backupPath = await backupFile(commandPath)
|
||||
if (backupPath) {
|
||||
console.log(`Backed up existing command file to ${backupPath}`)
|
||||
@@ -78,7 +78,7 @@ export async function syncCodexCommands(
|
||||
await writeText(path.join(outputRoot, "prompts", `${prompt.name}.md`), prompt.content + "\n")
|
||||
}
|
||||
for (const skill of bundle.generatedSkills) {
|
||||
await writeText(path.join(outputRoot, "skills", skill.name, "SKILL.md"), skill.content + "\n")
|
||||
await writeText(path.join(outputRoot, "skills", sanitizePathName(skill.name), "SKILL.md"), skill.content + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ export async function syncCopilotCommands(
|
||||
const bundle = convertClaudeToCopilot(plugin, DEFAULT_SYNC_OPTIONS)
|
||||
|
||||
for (const skill of bundle.generatedSkills) {
|
||||
await writeText(path.join(outputRoot, "skills", skill.name, "SKILL.md"), skill.content + "\n")
|
||||
await writeText(path.join(outputRoot, "skills", sanitizePathName(skill.name), "SKILL.md"), skill.content + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ export async function syncKiroCommands(
|
||||
const plugin = buildClaudeHomePlugin(config)
|
||||
const bundle = convertClaudeToKiro(plugin, DEFAULT_SYNC_OPTIONS)
|
||||
for (const skill of bundle.generatedSkills) {
|
||||
await writeText(path.join(outputRoot, "skills", skill.name, "SKILL.md"), skill.content + "\n")
|
||||
await writeText(path.join(outputRoot, "skills", sanitizePathName(skill.name), "SKILL.md"), skill.content + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import type { ClaudeHomeConfig } from "../parsers/claude-home"
|
||||
import type { ClaudeMcpServer } from "../types/claude"
|
||||
import { sanitizePathName } from "../utils/files"
|
||||
import { syncGeminiCommands } from "./commands"
|
||||
import { mergeJsonConfigAtKey } from "./json-config"
|
||||
import { syncSkills } from "./skills"
|
||||
@@ -85,7 +86,7 @@ async function removeGeminiMirrorConflicts(
|
||||
sharedSkillsDir: string,
|
||||
): Promise<void> {
|
||||
for (const skill of skills) {
|
||||
const duplicatePath = path.join(skillsDir, skill.name)
|
||||
const duplicatePath = path.join(skillsDir, sanitizePathName(skill.name))
|
||||
|
||||
let stat
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from "path"
|
||||
import type { ClaudeSkill } from "../types/claude"
|
||||
import { ensureDir } from "../utils/files"
|
||||
import { ensureDir, sanitizePathName } from "../utils/files"
|
||||
import { forceSymlink, isValidSkillName } from "../utils/symlink"
|
||||
|
||||
export async function syncSkills(
|
||||
@@ -9,13 +9,21 @@ export async function syncSkills(
|
||||
): Promise<void> {
|
||||
await ensureDir(skillsDir)
|
||||
|
||||
const seen = new Set<string>()
|
||||
for (const skill of skills) {
|
||||
if (!isValidSkillName(skill.name)) {
|
||||
console.warn(`Skipping skill with invalid name: ${skill.name}`)
|
||||
continue
|
||||
}
|
||||
|
||||
const target = path.join(skillsDir, skill.name)
|
||||
const safeName = sanitizePathName(skill.name)
|
||||
if (seen.has(safeName)) {
|
||||
console.warn(`Skipping skill "${skill.name}": sanitized name "${safeName}" collides with another skill`)
|
||||
continue
|
||||
}
|
||||
seen.add(safeName)
|
||||
|
||||
const target = path.join(skillsDir, safeName)
|
||||
await forceSymlink(skill.sourceDir, target)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user