mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-08 02:16:41 +02:00
e1060193d0
Prioritize cached first-paint data, defer heavyweight feed synthesis, make MeshChat activation explicit, improve CCTV media handling, and tighten desktop runtime packaging filters.
175 lines
5.0 KiB
JavaScript
175 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { spawnSync } = require('node:child_process');
|
|
|
|
const scriptDir = __dirname;
|
|
const tauriDir = path.resolve(scriptDir, '..');
|
|
const repoRoot = path.resolve(tauriDir, '..', '..');
|
|
const backendDir = path.join(repoRoot, 'backend');
|
|
const privacyCoreDir = path.join(repoRoot, 'privacy-core');
|
|
const outputDir = path.join(tauriDir, 'src-tauri', 'backend-runtime');
|
|
const venvMarkerPath = path.join(backendDir, '.venv-dir');
|
|
const releaseAttestationPath = path.join(backendDir, 'data', 'release_attestation.json');
|
|
const stagedReleaseAttestationPath = path.join(
|
|
outputDir,
|
|
'data',
|
|
'release_attestation.json',
|
|
);
|
|
|
|
const excludedNames = new Set([
|
|
'.env',
|
|
'.pytest_cache',
|
|
'.ruff_cache',
|
|
'__pycache__',
|
|
'backend.egg-info',
|
|
'build',
|
|
'data',
|
|
'tests',
|
|
'timemachine',
|
|
]);
|
|
|
|
const excludedFiles = new Set([
|
|
'.env.example',
|
|
'ais_cache.json',
|
|
'carrier_cache.json',
|
|
'cctv.db',
|
|
'dm_token_pepper.key',
|
|
'pytest.ini',
|
|
]);
|
|
|
|
function backendPythonPath() {
|
|
let venvDir = 'venv';
|
|
try {
|
|
const persisted = fs.readFileSync(venvMarkerPath, 'utf8').trim();
|
|
if (persisted) {
|
|
venvDir = persisted;
|
|
}
|
|
} catch {}
|
|
|
|
if (process.platform === 'win32') {
|
|
return path.join(backendDir, venvDir, 'Scripts', 'python.exe');
|
|
}
|
|
return path.join(backendDir, venvDir, 'bin', 'python3');
|
|
}
|
|
|
|
function shouldCopy(srcPath) {
|
|
const relativePath = path.relative(backendDir, srcPath);
|
|
if (!relativePath) return true;
|
|
|
|
const parts = relativePath.split(path.sep);
|
|
return parts.every((part, index) => {
|
|
const isLeaf = index === parts.length - 1;
|
|
if (excludedNames.has(part)) return false;
|
|
if (isLeaf && excludedFiles.has(part)) return false;
|
|
if (/^test_.*\.py$/i.test(part)) return false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
function ensureRuntimePrereqs() {
|
|
if (!fs.existsSync(path.join(backendDir, 'main.py'))) {
|
|
throw new Error(`Missing backend/main.py at ${backendDir}`);
|
|
}
|
|
if (!fs.existsSync(backendPythonPath())) {
|
|
throw new Error(
|
|
`Missing bundled backend Python runtime at ${backendPythonPath()}. ` +
|
|
'Create the backend venv before packaging the desktop app.',
|
|
);
|
|
}
|
|
if (!fs.existsSync(path.join(backendDir, 'node_modules', 'ws'))) {
|
|
throw new Error(
|
|
`Missing backend/node_modules/ws at ${path.join(backendDir, 'node_modules', 'ws')}. ` +
|
|
'Install backend Node dependencies before packaging the desktop app.',
|
|
);
|
|
}
|
|
}
|
|
|
|
function privacyCoreArtifactName() {
|
|
if (process.platform === 'win32') return 'privacy_core.dll';
|
|
if (process.platform === 'darwin') return 'libprivacy_core.dylib';
|
|
return 'libprivacy_core.so';
|
|
}
|
|
|
|
function privacyCoreArtifactPath() {
|
|
return path.join(privacyCoreDir, 'target', 'release', privacyCoreArtifactName());
|
|
}
|
|
|
|
function ensurePrivacyCoreArtifact() {
|
|
const artifact = privacyCoreArtifactPath();
|
|
if (fs.existsSync(artifact)) {
|
|
return artifact;
|
|
}
|
|
console.log('privacy-core release library missing; building it for desktop packaging...');
|
|
const result = spawnSync(
|
|
'cargo',
|
|
['build', '--release', '--manifest-path', path.join(privacyCoreDir, 'Cargo.toml')],
|
|
{
|
|
cwd: repoRoot,
|
|
env: process.env,
|
|
stdio: 'inherit',
|
|
},
|
|
);
|
|
if (result.error || result.status !== 0) {
|
|
throw new Error(
|
|
'Failed to build privacy-core release library. Install Rust/Cargo and rerun the desktop build.',
|
|
);
|
|
}
|
|
if (!fs.existsSync(artifact)) {
|
|
throw new Error(`privacy-core build completed but artifact is missing: ${artifact}`);
|
|
}
|
|
return artifact;
|
|
}
|
|
|
|
function stageBackendRuntime() {
|
|
fs.rmSync(outputDir, { recursive: true, force: true });
|
|
fs.cpSync(backendDir, outputDir, {
|
|
recursive: true,
|
|
filter: shouldCopy,
|
|
});
|
|
stagePrivacyCoreArtifact();
|
|
stageReleaseAttestation();
|
|
}
|
|
|
|
function stagePrivacyCoreArtifact() {
|
|
const artifact = ensurePrivacyCoreArtifact();
|
|
const stagedPath = path.join(outputDir, path.basename(artifact));
|
|
fs.copyFileSync(artifact, stagedPath);
|
|
}
|
|
|
|
function stageReleaseAttestation() {
|
|
if (!fs.existsSync(releaseAttestationPath)) {
|
|
console.warn(`backend-runtime staged without release attestation: ${releaseAttestationPath}`);
|
|
return;
|
|
}
|
|
fs.mkdirSync(path.dirname(stagedReleaseAttestationPath), { recursive: true });
|
|
fs.copyFileSync(releaseAttestationPath, stagedReleaseAttestationPath);
|
|
}
|
|
|
|
function writeBundleVersion() {
|
|
const versionPath = path.join(outputDir, '.bundle-version');
|
|
const pkg = JSON.parse(
|
|
fs.readFileSync(path.join(repoRoot, 'desktop-shell', 'package.json'), 'utf8'),
|
|
);
|
|
fs.writeFileSync(versionPath, `${pkg.version || '0.0.0'}\n`, 'utf8');
|
|
}
|
|
|
|
function fileCount(root) {
|
|
let count = 0;
|
|
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
const fullPath = path.join(root, entry.name);
|
|
if (entry.isDirectory()) {
|
|
count += fileCount(fullPath);
|
|
} else {
|
|
count += 1;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
ensureRuntimePrereqs();
|
|
stageBackendRuntime();
|
|
writeBundleVersion();
|
|
console.log(`backend-runtime staged: ${fileCount(outputDir)} files`);
|