repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import { readJSONSync, writeJSONSync } from 'fs-extra'; |
| #2 | import { merge } from 'lodash-es'; |
| #3 | import { Dirent, copyFileSync, existsSync } from 'node:fs'; |
| #4 | import { resolve } from 'node:path'; |
| #5 | import pMap from 'p-map'; |
| #6 | import { zodToJsonSchema } from 'zod-to-json-schema'; |
| #7 | |
| #8 | import { agents, config, localesDir, meta, publicDir, root, schemasDir } from '../core/constants'; |
| #9 | import { AgentParser } from '../parsers/agent-parser'; |
| #10 | import { ClawdAgent, clawdAgentSchema } from '../schema/agentMeta'; |
| #11 | import { findDuplicates } from '../utils/common'; |
| #12 | import { |
| #13 | checkDir, |
| #14 | checkJSON, |
| #15 | getBuildLocaleAgentFileName, |
| #16 | getLocaleAgentFileName, |
| #17 | } from '../utils/file'; |
| #18 | import { Logger } from '../utils/logger'; |
| #19 | import { updateAgentWithTokenUsage } from '../utils/token'; |
| #20 | |
| #21 | /** |
| #22 | * Agent 构建器类 |
| #23 | * 负责构建所有语言版本的 Agent 文件和索引 |
| #24 | */ |
| #25 | class AgentBuilder { |
| #26 | private agents: Dirent[]; |
| #27 | |
| #28 | constructor(agents: Dirent[]) { |
| #29 | checkDir(publicDir); |
| #30 | this.agents = agents; |
| #31 | } |
| #32 | |
| #33 | /** |
| #34 | * 构建指定语言的 Agent 文件 |
| #35 | * @param locale 语言代码 |
| #36 | * @returns Agent 索引数组 |
| #37 | */ |
| #38 | private buildSingleLocaleAgents = async (locale: string) => { |
| #39 | // 并行处理所有 JSON 文件 |
| #40 | const agentIndex = await pMap( |
| #41 | this.agents.filter((file) => checkJSON(file)), |
| #42 | async (file) => { |
| #43 | const { content, id } = AgentParser.parseFile(file.name); |
| #44 | const localeFileName = getLocaleAgentFileName(id, locale); |
| #45 | |
| #46 | // 查找正确的 Agent 内容 |
| #47 | let agent: LobeAgent; |
| #48 | |
| #49 | // 如果本地化文件不存在,跳过 |
| #50 | const filePath = resolve(localesDir, localeFileName); |
| #51 | if (!existsSync(filePath)) return null; |
| #52 | |
| #53 | // 合并默认 Agent 与本地化数据 |
| #54 | const data = readJSONSync(filePath); |
| #55 | agent = merge({}, content, data); |
| #56 | |
| #57 | // 计算并添加 token 使用量 |
| #58 | agent = updateAgentWithTokenUsage(agent); |
| #59 | |
| #60 | // Add openingMessage and openingQuestions at root level (LobeHub compatibility) |
| #61 | if (agent.config?.openingMessage) { |
| #62 | agent.openingMessage = agent.config.openingMessage; |
| #63 | } |
| #64 | if (agent.config?.openingQuestions) { |
| #65 | agent.openingQuestions = agent.config.openingQuestions; |
| #66 | } |
| #67 | |
| #68 | // 写入 Agent 文件到 public 目录 |
| #69 | if (locale === config.entryLocale) { |
| #70 | writeJSONSync(resolve(publicDir, `${id}.en-US.json`), agent, { spaces: 2 }); |
| #71 | } |
| #72 | writeJSONSync(resolve(publicDir, getBuildLocaleAgentFileName(id, locale)), agent, { spaces: 2 }); |
| #73 | |
| #74 | // 返回 Agent 元数据 |
| #75 | return { |
| #76 | author: agent.author, |
| #77 | createdAt: agent.createdAt, |
| #78 | homepage: agent.homepage, |
| #79 | identifier: agent.identifier, |
| #80 | knowledgeCount: agent.knowledgeCount || 0, |
| #81 | meta: agent.meta, |
| #82 | pluginCount: agent.pluginCount || 0, |
| #83 | schemaVersion: agent.schemaVersion, |
| #84 | tokenUsage: agent.tokenUsage, |
| #85 | }; |
| #86 | }, |
| #87 | { concurrency: config.concurrency }, // 使用配置中的并发数控制 |
| #88 | ); |
| #89 | |
| #90 | // 过滤掉跳过的项目并按创建时间倒序排列 |
| #91 | return agentIndex.filter(Boolean).sort( |
| #92 | // @ts-ignore |
| #93 | (a, b) => new Date(b.createdAt) - new Date(a.createdAt), |
| #94 | ); |
| #95 | }; |
| #96 | |
| #97 | /** |
| #98 | * 构建 Schema 文件 |
| #99 | */ |
| #100 | buildSchema = () => { |
| #101 | Logger.start('构建 Agent Schema', `v${meta.schemaVersion}`); |
| #102 | checkDir(schemasDir); |
| #103 | checkDir(resolve(publicDir, 'schema')); |
| #104 | |
| #105 | const schema = zodToJsonSchema(clawdAgentSchema); |
| #106 | const fileName = `clawdAgentSchema_v${meta.schemaVersion}.json`; |
| #107 | |
| #108 | const schemaPath = resolve(schemasDir, fileName); |
| #109 | const publicSchemaPath = resolve(publicDir, 'schema', fileName); |
| #110 | |
| #111 | writeJSONSync(schemaPath, schema, { spaces: 2 }); |
| #112 | writeJSONSync(publicSchemaPath, schema, { spaces: 2 }); |
| #113 | |
| #114 | Logger.file('write', schemaPath); |
| #115 | Logger.file('write', publicSchemaPath); |
| #116 | Logger.success('Schema 构建完成', `v${meta.schemaVersion}`); |
| #117 | }; |
| #118 | |
| #119 | /** |
| #120 | * 构建所有语言版本的 Agent 文件 |
| #121 | */ |
| #122 | buildFullLocaleAgents = async () => { |
| #123 | Logger.split('构建多语言版本'); |
| #124 | |
| #125 | // 并行构建所有语言版本 |
| #126 | await pMap( |
| #127 | config.outputLocales, |
| #128 | async (locale: string, index: number) => { |
| #129 | Logger.start('构建语言版本', locale, `${index + 1}/${config.outputLocales.length}`); |
| #130 | |
| #131 | const agents = await this.buildSingleLocaleAgents(locale); |
| #132 | Logger.info(`收集到 Agents`, agents.length); |
| #133 | |
| #134 | // 统计标签使用频率 |
| #135 | let tags = []; |
| #136 | for (const agent of agents) { |
| #137 | tags = [...tags, ...agent.meta.tags]; |
| #138 | } |
| #139 | tags = findDuplicates(tags); |
| #140 | |
| #141 | // 生成索引文件 |
| #142 | const agentsIndex = { ...meta, agents, tags }; |
| #143 | const indexFileName = getBuildLocaleAgentFileName('index', locale); |
| #144 | |
| #145 | if (locale === config.entryLocale) { |
| #146 | const entryIndexPath = resolve(publicDir, 'index.en-US.json'); |
| #147 | writeJSONSync(entryIndexPath, agentsIndex, { spaces: 2 }); |
| #148 | Logger.file('write', entryIndexPath); |
| #149 | } |
| #150 | |
| #151 | const indexPath = resolve(publicDir, indexFileName); |
| #152 | writeJSONSync(indexPath, agentsIndex, { spaces: 2 }); |
| #153 | Logger.file('write', indexPath); |
| #154 | |
| #155 | // 统计信息 |
| #156 | Logger.stats({ |
| #157 | 'Agents 数量': agents.length, |
| #158 | '热门标签数量': tags.length, |
| #159 | '索引文件': indexFileName, |
| #160 | '语言版本': locale, |
| #161 | }); |
| #162 | |
| #163 | Logger.success('语言版本构建完成', locale); |
| #164 | }, |
| #165 | { concurrency: config.concurrency }, // 使用配置中的并发数控制 |
| #166 | ); |
| #167 | }; |
| #168 | |
| #169 | /** |
| #170 | * 复制 CNAME 文件到 public 目录(如果存在) |
| #171 | * 这允许自定义域名在 GitHub Pages 部署时保持不变 |
| #172 | */ |
| #173 | copyCNAME = () => { |
| #174 | const cnamePath = resolve(root, 'CNAME'); |
| #175 | const publicCNAMEPath = resolve(publicDir, 'CNAME'); |
| #176 | |
| #177 | if (existsSync(cnamePath)) { |
| #178 | copyFileSync(cnamePath, publicCNAMEPath); |
| #179 | Logger.success('CNAME 文件已复制到 public 目录'); |
| #180 | } |
| #181 | }; |
| #182 | |
| #183 | /** |
| #184 | * 执行构建流程 |
| #185 | */ |
| #186 | run = async () => { |
| #187 | Logger.split('开始构建流程'); |
| #188 | const startTime = Date.now(); |
| #189 | |
| #190 | this.buildSchema(); |
| #191 | await this.buildFullLocaleAgents(); |
| #192 | this.copyCNAME(); |
| #193 | |
| #194 | const duration = Date.now() - startTime; |
| #195 | Logger.success('构建流程完成', '', `耗时 ${duration}ms`); |
| #196 | }; |
| #197 | } |
| #198 | |
| #199 | /** |
| #200 | * 导出构建器实例 |
| #201 | */ |
| #202 | export const agentBuilder = new AgentBuilder(agents); |
| #203 | |
| #204 | |
| #205 |