/** * 生成技能库机器可读 manifest:js/data/manifest/skills.json * 用法:node scripts/build-skill-manifest.js * 仅导出技能元数据(含流程步骤/性质/工作区),run/test 实现留在 js/skills/、js/poster-skills/、js/sticker-skills/ 供系统执行。 * 注意:技能文件顶层 const HGB_* 是词法绑定,不挂 sandbox,必须全部拼接进同一 vm 代码串后直接引用。 */ const fs = require('fs'); const path = require('path'); const vm = require('vm'); const ROOT = process.cwd(); const read = f => fs.readFileSync(path.join(ROOT, f), 'utf8'); // 共享技能(core + 7 分类)+ 海报技能(core + skills)+ 表情技能(core + skills) const SKILL_FILES = [ 'js/skills/core.js', 'js/skills/layout.js', 'js/skills/color.js', 'js/skills/typography.js', 'js/skills/icon.js', 'js/skills/ai.js', 'js/skills/presentation.js', 'js/skills/export.js', 'js/poster-skills/core.js', 'js/poster-skills/skills.js', 'js/sticker-skills/core.js', 'js/sticker-skills/skills.js' ]; // 技能定义期/自测可能引用的数据依赖(与浏览器加载顺序一致;表情技能可能引用动画引擎) const DEP_FILES = [ 'js/data/icons.js', 'js/data/industries.js', 'js/data/styles.js', 'js/data/decorations.js', 'js/data/palettes.js', 'js/data/fonts.js', 'js/data/builtin-icons.js', 'js/core/generator.js', 'js/core/motion.js' ]; const code = DEP_FILES.map(read).join('\n') + '\n' + SKILL_FILES.map(read).join('\n') + ` ;globalThis.__MANIFEST = (function () { var catOf = function (list) { var m = {}; list.forEach(function (s) { m[s.category] = (m[s.category] || 0) + 1; }); return m; }; var shared = (typeof HGB_Skills !== 'undefined') ? HGB_Skills.all().map(function (s) { return { id: s.id, name: s.name, category: s.category, emoji: s.emoji, scene: s.scene, summary: s.summary, params: s.params, source: s.source, step: HGB_Skills.stepOf(s.id), kind: HGB_Skills.kind(s.id), workspaces: HGB_Skills.workspacesOf(s.id) }; }) : []; var poster = (typeof HGB_PosterSkills !== 'undefined') ? HGB_PosterSkills.all().map(function (s) { return { id: s.id, name: s.name, category: s.category, emoji: s.emoji, scene: s.scene, summary: s.summary, params: s.params, source: s.source, workspaces: HGB_PosterSkills.workspacesOf(s.id) }; }) : []; var sticker = (typeof HGB_StickerSkills !== 'undefined') ? HGB_StickerSkills.all().map(function (s) { return { id: s.id, name: s.name, category: s.category, emoji: s.emoji, scene: s.scene, summary: s.summary, params: s.params, source: s.source, workspaces: HGB_StickerSkills.workspacesOf(s.id) }; }) : []; return { shared: shared, poster: poster, sticker: sticker, steps: (typeof HGB_Skills !== 'undefined' && HGB_Skills.steps) ? HGB_Skills.steps() : [] }; })(); `; const sandbox = { console, setTimeout, clearTimeout, window: null, self: null }; sandbox.window = sandbox; sandbox.self = sandbox; try { vm.runInNewContext(code, sandbox, { filename: 'skills-manifest.js' }); } catch (e) { console.error('❌ 技能 manifest 生成失败:' + e.message); process.exit(1); } const m = sandbox.__MANIFEST; if (!m.shared.length && !m.poster.length && !m.sticker.length) { console.error('❌ 未注册任何技能,检查技能文件加载'); process.exit(1); } const out = { kind: 'skills', generatedAt: new Date().toISOString(), guide: 'js/data/manifest/README.md', shared: { total: m.shared.length, categories: m.steps.map(s => s), // 设计流程 5 步元数据(共享技能按流水线组织) skills: m.shared }, poster: { total: m.poster.length, categories: null, // 海报技能按 8 分类,见各 skill.category skills: m.poster }, sticker: { total: m.sticker.length, categories: null, // 表情技能按 motion/emotion 分类,见各 skill.category skills: m.sticker } }; const manifestDir = path.join(ROOT, 'js/data/manifest'); fs.mkdirSync(manifestDir, { recursive: true }); fs.writeFileSync(path.join(manifestDir, 'skills.json'), JSON.stringify(out, null, 1), 'utf8'); console.log(`✅ 技能 manifest:共享 ${m.shared.length} 个 / 海报 ${m.poster.length} 个 / 表情 ${m.sticker.length} 个 → js/data/manifest/skills.json`);