claude-code-best/src/jobs/templates.ts
claude-code-best c8d08d235b
Feat/integrate lint preview (#285)
* feat: 适配 zed acp 协议

* docs: 完善 acp 文档

* feat: integrate feature branches + daemon/job 命令层级化 + 跨平台后台引擎

Cherry-picked from origin/lint/preview (637c908), excluding lint-only changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: correct detectMimeFromBase64 to decode raw bytes from base64

Cherry-picked from origin/lint/preview (ee36954).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: daemon 子进程 spawn 跨平台修复 + CliLaunchSpec 集中化重构

Cherry-picked from origin/lint/preview (c5f52cd), excluding lint-only formatting changes.

- 新建 src/utils/cliLaunch.ts: 集中化 CLI 子进程启动层
- 修复 --daemon-worker=kind 等号格式解析
- 修复 daemon/bg fast path 缺少 setShellIfWindows()
- 修复 checkPathExists 用 existsSync 替代 execSync('dir')
- 7 个 spawn 站点迁移到 CliLaunchSpec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: merge tsconfig.base.json into tsconfig.json with full compiler options

The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing
tsconfig.base.json. This commit restores them in a single tsconfig.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: merge tsconfig.base.json into tsconfig.json with full compiler options

The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing
tsconfig.base.json. This commit restores them in a single tsconfig.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:59:29 +08:00

87 lines
2.2 KiB
TypeScript

import { readdirSync, readFileSync } from 'fs'
import { join, basename } from 'path'
import { parseFrontmatter } from '../utils/frontmatterParser.js'
import type { FrontmatterData } from '../utils/frontmatterParser.js'
import { getClaudeConfigHomeDir } from '../utils/envUtils.js'
import {
getProjectDirsUpToHome,
extractDescriptionFromMarkdown,
type ClaudeConfigDirectory,
} from '../utils/markdownConfigLoader.js'
export interface TemplateInfo {
name: string
description: string
filePath: string
frontmatter: FrontmatterData
content: string
}
/**
* Discover .claude/templates directories from CWD up to git root,
* plus the user-level ~/.claude/templates.
*/
function getTemplatesDirs(): string[] {
const projectDirs = getProjectDirsUpToHome(
'templates' as ClaudeConfigDirectory,
process.cwd(),
)
// User-level dir (getProjectDirsUpToHome stops before home)
const userDir = join(getClaudeConfigHomeDir(), 'templates')
try {
readdirSync(userDir)
return [...projectDirs, userDir]
} catch {
return projectDirs
}
}
/**
* List all available templates.
*/
export function listTemplates(): TemplateInfo[] {
const templates: TemplateInfo[] = []
const seenNames = new Set<string>()
for (const dir of getTemplatesDirs()) {
let files: string[]
try {
files = readdirSync(dir)
} catch {
continue
}
for (const file of files) {
if (!file.endsWith('.md')) continue
const name = basename(file, '.md')
if (seenNames.has(name)) continue
seenNames.add(name)
const filePath = join(dir, file)
try {
const raw = readFileSync(filePath, 'utf-8')
const { frontmatter, content } = parseFrontmatter(raw, filePath)
const description =
(typeof frontmatter.description === 'string'
? frontmatter.description
: '') || extractDescriptionFromMarkdown(content, 'No description')
templates.push({ name, description, filePath, frontmatter, content })
} catch {
// Skip unreadable files
}
}
}
return templates
}
/**
* Load a specific template by name.
*/
export function loadTemplate(name: string): TemplateInfo | null {
const all = listTemplates()
return all.find(t => t.name === name) ?? null
}