import fs from 'node:fs' import path from 'node:path' import vm from 'node:vm' import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const rootDir = path.resolve(__dirname, '..') const dataDir = path.join(rootDir, 'src', 'data') const apiDir = path.join(rootDir, 'public', 'api') const apiDocPath = path.join(rootDir, 'public', 'apidoc') function readJson(relativePath) { return JSON.parse(fs.readFileSync(path.join(rootDir, relativePath), 'utf8')) } function ensureDir(dir) { fs.mkdirSync(dir, { recursive: true }) } function writeJson(relativePath, data) { const target = path.join(apiDir, relativePath) ensureDir(path.dirname(target)) fs.writeFileSync(target, `${JSON.stringify(data, null, 2)}\n`, 'utf8') } function cleanApiDir() { fs.rmSync(apiDir, { recursive: true, force: true }) fs.rmSync(apiDocPath, { force: true }) ensureDir(apiDir) } function writeTextFile(target, content) { ensureDir(path.dirname(target)) fs.writeFileSync(target, content, 'utf8') } function copyApiDoc() { const source = path.join(rootDir, 'docs', '知识库API接口说明.md') const content = fs.readFileSync(source, 'utf8') writeTextFile(apiDocPath, content) } function extractConstArrayFromTs(filePath, constName) { const text = fs.readFileSync(filePath, 'utf8') const marker = `export const ${constName}` const markerIndex = text.indexOf(marker) if (markerIndex === -1) { throw new Error(`未找到 ${constName}`) } const assignmentIndex = text.indexOf('=', markerIndex) if (assignmentIndex === -1) { throw new Error(`未找到 ${constName} 赋值符号`) } const arrayStart = text.indexOf('[', assignmentIndex) if (arrayStart === -1) { throw new Error(`未找到 ${constName} 数组起点`) } let depth = 0 let quote = null let escaped = false let lineComment = false let blockComment = false for (let index = arrayStart; index < text.length; index += 1) { const char = text[index] const next = text[index + 1] if (lineComment) { if (char === '\n') lineComment = false continue } if (blockComment) { if (char === '*' && next === '/') { blockComment = false index += 1 } continue } if (quote) { if (escaped) { escaped = false } else if (char === '\\') { escaped = true } else if (char === quote) { quote = null } continue } if (char === '/' && next === '/') { lineComment = true index += 1 continue } if (char === '/' && next === '*') { blockComment = true index += 1 continue } if (char === '\'' || char === '"' || char === '`') { quote = char continue } if (char === '[') depth += 1 if (char === ']') { depth -= 1 if (depth === 0) { const source = text.slice(arrayStart, index + 1) return vm.runInNewContext(`(${source})`, {}, { timeout: 1000 }) } } } throw new Error(`未能完整解析 ${constName}`) } const knowledgeAreas = readJson('src/data/knowledge-areas.json').knowledgeAreas const processGroups = readJson('src/data/process-groups.json').processGroups const processes = readJson('src/data/processes.json').processes const artifacts = readJson('src/data/artifacts.json').artifacts const tools = readJson('src/data/tools.json').tools const performanceDomains = extractConstArrayFromTs( path.join(dataDir, 'performance-domains.ts'), 'performanceDomains' ) const knowledgeAreaMap = new Map(knowledgeAreas.map((item) => [item.id, item])) const processGroupMap = new Map(processGroups.map((item) => [item.id, item])) const artifactMap = new Map(artifacts.map((item) => [item.id, item])) const toolMap = new Map(tools.map((item) => [item.id, item])) function normalizeRef(ref) { if (typeof ref === 'string') return { id: ref, details: [], note: undefined } return { id: ref.id, details: Array.isArray(ref.detail) ? ref.detail.map((item) => ({ label: item.label })) : [], note: ref.note, } } function processSummary(process) { const knowledgeArea = knowledgeAreaMap.get(process.knowledgeAreaId) const processGroup = processGroupMap.get(process.processGroupId) return { id: process.id, name: process.name, knowledgeAreaId: process.knowledgeAreaId, knowledgeAreaName: knowledgeArea?.name ?? '', processGroupId: process.processGroupId, processGroupName: processGroup?.name ?? '', purpose: process.purpose ?? '', } } function attachRefMeta(ref, entityMap) { const normalized = normalizeRef(ref) const entity = entityMap.get(normalized.id) return { id: normalized.id, name: entity?.name ?? normalized.id, details: normalized.details, ...(normalized.note ? { note: normalized.note } : {}), } } function processItto(process) { return { id: process.id, name: process.name, inputs: process.inputs.map((ref) => attachRefMeta(ref, artifactMap)), tools: process.tools.map((ref) => attachRefMeta(ref, toolMap)), outputs: process.outputs.map((ref) => attachRefMeta(ref, artifactMap)), } } function includesRef(refs, targetId) { return refs.some((ref) => normalizeRef(ref).id === targetId) } function artifactUsage(artifact) { return { id: artifact.id, name: artifact.name, asInput: processes.filter((process) => includesRef(process.inputs, artifact.id)).map(processSummary), asOutput: processes.filter((process) => includesRef(process.outputs, artifact.id)).map(processSummary), } } function toolUsage(tool) { return { id: tool.id, name: tool.name, usedIn: processes.filter((process) => includesRef(process.tools, tool.id)).map(processSummary), } } cleanApiDir() writeJson('process-groups.json', processGroups.map((item) => ({ id: item.id, name: item.name }))) writeJson( 'knowledge-areas.json', knowledgeAreas.map((item) => ({ id: item.id, name: item.name, tailoringFactors: (item.tailoringFactors ?? []).map((factor) => ({ title: factor.title, description: factor.description, })), })) ) for (const knowledgeArea of knowledgeAreas) { writeJson( `knowledge-areas/${knowledgeArea.id}/tailoring-factors.json`, (knowledgeArea.tailoringFactors ?? []).map((factor) => ({ title: factor.title, description: factor.description, })) ) writeJson( `knowledge-areas/${knowledgeArea.id}/processes.json`, processes .filter((process) => process.knowledgeAreaId === knowledgeArea.id) .map((process) => { const summary = processSummary(process) return { id: summary.id, name: summary.name, processGroupId: summary.processGroupId, processGroupName: summary.processGroupName, purpose: summary.purpose, } }) ) } for (const processGroup of processGroups) { writeJson( `process-groups/${processGroup.id}/processes.json`, processes .filter((process) => process.processGroupId === processGroup.id) .map((process) => { const summary = processSummary(process) return { id: summary.id, name: summary.name, knowledgeAreaId: summary.knowledgeAreaId, knowledgeAreaName: summary.knowledgeAreaName, purpose: summary.purpose, } }) ) } writeJson('processes.json', processes.map(processSummary)) for (const process of processes) { writeJson(`processes/${process.id}.json`, processSummary(process)) writeJson(`processes/${process.id}/itto.json`, processItto(process)) } writeJson('performance-domains.json', performanceDomains.map((item) => ({ id: item.id, name: item.name }))) for (const domain of performanceDomains) { writeJson(`performance-domains/${domain.id}.json`, { id: domain.id, name: domain.name, expectedGoals: domain.detail?.expectedGoals ?? [], keyPoints: domain.detail?.keyPoints ?? [], interactions: domain.detail?.interactions ?? [], checks: domain.detail?.checks ?? [], }) } writeJson('artifacts.json', artifacts.map((item) => ({ id: item.id, name: item.name }))) writeJson('tools.json', tools.map((item) => ({ id: item.id, name: item.name }))) for (const artifact of artifacts) { writeJson(`artifacts/${artifact.id}/usage.json`, artifactUsage(artifact)) } for (const tool of tools) { writeJson(`tools/${tool.id}/usage.json`, toolUsage(tool)) } copyApiDoc() console.log(`已生成静态 API 文件:${path.relative(rootDir, apiDir)}`) console.log(`已生成 Markdown 接口文档:${path.relative(rootDir, apiDocPath)}`)