.cursor/skills/fantasia-electron-main/SKILL.md
Works on Fantasia Archive Electron main process: app lifecycle, window management, platform tweaks, native integrations, and ipcMain registration (register*Ipc + electron-ipc-bridge channel names). Use when editing electron-main.ts, src-electron/mainScripts/, or main-side tests.
npx skillsauth add vishiri/fantasia-archive fantasia-electron-mainInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
src-electron/electron-main.ts orchestrates startup in order: Chromium stderr filter (chromiumFixes/suppressChromiumDevtoolsAutofillStderrNoise), app name and userData (appIdentity/fixAppName), Windows DevTools workaround (chromiumFixes/windowsDevToolsExtensionsFix), startApp (all ipcMain registrars — DevTools, extra-env snapshot for sandboxed preload, external links / shell.openExternal, user settings, window chrome, app metadata), nativeShell/tweaks menu removal, then openAppWindowManager / closeAppManager from appManagement.ts. startApp() must run before any BrowserWindow is created so ipcMain.handle channels used from preload exist before the renderer loads.ipcMain.handle with ipcRenderer.invoke for preload-facing channels whenever the flow can be async. ipcRenderer.sendSync / blocking one-way IPC is not forbidden but is a last resort — avoid it if any remotely reasonable async design exists; document exceptions with a short comment near the handler or in review.userData: fixAppName() in appIdentity/fixAppName.ts sets app.setPath('userData', …). When process.env.TEST_ENV is components or e2e, userData is %APPDATA%/<package.json name>/playwright-user-data (stable; not under the *-dev folder used by quasar dev with DEBUGGING). The folder segment is PLAYWRIGHT_ISOLATED_USER_DATA_DIR_NAME in appIdentity/playwrightIsolatedUserDataDirName.ts (re-exported from fixAppName.ts for Electron callers).src-electron/mainScripts/ feature folders — appIdentity/, windowManagement/, chromiumFixes/, userSettings/, nativeShell/, ipcManagement/ — plus root appManagement.ts, over growing electron-main.ts indefinitely.src-electron/electron-ipc-bridge.ts. Main-process ipcMain handlers for preload-invoked channels belong in mainScripts/ipcManagement/register*Ipc.ts (e.g. registerFaDevToolsIpc.ts, registerFaExtraEnvIpc.ts, registerFaExternalLinksIpc.ts, registerFaUserSettingsIpc.ts, registerFaWindowControlIpc.ts, registerFaAppDetailsIpc.ts, registerFaKeybindsIpc.ts for FA_KEYBINDS_IPC and mainScripts/keybinds/faKeybindsStore.ts). Call those registrars from app startup (startApp() in appManagement.ts today) so preload and main always use the same names.ipcMain.handle arguments are untrusted at runtime even when preload and types/ use correct TypeScript shapes. Anything the renderer can reach (including after a future XSS) may call the bridge with arbitrary structured-clone values.src-electron/shared/ (Electron-free, no import from electron) and parse with .parse() or .safeParse() in the registrar before merging into stores or calling privileged APIs. Reference: faUserSettingsPatchSchema.ts — builds a .strict() object from FA_USER_SETTINGS_DEFAULTS keys so unknown keys fail and allowed keys stay aligned with cleanupFaUserSettings. Export a small parse… helper that rejects non–plain objects if you want clearer errors than Zod’s defaults for null/arrays.ipcRenderer.invoke rejects; document or handle failures in the renderer (for example Pinia try/catch around setSettings).typeof plus an existing predicate (e.g. checkIfExternalUrl in registerFaExternalLinksIpc) is fine; optional z.string().refine(...) only if it improves readability or shared error formatting.registerFaExtraEnvIpc builds COMPONENT_PROPS from process.env via JSON.parse — that is harness/env trust, not preload IPC; Zod there would harden env-driven shapes but is a separate decision from channel handlers.zod is listed under package.json dependencies so production main bundles resolve it.src-electron/shared/_tests/ and extend register*Ipc tests so invalid payloads do not call store.set (or equivalent).registerFaExternalLinksIpc: one string argument plus checkIfExternalUrl — no structured object; switching to Zod would be z.string() plus refine duplicating the same predicate without simplifying the flow.registerFaWindowControlIpc, registerFaAppDetailsIpc, registerFaDevToolsIpc: async handle / invoke channels with no structured payload from the renderer beyond implicit sender context (resolve the owning window from event.sender).registerFaExtraEnvIpc: snapshot is built from process.env in main, not from renderer IPC; parseComponentProps uses JSON.parse on COMPONENT_PROPS — optional future Zod there would harden harness/env JSON, not the preload IPC boundary.invoke: prefer Zod (or the same pattern as faUserSettingsPatchSchema) from the start.src-electron/mainScripts/_tests/ (e.g. appManagement), each mainScripts/<area>/_tests/ (appIdentity, windowManagement, chromiumFixes, userSettings, nativeShell, ipcManagement), and src-electron/contentBridgeAPIs/_tests/ for bridge modules.yarn testbatch:verify (testing-terminal-isolation.mdc) — see eslint-typescript.mdc.BrowserWindow in windowManagement/mainWindowCreation.ts uses webPreferences.sandbox: true, contextIsolation: true, and explicit nodeIntegration: false (Electron disables the sandbox if nodeIntegration is true for that window). Preload must not import arbitrary Node modules; privileged work uses main + IPC — see registerFaExtraEnvIpc.ts (harness snapshot, paths) and registerFaExternalLinksIpc.ts (shell.openExternal). Official overview: Electron Process Sandboxing.ipcMain.handle in registerFaWindowControlIpc.ts and registerFaAppDetailsIpc.ts; preload uses ipcRenderer.invoke with channels from electron-ipc-bridge.ts. Handlers resolve BrowserWindow via BrowserWindow.fromWebContents(event.sender) so the correct window is targeted when focus moves to native menus.windowManagement/mainWindowCreation.ts): Resolve electron-preload and the window icon with path.resolve(currentDir, …) where currentDir is dirname(fileURLToPath(import.meta.url)) for the bundled main-process chunk (Quasar emits one main bundle; nested source folders like windowManagement/ do not appear in that path). Do not add an extra parent .. assuming currentDir is a subfolder of mainScripts/ — that breaks preload loading, skips contextBridge, and leaves window.faContentBridgeAPIs undefined (component tests fall back to / instead of /componentTesting/...).mainScripts/keybinds/)faKeybindsStore.ts, defaults, Zod patch schema under src-electron/shared/). registerFaKeybindsIpc.ts validates patches and reads/writes the store; preload faKeybindsAPI is the renderer entry. Adding commands or changing stored shapes: see fantasia-keybinds.app.getPath('userData') and _faProjectTemp/ (see electron-main.ts). For full DB design, follow fantasia-sqlite-main.types/)interface / type declarations in repository-root types/ (import with app/types/...). Prefer one domain-oriented module per feature area with brief JSDoc on exports (see types/I_appMenusDataList.ts). Do not add colocated <filename>.types.ts under src/, src-electron/, or .storybook-workspace/. Ambient augmentations for third-party modules also live under types/ and are loaded with a side-effect import from the owning boot file or src/stores/index.ts (see types/piniaModuleAugmentation.ts)..js), TypeScript (.ts), Vue (.vue), and JSON (.json, .jsonc, .json5) files, enforce expanded multi-line object literals via ESLint (object-curly-newline + object-property-newline) and keep files auto-fixable with eslint --fix.development
Splits working tree changes into logical Git commits with conventional messages (feat, fix, test, chore, refactor, style, docs). Proposes commits one at a time and waits for explicit user approval before each git commit. Use when the user asks to commit, split commits, stage by topic, or use conventional / semantic commit messages.
development
Aligns AI suggestions with Fantasia Archive as a worldbuilding database manager: projects, documents, and in-app concepts. Use when designing UX, data models, menus, or copy that should match the product purpose.
development
Runs and extends Fantasia Archive tests: Vitest unit tests vs Playwright component and E2E tests, including rebuild-before-Playwright rules and file naming. Use when writing tests, debugging CI, or when the user mentions Vitest, Playwright, component tests, or e2e.
development
Designs SQLite usage in Fantasia Archive’s Electron main process: file locations under userData, native better-sqlite3 module constraints, and migrations. Use when editing electron-main database code, schema, or persistence paths.