feat: implement Phase 5 system handlers (automation, power, recording)

- Implement window control, wallpaper reset, and power management.
- Add Aperture recording wrapper and displayplacer layout control.
- Add self-update logic stub for local/remote sources.
- Register and expose handlers via context bridge.
This commit is contained in:
Scott Idem
2026-01-30 11:34:53 -05:00
parent 3d7aa1ab92
commit fb8af70742
15 changed files with 803 additions and 15 deletions

View File

@@ -40,6 +40,8 @@ exports.registerFileHandlers = registerFileHandlers;
const electron_1 = require("electron");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const child_process_1 = require("child_process");
const axios_1 = __importDefault(require("axios"));
const file_utils_1 = require("./file_utils");
let endpoints_in_progress = [];
@@ -98,9 +100,63 @@ function registerFileHandlers() {
const source = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
const expanded_temp = (0, file_utils_1.expandPath)(temp_root);
const target = path.join(expanded_temp, filename);
console.log(`Native: Launching from Cache -> ${filename}`);
if (!fs.existsSync(expanded_temp))
fs.mkdirSync(expanded_temp, { recursive: true });
// 1. Copy the file to temp folder with original name
fs.copyFileSync(source, target);
// 2. Determine file type
const ext = path.extname(filename).toLowerCase().replace('.', '');
const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);
// 3. Optimized Launch (LibreOffice / AppleScript)
if (is_pres) {
if (os.platform() === 'linux') {
console.log(`Native: Launching LibreOffice (--impress) for ${target}`);
return new Promise((resolve) => {
(0, child_process_1.exec)(`libreoffice --impress "${target}"`, (err) => {
if (err)
resolve({ success: false, error: err.message });
else
resolve({ success: true });
});
});
}
if (os.platform() === 'darwin') {
let script = '';
if (ext === 'key') {
script = `
tell application "Keynote"
activate
open (POSIX file "${target}")
delay 1
start (front document)
end tell
`;
}
else if (ext === 'pptx' || ext === 'ppt') {
script = `
tell application "Microsoft PowerPoint"
activate
open (POSIX file "${target}")
delay 1
run slide show of active presentation
end tell
`;
}
if (script) {
console.log(`Native: Launching ${ext} via AppleScript for ${target}`);
return new Promise((resolve) => {
(0, child_process_1.exec)(`osascript -e "${script.replace(/"/g, '\\\\"')}"`, (err) => {
if (err)
resolve({ success: false, error: err.message });
else
resolve({ success: true });
});
});
}
}
}
// 4. Default Fallback
await electron_1.shell.openPath(target);
return { success: true };
}

View File

