Files
u-claw/portable/lib/publish-latest.mjs
hfshfg d9dd98d650 feat(portable): 便携版更新检测 — config-server 加 /api/update-status + check/publish 脚本 + CI 剥 BOM
config-server 新增 /api/update-status 和 /api/update-check,读取 check-update.mjs
写入的 update-available.json,便携版可提示有无新版本。publish-latest.mjs 用于
发布端生成 manifest。release.yml 顺手修打包时 .bat 的 UTF-8 BOM(BOM 会让 cmd.exe
把首条命令认错报 not internal/external command)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 13:12:16 +08:00

113 lines
4.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 发版辅助:生成 latest.json 用于上传到阿里云 OSS
//
// 用法(在仓库根目录跑):
// node portable/lib/publish-latest.mjs
// node portable/lib/publish-latest.mjs --notes "修复了 xxx"
//
// 输出:
// - dist/latest.json — 你手动(或 ossutil上传到 OSS 的同一个路径
//
// 上传命令示例(自己装 ossutil 后用):
// ossutil cp dist/latest.json oss://u-claw-oss/u-claw-open/latest.json
//
// 这个脚本不直接调 OSS避免硬编码 access key。把生成 + 上传分开,发版人自己负责上传。
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = resolve(__dirname, '../..');
// 默认 OSS 路径前缀(你可以改成自己的 bucket / domain
const DEFAULT_OSS_BASE = 'https://u-claw-oss.56chat.cn/u-claw-open';
const GH_RELEASES_BASE = 'https://github.com/dongsheng123132/u-claw/releases';
function parseArgs(argv) {
const args = { notes: '', ossBase: DEFAULT_OSS_BASE };
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
if (a === '--notes' || a === '-n') args.notes = argv[++i] || '';
else if (a === '--oss-base') args.ossBase = argv[++i] || DEFAULT_OSS_BASE;
else if (a === '--help' || a === '-h') {
process.stdout.write([
'Usage: node portable/lib/publish-latest.mjs [options]',
' --notes "<text>" Release notes (single line)',
' --oss-base <url> OSS public URL prefix (default: ' + DEFAULT_OSS_BASE + ')',
' --help Show this help',
'',
'Output: dist/latest.json — upload it to <oss-base>/latest.json',
].join('\n') + '\n');
process.exit(0);
}
}
return args;
}
function readVersion() {
const versionFile = resolve(REPO_ROOT, 'OPENCLAW_VERSION');
if (!existsSync(versionFile)) {
throw new Error(`OPENCLAW_VERSION file not found at ${versionFile}`);
}
const v = readFileSync(versionFile, 'utf8').trim();
if (!v) throw new Error('OPENCLAW_VERSION is empty');
return v;
}
function todayIso() {
const d = new Date();
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
return `${yyyy}-${mm}-${dd}`;
}
function main() {
const args = parseArgs(process.argv);
const version = readVersion();
const tag = `v${version}`;
// Naming convention matches release.yml:
// dist/u-claw-portable-${tag_name}.zip
const zipName = `u-claw-portable-${tag}.zip`;
const downloadUrl = `${args.ossBase}/${zipName}`;
const releasePageUrl = `${GH_RELEASES_BASE}/tag/${tag}`;
const manifest = {
version,
releaseDate: todayIso(),
downloadUrl,
releasePageUrl,
notes: args.notes || '',
// Mirror fallback if user wants — check-update.mjs only looks at the top-level fields
mirrors: {
oss: downloadUrl,
github: `${releasePageUrl}/${zipName}`,
},
};
const distDir = resolve(REPO_ROOT, 'dist');
if (!existsSync(distDir)) mkdirSync(distDir, { recursive: true });
const outFile = resolve(distDir, 'latest.json');
writeFileSync(outFile, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
process.stdout.write(`\nGenerated: ${outFile}\n`);
process.stdout.write(`Version: ${version}\n`);
process.stdout.write(`Download: ${downloadUrl}\n`);
process.stdout.write('\nNext steps (manual):\n');
process.stdout.write(` 1. Upload portable zip to OSS: ${args.ossBase}/${zipName}\n`);
process.stdout.write(` 2. Upload latest.json to OSS: ${args.ossBase}/latest.json\n`);
process.stdout.write('\nExample (with ossutil):\n');
process.stdout.write(` ossutil cp dist/${zipName} oss://<your-bucket>/u-claw-open/${zipName}\n`);
process.stdout.write(` ossutil cp dist/latest.json oss://<your-bucket>/u-claw-open/latest.json\n`);
process.stdout.write('\nVerify after upload:\n');
process.stdout.write(` curl -s ${args.ossBase}/latest.json | head -20\n\n`);
}
try {
main();
} catch (err) {
process.stderr.write(`publish-latest error: ${err.message}\n`);
process.exit(1);
}