skill:目录假设改成 game/;pack.mjs 去掉 --zip 与代跑的校验,保留 --vite-built-dir

- `SKILL.md` 的 vite 项目目录假设写的是 `games/`,实际是 `game/`;默认参数都按「cwd 就是 vite 项目根」给,非标准目录结构用 `--vite-built-dir` 指全路径;
- `pack.mjs` 删掉打包后调用 `validate.mjs` 的那一步,连带 `--skip-validate` / `--no-strict`:校验归 `validate.mjs` 与项目构建脚本,pack 只管整理产物、写 zip、按体积门禁审计;
- `pack.mjs` 删掉 `--zip` 与它专用的 `readPackageName()`(默认文件名):落点统一由 `--zip-out` 指定;`--vite-built-dir` 保留;
- 参数解析改成「只认 `--vite-built-dir` / `--zip-out`」:不认识的参数、缺值、缺 `--zip-out` 都当场打印用法并退出 2,打包本身失败仍退出 1,不再有静默退回默认目录的路径;
- `SKILL.md` 新增「脚本参数」一节,列出三个脚本各自的参数;
- `pack.mjs` 的用例改成「CLI 拒绝不认识的参数,且不写出 zip」;
- 同步 manifest 指纹(version=2026-08-26.49)。
This commit is contained in:
2026-10-06 15:25:31 +08:00
parent 6e33768b8b
commit aeec2f86bd
4 changed files with 50 additions and 67 deletions
@@ -1,6 +1,6 @@
{
"schemaVersion": "agc-skill-pack.v1",
"version": "2026-08-26.46",
"version": "2026-08-26.49",
"skills": [
{
"name": "agc-unity-editor",
@@ -204,7 +204,7 @@
"scripts/validate.mjs",
"scripts/vite.config.xhs-minitool.mjs"
],
"sha256": "e80b5c6a3f9a1619af1f789a74ea6e7577e58a4efa208d1d7b29e869f40b3725"
"sha256": "ad78485332009c5c72675a00ba525836b1ed94db34616256052ef9b30ca2d869"
}
]
}
@@ -28,7 +28,7 @@ metadata:
|---|---|
| `scripts/vite.config.xhs-minitool.mjs` | `build.outDir`(与打包时的 `--vite-built-dir` 必须是同一个目录); `defineMinitoolConfig(overrides)`(项目已有 vite.config 时用它合并) |
| `scripts/validate.mjs` | `[project]`、`--json`、`--strict` |
| `scripts/pack.mjs` | `--vite-built-dir <dir>`、`--zip-out <path>`、`--zip <name>`、`--skip-validate`、`--no-strict` |
| `scripts/pack.mjs` | `--vite-built-dir <dir>`、`--zip-out <path>` |
# 一些情况:
* 打包大小限制, 需要精简游戏内容/删减资源/压缩素材 请和用户讨论
@@ -61,7 +61,6 @@ test('存在不支持文件时打包整体失败,且不删除任何文件', ()
cwd: BASE,
viteBuiltDir: 'no-delete',
zipOut: 'no-delete-out/xhs-minitool.zip',
skipValidate: true,
}),
/没有删除任何文件/,
);
@@ -77,19 +76,20 @@ test('干净产物目录仍能正常打包', () => {
cwd: BASE,
viteBuiltDir: 'clean',
zipOut,
skipValidate: true,
});
assert.equal(code, 0);
assert.ok(existsSync(zipOut), 'zip 未生成');
});
test('CLI 拒绝旧名 --out-dir,不再静默退回默认目录', () => {
test('CLI 拒绝不认识的参数,不写出 zip', () => {
const dir = writeBuiltDir('cli');
const zipOut = join(BASE, 'cli-out.zip');
const result = spawnSync(
process.execPath,
[PACK, '--vite-built-dir', dir, '--out-dir', dir, '--skip-validate'],
[PACK, '--vite-built-dir', dir, '--out-dir', dir, '--zip-out', zipOut],
{ cwd: BASE, encoding: 'utf8' },
);
assert.equal(result.status, 1);
assert.match(result.stderr, /--vite-built-dir/);
assert.equal(result.status, 2);
assert.match(result.stderr, /不认识的参数/);
assert.equal(existsSync(zipOut), false, '参数被拒时不应写出 zip');
});
@@ -5,7 +5,6 @@
* - 校正 HTML 资源为相对路径、去掉 module 痕迹
* - 将脚本移到 body 末尾并保持顺序
* - 用 node:zlib 写出 zip(index.html 在 zip 根目录、不多套一层目录)
* - 再跑一遍静态校验
*/
import {
copyFileSync,
@@ -22,7 +21,7 @@ import { basename, dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { deflateRawSync } from 'node:zlib';
import { findUnsupportedFiles, runCli } from './validate.mjs';
import { findUnsupportedFiles } from './validate.mjs';
const MIB = 1024 * 1024;
const ZIP_HARD_LIMIT = 10 * MIB;
@@ -31,17 +30,14 @@ const ZIP_RECOMMENDED = 2 * MIB;
const FORBIDDEN_ENTRY =
/(^|\/)(?:node_modules|\.git)\/|(^|\/)\.DS_Store$|\.map$|(^|\/)(?:vite|webpack|rollup)\.config\.[^/]+$/i;
const USAGE = `用法:node pack.mjs [--vite-built-dir <dir>] [--zip <name>] [--zip-out <path>] [--skip-validate] [--no-strict]
const USAGE = `用法:node pack.mjs [--vite-built-dir <dir>] --zip-out <path>
把 vite 构建产物整理成符合小红书规范、根目录带 index.html 的 zip。
--vite-built-dir <dir> vite 的构建输出目录,必须与 vite config 的 build.outDir 一致。默认 dist-xhs-minitool。
该目录出现白名单之外的文件类型时直接报错退出并列出文件,不会删除任何文件。
--zip <name> 只给文件名时用:写到当前工作目录下。
--zip-out <path> 需要指定落点(例如 AGC 导出面板要求的 .export/xhs-minitool.zip)时用:
相对路径按当前工作目录解析,父目录不存在会自动建。
--skip-validate 写完 zip 后不再跑一遍静态校验。
--no-strict 校验时不把 WARNING 当失败。`;
--zip-out <path> 落点(例如 AGC 导出面板要求的 .export/xhs-minitool.zip):
相对路径按当前工作目录解析,父目录不存在会自动建。`;
/**
* 打包前预检:产物目录里出现小红书白名单之外的文件类型时整体失败,列出路径但**不改磁盘**。
@@ -272,38 +268,22 @@ function makeZip(viteBuiltDir, zipPath) {
console.log(`zip 已生成:${zipPath}(${entries.length} 个条目,${(size / MIB).toFixed(2)} MiB)`);
}
function readPackageName(cwd) {
const pkgPath = join(cwd, 'package.json');
if (!existsSync(pkgPath)) return 'minitool';
try {
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
return pkg.name || 'minitool';
} catch {
return 'minitool';
}
}
/**
* @param {{
* cwd?: string,
* viteBuiltDir?: string,
* zipName?: string,
* zipOut?: string,
* zipOut: string,
* publicDir?: string,
* skipValidate?: boolean,
* strict?: boolean,
* }} [options]
* }} options
*/
export function packMinitool(options = {}) {
if (!options.zipOut) {
throw new Error('缺少 --zip-out:打包要给出 zip 的落点');
}
const cwd = resolve(options.cwd || process.cwd());
const viteBuiltDir = resolve(cwd, options.viteBuiltDir || 'dist-xhs-minitool');
const zipName = options.zipName || `${readPackageName(cwd)}-xhs-tool.zip`;
// `zipOut` 优先:调用方(如 .export/ 下的项目拷贝)要的是确定的落点,而不是"当前目录下叫什么名字"。
const zipPath = options.zipOut
? resolve(cwd, options.zipOut)
: resolve(cwd, zipName);
const zipPath = resolve(cwd, options.zipOut);
const publicDir = resolve(cwd, options.publicDir || 'public');
const strict = options.strict !== false;
if (!existsSync(viteBuiltDir)) {
throw new Error(`缺少 vite 构建产物目录 ${viteBuiltDir}`);
@@ -328,16 +308,7 @@ export function packMinitool(options = {}) {
makeZip(viteBuiltDir, zipPath);
console.log(`\n小红书小工具包已整理:${viteBuiltDir}`);
if (options.skipValidate) return 0;
const args = [viteBuiltDir];
if (strict) args.push('--strict');
const code = runCli(args);
if (code !== 0) {
process.exitCode = code;
}
return code;
return 0;
}
export default packMinitool;
@@ -359,33 +330,45 @@ function isMainModule() {
if (isMainModule()) {
const raw = process.argv.slice(2);
const flags = new Set(raw.filter((arg) => arg.startsWith('-')));
if (flags.has('--help') || flags.has('-h')) {
if (raw.includes('--help') || raw.includes('-h')) {
console.log(USAGE);
process.exit(0);
}
// 旧名不能静默退回默认目录:否则适配脚本里的 --out-dir 会被忽略,产物落到别处还查不出来。
if (flags.has('--out-dir')) {
console.error('--out-dir 已更名为 --vite-built-dir,请改用新名字(`node pack.mjs --help`)。');
process.exit(1);
}
const getFlagValue = (name) => {
// 取走一个参数和它的值;剩下的非空参数说明调用方传了本脚本不认的东西。
const takeFlag = (name) => {
const idx = raw.indexOf(name);
return idx === -1 ? undefined : raw[idx + 1];
if (idx === -1) return undefined;
const value = raw[idx + 1];
if (!value || value.startsWith('-')) {
throw new Error(`${name} 后面要跟一个值`);
}
raw.splice(idx, 2);
return value;
};
let viteBuiltDir;
let zipOut;
try {
const code = packMinitool({
viteBuiltDir: getFlagValue('--vite-built-dir'),
zipName: getFlagValue('--zip'),
zipOut: getFlagValue('--zip-out'),
skipValidate: flags.has('--skip-validate'),
strict: !flags.has('--no-strict'),
});
process.exit(code ?? 0);
viteBuiltDir = takeFlag('--vite-built-dir');
zipOut = takeFlag('--zip-out');
// 不认识的参数当场拒绝:否则调用方以为它生效了,产物落到别处还查不出来。
if (raw.length > 0) {
throw new Error(`不认识的参数:${raw.join(' ')}`);
}
if (!zipOut) {
throw new Error('缺少 --zip-out');
}
} catch (err) {
console.error(err instanceof Error ? err.message : err);
console.error(USAGE);
process.exit(2);
}
try {
packMinitool({ viteBuiltDir, zipOut });
process.exit(0);
} catch (err) {
console.error(err instanceof Error ? err.message : err);
process.exit(1);