|
|
@@ -138,7 +138,32 @@ for (const f of files) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 6. 打 zip
|
|
|
+// 6. 文件类型白名单校验(SkillHub 有严格限制,提前拦住)
|
|
|
+const ALLOWED_EXT = new Set([
|
|
|
+ '.md', '.json', '.js', '.mjs', '.cjs', '.ts', '.py', '.sh',
|
|
|
+ '.html', '.htm', '.css', '.txt', '.yaml', '.yml',
|
|
|
+ '.svg', '.png', '.jpg', '.jpeg', '.webp', '.gif',
|
|
|
+]);
|
|
|
+const badExt = [];
|
|
|
+(function scan(d, rel = '') {
|
|
|
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
|
+ const p = path.join(d, e.name);
|
|
|
+ if (e.isDirectory()) { scan(p, `${rel}${e.name}/`); continue; }
|
|
|
+ const ext = path.extname(e.name).toLowerCase();
|
|
|
+ if (!ext || !ALLOWED_EXT.has(ext)) badExt.push(`${rel}${e.name}`);
|
|
|
+ }
|
|
|
+})(stageDir);
|
|
|
+
|
|
|
+if (badExt.length) {
|
|
|
+ console.log('\n✗ 发现 SkillHub 不支持的文件类型,已中止打包:');
|
|
|
+ for (const f of badExt) console.log(` ${f}`);
|
|
|
+ console.log('\n处理建议:');
|
|
|
+ console.log(' .j2 → .template.html (Jinja2 模板改扩展名,同步改引用)');
|
|
|
+ console.log(' LICENSE(无扩展名)→ LICENSE.md');
|
|
|
+ process.exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+// 7. 打 zip
|
|
|
const zipName = `${pkg.name || 'fmode-harness'}-${stamp}.zip`;
|
|
|
const zipPath = path.join(RELEASE, zipName);
|
|
|
fs.rmSync(zipPath, { force: true });
|