// 生成 js/data/manifest/BASELINE.md —— 系统现状基线快照(构建后运行,AI 采集指令的「执行前自查」数据源) // 用法:node scripts/build-baseline.js const fs = require('fs'); const path = require('path'); const MAN = 'js/data/manifest'; const read = (f) => JSON.parse(fs.readFileSync(path.join(MAN, f), 'utf8')); const icons = read('icons.json'); const posters = read('posters.json'); const skills = read('skills.json'); const countBy = (arr, key) => { const m = {}; arr.forEach((x) => { m[x[key]] = (m[x[key]] || 0) + 1; }); return m; }; // 三区覆盖:优先 workspaces 字段,缺省按 scene 关键词统计 const wsCount = (skill) => { if (Array.isArray(skill.workspaces) && skill.workspaces.length) { return { logo: skill.workspaces.includes('logo'), avatar: skill.workspaces.includes('avatar'), poster: skill.workspaces.includes('poster'), }; } const sc = skill.scene || ''; return { logo: /LOGO|logo/.test(sc), avatar: /头像|avatar/.test(sc), poster: /海报|poster/.test(sc), }; }; const cover = (list) => { const c = { logo: 0, avatar: 0, poster: 0, none: 0 }; list.forEach((s) => { const w = wsCount(s); if (!w.logo && !w.avatar && !w.poster) c.none++; if (w.logo) c.logo++; if (w.avatar) c.avatar++; if (w.poster) c.poster++; }); return c; }; const sharedSkills = skills.shared.skills || []; const posterSkills = (skills.poster && skills.poster.skills) || []; const stickerSkills = (skills.sticker && skills.sticker.skills) || []; const sharedCat = countBy(sharedSkills, 'category'); const posterCat = countBy(posterSkills, 'category'); const stickerCat = countBy(stickerSkills, 'category'); const sharedCover = cover(sharedSkills); const posterCover = cover(posterSkills); const iconTypes = countBy(icons.sources, 'type'); const posterTypes = countBy(posters.sources, 'type'); const lines = []; lines.push('# 画个标 · 系统基线(构建自动生成,勿手改)'); lines.push(''); lines.push('> 由 `scripts/build-baseline.js` 生成。素材/技能变更并构建后,重新运行 `node scripts/build-baseline.js` 即自动更新。'); lines.push('> 执行「AI 指令库 指令一~四」前,先读本文件获取当前基线,勿依赖记忆中的数字。'); lines.push(''); lines.push('## 生成时间'); lines.push(''); lines.push(new Date().toISOString()); lines.push(''); lines.push('## ① 图标库(共享,LOGO/头像/海报共用)'); lines.push(''); lines.push(`- 源数:${icons.sources.length} | 图标总数:${icons.total}`); lines.push(`- 类型分布:${Object.entries(iconTypes).map(([k, v]) => `${k} ${v}`).join(' / ')}`); lines.push('- 源清单(含 count/file/workspaces):js/data/manifest/icons.json'); lines.push(''); lines.push('## ② 海报素材库'); lines.push(''); lines.push(`- 源数:${posters.sources.length} | 素材总数:${posters.total}`); lines.push(`- 类型分布:${Object.entries(posterTypes).map(([k, v]) => `${k} ${v}`).join(' / ')}`); lines.push('- 源清单:js/data/manifest/posters.json'); lines.push(''); lines.push('## ③ 技能库'); lines.push(''); lines.push(`- 共享技能:${sharedSkills.length}(分类:${Object.entries(sharedCat).map(([k, v]) => `${k} ${v}`).join(' / ')})`); lines.push(`- 海报技能:${posterSkills.length}(分类:${Object.entries(posterCat).map(([k, v]) => `${k} ${v}`).join(' / ')})`); lines.push(`- 表情技能:${stickerSkills.length}(分类:${Object.entries(stickerCat).map(([k, v]) => `${k} ${v}`).join(' / ')})`); lines.push(`- 三区覆盖(共享,按 scene/workspaces):LOGO 向 ${sharedCover.logo} / 头像向 ${sharedCover.avatar} / 海报向 ${sharedCover.poster} / 未标注 ${sharedCover.none}`); lines.push(`- 三区覆盖(海报专属):LOGO 向 ${posterCover.logo} / 头像向 ${posterCover.avatar} / 海报向 ${posterCover.poster}`); lines.push('- 技能明细:js/data/manifest/skills.json'); lines.push(''); lines.push('## 指令使用提示'); lines.push(''); lines.push('- 指令一(新增图标源):去重以本文件 ① 的源清单 + icon-sources.js 现有 id 为准'); lines.push('- 指令二(新增海报源):去重以 ② + poster-sources.js 现有 id 为准'); lines.push('- 指令三(新增技能):看 ③ 三区覆盖找缺口(头像向最少则优先补头像);表情向技能看表情技能分类分布'); lines.push(''); const out = path.join(MAN, 'BASELINE.md'); fs.writeFileSync(out, lines.join('\n'), 'utf8'); console.log('已生成 ' + out); console.log(lines.join('\n'));