swictation
Version:
Cross-platform voice-to-text dictation for Linux and macOS with GPU acceleration (NVIDIA CUDA/CoreML), Secretary Mode (60+ natural language commands), Context-Aware Meta-Learning, and pure Rust performance. Meta-package that automatically installs platfor
262 lines (226 loc) ⢠8.14 kB
JavaScript
/**
* Version Verification Script
*
* Validates that all package.json files have synchronized versions before publishing.
* Ensures swictation, @agidreams/linux-x64, and @agidreams/darwin-arm64 all have
* the same version as specified in versions.json.
*
* Usage:
* node scripts/verify-versions.js [--verbose] [--allow-missing]
*
* Exit codes:
* 0 - All versions are synchronized
* 1 - Versions are out of sync or validation failed
* 2 - File read/parse error
*/
const fs = require('fs');
const path = require('path');
// Colors for terminal output
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
yellow: '\x1b[33m',
cyan: '\x1b[36m',
red: '\x1b[31m',
dim: '\x1b[2m',
bold: '\x1b[1m'
};
function log(color, message) {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function logDim(message) {
console.log(`${colors.dim}${message}${colors.reset}`);
}
function logBold(message) {
console.log(`${colors.bold}${message}${colors.reset}`);
}
// Parse command line arguments
const args = process.argv.slice(2);
const isVerbose = args.includes('--verbose');
const allowMissing = args.includes('--allow-missing');
// Paths
const rootDir = path.join(__dirname, '..');
const versionsFile = path.join(rootDir, 'versions.json');
const mainPackageFile = path.join(rootDir, 'package.json');
const linuxPackageFile = path.join(rootDir, 'packages', 'linux-x64', 'package.json');
const macosPackageFile = path.join(rootDir, 'packages', 'darwin-arm64', 'package.json');
/**
* Read and parse versions.json
*/
function readVersions() {
if (isVerbose) {
log('cyan', 'š Reading versions.json...');
}
if (!fs.existsSync(versionsFile)) {
log('red', 'ā ERROR: versions.json not found');
logDim(` Expected at: ${versionsFile}`);
process.exit(2);
}
try {
const content = fs.readFileSync(versionsFile, 'utf8');
const versions = JSON.parse(content);
if (!versions.distribution) {
log('red', 'ā ERROR: versions.json missing "distribution" field');
process.exit(2);
}
const semverRegex = /^\d+\.\d+\.\d+$/;
if (!semverRegex.test(versions.distribution)) {
log('red', `ā ERROR: Invalid distribution version format: "${versions.distribution}"`);
log('yellow', ' Expected semver format: X.Y.Z');
process.exit(2);
}
if (isVerbose) {
log('green', `ā Distribution version: ${versions.distribution}`);
}
return versions;
} catch (err) {
log('red', 'ā ERROR: Failed to parse versions.json');
logDim(` ${err.message}`);
process.exit(2);
}
}
/**
* Verify a package.json file has correct version
*/
function verifyPackageJson(filePath, expectedVersion, packageName, isMainPackage = false) {
const relativePath = path.relative(rootDir, filePath);
if (isVerbose) {
log('cyan', `\nš¦ Verifying ${relativePath}...`);
}
// Check if file exists
if (!fs.existsSync(filePath)) {
if (allowMissing) {
if (isVerbose) {
log('yellow', `ā ļø File not found (allowed with --allow-missing)`);
}
return { missing: true, valid: true };
} else {
log('red', `ā ${packageName}: package.json not found`);
logDim(` Expected at: ${filePath}`);
logDim(` Hint: Use --allow-missing if platform packages not created yet`);
return { missing: true, valid: false };
}
}
// Read and parse package.json
let pkg;
try {
const content = fs.readFileSync(filePath, 'utf8');
pkg = JSON.parse(content);
} catch (err) {
log('red', `ā ${packageName}: Failed to parse package.json`);
logDim(` ${err.message}`);
return { error: true, valid: false };
}
const errors = [];
// Verify version field
if (!pkg.version) {
errors.push('version field missing');
} else if (pkg.version !== expectedVersion) {
errors.push(`version mismatch: ${pkg.version} (expected ${expectedVersion})`);
}
// For main package, verify optionalDependencies
if (isMainPackage && pkg.optionalDependencies) {
if (pkg.optionalDependencies['@agidreams/linux-x64']) {
const linuxVersion = pkg.optionalDependencies['@agidreams/linux-x64'];
if (linuxVersion !== expectedVersion) {
errors.push(`optionalDependencies.@agidreams/linux-x64 mismatch: ${linuxVersion} (expected ${expectedVersion})`);
}
}
if (pkg.optionalDependencies['@agidreams/darwin-arm64']) {
const macosVersion = pkg.optionalDependencies['@agidreams/darwin-arm64'];
if (macosVersion !== expectedVersion) {
errors.push(`optionalDependencies.@agidreams/darwin-arm64 mismatch: ${macosVersion} (expected ${expectedVersion})`);
}
}
}
// Report results
if (errors.length > 0) {
log('red', `ā ${packageName}: FAILED`);
errors.forEach(err => logDim(` - ${err}`));
return { errors, valid: false };
} else {
if (isVerbose) {
log('green', `ā ${packageName}: OK (version ${pkg.version})`);
}
return { valid: true, version: pkg.version };
}
}
/**
* Main execution
*/
function main() {
logBold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
logBold(' Swictation Version Verification');
logBold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
// Read versions.json
const versions = readVersions();
const expectedVersion = versions.distribution;
log('cyan', `\nšÆ Expected version: ${expectedVersion}\n`);
// Track results
const results = {
main: verifyPackageJson(mainPackageFile, expectedVersion, 'swictation (main)', true),
linux: verifyPackageJson(linuxPackageFile, expectedVersion, '@agidreams/linux-x64', false),
macos: verifyPackageJson(macosPackageFile, expectedVersion, '@agidreams/darwin-arm64', false)
};
// Summary
logBold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
logBold(' Summary');
logBold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
const packages = [
{ name: 'swictation (main)', result: results.main },
{ name: '@agidreams/linux-x64', result: results.linux },
{ name: '@agidreams/darwin-arm64', result: results.macos }
];
let validCount = 0;
let missingCount = 0;
let errorCount = 0;
packages.forEach(({ name, result }) => {
if (result.error) {
log('red', `ā ${name}: ERROR`);
errorCount++;
} else if (result.missing) {
if (allowMissing) {
log('yellow', `ā ļø ${name}: MISSING (allowed)`);
validCount++; // Count as valid since we're allowing missing
} else {
log('red', `ā ${name}: MISSING`);
errorCount++;
}
missingCount++;
} else if (!result.valid) {
log('red', `ā ${name}: OUT OF SYNC`);
errorCount++;
} else {
log('green', `ā ${name}: OK`);
validCount++;
}
});
console.log('');
log('cyan', `Distribution version: ${expectedVersion}`);
log('green', `Valid: ${validCount}`);
if (missingCount > 0) {
log('yellow', `Missing: ${missingCount}`);
}
if (errorCount > 0) {
log('red', `Errors: ${errorCount}`);
}
// Exit with appropriate code
if (errorCount > 0) {
log('red', '\nā Version verification FAILED');
log('yellow', '\n Fix versions by running: npm run version:sync');
process.exit(1);
} else if (missingCount > 0 && !allowMissing) {
log('red', '\nā Version verification FAILED - platform packages missing');
log('yellow', '\n Options:');
logDim(' 1. Create platform packages first (recommended)');
logDim(' 2. Run with --allow-missing flag to skip validation');
process.exit(1);
} else {
log('green', '\nā
All versions are synchronized');
log('cyan', '\n Safe to publish packages');
process.exit(0);
}
}
// Run
main();