mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 16:25:51 +00:00
Merge branch 'main' into feature/docker/run
This commit is contained in:
@@ -14,6 +14,39 @@ let currentModeSlug: string | null = null
|
|||||||
let customModes: CCBMode[] | null = null
|
let customModes: CCBMode[] | null = null
|
||||||
const modeListeners = new Set<() => void>()
|
const modeListeners = new Set<() => void>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a human-readable name to a URL-safe slug.
|
||||||
|
* @example kebabCase('Claude Persona') → 'claude-persona'
|
||||||
|
*/
|
||||||
|
function kebabCase(name: string): string {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts YAML frontmatter and Markdown body from a string.
|
||||||
|
* Expects the format used by Claude Code SKILL.md, OpenCode agents,
|
||||||
|
* and Cursor rules: `---` delimited YAML followed by Markdown content.
|
||||||
|
*
|
||||||
|
* @throws {Error} If the string does not contain valid `---` delimiters.
|
||||||
|
* @returns The parsed frontmatter object and the body text.
|
||||||
|
*/
|
||||||
|
function parseMarkdownFrontmatter(raw: string): {
|
||||||
|
frontmatter: Record<string, unknown>
|
||||||
|
body: string
|
||||||
|
} {
|
||||||
|
const parts = raw.split(/^---$/m)
|
||||||
|
if (parts.length < 3) {
|
||||||
|
throw new Error('Invalid markdown frontmatter: missing --- delimiters')
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
frontmatter: parseYaml(parts[1]) as Record<string, unknown>,
|
||||||
|
body: parts.slice(2).join('---').trim(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadCustomModes(): CCBMode[] {
|
function loadCustomModes(): CCBMode[] {
|
||||||
if (customModes !== null) return customModes
|
if (customModes !== null) return customModes
|
||||||
customModes = []
|
customModes = []
|
||||||
@@ -23,12 +56,22 @@ function loadCustomModes(): CCBMode[] {
|
|||||||
mkdirSync(modesDir, { recursive: true })
|
mkdirSync(modesDir, { recursive: true })
|
||||||
}
|
}
|
||||||
const files = readdirSync(modesDir).filter(
|
const files = readdirSync(modesDir).filter(
|
||||||
f => f.endsWith('.yaml') || f.endsWith('.yml'),
|
f => f.endsWith('.yaml') || f.endsWith('.yml') || f.endsWith('.md'),
|
||||||
)
|
)
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
try {
|
try {
|
||||||
const raw = readFileSync(join(modesDir, file), 'utf-8')
|
const raw = readFileSync(join(modesDir, file), 'utf-8')
|
||||||
const data = parseYaml(raw) as Record<string, unknown>
|
let data: Record<string, unknown>
|
||||||
|
if (file.endsWith('.md')) {
|
||||||
|
const { frontmatter, body } = parseMarkdownFrontmatter(raw)
|
||||||
|
data = { ...frontmatter, system_prompt: body }
|
||||||
|
if (!data.slug) {
|
||||||
|
data.slug = data.name ? kebabCase(String(data.name)) : ''
|
||||||
|
}
|
||||||
|
data.icon = data.icon || '🤖'
|
||||||
|
} else {
|
||||||
|
data = parseYaml(raw) as Record<string, unknown>
|
||||||
|
}
|
||||||
if (!data.slug || !data.name) continue
|
if (!data.slug || !data.name) continue
|
||||||
customModes.push({
|
customModes.push({
|
||||||
name: String(data.name),
|
name: String(data.name),
|
||||||
@@ -36,6 +79,7 @@ function loadCustomModes(): CCBMode[] {
|
|||||||
description: String(data.description || ''),
|
description: String(data.description || ''),
|
||||||
icon: String(data.icon || '🔧'),
|
icon: String(data.icon || '🔧'),
|
||||||
systemPrompt: String(data.system_prompt || ''),
|
systemPrompt: String(data.system_prompt || ''),
|
||||||
|
model: data.model ? String(data.model) : undefined,
|
||||||
ui: {
|
ui: {
|
||||||
accentColor: String(
|
accentColor: String(
|
||||||
(data.ui as Record<string, unknown>)?.accent_color || '#00D4AA',
|
(data.ui as Record<string, unknown>)?.accent_color || '#00D4AA',
|
||||||
@@ -62,7 +106,7 @@ function loadCustomModes(): CCBMode[] {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch {
|
} catch {
|
||||||
// skip invalid yaml files
|
// skip invalid yaml or markdown files
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface CCBMode {
|
|||||||
description: string
|
description: string
|
||||||
icon: string
|
icon: string
|
||||||
systemPrompt: string
|
systemPrompt: string
|
||||||
|
model?: string
|
||||||
ui: {
|
ui: {
|
||||||
accentColor: string
|
accentColor: string
|
||||||
promptPrefix: string
|
promptPrefix: string
|
||||||
|
|||||||
Reference in New Issue
Block a user