feat: reconcile WebAVP desktop parity and releases

This commit is contained in:
2026-08-19 12:14:29 +00:00
parent 407892ed9a
commit 2a275fc536
26 changed files with 2155 additions and 1508 deletions
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env node
'use strict';
const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const ROOT_DIR = path.resolve(__dirname, '..');
function run(command, args, options = {}) {
const result = spawnSync(command, args, {
cwd: ROOT_DIR,
stdio: 'inherit',
shell: false,
windowsHide: true,
});
if (result.error) {
if (result.error.code === 'ENOENT' && options.allowMissing) return { missing: true };
console.error(`[WebAVP] Failed to run ${command}: ${result.error.message}`);
process.exit(1);
}
if (result.status !== 0) process.exit(result.status || 1);
return { ok: true };
}
for (const file of ['electron/main.js', 'electron/preload.js', 'static/webavp-utils.js', 'tests/webavp-utils.test.js']) {
run(process.execPath, ['--check', file]);
}
run(process.execPath, ['tests/webavp-utils.test.js']);
const html = fs.readFileSync(path.join(ROOT_DIR, 'templates/index.html'), 'utf8');
const required = [
'data-layout="4x4"',
'WebAVPUtils.getAutoGrid',
'Download Desktop App',
'Check for Updates',
'verifyEntryAuth',
'activeSegmentsDirty',
'cameraIdFromFile',
];
for (const marker of required) {
if (!html.includes(marker)) {
console.error(`[WebAVP] Missing required template marker: ${marker}`);
process.exit(1);
}
}
if (/dewarp|fisheye/i.test(html)) {
console.error('[WebAVP] Fisheye dewarp code must not be reintroduced.');
process.exit(1);
}
const pythonCandidates = process.platform === 'win32'
? [['py', ['-3']], ['python', []], ['python3', []]]
: [['python3', []], ['python', []]];
let pythonChecked = false;
for (const [command, prefix] of pythonCandidates) {
const result = spawnSync(command, [...prefix, '-m', 'py_compile', 'app.py'], {
cwd: ROOT_DIR,
stdio: 'inherit',
shell: false,
windowsHide: true,
});
if (result.error?.code === 'ENOENT') continue;
if (result.error || result.status !== 0) process.exit(result.status || 1);
run(command, [...prefix, '-m', 'unittest', 'discover', '-s', 'tests', '-p', '*_test.py']);
pythonChecked = true;
break;
}
if (!pythonChecked) console.warn('[WebAVP] Python unavailable; optional web-server checks skipped.');
console.log('[WebAVP] checks passed');
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env node
'use strict';
const { spawn } = require('node:child_process');
const path = require('node:path');
const ROOT_DIR = path.resolve(__dirname, '..');
const electronPath = require('electron');
const env = {
...process.env,
WEBAVP_DISABLE_GPU: process.env.WEBAVP_DISABLE_GPU || '1',
WEBAVP_SMOKE_QUIT_AFTER_MS: process.env.WEBAVP_SMOKE_QUIT_AFTER_MS || '250',
};
const child = spawn(electronPath, ['.'], {
cwd: ROOT_DIR,
env,
stdio: 'inherit',
shell: false,
windowsHide: true,
});
child.on('error', (err) => {
console.error(`[WebAVP] Failed to start Electron smoke test: ${err.message}`);
process.exit(1);
});
child.on('exit', (code, signal) => {
if (signal) {
console.error(`[WebAVP] Electron smoke test exited via signal ${signal}`);
process.exit(1);
}
process.exit(code || 0);
});