feat: 品牌替换 + 启动优化 + AGENTS.md 模板定制

- 品牌替换:OpenCode/opencode → AirCoding/aircoding(16+ 文件)
- Logo ASCII art:修复 left/right 行数不匹配导致的启动崩溃
- 启动诊断:添加 OPENCODE_PRINT_TIMING 计时探针
- dev 模式默认 --pure 跳过外部插件加载
- AGENTS.md 模板:追加 AirCoding 多 Agent 专项段落
- architect prompt + plugin:强化 AGENTS.md 产出验证
This commit is contained in:
airlongdian
2026-06-14 09:31:29 +08:00
commit e2fd375a1c
5757 changed files with 1170016 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
export const kebab = (value: string) =>
value
.trim()
.replace(/['"]/g, "")
.replace(/[^a-zA-Z0-9]+/g, "-")
.replace(/^-|-$/g, "")
.toLowerCase()
export const missingEnv = (names: ReadonlyArray<string>) => names.filter((name) => !process.env[name])
export const envList = (name: string) =>
(process.env[name] ?? "")
.split(",")
.map((item) => item.trim().toLowerCase())
.filter((item) => item !== "")
export const unique = (items: ReadonlyArray<string>) => Array.from(new Set(items))
export const classifiedTags = (input: {
readonly prefix?: string
readonly provider?: string
readonly protocol?: string
readonly tags?: ReadonlyArray<string>
}) =>
unique([
...(input.prefix ? [`prefix:${input.prefix}`] : []),
...(input.provider ? [`provider:${input.provider}`] : []),
...(input.protocol ? [`protocol:${input.protocol}`] : []),
...(input.tags ?? []),
])
export const matchesSelected = (input: {
readonly prefix: string
readonly name: string
readonly cassette: string
readonly tags: ReadonlyArray<string>
}) => {
const prefixes = envList("RECORDED_PREFIX")
const providers = envList("RECORDED_PROVIDER")
const requiredTags = envList("RECORDED_TAGS")
const tests = envList("RECORDED_TEST")
const tags = input.tags.map((tag) => tag.toLowerCase())
const names = [input.name, kebab(input.name), input.cassette].map((item) => item.toLowerCase())
if (prefixes.length > 0 && !prefixes.includes(input.prefix.toLowerCase())) return false
if (providers.length > 0 && !providers.some((provider) => tags.includes(`provider:${provider}`))) return false
if (requiredTags.length > 0 && !requiredTags.every((tag) => tags.includes(tag))) return false
if (tests.length > 0 && !tests.some((test) => names.some((name) => name.includes(test)))) return false
return true
}
export const cassetteName = (
prefix: string,
name: string,
options: { readonly cassette?: string; readonly id?: string },
) => options.cassette ?? `${prefix}/${options.id ?? kebab(name)}`