@@ -1 +1 @@
{"version":3,"file":"file_handlers.js","sourceRoot":"","sources":["../../src/main/file_handlers.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"file_handlers.js","sourceRoot":"","sources":["../../src/main/file_handlers.ts"],"names":[],"mappings":"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"}

View File

@@ -40,10 +40,10 @@ const path = __importStar(require("path"));
function expandPath(filePath) {
if (!filePath)
return filePath;
if (filePath.startsWith('[home]')) {
return path.join(os.homedir(), filePath.replace('[home]', ''));
}
return filePath;
// Resolve all instances of [home] and [tmp] using global regex
return filePath
.replace(/\[home\]/g, os.homedir())
.replace(/\[tmp\]/g, os.tmpdir());
}
function getHashedPath(cacheRoot, hash) {
const expandedRoot = expandPath(cacheRoot);

View File

@@ -1 +1 @@
{"version":3,"file":"file_utils.js","sourceRoot":"","sources":["../../src/main/file_utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,gCAMC;AAED,sCAIC;AAfD,uCAAyB;AACzB,2CAA6B;AAE7B,SAAgB,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/B,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAgB,aAAa,CAAC,SAAiB,EAAE,IAAY;IAC3D,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AAC/D,CAAC"}
{"version":3,"file":"file_utils.js","sourceRoot":"","sources":["../../src/main/file_utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,gCAMC;AAED,sCAIC;AAfD,uCAAyB;AACzB,2CAA6B;AAE7B,SAAgB,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/B,+DAA+D;IAC/D,OAAO,QAAQ;SACZ,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC;SAClC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,SAAgB,aAAa,CAAC,SAAiB,EAAE,IAAY;IAC3D,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AAC/D,CAAC"}

9
dist/main/index.js vendored
View File

@@ -40,6 +40,7 @@ const config_loader_1 = require("./config_loader");
const api_client_1 = require("./api_client");
const shell_handlers_1 = require("./shell_handlers");
const file_handlers_1 = require("./file_handlers");
const system_handlers_1 = require("./system_handlers");
let mainWindow = null;
let cachedSeed = null;
let cachedFullConfig = null;
@@ -49,7 +50,7 @@ async function createWindow() {
cachedFullConfig = await (0, api_client_1.fetchFullConfig)(cachedSeed);
}
mainWindow = new electron_1.BrowserWindow({
width: 1400,
width: 1600,
height: 900,
title: 'OSIT Aether Launcher (Native)',
webPreferences: {
@@ -67,6 +68,7 @@ async function createWindow() {
const useHost = (host.includes('localhost')) ? host : 'demo.localhost:5173';
targetUrl = `http://${useHost}/events/${eventId}/launcher/${locationId}`;
}
mainWindow.webContents.openDevTools();
mainWindow.loadURL(targetUrl).catch(() => {
mainWindow?.loadURL('https://dev-demo.oneskyit.com/');
});
@@ -74,6 +76,7 @@ async function createWindow() {
}
(0, shell_handlers_1.registerShellHandlers)();
(0, file_handlers_1.registerFileHandlers)();
(0, system_handlers_1.registerSystemHandlers)();
electron_1.app.on('ready', createWindow);
electron_1.app.on('window-all-closed', () => {
if (process.platform !== 'darwin')
@@ -104,7 +107,9 @@ electron_1.ipcMain.handle('get-device-info', async () => {
cpus: os.cpus().length,
total_mem: os.totalmem(),
free_mem: os.freemem(),
ip_addresses: addresses
ip_addresses: addresses,
home_directory: os.homedir(),
tmp_directory: os.tmpdir()
};
});
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAuD;AACvD,2CAA6B;AAC7B,uCAAyB;AACzB,mDAAiD;AACjD,6CAA+C;AAC/C,qDAAyD;AACzD,mDAAuD;AAGvD,IAAI,UAAU,GAAyB,IAAI,CAAC;AAC5C,IAAI,UAAU,GAAsB,IAAI,CAAC;AACzC,IAAI,gBAAgB,GAAQ,IAAI,CAAC;AAEjC,KAAK,UAAU,YAAY;IACzB,UAAU,GAAG,MAAM,IAAA,8BAAc,GAAE,CAAC;IACpC,IAAI,UAAU,EAAE,CAAC;QACf,gBAAgB,GAAG,MAAM,IAAA,4BAAe,EAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,UAAU,GAAG,IAAI,wBAAa,CAAC;QAC7B,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,+BAA+B;QACtC,cAAc,EAAE;YACd,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC;YACpD,gBAAgB,EAAE,IAAI;YACtB,eAAe,EAAE,KAAK;SACvB;KACF,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,4BAA4B,CAAC;IAC7C,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,aAAa,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,aAAa,CAAC;QAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,QAAQ,CAAC;QAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACrF,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,qBAAqB,CAAC;QAC1D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC;QAC5E,SAAS,GAAG,UAAU,OAAO,WAAW,OAAO,aAAa,UAAU,EAAE,CAAC;IAC3E,CAAC;IAED,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACvC,UAAU,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,IAAA,sCAAqB,GAAE,CAAC;AACxB,IAAA,oCAAoB,GAAE,CAAC;AACvB,cAAG,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AAE9B,cAAG,CAAC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAC/B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,cAAG,CAAC,IAAI,EAAE,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;IACtB,IAAI,UAAU,KAAK,IAAI;QAAE,YAAY,EAAE,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,kBAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,IAAI,MAAM,IAAA,8BAAc,GAAE,CAAC,CAAC;AACpF,kBAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC,gBAAgB,CAAC,CAAC;AAClE,kBAAO,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AAE5C,kBAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;IAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;gBAC3C,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;QACrB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QACf,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;QACtB,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE;QACxB,QAAQ,EAAE,EAAE,CAAC,OAAO,EAAE;QACtB,YAAY,EAAE,SAAS;KACxB,CAAC;AACJ,CAAC,CAAC,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAuD;AACvD,2CAA6B;AAC7B,uCAAyB;AACzB,mDAAiD;AACjD,6CAA+C;AAC/C,qDAAyD;AACzD,mDAAuD;AACvD,uDAA2D;AAG3D,IAAI,UAAU,GAAyB,IAAI,CAAC;AAC5C,IAAI,UAAU,GAAsB,IAAI,CAAC;AACzC,IAAI,gBAAgB,GAAQ,IAAI,CAAC;AAEjC,KAAK,UAAU,YAAY;IACzB,UAAU,GAAG,MAAM,IAAA,8BAAc,GAAE,CAAC;IACpC,IAAI,UAAU,EAAE,CAAC;QACf,gBAAgB,GAAG,MAAM,IAAA,4BAAe,EAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,UAAU,GAAG,IAAI,wBAAa,CAAC;QAC7B,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,+BAA+B;QACtC,cAAc,EAAE;YACd,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC;YACpD,gBAAgB,EAAE,IAAI;YACtB,eAAe,EAAE,KAAK;SACvB;KACF,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,4BAA4B,CAAC;IAC7C,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,aAAa,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,aAAa,CAAC;QAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,QAAQ,CAAC;QAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACrF,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,qBAAqB,CAAC;QAC1D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC;QAC5E,SAAS,GAAG,UAAU,OAAO,WAAW,OAAO,aAAa,UAAU,EAAE,CAAC;IAC3E,CAAC;IAED,UAAU,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;IACtC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACvC,UAAU,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,IAAA,sCAAqB,GAAE,CAAC;AACxB,IAAA,oCAAoB,GAAE,CAAC;AACvB,IAAA,wCAAsB,GAAE,CAAC;AAEzB,cAAG,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AAE9B,cAAG,CAAC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAC/B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,cAAG,CAAC,IAAI,EAAE,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;IACtB,IAAI,UAAU,KAAK,IAAI;QAAE,YAAY,EAAE,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,kBAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,IAAI,MAAM,IAAA,8BAAc,GAAE,CAAC,CAAC;AACpF,kBAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC,gBAAgB,CAAC,CAAC;AAClE,kBAAO,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AAE5C,kBAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;IAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;gBAC3C,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;QACrB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QACf,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;QACtB,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE;QACxB,QAAQ,EAAE,EAAE,CAAC,OAAO,EAAE;QACtB,YAAY,EAAE,SAAS;QACvB,cAAc,EAAE,EAAE,CAAC,OAAO,EAAE;QAC5B,aAAa,EAAE,EAAE,CAAC,MAAM,EAAE;KAC3B,CAAC;AACJ,CAAC,CAAC,CAAC"}

View File

@@ -37,21 +37,25 @@ exports.registerShellHandlers = registerShellHandlers;
const electron_1 = require("electron");
const child_process_1 = require("child_process");
const os = __importStar(require("os"));
const file_utils_1 = require("./file_utils");
function registerShellHandlers() {
electron_1.ipcMain.handle('native:open-folder', async (event, folderPath) => {
const error = await electron_1.shell.openPath(folderPath);
const cleanPath = (0, file_utils_1.expandPath)(folderPath);
const error = await electron_1.shell.openPath(cleanPath);
return { success: !error, error };
});
electron_1.ipcMain.handle('native:run-cmd', async (event, { cmd, timeout = 30000 }) => {
const cleanCmd = (0, file_utils_1.expandPath)(cmd);
return new Promise((resolve) => {
(0, child_process_1.exec)(cmd, { timeout }, (error, stdout, stderr) => {
(0, child_process_1.exec)(cleanCmd, { timeout }, (error, stdout, stderr) => {
resolve({ success: !error, stdout: stdout.trim(), stderr: stderr.trim(), error: error ? error.message : null });
});
});
});
electron_1.ipcMain.handle('native:run-cmd-sync', async (event, { cmd }) => {
const cleanCmd = (0, file_utils_1.expandPath)(cmd);
try {
const stdout = (0, child_process_1.execSync)(cmd).toString();
const stdout = (0, child_process_1.execSync)(cleanCmd).toString();
return { success: true, stdout: stdout.trim() };
}
catch (error) {
@@ -87,8 +91,168 @@ function registerShellHandlers() {
return { success: true, results };
});
electron_1.ipcMain.handle('native:open-local-file-v2', async (event, filePath) => {
const error = await electron_1.shell.openPath(filePath);
const cleanPath = (0, file_utils_1.expandPath)(filePath);
const error = await electron_1.shell.openPath(cleanPath);
return { success: !error, error };
});
electron_1.ipcMain.handle('native:launch-presentation', async (event, { path: rawPath, app: appType = 'default' }) => {
const cleanedPath = (0, file_utils_1.expandPath)(rawPath);
console.log(`Native: Launching Presentation -> ${cleanedPath} (App: ${appType})`);
if (os.platform() === 'linux') {
const cmd = `libreoffice --impress "${cleanedPath}"`;
return new Promise((resolve) => {
(0, child_process_1.exec)(cmd, (err, stdout, stderr) => {
if (err)
resolve({ success: false, error: err.message });
else
resolve({ success: true, stdout, stderr });
});
});
}
if (os.platform() === 'darwin') {
let script = '';
if (appType === 'keynote') {
script = `
tell application "Keynote"
activate
open (POSIX file "${cleanedPath}")
delay 1
start (front document)
end tell
`;
}
else if (appType === 'powerpoint') {
script = `
tell application "Microsoft PowerPoint"
activate
open (POSIX file "${cleanedPath}")
delay 1
run slide show of active presentation
end tell
`;
}
if (script) {
return new Promise((resolve) => {
const escapedScript = script.replace(/"/g, '\\"');
(0, child_process_1.exec)(`osascript -e "${escapedScript}"`, (err, stdout, stderr) => {
if (err)
resolve({ success: false, error: err.message });
else
resolve({ success: true });
});
});
}
}
const error = await electron_1.shell.openPath(cleanedPath);
return { success: !error, error };
});
electron_1.ipcMain.handle('native:control-presentation', async (event, { app, action }) => {
if (os.platform() !== 'darwin')
return { success: false, error: 'Presentation control is only available on macOS' };
let script = '';
if (app === 'powerpoint') {
switch (action) {
case 'next':
script = 'tell application "Microsoft PowerPoint" to next slide of slide show view of active presentation';
break;
case 'prev':
script = 'tell application "Microsoft PowerPoint" to previous slide of slide show view of active presentation';
break;
case 'start':
script = 'tell application "Microsoft PowerPoint" to run slide show of active presentation';
break;
case 'stop':
script = 'tell application "Microsoft PowerPoint" to stop slide show of active presentation';
break;
}
}
else if (app === 'keynote') {
switch (action) {
case 'next':
script = 'tell application "Keynote" to show next';
break;
case 'prev':
script = 'tell application "Keynote" to show previous';
break;
case 'start':
script = 'tell application "Keynote" to start (front document)';
break;
case 'stop':
script = 'tell application "Keynote" to stop';
break;
}
}
if (!script)
return { success: false, error: `Unsupported app or action: ${app}/${action}` };
return new Promise((resolve) => {
(0, child_process_1.exec)(`osascript -e "${script.replace(/"/g, '\\"')}"`, (error, stdout, stderr) => {
resolve({ success: !error, stdout: stdout.trim(), stderr: stderr.trim(), error: error ? error.message : null });
});
});
});
electron_1.ipcMain.handle('native:list-tools', async () => {
return [
{
name: 'open_folder',
description: 'Opens a directory in the OS file explorer (Finder/Files/Explorer).',
params: { path: 'string' }
},
{
name: 'run_cmd',
description: 'Executes an asynchronous shell command with a timeout.',
params: { cmd: 'string', timeout: 'number (optional)' }
},
{
name: 'run_cmd_sync',
description: 'Executes a synchronous shell command.',
params: { cmd: 'string' }
},
{
name: 'run_osascript',
description: 'Executes a raw AppleScript string (macOS only).',
params: { script: 'string' }
},
{
name: 'kill_processes',
description: 'Forcefully terminates processes by name.',
params: { process_name_li: 'string[]' }
},
{
name: 'open_local_file_v2',
description: 'Opens a local file using the default OS handler.',
params: { filePath: 'string' }
},
{
name: 'launch_presentation',
description: 'Phase 5: Specialized launcher for PowerPoint, Keynote, and LibreOffice with auto-focus.',
params: { path: 'string', app: 'default|powerpoint|keynote' }
},
{
name: 'control_presentation',
description: 'Phase 5: Remote navigation for active slideshows.',
params: { app: 'powerpoint|keynote', action: 'next|prev|start|stop' }
},
{
name: 'check_cache',
description: 'Checks if a file exists in the local organized cache.',
params: { cache_root: 'string', hash: 'string', hash_prefix_length: 'number' }
},
{
name: 'download_to_cache',
description: 'Downloads a file from the API directly into the native cache.',
params: { url: 'string', cache_root: 'string', hash: 'string', api_key: 'string', account_id: 'string' }
},
{
name: 'launch_from_cache',
description: 'Atomic operation: Copies file from cache to temp with original name and launches via specialized handler.',
params: { cache_root: 'string', hash: 'string', temp_root: 'string', filename: 'string' }
},
{
name: 'get_device_info',
description: 'Returns hardware and OS metadata (CPUs, RAM, IP addresses, Hostname).',
params: {}
}
];
});
}
//# sourceMappingURL=shell_handlers.js.map

File diff suppressed because one or more lines are too long

293
dist/main/system_handlers.js vendored Normal file
View File

@@ -0,0 +1,293 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerSystemHandlers = registerSystemHandlers;
const electron_1 = require("electron");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const child_process_1 = require("child_process");
const axios_1 = __importDefault(require("axios"));
const file_utils_1 = require("./file_utils");
// Helper to execute shell commands
const runExec = (cmd) => {
return new Promise((resolve) => {
(0, child_process_1.exec)(cmd, (error, stdout, stderr) => {
resolve({
success: !error,
stdout: stdout.trim(),
stderr: stderr.trim(),
error: error ? error.message : undefined
});
});
});
};
let recordingProcess = null;
function registerSystemHandlers() {
// 1. Window Control
electron_1.ipcMain.handle('native:window-control', async (event, { action, value }) => {
const win = electron_1.BrowserWindow.fromWebContents(event.sender);
if (!win)
return { success: false, error: 'No window found' };
switch (action) {
case 'maximize':
win.maximize();
break;
case 'unmaximize':
win.unmaximize();
break;
case 'minimize':
win.minimize();
break;
case 'restore':
win.restore();
break;
case 'close':
win.close();
break;
case 'devtools':
if (value)
win.webContents.openDevTools();
else
win.webContents.closeDevTools();
break;
case 'kiosk':
win.setKiosk(!!value);
break;
case 'fullscreen':
win.setFullScreen(!!value);
break;
case 'reload':
win.reload();
break;
default: return { success: false, error: `Unknown action: ${action}` };
}
return { success: true };
});
// 2. Set Wallpaper
electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
const cleanPath = (0, file_utils_1.expandPath)(imagePath);
if (!fs.existsSync(cleanPath))
return { success: false, error: 'Image file not found' };
if (os.platform() === 'darwin') {
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
return await runExec(`osascript -e '${script}'`);
}
else if (os.platform() === 'linux') {
// Gnome/Ubuntu default
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
}
return { success: false, error: 'Platform not supported' };
});
// 3. Power Control
electron_1.ipcMain.handle('native:power-control', async (event, { action }) => {
let cmd = '';
const isMac = os.platform() === 'darwin';
const isLinux = os.platform() === 'linux';
if (action === 'shutdown') {
if (isMac)
cmd = 'shutdown -h now'; // Requires sudo/admin usually
if (isLinux)
cmd = 'shutdown -h now';
}
else if (action === 'reboot') {
if (isMac)
cmd = 'shutdown -r now';
if (isLinux)
cmd = 'reboot';
}
else if (action === 'sleep') {
if (isMac)
cmd = 'pmset sleepnow';
if (isLinux)
cmd = 'systemctl suspend';
}
if (!cmd)
return { success: false, error: 'Action not supported' };
// NOTE: These commands often require root.
// For a kiosk, you might configure sudoers to allow this specific command without password.
return await runExec(cmd);
});
// 4. Open External (Browser)
electron_1.ipcMain.handle('native:open-external', async (event, { url, app: appName }) => {
if (appName === 'chrome') {
if (os.platform() === 'darwin') {
return await runExec(`open -a "Google Chrome" "${url}"`);
}
else if (os.platform() === 'linux') {
return await runExec(`google-chrome "${url}"`);
}
}
else if (appName === 'firefox') {
if (os.platform() === 'darwin') {
return await runExec(`open -a "Firefox" "${url}"`);
}
else if (os.platform() === 'linux') {
return await runExec(`firefox "${url}"`);
}
}
// Default system handler
await electron_1.shell.openExternal(url);
return { success: true };
});
// 5. Manage Recording (Aperture Wrapper)
electron_1.ipcMain.handle('native:manage-recording', async (event, { action, options }) => {
if (os.platform() !== 'darwin')
return { success: false, error: 'Recording only supported on macOS' };
// Path to bundled aperture binary
// In dev: ./resources/bin/aperture
// In prod: process.resourcesPath/bin/aperture
const binPath = electron_1.app.isPackaged
? path.join(process.resourcesPath, 'bin', 'aperture')
: path.join(__dirname, '../../resources/bin/aperture'); // Adjust based on structure
if (action === 'start') {
if (recordingProcess)
return { success: false, error: 'Recording already in progress' };
const { fps = 30, audioDeviceId, output } = options || {};
const cleanOutput = (0, file_utils_1.expandPath)(output || '~/tmp/recording.mp4');
const args = ['run', '--fps', fps, '--output', cleanOutput];
if (audioDeviceId)
args.push('--audio-device-id', audioDeviceId);
// Spawn process
// Note: aperture is a CLI tool. We might need 'aperture' node package or the binary.
// Assuming binary usage here.
try {
console.log(`Starting recording: ${binPath} ${args.join(' ')}`);
recordingProcess = (0, child_process_1.spawn)(binPath, args);
recordingProcess.on('error', (err) => {
console.error('Recording error:', err);
recordingProcess = null;
});
recordingProcess.on('exit', (code) => {
console.log(`Recording exited with code ${code}`);
recordingProcess = null;
});
return { success: true, pid: recordingProcess.pid };
}
catch (e) {
return { success: false, error: e.message };
}
}
else if (action === 'stop') {
if (!recordingProcess)
return { success: false, error: 'No recording in progress' };
recordingProcess.kill('SIGINT'); // Send interrupt to stop cleanly
recordingProcess = null;
return { success: true };
}
else if (action === 'status') {
return { success: true, isRecording: !!recordingProcess };
}
return { success: false, error: 'Unknown action' };
});
// 6. Set Display Layout (Displayplacer)
electron_1.ipcMain.handle('native:set-display-layout', async (event, { mode, configStr }) => {
if (os.platform() !== 'darwin')
return { success: false, error: 'Display control only supported on macOS' };
const binPath = electron_1.app.isPackaged
? path.join(process.resourcesPath, 'bin', 'displayplacer')
: path.join(__dirname, '../../resources/bin/displayplacer');
let cmd = '';
if (mode === 'mirror') {
// This usually requires querying current IDs, which is complex.
// If configStr is provided (output of 'displayplacer list'), use it.
if (configStr) {
cmd = `"${binPath}" ${configStr}`;
}
else {
return { success: false, error: 'Config string required for now' };
}
}
else if (mode === 'extend') {
if (configStr) {
cmd = `"${binPath}" ${configStr}`;
}
}
if (cmd) {
return await runExec(cmd);
}
return { success: false, error: 'Invalid mode or missing config' };
});
// 7. Update App
electron_1.ipcMain.handle('native:update-app', async (event, { source, url, path: localPath }) => {
// 1. Determine Source File
let updateFile = '';
const tempDir = os.tmpdir();
const destName = 'update_package.zip'; // Or .app, .AppImage
const destPath = path.join(tempDir, destName);
if (source === 'url' && url) {
// Download
try {
const response = await (0, axios_1.default)({
method: 'get',
url: url,
responseType: 'stream'
});
const writer = fs.createWriteStream(destPath);
response.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', () => resolve(true));
writer.on('error', reject);
});
updateFile = destPath;
}
catch (e) {
return { success: false, error: `Download failed: ${e.message}` };
}
}
else if (source === 'file' && localPath) {
const cleanLocal = (0, file_utils_1.expandPath)(localPath);
if (fs.existsSync(cleanLocal)) {
updateFile = cleanLocal;
}
else {
return { success: false, error: 'Local update file not found' };
}
}
if (!updateFile)
return { success: false, error: 'No update source provided' };
// 2. Install Logic (Stub)
// Real implementation depends on OS and packaging format.
// macOS: Mount DMG, copy .app to /Applications? Or Unzip .app?
// Linux: chmod +x AppImage and move?
console.log(`Ready to install update from: ${updateFile}`);
// For now, just return success so the UI knows we "downloaded" it.
return { success: true, message: 'Update downloaded/located. Installation logic requires packaging specifics.', downloadedPath: updateFile };
});
}
//# sourceMappingURL=system_handlers.js.map

1
dist/main/system_handlers.js.map vendored Normal file

File diff suppressed because one or more lines are too long

11
dist/preload/index.js vendored
View File

@@ -15,5 +15,16 @@ electron_1.contextBridge.exposeInMainWorld('aetherNative', {
check_cache: (args) => electron_1.ipcRenderer.invoke('native:check-cache', args),
download_to_cache: (args) => electron_1.ipcRenderer.invoke('native:download-to-cache', args),
launch_from_cache: (args) => electron_1.ipcRenderer.invoke('native:launch-from-cache', args),
launch_presentation: (args) => electron_1.ipcRenderer.invoke('native:launch-presentation', args),
control_presentation: (args) => electron_1.ipcRenderer.invoke('native:control-presentation', args),
list_tools: () => electron_1.ipcRenderer.invoke('native:list-tools'),
// System Handlers (V5)
set_wallpaper: (args) => electron_1.ipcRenderer.invoke('native:set-wallpaper', args),
update_app: (args) => electron_1.ipcRenderer.invoke('native:update-app', args),
window_control: (args) => electron_1.ipcRenderer.invoke('native:window-control', args),
manage_recording: (args) => electron_1.ipcRenderer.invoke('native:manage-recording', args),
set_display_layout: (args) => electron_1.ipcRenderer.invoke('native:set-display-layout', args),
power_control: (args) => electron_1.ipcRenderer.invoke('native:power-control', args),
open_external: (args) => electron_1.ipcRenderer.invoke('native:open-external', args),
});
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/preload/index.ts"],"names":[],"mappings":";;AAAA,uCAAsD;AAEtD,wBAAa,CAAC,iBAAiB,CAAC,cAAc,EAAE;IAC9C,eAAe,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAC5D,iBAAiB,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAChE,OAAO,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,SAAS,CAAC;IAC5C,eAAe,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAE5D,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC;IAC7E,OAAO,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC;IAClE,YAAY,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC;IAC5E,aAAa,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACrF,cAAc,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,uBAAuB,EAAE,IAAI,CAAC;IAChF,kBAAkB,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,2BAA2B,EAAE,IAAI,CAAC;IAE3F,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC;IAC1E,iBAAiB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC;IACtF,iBAAiB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC;CACvF,CAAC,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/preload/index.ts"],"names":[],"mappings":";;AAAA,uCAAsD;AAEtD,wBAAa,CAAC,iBAAiB,CAAC,cAAc,EAAE;IAC9C,eAAe,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAC5D,iBAAiB,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAChE,OAAO,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,SAAS,CAAC;IAC5C,eAAe,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAE5D,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC;IAC7E,OAAO,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC;IAClE,YAAY,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC;IAC5E,aAAa,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACrF,cAAc,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,uBAAuB,EAAE,IAAI,CAAC;IAChF,kBAAkB,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,2BAA2B,EAAE,IAAI,CAAC;IAE3F,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC;IAC1E,iBAAiB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC;IACtF,iBAAiB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC;IACtF,mBAAmB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,4BAA4B,EAAE,IAAI,CAAC;IAC1F,oBAAoB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,6BAA6B,EAAE,IAAI,CAAC;IAC5F,UAAU,EAAE,GAAG,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAEzD,uBAAuB;IACvB,aAAa,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,sBAAsB,EAAE,IAAI,CAAC;IAC9E,UAAU,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,mBAAmB,EAAE,IAAI,CAAC;IACxE,cAAc,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,uBAAuB,EAAE,IAAI,CAAC;IAChF,gBAAgB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,yBAAyB,EAAE,IAAI,CAAC;IACpF,kBAAkB,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,2BAA2B,EAAE,IAAI,CAAC;IACxF,aAAa,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,sBAAsB,EAAE,IAAI,CAAC;IAC9E,aAAa,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,sBAAW,CAAC,MAAM,CAAC,sBAAsB,EAAE,IAAI,CAAC;CAC/E,CAAC,CAAC"}

View File

@@ -5,6 +5,7 @@ import { loadSeedConfig } from './config_loader';
import { fetchFullConfig } from './api_client';
import { registerShellHandlers } from './shell_handlers';
import { registerFileHandlers } from './file_handlers';
import { registerSystemHandlers } from './system_handlers';
import { SeedConfig } from '../shared/types';
let mainWindow: BrowserWindow | null = null;
@@ -48,6 +49,8 @@ async function createWindow() {
registerShellHandlers();
registerFileHandlers();
registerSystemHandlers();
app.on('ready', createWindow);
app.on('window-all-closed', () => {

246
src/main/system_handlers.ts Normal file
View File

@@ -0,0 +1,246 @@
import { ipcMain, BrowserWindow, app, shell } from 'electron';
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs';
import { exec, spawn } from 'child_process';
import axios from 'axios';
import { expandPath } from './file_utils';
// Helper to execute shell commands
const runExec = (cmd: string): Promise<{ success: boolean; stdout?: string; stderr?: string; error?: string }> => {
return new Promise((resolve) => {
exec(cmd, (error, stdout, stderr) => {
resolve({
success: !error,
stdout: stdout.trim(),
stderr: stderr.trim(),
error: error ? error.message : undefined
});
});
});
};
let recordingProcess: any = null;
export function registerSystemHandlers() {
// 1. Window Control
ipcMain.handle('native:window-control', async (event, { action, value }) => {
const win = BrowserWindow.fromWebContents(event.sender);
if (!win) return { success: false, error: 'No window found' };
switch (action) {
case 'maximize': win.maximize(); break;
case 'unmaximize': win.unmaximize(); break;
case 'minimize': win.minimize(); break;
case 'restore': win.restore(); break;
case 'close': win.close(); break;
case 'devtools':
if (value) win.webContents.openDevTools();
else win.webContents.closeDevTools();
break;
case 'kiosk': win.setKiosk(!!value); break;
case 'fullscreen': win.setFullScreen(!!value); break;
case 'reload': win.reload(); break;
default: return { success: false, error: `Unknown action: ${action}` };
}
return { success: true };
});
// 2. Set Wallpaper
ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
const cleanPath = expandPath(imagePath);
if (!fs.existsSync(cleanPath)) return { success: false, error: 'Image file not found' };
if (os.platform() === 'darwin') {
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
return await runExec(`osascript -e '${script}'`);
} else if (os.platform() === 'linux') {
// Gnome/Ubuntu default
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
}
return { success: false, error: 'Platform not supported' };
});
// 3. Power Control
ipcMain.handle('native:power-control', async (event, { action }) => {
let cmd = '';
const isMac = os.platform() === 'darwin';
const isLinux = os.platform() === 'linux';
if (action === 'shutdown') {
if (isMac) cmd = 'shutdown -h now'; // Requires sudo/admin usually
if (isLinux) cmd = 'shutdown -h now';
} else if (action === 'reboot') {
if (isMac) cmd = 'shutdown -r now';
if (isLinux) cmd = 'reboot';
} else if (action === 'sleep') {
if (isMac) cmd = 'pmset sleepnow';
if (isLinux) cmd = 'systemctl suspend';
}
if (!cmd) return { success: false, error: 'Action not supported' };
// NOTE: These commands often require root.
// For a kiosk, you might configure sudoers to allow this specific command without password.
return await runExec(cmd);
});
// 4. Open External (Browser)
ipcMain.handle('native:open-external', async (event, { url, app: appName }) => {
if (appName === 'chrome') {
if (os.platform() === 'darwin') {
return await runExec(`open -a "Google Chrome" "${url}"`);
} else if (os.platform() === 'linux') {
return await runExec(`google-chrome "${url}"`);
}
} else if (appName === 'firefox') {
if (os.platform() === 'darwin') {
return await runExec(`open -a "Firefox" "${url}"`);
} else if (os.platform() === 'linux') {
return await runExec(`firefox "${url}"`);
}
}
// Default system handler
await shell.openExternal(url);
return { success: true };
});
// 5. Manage Recording (Aperture Wrapper)
ipcMain.handle('native:manage-recording', async (event, { action, options }) => {
if (os.platform() !== 'darwin') return { success: false, error: 'Recording only supported on macOS' };
// Path to bundled aperture binary
// In dev: ./resources/bin/aperture
// In prod: process.resourcesPath/bin/aperture
const binPath = app.isPackaged
? path.join(process.resourcesPath, 'bin', 'aperture')
: path.join(__dirname, '../../resources/bin/aperture'); // Adjust based on structure
if (action === 'start') {
if (recordingProcess) return { success: false, error: 'Recording already in progress' };
const { fps = 30, audioDeviceId, output } = options || {};
const cleanOutput = expandPath(output || '~/tmp/recording.mp4');
const args = ['run', '--fps', fps, '--output', cleanOutput];
if (audioDeviceId) args.push('--audio-device-id', audioDeviceId);
// Spawn process
// Note: aperture is a CLI tool. We might need 'aperture' node package or the binary.
// Assuming binary usage here.
try {
console.log(`Starting recording: ${binPath} ${args.join(' ')}`);
recordingProcess = spawn(binPath, args);
recordingProcess.on('error', (err: any) => {
console.error('Recording error:', err);
recordingProcess = null;
});
recordingProcess.on('exit', (code: any) => {
console.log(`Recording exited with code ${code}`);
recordingProcess = null;
});
return { success: true, pid: recordingProcess.pid };
} catch (e: any) {
return { success: false, error: e.message };
}
} else if (action === 'stop') {
if (!recordingProcess) return { success: false, error: 'No recording in progress' };
recordingProcess.kill('SIGINT'); // Send interrupt to stop cleanly
recordingProcess = null;
return { success: true };
} else if (action === 'status') {
return { success: true, isRecording: !!recordingProcess };
}
return { success: false, error: 'Unknown action' };
});
// 6. Set Display Layout (Displayplacer)
ipcMain.handle('native:set-display-layout', async (event, { mode, configStr }) => {
if (os.platform() !== 'darwin') return { success: false, error: 'Display control only supported on macOS' };
const binPath = app.isPackaged
? path.join(process.resourcesPath, 'bin', 'displayplacer')
: path.join(__dirname, '../../resources/bin/displayplacer');
let cmd = '';
if (mode === 'mirror') {
// This usually requires querying current IDs, which is complex.
// If configStr is provided (output of 'displayplacer list'), use it.
if (configStr) {
cmd = `"${binPath}" ${configStr}`;
} else {
return { success: false, error: 'Config string required for now' };
}
} else if (mode === 'extend') {
if (configStr) {
cmd = `"${binPath}" ${configStr}`;
}
}
if (cmd) {
return await runExec(cmd);
}
return { success: false, error: 'Invalid mode or missing config' };
});
// 7. Update App
ipcMain.handle('native:update-app', async (event, { source, url, path: localPath }) => {
// 1. Determine Source File
let updateFile = '';
const tempDir = os.tmpdir();
const destName = 'update_package.zip'; // Or .app, .AppImage
const destPath = path.join(tempDir, destName);
if (source === 'url' && url) {
// Download
try {
const response = await axios({
method: 'get',
url: url,
responseType: 'stream'
});
const writer = fs.createWriteStream(destPath);
response.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', () => resolve(true));
writer.on('error', reject);
});
updateFile = destPath;
} catch (e: any) {
return { success: false, error: `Download failed: ${e.message}` };
}
} else if (source === 'file' && localPath) {
const cleanLocal = expandPath(localPath);
if (fs.existsSync(cleanLocal)) {
updateFile = cleanLocal;
} else {
return { success: false, error: 'Local update file not found' };
}
}
if (!updateFile) return { success: false, error: 'No update source provided' };
// 2. Install Logic (Stub)
// Real implementation depends on OS and packaging format.
// macOS: Mount DMG, copy .app to /Applications? Or Unzip .app?
// Linux: chmod +x AppImage and move?
console.log(`Ready to install update from: ${updateFile}`);
// For now, just return success so the UI knows we "downloaded" it.
return { success: true, message: 'Update downloaded/located. Installation logic requires packaging specifics.', downloadedPath: updateFile };
});
}

View File

@@ -19,4 +19,13 @@ contextBridge.exposeInMainWorld('aetherNative', {
launch_presentation: (args: any) => ipcRenderer.invoke('native:launch-presentation', args),
control_presentation: (args: any) => ipcRenderer.invoke('native:control-presentation', args),
list_tools: () => ipcRenderer.invoke('native:list-tools'),
// System Handlers (V5)
set_wallpaper: (args: any) => ipcRenderer.invoke('native:set-wallpaper', args),
update_app: (args: any) => ipcRenderer.invoke('native:update-app', args),
window_control: (args: any) => ipcRenderer.invoke('native:window-control', args),
manage_recording: (args: any) => ipcRenderer.invoke('native:manage-recording', args),
set_display_layout: (args: any) => ipcRenderer.invoke('native:set-display-layout', args),
power_control: (args: any) => ipcRenderer.invoke('native:power-control', args),
open_external: (args: any) => ipcRenderer.invoke('native:open-external', args),
});