mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-04-28 11:40:25 +00:00
Co-authored-by: a7m-1st <Ahmed.jimi.awelkeir500@gmail.com> Co-authored-by: eigent-ai <camel@eigent.ai> Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com> Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
345 lines
9.9 KiB
JavaScript
345 lines
9.9 KiB
JavaScript
#!/usr/bin/env node
|
|
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
|
|
/* global console, process */
|
|
|
|
/**
|
|
* Test script for macOS notarization issues
|
|
* This script checks for common issues that cause notarization to fail:
|
|
* 1. .npm-cache directories
|
|
* 2. flac-mac binary (outdated SDK)
|
|
* 3. Unsigned native binaries (.node files)
|
|
* 4. Other problematic files
|
|
*/
|
|
|
|
import { execSync } from 'child_process';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const projectRoot = path.resolve(__dirname, '..');
|
|
|
|
const RELEASE_DIR = path.join(projectRoot, 'release');
|
|
const APP_BUNDLE_PATTERN = /Eigent\.app$/;
|
|
|
|
/**
|
|
* Find the app bundle in release directory
|
|
*/
|
|
function findAppBundle() {
|
|
if (!fs.existsSync(RELEASE_DIR)) {
|
|
console.log(
|
|
'❌ Release directory does not exist. Please build the app first.'
|
|
);
|
|
console.log(' Run: npm run build:mac');
|
|
return null;
|
|
}
|
|
|
|
const entries = fs.readdirSync(RELEASE_DIR, { withFileTypes: true });
|
|
|
|
for (const entry of entries) {
|
|
if (entry.isDirectory() && entry.name.match(APP_BUNDLE_PATTERN)) {
|
|
return path.join(RELEASE_DIR, entry.name);
|
|
}
|
|
|
|
// Check subdirectories (e.g., mac-arm64/Eigent.app)
|
|
if (entry.isDirectory()) {
|
|
const subDir = path.join(RELEASE_DIR, entry.name);
|
|
const subEntries = fs.readdirSync(subDir, { withFileTypes: true });
|
|
for (const subEntry of subEntries) {
|
|
if (subEntry.isDirectory() && subEntry.name.match(APP_BUNDLE_PATTERN)) {
|
|
return path.join(subDir, subEntry.name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check for .npm-cache directories
|
|
*/
|
|
function checkNpmCache(bundlePath) {
|
|
console.log('\n🔍 Checking for .npm-cache directories...');
|
|
const issues = [];
|
|
|
|
function scanDir(dir) {
|
|
if (!fs.existsSync(dir)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
|
|
if (entry.name === '.npm-cache' && entry.isDirectory()) {
|
|
issues.push(fullPath);
|
|
} else if (entry.isDirectory()) {
|
|
// Skip node_modules to avoid deep scanning
|
|
if (entry.name !== 'node_modules' && entry.name !== '__pycache__') {
|
|
scanDir(fullPath);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error checking npm cache: ${error}`);
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
const resourcesPath = path.join(bundlePath, 'Contents', 'Resources');
|
|
const prebuiltPath = path.join(resourcesPath, 'prebuilt');
|
|
|
|
if (fs.existsSync(prebuiltPath)) {
|
|
scanDir(prebuiltPath);
|
|
}
|
|
|
|
if (issues.length > 0) {
|
|
console.log(`❌ Found ${issues.length} .npm-cache directory(ies):`);
|
|
issues.forEach((issue) => console.log(` - ${issue}`));
|
|
return false;
|
|
} else {
|
|
console.log('✅ No .npm-cache directories found');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for flac-mac binary
|
|
*/
|
|
function checkFlacMac(bundlePath) {
|
|
console.log('\n🔍 Checking for flac-mac binary...');
|
|
const issues = [];
|
|
|
|
const resourcesPath = path.join(bundlePath, 'Contents', 'Resources');
|
|
const prebuiltPath = path.join(resourcesPath, 'prebuilt');
|
|
const venvLibPath = path.join(prebuiltPath, 'venv', 'lib');
|
|
|
|
if (fs.existsSync(venvLibPath)) {
|
|
try {
|
|
const entries = fs.readdirSync(venvLibPath, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
if (entry.isDirectory() && entry.name.startsWith('python')) {
|
|
const flacMacPath = path.join(
|
|
venvLibPath,
|
|
entry.name,
|
|
'site-packages',
|
|
'speech_recognition',
|
|
'flac-mac'
|
|
);
|
|
if (fs.existsSync(flacMacPath)) {
|
|
issues.push(flacMacPath);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error checking flac-mac binary: ${error}`);
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
if (issues.length > 0) {
|
|
console.log(
|
|
`❌ Found ${issues.length} flac-mac binary(ies) (outdated SDK):`
|
|
);
|
|
issues.forEach((issue) => console.log(` - ${issue}`));
|
|
return false;
|
|
} else {
|
|
console.log('✅ No flac-mac binaries found');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for unsigned native binaries
|
|
*/
|
|
function checkUnsignedBinaries(bundlePath) {
|
|
console.log('\n🔍 Checking for unsigned native binaries (.node files)...');
|
|
const issues = [];
|
|
|
|
function scanForNodeFiles(dir) {
|
|
if (!fs.existsSync(dir)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
|
|
if (entry.isFile() && entry.name.endsWith('.node')) {
|
|
// Check if file is signed
|
|
try {
|
|
const output = execSync(`codesign -dv "${fullPath}" 2>&1 || true`, {
|
|
encoding: 'utf-8',
|
|
});
|
|
if (output.includes('code object is not signed')) {
|
|
issues.push({
|
|
path: fullPath,
|
|
reason: 'Not signed',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error checking unsigned native binaries: ${error}`);
|
|
// If codesign fails, assume it's not signed
|
|
issues.push({
|
|
path: fullPath,
|
|
reason: 'Could not verify signature',
|
|
});
|
|
}
|
|
} else if (entry.isDirectory()) {
|
|
// Skip certain directories
|
|
if (
|
|
entry.name !== 'node_modules' &&
|
|
entry.name !== '__pycache__' &&
|
|
!entry.name.startsWith('.')
|
|
) {
|
|
scanForNodeFiles(fullPath);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error checking unsigned native binaries: ${error}`);
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
const resourcesPath = path.join(bundlePath, 'Contents', 'Resources');
|
|
const prebuiltPath = path.join(resourcesPath, 'prebuilt');
|
|
|
|
if (fs.existsSync(prebuiltPath)) {
|
|
scanForNodeFiles(prebuiltPath);
|
|
}
|
|
|
|
if (issues.length > 0) {
|
|
console.log(`❌ Found ${issues.length} unsigned .node file(s):`);
|
|
issues.forEach((issue) => {
|
|
console.log(` - ${issue.path}`);
|
|
console.log(` Reason: ${issue.reason}`);
|
|
});
|
|
return false;
|
|
} else {
|
|
console.log('✅ No unsigned .node files found');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check app bundle size
|
|
*/
|
|
function checkBundleSize(bundlePath) {
|
|
console.log('\n🔍 Checking app bundle size...');
|
|
|
|
try {
|
|
function getDirSize(dir) {
|
|
let size = 0;
|
|
try {
|
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isFile()) {
|
|
size += fs.statSync(fullPath).size;
|
|
} else if (entry.isDirectory()) {
|
|
size += getDirSize(fullPath);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error checking bundle size: ${error}`);
|
|
// Ignore errors
|
|
}
|
|
return size;
|
|
}
|
|
|
|
const size = getDirSize(bundlePath);
|
|
const sizeInMB = (size / (1024 * 1024)).toFixed(2);
|
|
console.log(` App bundle size: ${sizeInMB} MB`);
|
|
|
|
if (size > 500 * 1024 * 1024) {
|
|
console.log(
|
|
` ⚠️ Large bundle size (>500MB) may cause slow notarization (30-60 minutes)`
|
|
);
|
|
} else if (size > 200 * 1024 * 1024) {
|
|
console.log(
|
|
` ⚠️ Medium bundle size (200-500MB) may take 15-30 minutes to notarize`
|
|
);
|
|
} else {
|
|
console.log(` ✅ Bundle size is reasonable for notarization`);
|
|
}
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.log(` ⚠️ Could not calculate bundle size: ${error.message}`);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main function
|
|
*/
|
|
function main() {
|
|
console.log('🧪 macOS Notarization Test Script\n');
|
|
|
|
const appBundle = findAppBundle();
|
|
|
|
if (!appBundle) {
|
|
console.log('\n💡 To build the app for testing:');
|
|
console.log(' npm run build:mac');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`📦 Found app bundle: ${appBundle}\n`);
|
|
|
|
const results = {
|
|
npmCache: checkNpmCache(appBundle),
|
|
flacMac: checkFlacMac(appBundle),
|
|
unsignedBinaries: checkUnsignedBinaries(appBundle),
|
|
bundleSize: checkBundleSize(appBundle),
|
|
};
|
|
|
|
console.log('\n📊 Summary:');
|
|
console.log(` .npm-cache directories: ${results.npmCache ? '✅' : '❌'}`);
|
|
console.log(` flac-mac binaries: ${results.flacMac ? '✅' : '❌'}`);
|
|
console.log(
|
|
` Unsigned .node files: ${results.unsignedBinaries ? '✅' : '❌'}`
|
|
);
|
|
console.log(` Bundle size: ${results.bundleSize ? '✅' : '⚠️'}`);
|
|
|
|
const allPassed = Object.values(results).every((r) => r);
|
|
|
|
if (allPassed) {
|
|
console.log(
|
|
'\n✅ All checks passed! The app should be ready for notarization.'
|
|
);
|
|
console.log('\n💡 Note: This script only checks for common issues.');
|
|
console.log(' Actual notarization may still fail for other reasons.');
|
|
console.log(' To test actual notarization, you need:');
|
|
console.log(' - Valid Apple Developer ID certificate');
|
|
console.log(
|
|
' - APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID environment variables'
|
|
);
|
|
} else {
|
|
console.log(
|
|
'\n❌ Some checks failed. Please fix the issues above before notarization.'
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|