
























1+// Android Pin Version script supports OpenClaw repository automation.
2+import path from "node:path";
3+import {
4+canonicalAndroidVersionCode,
5+normalizeAndroidVersionCode,
6+normalizePinnedAndroidVersion,
7+resolveAndroidVersion,
8+resolveGatewayVersionForAndroidRelease,
9+syncAndroidVersioning,
10+writeAndroidVersionManifest,
11+} from "./lib/android-version.ts";
12+13+type CliOptions = {
14+explicitVersion: string | null;
15+explicitVersionCode: number | null;
16+fromGateway: boolean;
17+rootDir: string;
18+sync: boolean;
19+};
20+21+export type PinAndroidVersionResult = {
22+previousVersion: string | null;
23+previousVersionCode: number | null;
24+nextVersion: string;
25+nextVersionCode: number;
26+packageVersion: string | null;
27+versionFilePath: string;
28+syncedPaths: string[];
29+};
30+31+function usage(): string {
32+return [
33+"Usage: node --import tsx scripts/android-pin-version.ts (--from-gateway | --version <YYYY.M.PATCH>) [--version-code <int>] [--no-sync] [--root dir]",
34+"",
35+"Examples:",
36+" node --import tsx scripts/android-pin-version.ts --from-gateway",
37+" node --import tsx scripts/android-pin-version.ts --version 2026.6.5",
38+" node --import tsx scripts/android-pin-version.ts --version 2026.6.5 --version-code 2026060502",
39+].join("\n");
40+}
41+42+export function parseArgs(argv: string[]): CliOptions {
43+let explicitVersion: string | null = null;
44+let explicitVersionCode: number | null = null;
45+let fromGateway = false;
46+let rootDir = path.resolve(".");
47+let sync = true;
48+49+for (let index = 0; index < argv.length; index += 1) {
50+const arg = argv[index];
51+switch (arg) {
52+case "--from-gateway": {
53+fromGateway = true;
54+break;
55+}
56+case "--version": {
57+explicitVersion = argv[index + 1] ?? null;
58+index += 1;
59+break;
60+}
61+case "--version-code": {
62+const value = argv[index + 1];
63+if (!value) {
64+throw new Error("Missing value for --version-code.");
65+}
66+explicitVersionCode = Number.parseInt(value, 10);
67+index += 1;
68+break;
69+}
70+case "--no-sync": {
71+sync = false;
72+break;
73+}
74+case "--root": {
75+const value = argv[index + 1];
76+if (!value) {
77+throw new Error("Missing value for --root.");
78+}
79+rootDir = path.resolve(value);
80+index += 1;
81+break;
82+}
83+case "-h":
84+case "--help": {
85+console.log(`${usage()}\n`);
86+process.exit(0);
87+}
88+default: {
89+throw new Error(`Unknown argument: ${arg}`);
90+}
91+}
92+}
93+94+if (fromGateway === (explicitVersion !== null)) {
95+throw new Error("Choose exactly one of --from-gateway or --version <YYYY.M.PATCH>.");
96+}
97+98+if (explicitVersion !== null && !explicitVersion.trim()) {
99+throw new Error("Missing value for --version.");
100+}
101+102+return { explicitVersion, explicitVersionCode, fromGateway, rootDir, sync };
103+}
104+105+export function pinAndroidVersion(params: CliOptions): PinAndroidVersionResult {
106+const rootDir = path.resolve(params.rootDir);
107+let previousVersion: string | null;
108+let previousVersionCode: number | null;
109+try {
110+const currentVersion = resolveAndroidVersion(rootDir);
111+previousVersion = currentVersion.canonicalVersion;
112+previousVersionCode = currentVersion.versionCode;
113+} catch {
114+previousVersion = null;
115+previousVersionCode = null;
116+}
117+118+const gatewayVersion = params.fromGateway
119+ ? resolveGatewayVersionForAndroidRelease(rootDir)
120+ : null;
121+const packageVersion = gatewayVersion?.packageVersion ?? null;
122+const nextVersion =
123+gatewayVersion?.pinnedAndroidVersion ??
124+normalizePinnedAndroidVersion(params.explicitVersion ?? "");
125+const nextVersionCode =
126+params.explicitVersionCode === null
127+ ? (gatewayVersion?.versionCode ?? canonicalAndroidVersionCode(nextVersion))
128+ : normalizeAndroidVersionCode(params.explicitVersionCode, nextVersion);
129+const versionFilePath = writeAndroidVersionManifest(nextVersion, nextVersionCode, rootDir);
130+const syncedPaths = params.sync
131+ ? syncAndroidVersioning({ mode: "write", rootDir }).updatedPaths
132+ : [];
133+134+return {
135+ previousVersion,
136+ previousVersionCode,
137+ nextVersion,
138+ nextVersionCode,
139+ packageVersion,
140+ versionFilePath,
141+ syncedPaths,
142+};
143+}
144+145+export async function main(argv: string[]): Promise<number> {
146+try {
147+const options = parseArgs(argv);
148+const result = pinAndroidVersion(options);
149+const sourceText = result.packageVersion
150+ ? ` from gateway version ${result.packageVersion}`
151+ : "";
152+process.stdout.write(
153+`Pinned Android version to ${result.nextVersion} (${result.nextVersionCode})${sourceText}.\n`,
154+);
155+if (
156+result.previousVersion &&
157+(result.previousVersion !== result.nextVersion ||
158+result.previousVersionCode !== result.nextVersionCode)
159+) {
160+process.stdout.write(
161+`Previous pinned Android version: ${result.previousVersion} (${result.previousVersionCode}).\n`,
162+);
163+}
164+process.stdout.write(
165+`Updated version manifest: ${path.relative(process.cwd(), result.versionFilePath)}\n`,
166+);
167+if (options.sync) {
168+if (result.syncedPaths.length === 0) {
169+process.stdout.write("Android versioning artifacts already up to date.\n");
170+} else {
171+process.stdout.write(
172+`Updated Android versioning artifacts:\n- ${result.syncedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`,
173+);
174+}
175+}
176+return 0;
177+} catch (error) {
178+process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
179+return 1;
180+}
181+}
182+183+if (import.meta.url === `file://${process.argv[1]}`) {
184+const exitCode = await main(process.argv.slice(2));
185+if (exitCode !== 0) {
186+process.exit(exitCode);
187+}
188+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。