统一 Rust 与 TypeScript 格式化门禁

纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
This commit is contained in:
2026-09-01 16:26:20 +08:00
parent ae79d50b14
commit 071faa482c
1051 changed files with 28412 additions and 19834 deletions
@@ -1,4 +1,4 @@
import {spawnSync} from 'node:child_process';
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
@@ -69,7 +69,9 @@ function run(command, args, label) {
throw new Error(`${label} failed to start: ${result.error.message}`);
}
if ((result.status ?? 0) !== 0) {
throw new Error(`${label} failed: ${(result.stderr || result.stdout).trim()}`);
throw new Error(
`${label} failed: ${(result.stderr || result.stdout).trim()}`,
);
}
return result.stdout;
}
@@ -82,20 +84,47 @@ function assertIncludes(source, snippet, label) {
assertFile(androidArtifactPath, 'Android mobile shell APK', 1024 * 1024);
assertZipHeader(androidArtifactPath, 'Android mobile shell APK');
const androidListing = run('unzip', ['-l', androidArtifactPath], 'Android APK listing');
assertIncludes(androidListing, 'AndroidManifest.xml', 'Android mobile shell APK');
const androidListing = run(
'unzip',
['-l', androidArtifactPath],
'Android APK listing',
);
assertIncludes(
androidListing,
'AndroidManifest.xml',
'Android mobile shell APK',
);
assertIncludes(androidListing, 'classes.dex', 'Android mobile shell APK');
assertIncludes(androidListing, 'assets/index.android.bundle', 'Android mobile shell APK');
assertIncludes(
androidListing,
'assets/index.android.bundle',
'Android mobile shell APK',
);
assertFile(iosSimulatorArtifactPath, 'iOS simulator mobile shell archive', 1024 * 1024);
assertGzipHeader(iosSimulatorArtifactPath, 'iOS simulator mobile shell archive');
assertFile(
iosSimulatorArtifactPath,
'iOS simulator mobile shell archive',
1024 * 1024,
);
assertGzipHeader(
iosSimulatorArtifactPath,
'iOS simulator mobile shell archive',
);
const iosListing = run(
'tar',
['-tzf', iosSimulatorArtifactPath],
'iOS simulator archive listing',
);
assertIncludes(iosListing, '.app/Info.plist', 'iOS simulator mobile shell archive');
assertIncludes(iosListing, '.app/Genarrative', 'iOS simulator mobile shell archive');
assertIncludes(
iosListing,
'.app/Info.plist',
'iOS simulator mobile shell archive',
);
assertIncludes(
iosListing,
'.app/Genarrative',
'iOS simulator mobile shell archive',
);
assertIncludes(
iosListing,
'.app/main.jsbundle',
@@ -1,4 +1,4 @@
import {spawnSync} from 'node:child_process';
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
const shellRoot = new URL('../', import.meta.url);
@@ -31,24 +31,36 @@ assertObject(easConfig.cli, 'EAS cli config');
assertObject(easConfig.build, 'EAS build config');
if (easConfig.cli.version !== '>= 20.3.0') {
throw new Error('mobile shell EAS CLI version gate must stay pinned to the checked devDependency floor');
throw new Error(
'mobile shell EAS CLI version gate must stay pinned to the checked devDependency floor',
);
}
if (packageConfig.devDependencies?.['eas-cli'] !== '^20.3.0') {
throw new Error('mobile shell package must declare the checked EAS CLI devDependency');
throw new Error(
'mobile shell package must declare the checked EAS CLI devDependency',
);
}
const easVersionResult = spawnSync(npmCommand, ['exec', 'eas', '--', '--version'], {
cwd: shellRoot,
encoding: 'utf8',
});
const easVersionResult = spawnSync(
npmCommand,
['exec', 'eas', '--', '--version'],
{
cwd: shellRoot,
encoding: 'utf8',
},
);
if (easVersionResult.error) {
throw new Error(`failed to start local EAS CLI version check: ${easVersionResult.error.message}`);
throw new Error(
`failed to start local EAS CLI version check: ${easVersionResult.error.message}`,
);
}
if (easVersionResult.signal) {
throw new Error(`local EAS CLI version check was terminated by signal ${easVersionResult.signal}`);
throw new Error(
`local EAS CLI version check was terminated by signal ${easVersionResult.signal}`,
);
}
if ((easVersionResult.status ?? 0) !== 0) {
@@ -62,7 +74,9 @@ if (!(easVersionResult.stdout ?? '').trim().startsWith('eas-cli/20.3.0 ')) {
}
if (easConfig.cli.appVersionSource !== 'local') {
throw new Error('mobile shell EAS builds must use local app.json version fields');
throw new Error(
'mobile shell EAS builds must use local app.json version fields',
);
}
for (const scriptName of ['build:android', 'build:ios', 'build-config:smoke']) {
@@ -90,14 +104,21 @@ for (const [label, outputPath, extension] of [
['iOS simulator', iosSimulatorBuildOutputPath, '.tar.gz'],
]) {
if (!outputPath.startsWith('../../build/native/mobile/')) {
throw new Error(`mobile shell ${label} local build output must stay under root build/native/mobile`);
throw new Error(
`mobile shell ${label} local build output must stay under root build/native/mobile`,
);
}
if (!outputPath.endsWith(extension)) {
throw new Error(`mobile shell ${label} local build output must end with ${extension}`);
throw new Error(
`mobile shell ${label} local build output must end with ${extension}`,
);
}
}
if (packageConfig.scripts['build-config:smoke'] !== 'node scripts/check-eas-build-config.mjs') {
if (
packageConfig.scripts['build-config:smoke'] !==
'node scripts/check-eas-build-config.mjs'
) {
throw new Error('mobile shell EAS config smoke script drifted');
}
@@ -106,31 +127,46 @@ const productionSimulator = easConfig.build['production-simulator'];
assertObject(production, 'EAS Android production profile');
assertObject(productionSimulator, 'EAS iOS simulator production profile');
if (production.distribution !== 'internal' || production.channel !== 'production') {
throw new Error('mobile shell Android production profile must build an internal production package');
if (
production.distribution !== 'internal' ||
production.channel !== 'production'
) {
throw new Error(
'mobile shell Android production profile must build an internal production package',
);
}
if (production.android?.buildType !== 'apk') {
throw new Error('mobile shell Android production profile must produce an installable APK');
throw new Error(
'mobile shell Android production profile must produce an installable APK',
);
}
if (production.env?.EXPO_NO_DOTENV !== '1') {
throw new Error('mobile shell Android production profile must ignore local dotenv files');
throw new Error(
'mobile shell Android production profile must ignore local dotenv files',
);
}
if (
productionSimulator.distribution !== 'internal' ||
productionSimulator.channel !== 'production'
) {
throw new Error('mobile shell iOS simulator production profile must stay internal production');
throw new Error(
'mobile shell iOS simulator production profile must stay internal production',
);
}
if (productionSimulator.ios?.simulator !== true) {
throw new Error('mobile shell iOS production smoke profile must target simulator builds until signing is configured');
throw new Error(
'mobile shell iOS production smoke profile must target simulator builds until signing is configured',
);
}
if (productionSimulator.env?.EXPO_NO_DOTENV !== '1') {
throw new Error('mobile shell iOS simulator production profile must ignore local dotenv files');
throw new Error(
'mobile shell iOS simulator production profile must ignore local dotenv files',
);
}
for (const [profileName, profile] of Object.entries(easConfig.build)) {
@@ -149,7 +185,9 @@ for (const [profileName, profile] of Object.entries(easConfig.build)) {
}
if ('submit' in easConfig) {
throw new Error('mobile shell EAS config must not include store submit profiles yet');
throw new Error(
'mobile shell EAS config must not include store submit profiles yet',
);
}
console.log('[mobile-shell:eas-build-config] OK');
@@ -1,4 +1,4 @@
import {spawnSync} from 'node:child_process';
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
const shellRoot = new URL('../', import.meta.url);
@@ -106,12 +106,16 @@ function readMetadata(platform) {
const fileMetadata = metadata.fileMetadata ?? {};
const metadataPlatforms = Object.keys(fileMetadata);
if (metadataPlatforms.length !== 1 || metadataPlatforms[0] !== platform) {
throw new Error(`Expo ${platform} export metadata must only include its platform`);
throw new Error(
`Expo ${platform} export metadata must only include its platform`,
);
}
const platformMetadata = fileMetadata[platform];
if (!Array.isArray(platformMetadata?.assets)) {
throw new Error(`Expo ${platform} export metadata must include an assets array`);
throw new Error(
`Expo ${platform} export metadata must include an assets array`,
);
}
const bundlePath = platformMetadata?.bundle;
@@ -164,7 +168,7 @@ function assertBundle(platform, bundlePath) {
}
}
fs.rmSync(outputRoot, {recursive: true, force: true});
fs.rmSync(outputRoot, { recursive: true, force: true });
try {
for (const platform of platforms) {
@@ -174,5 +178,5 @@ try {
console.log('[mobile-shell:expo-export] OK');
} finally {
fs.rmSync(outputRoot, {recursive: true, force: true});
fs.rmSync(outputRoot, { recursive: true, force: true });
}