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
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:
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user