additional clean
CI / Rust Format (pull_request) Failing after 13s
CI / TypeScript Lint + Typecheck (pull_request) Failing after 17s
CI / TypeScript Tests + Coverage (pull_request) Successful in 36s
CI / Clippy (SARIF) (pull_request) Successful in 1m3s
CI / Dependency-Track (BOM) (pull_request) Successful in 41s
CI / Rust Tests + Coverage (pull_request) Successful in 1m23s
CI / E2E Tests (Playwright + Electron) (pull_request) Failing after 1m21s
CI / Electron Release Build (pull_request) Failing after 1m38s
CI / SonarQube (pull_request) Successful in 44s

This commit is contained in:
2026-05-08 01:12:44 -04:00
parent b7be5d321d
commit 803ae9fd62
5 changed files with 63 additions and 57 deletions
+4 -4
View File
@@ -37,9 +37,9 @@ exports.startBridge = startBridge;
exports.callBridge = callBridge;
exports.stopBridge = stopBridge;
const electron_1 = require("electron");
const child_process_1 = require("child_process");
const cp = __importStar(require("child_process"));
const path = __importStar(require("path"));
const crypto_1 = require("crypto");
const crypto = __importStar(require("crypto"));
let proc = null;
let readBuffer = '';
const pending = new Map();
@@ -56,7 +56,7 @@ function binaryPath() {
function startBridge() {
const bin = binaryPath();
try {
proc = (0, child_process_1.spawn)(bin, ['--cli'], {
proc = cp.spawn(bin, ['--cli'], {
stdio: ['pipe', 'pipe', 'inherit'],
});
}
@@ -114,7 +114,7 @@ function callBridge(cmd, args = {}) {
reject('bridge not running — is the Rust binary built?');
return;
}
const id = (0, crypto_1.randomUUID)();
const id = crypto.randomUUID();
pending.set(id, {
resolve: (v) => resolve(v),
reject,
+2
View File
@@ -13,6 +13,8 @@ exports.RustBridgeCmd = {
ReadBinary: 'read_binary',
LoadSession: 'load_session',
SaveSession: 'save_session',
LoadUiPrefs: 'load_ui_prefs',
SaveUiPrefs: 'save_ui_prefs',
UpdateTabContent: 'update_tab_content',
ReadDirectory: 'read_directory',
ListWorkspaceFiles: 'list_workspace_files',
+26 -22
View File
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const path = __importStar(require("path"));
const bridgeCommands_1 = require("./bridgeCommands");
const bridge_1 = require("./bridge");
const bridge = __importStar(require("./bridge"));
const uiohook_napi_1 = require("uiohook-napi");
// Use PNG at runtime — nativeImage loads it more reliably than .icns in dev mode.
// The .icns file is used only by the electron-forge packager (forge.config.js).
@@ -145,7 +145,7 @@ electron_1.app.whenReady().then(() => {
if (process.platform === 'darwin' && !appIcon.isEmpty()) {
electron_1.app.dock?.setIcon(appIcon);
}
(0, bridge_1.startBridge)();
bridge.startBridge();
createWindow();
electron_1.app.on('activate', () => {
if (electron_1.BrowserWindow.getAllWindows().length === 0)
@@ -196,7 +196,7 @@ electron_1.app.on('window-all-closed', () => {
});
electron_1.app.on('before-quit', () => {
uiohook_napi_1.uIOhook.stop();
(0, bridge_1.stopBridge)();
bridge.stopBridge();
});
// ── Tear-off into a new window (preload `api.tearOffTab` → ipcMain) ───────────
// TitleBar serializes the tab to JSON; the new window receives `restoreTornTab`.
@@ -365,8 +365,10 @@ electron_1.ipcMain.handle('activate_prewarm_window', (_e, args) => {
}
});
// Snake-case session commands used by window.byteDraft bridge
electron_1.ipcMain.handle('load_session', () => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.LoadSession));
electron_1.ipcMain.handle('save_session', (_e, args) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.SaveSession, { session: args.session }));
electron_1.ipcMain.handle('load_session', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.LoadSession));
electron_1.ipcMain.handle('save_session', (_e, args) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveSession, { session: args.session }));
electron_1.ipcMain.handle('load_ui_prefs', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.LoadUiPrefs));
electron_1.ipcMain.handle('save_ui_prefs', (_e, args) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveUiPrefs, { prefs: args.prefs }));
// ── Native dialogs (handled in Electron, not the Rust subprocess) ─────────────
electron_1.ipcMain.handle('showMessageBox', async (e, opts) => {
const win = electron_1.BrowserWindow.fromWebContents(e.sender);
@@ -402,26 +404,28 @@ electron_1.ipcMain.handle('saveFileAs', async (e, content) => {
const result = await electron_1.dialog.showSaveDialog(win ?? electron_1.BrowserWindow.getFocusedWindow() ?? electron_1.BrowserWindow.getAllWindows()[0], { title: 'Save As' });
if (result.canceled || !result.filePath)
return null;
await (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.SaveFile, { path: result.filePath, content, encoding: 'UTF-8' });
await bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveFile, { path: result.filePath, content, encoding: 'UTF-8' });
return result.filePath;
});
// ── File operations (routed to Rust subprocess) ───────────────────────────────
electron_1.ipcMain.handle('openFile', (_e, filePath) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.OpenFile, { path: filePath }));
electron_1.ipcMain.handle('saveFile', (_e, filePath, content, encoding) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.SaveFile, { path: filePath, content, encoding }));
electron_1.ipcMain.handle('revertFile', (_e, filePath) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.RevertFile, { path: filePath }));
electron_1.ipcMain.handle('readFileWithEncoding', (_e, filePath, encoding) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ReadFileWithEncoding, { path: filePath, encoding }));
electron_1.ipcMain.handle('readBinary', (_e, filePath) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ReadBinary, { path: filePath }));
electron_1.ipcMain.handle('openFile', (_e, filePath) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.OpenFile, { path: filePath }));
electron_1.ipcMain.handle('saveFile', (_e, filePath, content, encoding) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveFile, { path: filePath, content, encoding }));
electron_1.ipcMain.handle('revertFile', (_e, filePath) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.RevertFile, { path: filePath }));
electron_1.ipcMain.handle('readFileWithEncoding', (_e, filePath, encoding) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ReadFileWithEncoding, { path: filePath, encoding }));
electron_1.ipcMain.handle('readBinary', (_e, filePath) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ReadBinary, { path: filePath }));
// ── Session (routed to Rust subprocess) ──────────────────────────────────────
electron_1.ipcMain.handle('loadSession', () => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.LoadSession));
electron_1.ipcMain.handle('saveSession', (_e, json) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.SaveSession, { session: json }));
electron_1.ipcMain.handle('updateTabContent', (_e, tabId, content) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.UpdateTabContent, { tab_id: tabId, content }));
electron_1.ipcMain.handle('loadSession', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.LoadSession));
electron_1.ipcMain.handle('saveSession', (_e, json) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveSession, { session: json }));
electron_1.ipcMain.handle('loadUiPrefs', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.LoadUiPrefs));
electron_1.ipcMain.handle('saveUiPrefs', (_e, prefs) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.SaveUiPrefs, { prefs }));
electron_1.ipcMain.handle('updateTabContent', (_e, tabId, content) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.UpdateTabContent, { tab_id: tabId, content }));
// ── Workspace (routed to Rust subprocess) ────────────────────────────────────
electron_1.ipcMain.handle('readDirectory', (_e, dirPath) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ReadDirectory, { path: dirPath }));
electron_1.ipcMain.handle('listWorkspaceFiles', (_e, root) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ListWorkspaceFiles, { root }));
electron_1.ipcMain.handle('readDirectory', (_e, dirPath) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ReadDirectory, { path: dirPath }));
electron_1.ipcMain.handle('listWorkspaceFiles', (_e, root) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ListWorkspaceFiles, { root }));
// ── Editor backend (routed to Rust subprocess) ────────────────────────────────
electron_1.ipcMain.handle('detectLanguage', (_e, filePath, content) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.DetectLanguage, { path: filePath, content }));
electron_1.ipcMain.handle('lintDocument', (_e, content, lang) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.LintDocument, { content, lang }));
electron_1.ipcMain.handle('formatDocument', (_e, content, lang) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.FormatDocument, { content, lang }));
electron_1.ipcMain.handle('detectEncoding', (_e, filePath) => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.DetectEncoding, { path: filePath }));
electron_1.ipcMain.handle('listLanguages', () => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ListLanguages));
electron_1.ipcMain.handle('listEncodings', () => (0, bridge_1.callBridge)(bridgeCommands_1.RustBridgeCmd.ListEncodings));
electron_1.ipcMain.handle('detectLanguage', (_e, filePath, content) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.DetectLanguage, { path: filePath, content }));
electron_1.ipcMain.handle('lintDocument', (_e, content, lang) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.LintDocument, { content, lang }));
electron_1.ipcMain.handle('formatDocument', (_e, content, lang) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.FormatDocument, { content, lang }));
electron_1.ipcMain.handle('detectEncoding', (_e, filePath) => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.DetectEncoding, { path: filePath }));
electron_1.ipcMain.handle('listLanguages', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ListLanguages));
electron_1.ipcMain.handle('listEncodings', () => bridge.callBridge(bridgeCommands_1.RustBridgeCmd.ListEncodings));
+5 -5
View File
@@ -1,14 +1,14 @@
import { app } from 'electron';
import { ChildProcess, spawn } from 'child_process';
import * as cp from 'child_process';
import * as path from 'path';
import { randomUUID } from 'crypto';
import * as crypto from 'crypto';
interface Pending {
resolve: (value: unknown) => void;
reject: (reason: string) => void;
}
let proc: ChildProcess | null = null;
let proc: cp.ChildProcess | null = null;
let readBuffer = '';
const pending = new Map<string, Pending>();
@@ -26,7 +26,7 @@ function binaryPath(): string {
export function startBridge(): void {
const bin = binaryPath();
try {
proc = spawn(bin, ['--cli'], {
proc = cp.spawn(bin, ['--cli'], {
stdio: ['pipe', 'pipe', 'inherit'],
});
} catch (err) {
@@ -86,7 +86,7 @@ export function callBridge<T = unknown>(
reject('bridge not running — is the Rust binary built?');
return;
}
const id = randomUUID();
const id = crypto.randomUUID();
pending.set(id, {
resolve: (v) => resolve(v as T),
reject,
+26 -26
View File
@@ -1,7 +1,7 @@
import { app, BrowserWindow, ipcMain, dialog, nativeImage, screen } from 'electron';
import * as path from 'path';
import { RustBridgeCmd } from './bridgeCommands';
import { startBridge, callBridge, stopBridge } from './bridge';
import * as bridge from './bridge';
import { uIOhook } from 'uiohook-napi';
// Use PNG at runtime — nativeImage loads it more reliably than .icns in dev mode.
@@ -122,7 +122,7 @@ app.whenReady().then(() => {
if (process.platform === 'darwin' && !appIcon.isEmpty()) {
app.dock?.setIcon(appIcon);
}
startBridge();
bridge.startBridge();
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
@@ -168,7 +168,7 @@ app.on('window-all-closed', () => {
app.on('before-quit', () => {
uIOhook.stop();
stopBridge();
bridge.stopBridge();
});
// ── Tear-off into a new window (preload `api.tearOffTab` → ipcMain) ───────────
@@ -344,13 +344,13 @@ ipcMain.handle('activate_prewarm_window', (_e, args: { label: string; x?: number
});
// Snake-case session commands used by window.byteDraft bridge
ipcMain.handle('load_session', () => callBridge(RustBridgeCmd.LoadSession));
ipcMain.handle('load_session', () => bridge.callBridge(RustBridgeCmd.LoadSession));
ipcMain.handle('save_session', (_e, args: { session: string }) =>
callBridge(RustBridgeCmd.SaveSession, { session: args.session }),
bridge.callBridge(RustBridgeCmd.SaveSession, { session: args.session }),
);
ipcMain.handle('load_ui_prefs', () => callBridge(RustBridgeCmd.LoadUiPrefs));
ipcMain.handle('load_ui_prefs', () => bridge.callBridge(RustBridgeCmd.LoadUiPrefs));
ipcMain.handle('save_ui_prefs', (_e, args: { prefs: string }) =>
callBridge(RustBridgeCmd.SaveUiPrefs, { prefs: args.prefs }),
bridge.callBridge(RustBridgeCmd.SaveUiPrefs, { prefs: args.prefs }),
);
// ── Native dialogs (handled in Electron, not the Rust subprocess) ─────────────
@@ -396,65 +396,65 @@ ipcMain.handle('saveFileAs', async (e, content: string) => {
{ title: 'Save As' },
);
if (result.canceled || !result.filePath) return null;
await callBridge(RustBridgeCmd.SaveFile, { path: result.filePath, content, encoding: 'UTF-8' });
await bridge.callBridge(RustBridgeCmd.SaveFile, { path: result.filePath, content, encoding: 'UTF-8' });
return result.filePath;
});
// ── File operations (routed to Rust subprocess) ───────────────────────────────
ipcMain.handle('openFile', (_e, filePath: string) =>
callBridge(RustBridgeCmd.OpenFile, { path: filePath }));
bridge.callBridge(RustBridgeCmd.OpenFile, { path: filePath }));
ipcMain.handle('saveFile', (_e, filePath: string, content: string, encoding: string) =>
callBridge(RustBridgeCmd.SaveFile, { path: filePath, content, encoding }));
bridge.callBridge(RustBridgeCmd.SaveFile, { path: filePath, content, encoding }));
ipcMain.handle('revertFile', (_e, filePath: string) =>
callBridge(RustBridgeCmd.RevertFile, { path: filePath }));
bridge.callBridge(RustBridgeCmd.RevertFile, { path: filePath }));
ipcMain.handle('readFileWithEncoding', (_e, filePath: string, encoding: string) =>
callBridge(RustBridgeCmd.ReadFileWithEncoding, { path: filePath, encoding }));
bridge.callBridge(RustBridgeCmd.ReadFileWithEncoding, { path: filePath, encoding }));
ipcMain.handle('readBinary', (_e, filePath: string) =>
callBridge(RustBridgeCmd.ReadBinary, { path: filePath }));
bridge.callBridge(RustBridgeCmd.ReadBinary, { path: filePath }));
// ── Session (routed to Rust subprocess) ──────────────────────────────────────
ipcMain.handle('loadSession', () =>
callBridge(RustBridgeCmd.LoadSession));
bridge.callBridge(RustBridgeCmd.LoadSession));
ipcMain.handle('saveSession', (_e, json: string) =>
callBridge(RustBridgeCmd.SaveSession, { session: json }));
bridge.callBridge(RustBridgeCmd.SaveSession, { session: json }));
ipcMain.handle('loadUiPrefs', () => callBridge(RustBridgeCmd.LoadUiPrefs));
ipcMain.handle('loadUiPrefs', () => bridge.callBridge(RustBridgeCmd.LoadUiPrefs));
ipcMain.handle('saveUiPrefs', (_e, prefs: string) =>
callBridge(RustBridgeCmd.SaveUiPrefs, { prefs }));
bridge.callBridge(RustBridgeCmd.SaveUiPrefs, { prefs }));
ipcMain.handle('updateTabContent', (_e, tabId: string, content: string) =>
callBridge(RustBridgeCmd.UpdateTabContent, { tab_id: tabId, content }));
bridge.callBridge(RustBridgeCmd.UpdateTabContent, { tab_id: tabId, content }));
// ── Workspace (routed to Rust subprocess) ────────────────────────────────────
ipcMain.handle('readDirectory', (_e, dirPath: string) =>
callBridge(RustBridgeCmd.ReadDirectory, { path: dirPath }));
bridge.callBridge(RustBridgeCmd.ReadDirectory, { path: dirPath }));
ipcMain.handle('listWorkspaceFiles', (_e, root: string) =>
callBridge(RustBridgeCmd.ListWorkspaceFiles, { root }));
bridge.callBridge(RustBridgeCmd.ListWorkspaceFiles, { root }));
// ── Editor backend (routed to Rust subprocess) ────────────────────────────────
ipcMain.handle('detectLanguage', (_e, filePath: string, content: string) =>
callBridge(RustBridgeCmd.DetectLanguage, { path: filePath, content }));
bridge.callBridge(RustBridgeCmd.DetectLanguage, { path: filePath, content }));
ipcMain.handle('lintDocument', (_e, content: string, lang: string) =>
callBridge(RustBridgeCmd.LintDocument, { content, lang }));
bridge.callBridge(RustBridgeCmd.LintDocument, { content, lang }));
ipcMain.handle('formatDocument', (_e, content: string, lang: string) =>
callBridge(RustBridgeCmd.FormatDocument, { content, lang }));
bridge.callBridge(RustBridgeCmd.FormatDocument, { content, lang }));
ipcMain.handle('detectEncoding', (_e, filePath: string) =>
callBridge(RustBridgeCmd.DetectEncoding, { path: filePath }));
bridge.callBridge(RustBridgeCmd.DetectEncoding, { path: filePath }));
ipcMain.handle('listLanguages', () => callBridge(RustBridgeCmd.ListLanguages));
ipcMain.handle('listLanguages', () => bridge.callBridge(RustBridgeCmd.ListLanguages));
ipcMain.handle('listEncodings', () => callBridge(RustBridgeCmd.ListEncodings));
ipcMain.handle('listEncodings', () => bridge.callBridge(RustBridgeCmd.ListEncodings));