Squashed commit of the following:
commit d6c92ea0ad95c0b640ac9c7df48197412c7518e3
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Thu Aug 21 23:27:44 2025 +0530
fix: unpacking amical/smart-whisper dep
commit 87819819bb12c07b94f5b52cbb0ea42a452c16e2
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Thu Aug 21 17:41:02 2025 +0530
fix: unpacking of smart-whisper
commit 81cec166834606cbff2cdd2e750dcc1fb769d4f3
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Thu Aug 21 16:08:39 2025 +0530
chore: re-enable mac builds
commit f13069c1f350fe06c69aa8f16af41f983f34131e
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Thu Aug 21 13:06:26 2025 +0530
feat: add smart-whisper package with updated build configuration
commit a24e06856cc595f5e6c5d914090531716d208d2a
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Thu Aug 21 11:37:25 2025 +0530
chore: bump smart-whisper ver
commit 98f84b6f89c873370f1bb356f11c97dab0185ab7
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Wed Aug 20 08:59:55 2025 +0530
feat: release wf updates for win builds
commit a85825d362f2a27fdef7b49533a9139aea4785b7
Author: haritabh-z01 <haritabh.z01+github@gmail.com>
Date: Wed Aug 20 08:36:13 2025 +0530
feat: add windows support basics
This commit is contained in:
parent
2d852a0d14
commit
17d034be80
59 changed files with 10524 additions and 3079 deletions
|
|
@ -167,8 +167,8 @@ export class AppManager {
|
|||
return this.serviceManager.getService("transcriptionService");
|
||||
}
|
||||
|
||||
getSwiftIOBridge() {
|
||||
return this.serviceManager.getService("swiftIOBridge");
|
||||
getNativeBridge() {
|
||||
return this.serviceManager.getService("nativeBridge");
|
||||
}
|
||||
|
||||
getAutoUpdaterService() {
|
||||
|
|
|
|||
|
|
@ -11,23 +11,23 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
setupEventHandlers(): void {
|
||||
this.setupSwiftBridgeEventHandlers();
|
||||
this.setupNativeBridgeEventHandlers();
|
||||
this.setupGeneralIPCHandlers();
|
||||
this.setupOnboardingIPCHandlers();
|
||||
// Note: Audio IPC handlers are now managed by RecordingService
|
||||
}
|
||||
|
||||
private setupSwiftBridgeEventHandlers(): void {
|
||||
private setupNativeBridgeEventHandlers(): void {
|
||||
try {
|
||||
const swiftBridge = this.appManager.getSwiftIOBridge();
|
||||
if (!swiftBridge) {
|
||||
logger.main.warn("Swift bridge not available for event handlers");
|
||||
const nativeBridge = this.appManager.getNativeBridge();
|
||||
if (!nativeBridge) {
|
||||
logger.main.warn("Native bridge not available for event handlers");
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle non-shortcut related events only
|
||||
swiftBridge.on("helperEvent", (event: HelperEvent) => {
|
||||
logger.swift.debug("Received helperEvent from SwiftIOBridge", {
|
||||
nativeBridge.on("helperEvent", (event: HelperEvent) => {
|
||||
logger.swift.debug("Received helperEvent from native bridge", {
|
||||
event,
|
||||
});
|
||||
|
||||
|
|
@ -35,15 +35,15 @@ export class EventHandlers {
|
|||
// This handler can process other helper events if needed
|
||||
});
|
||||
|
||||
swiftBridge.on("error", (error: Error) => {
|
||||
logger.main.error("SwiftIOBridge error:", error);
|
||||
nativeBridge.on("error", (error: Error) => {
|
||||
logger.main.error("Native bridge error:", error);
|
||||
});
|
||||
|
||||
swiftBridge.on("close", (code: number | null) => {
|
||||
logger.swift.warn("Swift helper process closed", { code });
|
||||
nativeBridge.on("close", (code: number | null) => {
|
||||
logger.swift.warn("Native helper process closed", { code });
|
||||
});
|
||||
} catch (error) {
|
||||
logger.main.warn("Swift bridge not available for event handlers");
|
||||
logger.main.warn("Native bridge not available for event handlers");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import { app } from "electron";
|
|||
import * as path from "path";
|
||||
|
||||
// Set GGML_METAL_PATH_RESOURCES before any other imports
|
||||
// This ensures smart-whisper can find its resources when unpacked from asar
|
||||
// This ensures @amical/smart-whisper can find its resources when unpacked from asar
|
||||
if (app.isPackaged) {
|
||||
// Point to the unpacked whisper.cpp directory
|
||||
process.env.GGML_METAL_PATH_RESOURCES = path.join(
|
||||
process.resourcesPath,
|
||||
"app.asar.unpacked",
|
||||
"node_modules",
|
||||
"@amical",
|
||||
"smart-whisper",
|
||||
"whisper.cpp",
|
||||
);
|
||||
|
|
|
|||
|
|
@ -218,12 +218,12 @@ export class RecordingManager extends EventEmitter {
|
|||
|
||||
// Mute system audio
|
||||
try {
|
||||
const swiftBridge = this.serviceManager.getService("swiftIOBridge");
|
||||
if (swiftBridge) {
|
||||
await swiftBridge.call("muteSystemAudio", {});
|
||||
const nativeBridge = this.serviceManager.getService("nativeBridge");
|
||||
if (nativeBridge) {
|
||||
await nativeBridge.call("muteSystemAudio", {});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.main.warn("Swift bridge not available for audio muting");
|
||||
logger.main.warn("Native bridge not available for audio muting");
|
||||
}
|
||||
|
||||
this.setState("recording");
|
||||
|
|
@ -252,12 +252,12 @@ export class RecordingManager extends EventEmitter {
|
|||
|
||||
// Restore system audio
|
||||
try {
|
||||
const swiftBridge = this.serviceManager.getService("swiftIOBridge");
|
||||
if (swiftBridge) {
|
||||
await swiftBridge.call("restoreSystemAudio", {});
|
||||
const nativeBridge = this.serviceManager.getService("nativeBridge");
|
||||
if (nativeBridge) {
|
||||
await nativeBridge.call("restoreSystemAudio", {});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.main.warn("Swift bridge not available for audio restore");
|
||||
logger.main.warn("Native bridge not available for audio restore");
|
||||
}
|
||||
|
||||
logger.audio.info("Recording stop initiated", {
|
||||
|
|
@ -412,14 +412,14 @@ export class RecordingManager extends EventEmitter {
|
|||
}
|
||||
|
||||
try {
|
||||
const swiftBridge = this.serviceManager.getService("swiftIOBridge");
|
||||
const nativeBridge = this.serviceManager.getService("nativeBridge");
|
||||
|
||||
logger.main.info("Pasting transcription to active application", {
|
||||
textLength: transcription.length,
|
||||
});
|
||||
|
||||
if (swiftBridge) {
|
||||
swiftBridge.call("pasteText", {
|
||||
if (nativeBridge) {
|
||||
nativeBridge.call("pasteText", {
|
||||
transcript: transcription,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { logger } from "../logger";
|
|||
import { ModelManagerService } from "../../services/model-manager";
|
||||
import { TranscriptionService } from "../../services/transcription-service";
|
||||
import { SettingsService } from "../../services/settings-service";
|
||||
import { SwiftIOBridge } from "../../services/platform/swift-bridge-service";
|
||||
import { NativeBridge } from "../../services/platform/native-bridge-service";
|
||||
import { AutoUpdaterService } from "../services/auto-updater";
|
||||
import { RecordingManager } from "./recording-manager";
|
||||
import { VADService } from "../../services/vad-service";
|
||||
|
|
@ -11,6 +11,7 @@ import { WindowManager } from "../core/window-manager";
|
|||
import { createIPCHandler } from "electron-trpc-experimental/main";
|
||||
import { router } from "../../trpc/router";
|
||||
import { createContext } from "../../trpc/context";
|
||||
import { isMacOS, isWindows } from "../../utils/platform";
|
||||
|
||||
/**
|
||||
* Service map for type-safe service access
|
||||
|
|
@ -20,7 +21,7 @@ export interface ServiceMap {
|
|||
transcriptionService: TranscriptionService;
|
||||
settingsService: SettingsService;
|
||||
vadService: VADService;
|
||||
swiftIOBridge: SwiftIOBridge;
|
||||
nativeBridge: NativeBridge;
|
||||
autoUpdaterService: AutoUpdaterService;
|
||||
recordingManager: RecordingManager;
|
||||
shortcutManager: ShortcutManager;
|
||||
|
|
@ -39,7 +40,7 @@ export class ServiceManager {
|
|||
private settingsService: SettingsService | null = null;
|
||||
private vadService: VADService | null = null;
|
||||
|
||||
private swiftIOBridge: SwiftIOBridge | null = null;
|
||||
private nativeBridge: NativeBridge | null = null;
|
||||
private autoUpdaterService: AutoUpdaterService | null = null;
|
||||
private recordingManager: RecordingManager | null = null;
|
||||
private shortcutManager: ShortcutManager | null = null;
|
||||
|
|
@ -145,9 +146,9 @@ export class ServiceManager {
|
|||
}
|
||||
|
||||
private initializePlatformServices(): void {
|
||||
// Initialize Swift bridge for macOS integration
|
||||
if (process.platform === "darwin") {
|
||||
this.swiftIOBridge = new SwiftIOBridge();
|
||||
// Initialize platform-specific bridge
|
||||
if (isMacOS() || isWindows()) {
|
||||
this.nativeBridge = new NativeBridge();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +164,7 @@ export class ServiceManager {
|
|||
);
|
||||
}
|
||||
this.shortcutManager = new ShortcutManager(this.settingsService);
|
||||
await this.shortcutManager.initialize(this.swiftIOBridge);
|
||||
await this.shortcutManager.initialize(this.nativeBridge);
|
||||
|
||||
// Connect shortcut events to recording manager
|
||||
this.recordingManager.setupShortcutListeners(this.shortcutManager);
|
||||
|
|
@ -213,7 +214,7 @@ export class ServiceManager {
|
|||
transcriptionService: this.transcriptionService ?? undefined,
|
||||
settingsService: this.settingsService ?? undefined,
|
||||
vadService: this.vadService ?? undefined,
|
||||
swiftIOBridge: this.swiftIOBridge ?? undefined,
|
||||
nativeBridge: this.nativeBridge ?? undefined,
|
||||
autoUpdaterService: this.autoUpdaterService ?? undefined,
|
||||
recordingManager: this.recordingManager ?? undefined,
|
||||
shortcutManager: this.shortcutManager ?? undefined,
|
||||
|
|
@ -242,9 +243,9 @@ export class ServiceManager {
|
|||
await this.vadService.dispose();
|
||||
}
|
||||
|
||||
if (this.swiftIOBridge) {
|
||||
logger.main.info("Stopping Swift helper...");
|
||||
this.swiftIOBridge.stopHelper();
|
||||
if (this.nativeBridge) {
|
||||
logger.main.info("Stopping native helper...");
|
||||
this.nativeBridge.stopHelper();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { EventEmitter } from "events";
|
||||
import { globalShortcut } from "electron";
|
||||
import { SettingsService } from "@/services/settings-service";
|
||||
import { SwiftIOBridge } from "@/services/platform/swift-bridge-service";
|
||||
import { matchesShortcutKey, getKeyNameFromPayload } from "@/utils/keycode-map";
|
||||
import { NativeBridge } from "@/services/platform/native-bridge-service";
|
||||
import { getKeyNameFromPayload } from "@/utils/keycode-map";
|
||||
import { KeyEventPayload, HelperEvent } from "@amical/types";
|
||||
import { logger } from "@/main/logger";
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ export class ShortcutManager extends EventEmitter {
|
|||
toggleRecording: "",
|
||||
};
|
||||
private settingsService: SettingsService;
|
||||
private swiftIOBridge: SwiftIOBridge | null = null;
|
||||
private nativeBridge: NativeBridge | null = null;
|
||||
private isRecordingShortcut: boolean = false;
|
||||
|
||||
constructor(settingsService: SettingsService) {
|
||||
|
|
@ -33,8 +33,8 @@ export class ShortcutManager extends EventEmitter {
|
|||
this.settingsService = settingsService;
|
||||
}
|
||||
|
||||
async initialize(swiftIOBridge: SwiftIOBridge | null) {
|
||||
this.swiftIOBridge = swiftIOBridge;
|
||||
async initialize(nativeBridge: NativeBridge | null) {
|
||||
this.nativeBridge = nativeBridge;
|
||||
await this.loadShortcuts();
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
|
@ -59,12 +59,12 @@ export class ShortcutManager extends EventEmitter {
|
|||
}
|
||||
|
||||
private setupEventListeners() {
|
||||
if (!this.swiftIOBridge) {
|
||||
log.warn("SwiftIOBridge not available, shortcuts will not work");
|
||||
if (!this.nativeBridge) {
|
||||
log.warn("Native bridge not available, shortcuts will not work");
|
||||
return;
|
||||
}
|
||||
|
||||
this.swiftIOBridge.on("helperEvent", (event: HelperEvent) => {
|
||||
this.nativeBridge.on("helperEvent", (event: HelperEvent) => {
|
||||
switch (event.type) {
|
||||
case "flagsChanged":
|
||||
this.handleFlagsChanged(event.payload);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Worker process entry point for fork
|
||||
import { Whisper } from "smart-whisper";
|
||||
import { Whisper } from "@amical/smart-whisper";
|
||||
|
||||
// Simple console-based logging for worker process
|
||||
const logger = {
|
||||
|
|
@ -29,7 +29,7 @@ const methods = {
|
|||
whisperInstance = null;
|
||||
}
|
||||
|
||||
const { Whisper } = await import("smart-whisper");
|
||||
const { Whisper } = await import("@amical/smart-whisper");
|
||||
whisperInstance = new Whisper(modelPath, { gpu: true });
|
||||
try {
|
||||
await whisperInstance.load();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// This file contains just the Whisper-specific operations that need to run in a separate process
|
||||
import { Whisper } from "smart-whisper";
|
||||
import { Whisper } from "@amical/smart-whisper";
|
||||
|
||||
// Simple console-based logging for worker process
|
||||
const logger = {
|
||||
|
|
@ -27,7 +27,7 @@ export async function initializeModel(modelPath: string): Promise<void> {
|
|||
whisperInstance = null;
|
||||
}
|
||||
|
||||
const { Whisper } = await import("smart-whisper");
|
||||
const { Whisper } = await import("@amical/smart-whisper");
|
||||
whisperInstance = new Whisper(modelPath, { gpu: true });
|
||||
try {
|
||||
await whisperInstance.load();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { spawn, ChildProcessWithoutNullStreams } from "child_process";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import process from "node:process"; // Added import for process
|
||||
import { app, app as electronApp } from "electron"; // electronApp for app.getAppPath() consistency
|
||||
import { app as electronApp } from "electron";
|
||||
import split2 from "split2";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { getNativeHelperName, getNativeHelperDir } from "../../utils/platform";
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { createScopedLogger } from "../../main/logger";
|
||||
|
|
@ -54,21 +54,21 @@ interface RPCMethods {
|
|||
}
|
||||
|
||||
// Define event types for the client
|
||||
interface SwiftIOBridgeEvents {
|
||||
interface NativeBridgeEvents {
|
||||
helperEvent: (event: HelperEvent) => void;
|
||||
error: (error: Error) => void;
|
||||
close: (code: number | null, signal: NodeJS.Signals | null) => void;
|
||||
ready: () => void; // Emitted when the helper process is successfully spawned
|
||||
}
|
||||
|
||||
export class SwiftIOBridge extends EventEmitter {
|
||||
export class NativeBridge extends EventEmitter {
|
||||
private proc: ChildProcessWithoutNullStreams | null = null;
|
||||
private pending = new Map<
|
||||
string,
|
||||
{ callback: (resp: RpcResponse) => void; startTime: number }
|
||||
>();
|
||||
private helperPath: string;
|
||||
private logger = createScopedLogger("swift-bridge");
|
||||
private logger = createScopedLogger("native-bridge");
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -77,7 +77,9 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
}
|
||||
|
||||
private determineHelperPath(): string {
|
||||
const helperName = "SwiftHelper"; // Swift native helper executable
|
||||
const helperName = getNativeHelperName();
|
||||
const helperDir = getNativeHelperDir();
|
||||
|
||||
return electronApp.isPackaged
|
||||
? path.join(process.resourcesPath, "bin", helperName)
|
||||
: path.join(
|
||||
|
|
@ -86,7 +88,7 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
"..",
|
||||
"packages",
|
||||
"native-helpers",
|
||||
"swift-helper",
|
||||
helperDir,
|
||||
"bin",
|
||||
helperName,
|
||||
);
|
||||
|
|
@ -96,20 +98,33 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
try {
|
||||
fs.accessSync(this.helperPath, fs.constants.X_OK);
|
||||
} catch (err) {
|
||||
this.logger.error("SwiftHelper executable not found or not executable", {
|
||||
helperPath: this.helperPath,
|
||||
});
|
||||
this.emit(
|
||||
"error",
|
||||
new Error(
|
||||
`Helper executable not found at ${this.helperPath}. Attempt to build it if in dev mode.`,
|
||||
),
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.error(
|
||||
`${helperName} executable not found or not executable`,
|
||||
{
|
||||
helperPath: this.helperPath,
|
||||
},
|
||||
);
|
||||
// In a real app, you might try to build it here or provide more robust error handling.
|
||||
// In production, provide a more user-friendly error message
|
||||
const errorMessage = electronApp.isPackaged
|
||||
? `${helperName} is not available. Some features may not work correctly.`
|
||||
: `Helper executable not found at ${this.helperPath}. Please build it first.`;
|
||||
|
||||
this.emit("error", new Error(errorMessage));
|
||||
|
||||
// Log detailed error for debugging
|
||||
this.logger.error("Helper initialization failed", {
|
||||
helperPath: this.helperPath,
|
||||
isPackaged: electronApp.isPackaged,
|
||||
platform: process.platform,
|
||||
error: err,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info("Spawning SwiftHelper", { helperPath: this.helperPath });
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.info(`Spawning ${helperName}`, { helperPath: this.helperPath });
|
||||
this.proc = spawn(this.helperPath, [], { stdio: ["pipe", "pipe", "pipe"] });
|
||||
|
||||
this.proc.stdout.pipe(split2()).on("data", (line: string) => {
|
||||
|
|
@ -150,19 +165,24 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
|
||||
this.proc.stderr.on("data", (data: Buffer) => {
|
||||
const errorMsg = data.toString();
|
||||
this.logger.warn("SwiftHelper stderr output", { message: errorMsg });
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.warn(`${helperName} stderr output`, { message: errorMsg });
|
||||
// Don't emit as error since stderr is often just debug info
|
||||
// this.emit('error', new Error(`Helper stderr: ${errorMsg}`));
|
||||
});
|
||||
|
||||
this.proc.on("error", (err) => {
|
||||
this.logger.error("Failed to start SwiftHelper process", { error: err });
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.error(`Failed to start ${helperName} process`, {
|
||||
error: err,
|
||||
});
|
||||
this.emit("error", err);
|
||||
this.proc = null;
|
||||
});
|
||||
|
||||
this.proc.on("close", (code, signal) => {
|
||||
this.logger.info("SwiftHelper process exited", { code, signal });
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.info(`${helperName} process exited`, { code, signal });
|
||||
this.emit("close", code, signal);
|
||||
this.proc = null;
|
||||
// Optionally, implement retry logic or notify further
|
||||
|
|
@ -180,11 +200,18 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
timeoutMs = 5000,
|
||||
): Promise<RPCMethods[M]["result"]> {
|
||||
if (!this.proc || !this.proc.stdin || !this.proc.stdin.writable) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
"Swift helper process is not running or stdin is not writable.",
|
||||
),
|
||||
);
|
||||
const helperName = getNativeHelperName();
|
||||
const errorMessage = electronApp.isPackaged
|
||||
? `${helperName} is not available for this operation.`
|
||||
: "Native helper process is not running or stdin is not writable.";
|
||||
|
||||
this.logger.warn(`Cannot call ${method}: helper not available`, {
|
||||
method,
|
||||
isPackaged: electronApp.isPackaged,
|
||||
platform: process.platform,
|
||||
});
|
||||
|
||||
return Promise.reject(new Error(errorMessage));
|
||||
}
|
||||
|
||||
const id = uuid();
|
||||
|
|
@ -267,7 +294,7 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
const duration = timedOutAt - startTime;
|
||||
reject(
|
||||
new Error(
|
||||
`SwiftIOBridge: RPC call "${method}" (id: ${id}) timed out after ${timeoutMs}ms (duration: ${duration}ms, started: ${new Date(startTime).toISOString()})`,
|
||||
`NativeBridge: RPC call "${method}" (id: ${id}) timed out after ${timeoutMs}ms (duration: ${duration}ms, started: ${new Date(startTime).toISOString()})`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -283,24 +310,25 @@ export class SwiftIOBridge extends EventEmitter {
|
|||
|
||||
public stopHelper(): void {
|
||||
if (this.proc) {
|
||||
this.logger.info("Stopping SwiftHelper process");
|
||||
const helperName = getNativeHelperName();
|
||||
this.logger.info(`Stopping ${helperName} process`);
|
||||
this.proc.kill();
|
||||
this.proc = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Typed event emitter methods
|
||||
on<E extends keyof SwiftIOBridgeEvents>(
|
||||
on<E extends keyof NativeBridgeEvents>(
|
||||
event: E,
|
||||
listener: SwiftIOBridgeEvents[E],
|
||||
listener: NativeBridgeEvents[E],
|
||||
): this {
|
||||
super.on(event, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
emit<E extends keyof SwiftIOBridgeEvents>(
|
||||
emit<E extends keyof NativeBridgeEvents>(
|
||||
event: E,
|
||||
...args: Parameters<SwiftIOBridgeEvents[E]>
|
||||
...args: Parameters<NativeBridgeEvents[E]>
|
||||
): boolean {
|
||||
return super.emit(event, ...args);
|
||||
}
|
||||
|
|
@ -10,12 +10,12 @@ class AppContextStore {
|
|||
const serviceManager = ServiceManager.getInstance();
|
||||
if (!serviceManager) return; // Silent fail
|
||||
|
||||
const swiftBridge = serviceManager.getService("swiftIOBridge");
|
||||
if (!swiftBridge) {
|
||||
logger.main.warn("SwiftIOBridge not available");
|
||||
const nativeBridge = serviceManager.getService("nativeBridge");
|
||||
if (!nativeBridge) {
|
||||
logger.main.warn("Native bridge not available");
|
||||
return;
|
||||
}
|
||||
const context = await swiftBridge.call("getAccessibilityContext", {
|
||||
const context = await nativeBridge.call("getAccessibilityContext", {
|
||||
editableOnly: false,
|
||||
});
|
||||
this.accessibilityContext = context;
|
||||
|
|
|
|||
53
apps/desktop/src/utils/platform.ts
Normal file
53
apps/desktop/src/utils/platform.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import process from "node:process";
|
||||
|
||||
/**
|
||||
* Platform detection utilities
|
||||
*/
|
||||
|
||||
export type Platform = "darwin" | "win32" | "linux";
|
||||
|
||||
export function getPlatform(): Platform {
|
||||
return process.platform as Platform;
|
||||
}
|
||||
|
||||
export function isWindows(): boolean {
|
||||
return process.platform === "win32";
|
||||
}
|
||||
|
||||
export function isMacOS(): boolean {
|
||||
return process.platform === "darwin";
|
||||
}
|
||||
|
||||
export function isLinux(): boolean {
|
||||
return process.platform === "linux";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the native helper name for the current platform
|
||||
*/
|
||||
export function getNativeHelperName(): string {
|
||||
return isWindows() ? "WindowsHelper.exe" : "SwiftHelper";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the native helper directory name for the current platform
|
||||
*/
|
||||
export function getNativeHelperDir(): string {
|
||||
return isWindows() ? "windows-helper" : "swift-helper";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a platform-specific display name
|
||||
*/
|
||||
export function getPlatformDisplayName(): string {
|
||||
switch (process.platform) {
|
||||
case "darwin":
|
||||
return "macOS";
|
||||
case "win32":
|
||||
return "Windows";
|
||||
case "linux":
|
||||
return "Linux";
|
||||
default:
|
||||
return process.platform;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue