feat(native): harden launcher bridge and implement presentation-aware handover

- Upgraded LauncherBackgroundSync to force-hydrate OS metadata (home/tmp) on mount.
- Hardened electron_relay.ts with robust placeholder resolution and global regex.
- Restored safe handover by making native.launch_from_cache presentation-aware.
- Integrated heartbeat and sync status into the formal Launcher Config UI.
- Added comprehensive technical documentation for the 2026 native architecture.
This commit is contained in:
Scott Idem
2026-01-26 15:12:03 -05:00
parent f0c4022675
commit b072857d68
6 changed files with 528 additions and 218 deletions

View File

@@ -1333,7 +1333,7 @@ exports.run_osascript = async function ({
};
// Run raw command
// Updated 2022-05-07
// Updated 2026-01-26
exports.run_cmd = async function ({
cmd = null,
return_stdout = null,
@@ -1342,12 +1342,18 @@ exports.run_cmd = async function ({
}) {
console.log('*** Electron framework export: run_cmd() ***');
console.log(`Command String: ${cmd}`);
// Resolve placeholders in the command string
let cleaned_cmd = cmd;
if (cmd && typeof cmd === 'string') {
cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
}
console.log(`Command String: ${cleaned_cmd}`);
let result;
if (!sync) {
result = child_process.exec(cmd, (err, stdout, stdin) => {
result = child_process.exec(cleaned_cmd, (err, stdout, stdin) => {
// if (err) throw err;
if (err) {
console.log('Error:', err);
@@ -1366,7 +1372,7 @@ exports.run_cmd = async function ({
}
});
} else {
result = child_process.execSync(cmd, (err, stdout, stdin) => {
result = child_process.execSync(cleaned_cmd, (err, stdout, stdin) => {
// if (err) throw err;
if (err) {
console.log('Error:', err);
@@ -1391,16 +1397,22 @@ exports.run_cmd = async function ({
};
// Run raw command sync
// Updated 2022-05-07
// Updated 2026-01-26
exports.run_cmd_sync = function ({ cmd = null, return_stdout = null, return_stdin = null }) {
console.log('*** Electron framework export: run_cmd() ***');
console.log('*** Electron framework export: run_cmd_sync() ***');
console.log(`Command String: ${cmd}`);
// Resolve placeholders in the command string
let cleaned_cmd = cmd;
if (cmd && typeof cmd === 'string') {
cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
}
console.log(`Command String: ${cleaned_cmd}`);
let stdout;
try {
stdout = child_process.execSync(cmd, { encoding: 'utf8' });
stdout = child_process.execSync(cleaned_cmd, { encoding: 'utf8' });
console.log('Std Out:', stdout);
} catch (err) {
console.error('Error:', err);
@@ -1414,40 +1426,10 @@ exports.run_cmd_sync = function ({ cmd = null, return_stdout = null, return_stdi
console.log('Finished and returning true');
return true;
}
// let result;
// let stdout;
// let stderr;
// try {
// let { stdout, stderr } = child_process.execSync(cmd, (err, stdout, stdin) => {
// // if (err) throw err;
// if (err) {
// console.log('Error:', err);
// return false;
// };
// console.log('stdout:', stdout);
// // console.log('stdin:', stdin);
// if (return_stdout) {
// console.log('Finished and returning stdout');
// return stdout;
// } else {
// console.log('Finished and returning true');
// return true;
// }
// });
// } catch (err) {
// console.error(err);
// return false;
// }
// console.log('Result:', result);
// return result;
};
// Run raw command
// Updated 2022-05-25
// Updated 2026-01-26
exports.get_device_info = async function () {
console.log('*** Electron framework export: get_device_info() ***');
@@ -1465,11 +1447,134 @@ exports.get_device_info = async function () {
data['release'] = os.release();
data['uptime'] = os.uptime();
data['version'] = os.version();
// Add directory info for placeholder resolution in UI
data['home_directory'] = home_directory;
data['tmp_directory'] = tmp_directory;
console.log(data);
return data;
};
/**
* Atomic Copy-and-Launch (Phase 2/5)
* Moves a file from the hashed cache to the operational temp directory
* and triggers the system launcher.
*/
exports.launch_from_cache = async function ({
cache_root,
hash,
temp_root,
filename,
hash_prefix_length = 2
}) {
console.log('*** Aether App Native export: launch_from_cache() ***');
// 1. Resolve Path Placeholders (using global regex)
const clean_cache_root = cache_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
const clean_temp_root = temp_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
const hash_filename = `${hash}.file`;
const prefix = hash.substring(0, hash_prefix_length);
const source_path = path.join(clean_cache_root, prefix, hash_filename);
const dest_path = path.join(clean_temp_root, filename);
console.log(`Source: ${source_path}`);
console.log(`Dest: ${dest_path}`);
try {
// 2. Ensure temp directory exists
if (!fs.existsSync(clean_temp_root)) {
fs.mkdirSync(clean_temp_root, { recursive: true });
}
// 3. Verify Source
if (!fs.existsSync(source_path)) {
throw new Error(`Source file not found in cache: ${source_path}`);
}
// 4. Perform atomic copy
fs.copyFileSync(source_path, dest_path);
console.log('File copied to temp successfully.');
// 5. Trigger Specialized Launcher (if presentation)
const ext = path.extname(filename).toLowerCase().replace('.', '');
const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);
if (is_pres) {
return await exports.launch_presentation({
path: dest_path,
app: ext === 'key' ? 'keynote' : 'default'
});
}
// 6. Default Fallback
return await ipcRenderer.invoke('open_local_file', '', dest_path);
} catch (err) {
console.error('Launch Error:', err);
return { success: false, error: err.message };
}
};
/**
* Specialized Presentation Launcher (Phase 5)
* Handles platform-specific application selection (LibreOffice on Linux,
* PowerPoint/Keynote on macOS).
* Updated 2026-01-26
*/
exports.launch_presentation = async function ({
path: raw_path,
app = 'default',
os_platform = 'auto'
}) {
console.log('*** Aether App Native export: launch_presentation() ***');
// Resolve placeholders if they exist in the incoming path (using global regex)
let cleaned_path = raw_path
.replace(/\[home\]/g, home_directory)
.replace(/\[tmp\]/g, tmp_directory);
console.log(`Raw Path: ${raw_path}; Cleaned Path: ${cleaned_path}; App: ${app}; OS: ${os_platform}`);
// 1. Detect OS
let platform = os_platform;
if (platform === 'auto') {
platform = os.platform();
}
// 2. Handle Linux (LibreOffice Testing)
if (platform === 'linux') {
console.log(`Native: Launching LibreOffice on Linux for path: ${cleaned_path}`);
const cmd = `libreoffice --impress "${cleaned_path}"`;
return new Promise((resolve) => {
child_process.exec(cmd, (err, stdout, stderr) => {
if (err) {
console.error('LibreOffice Launch Error:', err);
resolve({ success: false, error: err.message });
} else {
resolve({ success: true, stdout, stderr });
}
});
});
}
// 3. Handle macOS (Production)
if (platform === 'darwin') {
if (app === 'keynote') {
const script = `tell application "Keynote" to open POSIX file "${cleaned_path}"`;
return exports.run_osascript({ cmd: script });
}
// Default to shell open
return ipcRenderer.invoke('open_local_file', '', cleaned_path);
}
// 4. Default Fallback (Windows/Others)
return ipcRenderer.invoke('open_local_file', '', cleaned_path);
};
// For loading JS file
function loadJS() {
// Gives -1 when the given input is not in the string