Skip to content

fix(desktop): stabilize Windows installer + beta 0.0.64#1119

Closed
AXGZ21 wants to merge 15 commits into
superset-sh:mainfrom
AXGZ21:fix/windows-installer
Closed

fix(desktop): stabilize Windows installer + beta 0.0.64#1119
AXGZ21 wants to merge 15 commits into
superset-sh:mainfrom
AXGZ21:fix/windows-installer

Conversation

@AXGZ21
Copy link
Copy Markdown

@AXGZ21 AXGZ21 commented Feb 1, 2026

What this PR does\n- Fixes Windows packaging layout so the installed app starts reliably.\n- Keeps installer/build-only resources out of app asar packaging paths.\n- Ensures Windows shortcuts use the Superset icon path consistently.\n- Bumps desktop app version to

Summary by CodeRabbit

  • New Features

    • Windows: richer installer (desktop & Start Menu shortcuts, custom installer icons) and improved Windows app launching.
    • Desktop: integrated ringtone player with renderer-driven subscribe/play/stop and improved Windows playback behavior.
    • Better cross-platform terminal host support and more reliable native-module handling for packaging.
  • Bug Fixes

    • Safer fallback when opening files with external apps.
    • Quit confirmation now shown only on macOS.
    • Window controls drag behavior refined.
  • Chores

    • App version bumped to 0.0.64.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Adds Windows-specific packaging and signing controls, copies icons and node-pty outside ASAR, implements robust native-module copying, adds Windows app discovery and PowerShell-based ringtone playback with main↔renderer IPC, centralizes terminal-host cross-platform paths and adapts daemon/socket behavior, and extends NSIS installer UI.

Changes

Cohort / File(s) Summary
Build & Packaging
apps/desktop/electron-builder.ts, apps/desktop/package.json, apps/desktop/scripts/copy-native-modules.ts
Add env-driven Windows signing toggle, signAndEditExecutable flag, extraResources for icons, asarUnpack/copy rules for node-pty, consolidate files filter, exclude build/** from resources, and implement robust native-module copy with repo/Bun-store fallbacks.
Windows App Launchers
apps/desktop/src/lib/trpc/routers/external/helpers.ts, apps/desktop/src/lib/trpc/routers/external/helpers.test.ts, apps/desktop/src/lib/trpc/routers/external/index.ts
Introduce WindowsAppConfig and executable discovery (install dirs, JetBrains/Toolbox heuristics, CLI fallback), FS-based resolvers, platform-aware tests, and spawnAsync try/catch fallback to shell open.
Ringtone Playback & IPC
apps/desktop/src/main/lib/notification-sound.ts, apps/desktop/src/main/lib/trpc/routers/ringtone/index.ts, apps/desktop/src/renderer/components/RingtonePlayer/*, apps/desktop/src/renderer/lib/ringtone-urls.ts
Add main→renderer ringtone events (play/stop), TRPC subscribe/list, PowerShell playback fallback on Windows, renderer RingtonePlayer component, and ringtone URL mapping.
Terminal Host Paths & Daemon
apps/desktop/src/main/lib/terminal-host/paths.ts, apps/desktop/src/main/lib/terminal-host/client.ts, apps/desktop/src/main/terminal-host/index.ts, apps/desktop/src/main/terminal-host/daemon.test.ts, apps/desktop/src/main/terminal-host/session-lifecycle.test.ts, apps/desktop/src/main/lib/terminal/dev-reset.ts
Add TERMINAL_HOST_PATHS (IS_WINDOWS, SOCKET_PATH, token/pid/spawn paths), refactor client/daemon/tests/dev-reset to use centralized paths, use isSocketLive guards, and avoid Unix-socket file ops on Windows.
Window Creation & UI
apps/desktop/src/lib/electron-app/factories/windows/create.ts, apps/desktop/src/renderer/routes/layout.tsx, apps/desktop/src/renderer/components/.../WindowControls.tsx, apps/desktop/src/main/index.ts
Add Windows default window icon resolution and merge into BrowserWindow options, mount RingtonePlayer in root layout, add no-drag classes to window controls, and restrict quit-confirm to macOS.
NSIS Installer Script
apps/desktop/src/resources/build/installer.nsh
Extend NSIS with desktop/Start Menu shortcut checkbox UI, macros to persist choice, customInstall macro to create shortcuts, and installer/uninstaller icon handling.
Misc & Safety
apps/desktop/src/renderer/stores/tabs/store.ts, apps/api/src/app/api/agent/[transport]/route.ts, packages/trpc/src/router/*, tests and small fixes
Add null-safe session optional chaining, tighten migration typings, test scaffolding for platform-specific cases, and small spawn/error handling adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant Main as Main Process
    participant IPC as IPC (Main↔Renderer)
    participant Renderer as Renderer
    participant PS as PowerShell

    Note over Main,Renderer: Windows ringtone playback — IPC-first, PS fallback

    Main->>IPC: sendRingtoneEvent("ringtone-play", filename)
    alt renderer subscribed and receives event
        IPC->>Renderer: deliver "ringtone-play" with filename
        Renderer->>Renderer: set Audio.src and audio.play()
    else renderer unavailable or delivery fails
        Main->>PS: spawn PowerShell with player script + filename
        PS->>PS: play audio via WPF MediaPlayer
        PS-->>Main: exit/status
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • saddlepaddle

Poem

🐇 I hopped through builds and pipes today,

Icons unpacked, and sign flags sway,
PowerShell hums a ringtone tune,
Pipes and sockets stir by noon,
Installer boxes jump and shortcuts play. 🎶

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete; it cuts off mid-sentence without specifying the version number and lacks required template sections like Related Issues and Type of Change. Complete the description by specifying the version number (0.0.64), add Related Issues if applicable, explicitly select the Type of Change (Bug fix), describe testing steps, and add any additional notes about Windows-specific changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: stabilizing the Windows installer and bumping to version 0.0.64, which aligns with the detailed changes across build configuration, packaging layout, and version updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@apps/desktop/electron-builder.ts`:
- Around line 99-103: The copy rule for the Windows-only package
"@lydell/node-pty-win32-x64" is currently added unconditionally in the top-level
asarUnpack and files arrays; remove that rule from the global asarUnpack/files
entries in electron-builder.ts and add an equivalent copy rule inside the
existing win configuration block so it only applies to Windows builds. Locate
the global asarUnpack and files definitions and the win section in
electron-builder.ts (and reference OPTIONAL_PLATFORM_MODULES from
copy-native-modules.ts if needed) and move the entry for
"node_modules/@lydell/node-pty-win32-x64" into the win.files/asarUnpack block,
ensuring no remaining global references remain.

In `@apps/desktop/src/lib/electron-app/factories/windows/create.ts`:
- Around line 12-19: The packaged icon candidate paths are incorrect: when
app.isPackaged is true app.getAppPath() yields .../app.asar (so
join(app.getAppPath(), "resources", ...) is wrong) and process.resourcesPath
should point to the app's resources root so you must not add an extra
"resources" segment; update the candidates array in create.ts to remove the
app.getAppPath() resource path and instead use process.resourcesPath joined with
"build", "icons", "icon.ico" (keep the dev path using
app.getAppPath()/src/resources as before) so the variable candidates produces
the actual packaged icon path.

In `@apps/desktop/src/lib/trpc/routers/ringtone/index.ts`:
- Around line 182-190: The Windows branch currently calls
sendRingtoneEvent("ringtone-play", input.filename) and returns success without
checking its boolean result; update the handler in the ringtone router (the
Windows-specific branch around sendRingtoneEvent) to check the returned value
and, if it is false, either call playSoundFile(getSoundPath(input.filename)) as
a fallback or return/log an error and set success to false; apply the same
check-and-fallback logic to the other Windows branches mentioned (the ones
around lines 195-202 and 236-239) so success is only returned when playback was
actually initiated or a fallback was executed.
- Around line 131-143: The execFile callback for Windows playback currently
ignores its error parameter so PowerShell exits with non‑zero codes aren't
logged; update the execFile callback passed to currentSession.process (created
with execFile(powershellPath, buildWindowsPlayerArgs(soundPath), ...)) to accept
(error, stdout, stderr) and, if error is present, log it (including
error.message and stderr) using the domain/operation prefix pattern (e.g.
"[ringtone/play] Windows playback failed: ..."); keep the existing cleanup that
sets currentSession to null when sessionId matches.
- Around line 25-37: Replace the direct IPC pattern by adding a tRPC observable
subscription to the ringtone router and refactor sendRingtoneEvent to accept a
single params object; specifically, create a new subscribe procedure on the
ringtone router using observable from `@trpc/server/observable` that emits
play/stop events to subscribers (mirror patterns used in
auth/notifications/menu/ports/terminal/ui-state routers), update renderer to
call this tRPC subscribe instead of relying on BrowserWindow.webContents.send,
and change the sendRingtoneEvent signature from sendRingtoneEvent(channel:
"ringtone-play" | "ringtone-stop", filename?: string) to
sendRingtoneEvent(params: { channel: "ringtone-play" | "ringtone-stop";
filename?: string }) and update all callers to pass a single object.

In `@apps/desktop/src/renderer/components/RingtonePlayer/RingtonePlayer.tsx`:
- Around line 47-48: RingtonePlayer currently registers IPC listeners directly
with window.ipcRenderer for PLAY_CHANNEL/STOP_CHANNEL; replace this with tRPC
subscriptions and centralized channel defs: add play/stop channel names to
apps/desktop/src/shared/ipc-channels.ts (e.g., PLAY_CHANNEL, STOP_CHANNEL),
implement tRPC server-side observables for those channels, and in
RingtonePlayer.tsx subscribe via the tRPC client observable/subscription API
instead of window.ipcRenderer.on; wire the existing handlePlay and handleStop
callbacks to the subscription next/error handlers and remove the direct
ipcRenderer registrations.

In `@apps/desktop/src/resources/build/installer.nsh`:
- Around line 13-25: The customInstall macro currently always creates the
desktop shortcut when $newDesktopLink exists; update the logic in the
customInstall macro to check the installer flag $isNoDesktopShortcut (or its
truthiness) before creating the desktop shortcut: wrap the CreateShortCut and
subsequent ClearErrors/WinShell::SetLnkAUMI calls for $newDesktopLink in a
conditional that skips shortcut creation if $isNoDesktopShortcut is set, leaving
the existing $newStartMenuLink handling unchanged.
🧹 Nitpick comments (6)
apps/desktop/src/renderer/components/RingtonePlayer/RingtonePlayer.tsx (1)

10-14: Wrap helper functions in useCallback to satisfy exhaustive deps.

The playPlayback and stopPlayback functions are used in the useEffect but not listed in dependencies. While the current implementation works because these functions only reference stable values (a ref and a module-level import), this pattern violates React hooks rules and can cause subtle bugs if the functions evolve.

♻️ Proposed fix using useCallback
+import { useCallback, useEffect, useRef } from "react";
-import { useEffect, useRef } from "react";
 import { getRingtoneUrl } from "renderer/lib/ringtone-urls";
 
 const PLAY_CHANNEL = "ringtone-play";
 const STOP_CHANNEL = "ringtone-stop";
 
 export function RingtonePlayer() {
 	const audioRef = useRef<HTMLAudioElement | null>(null);
 
-	const stopPlayback = () => {
+	const stopPlayback = useCallback(() => {
 		if (!audioRef.current) return;
 		audioRef.current.pause();
 		audioRef.current.currentTime = 0;
-	};
+	}, []);
 
-	const playPlayback = (filename: string) => {
+	const playPlayback = useCallback((filename: string) => {
 		const url = getRingtoneUrl(filename);
 		if (!url) {
 			console.warn("[ringtone] Missing URL for filename:", filename);
 			return;
 		}
 
 		if (!audioRef.current) {
 			audioRef.current = new Audio();
 		}
 
 		const audio = audioRef.current;
 		audio.pause();
 		audio.src = url;
 		audio.currentTime = 0;
 		audio.volume = 1;
 		audio.play().catch((error) => {
 			console.warn("[ringtone] Failed to play audio:", error);
 		});
-	};
+	}, []);
 
 	useEffect(() => {
 		// ... handlers remain the same
-	}, []);
+	}, [playPlayback, stopPlayback]);

Also applies to: 16-35

apps/desktop/src/lib/trpc/routers/external/helpers.ts (1)

170-209: Consider extracting nested directory traversal for readability.

The 4-level nesting in findJetBrainsToolboxExe reflects the Toolbox directory structure but could be simplified by extracting the inner channel/build search into a helper function. This is optional given the domain complexity.

♻️ Optional extraction for clarity
+const findExeInToolboxProduct = (
+	productDir: string,
+	exeName: string,
+): string | null => {
+	try {
+		const channels = fs.readdirSync(productDir, { withFileTypes: true });
+		for (const channel of channels) {
+			if (!channel.isDirectory() || !channel.name.startsWith("ch-")) continue;
+			const channelDir = nodePath.join(productDir, channel.name);
+			const builds = fs.readdirSync(channelDir, { withFileTypes: true })
+				.filter((b) => b.isDirectory())
+				.map((b) => b.name)
+				.sort()
+				.reverse();
+			for (const buildName of builds) {
+				const candidate = nodePath.join(channelDir, buildName, "bin", exeName);
+				if (fs.existsSync(candidate)) return candidate;
+			}
+		}
+	} catch {
+		// Ignore lookup errors
+	}
+	return null;
+};
+
 const findJetBrainsToolboxExe = (
 	toolboxRoot: string,
 	exeName: string,
 ): string | null => {
 	try {
 		if (!fs.existsSync(toolboxRoot)) return null;
 		const products = fs.readdirSync(toolboxRoot, { withFileTypes: true });
 		for (const product of products) {
 			if (!product.isDirectory()) continue;
-			const productDir = nodePath.join(toolboxRoot, product.name);
-			const channels = fs.readdirSync(productDir, { withFileTypes: true });
-			// ... nested logic
+			const match = findExeInToolboxProduct(
+				nodePath.join(toolboxRoot, product.name),
+				exeName,
+			);
+			if (match) return match;
 		}
 	} catch {
 		// Ignore lookup errors and fall back
 	}
 	return null;
 };
apps/desktop/src/lib/trpc/routers/ringtone/index.ts (1)

13-23: Extract Windows playback helpers and timing constants to a shared module.
The PowerShell script’s hard-coded waits (300 / 200 ms) are magic numbers and the helper is duplicated with src/main/lib/notification-sound.ts; centralizing them will prevent drift and make the timings explicit.

As per coding guidelines: Avoid magic numbers by extracting them to named constants at module top.

Also applies to: 39-79

apps/desktop/src/main/lib/notification-sound.ts (2)

13-65: Consider extracting Windows playback helpers to a shared module.
The PowerShell script and timing values are duplicated with the ringtone router; centralizing them would prevent drift and allow named constants for the waits.

As per coding guidelines: Avoid magic numbers by extracting them to named constants at module top.


126-139: Align Windows playback warnings with [domain/operation] logging format.
Use a prefix like [notification-sound/playback] for this warning.

🔧 Suggested tweak
-					console.warn(
-						"[notification-sound] Windows playback failed:",
-						error.message,
-					);
+					console.warn(
+						"[notification-sound/playback] Windows playback failed:",
+						error.message,
+					);
As per coding guidelines: Use prefixed console logging with pattern `[domain/operation] message` for all logging.
apps/desktop/scripts/copy-native-modules.ts (1)

58-95: Replace positional/boolean args with params objects and add a log prefix.
copyModuleIfSymlink / ensureLocalModuleCopy are called with false, which is hard to read and violates the params-object guideline. Also, the script logs should use a consistent [domain/operation] prefix.

♻️ Example refactor
+const LOG_PREFIX = "[native-modules/prepare]";
-console.log("Preparing native modules for electron-builder...");
+console.log(`${LOG_PREFIX} Preparing native modules for electron-builder...`);

-function copyModuleIfSymlink(
-	nodeModulesDir: string,
-	moduleName: string,
-	required: boolean,
-): boolean {
+function copyModuleIfSymlink({
+	nodeModulesDir,
+	moduleName,
+	required,
+}: {
+	nodeModulesDir: string;
+	moduleName: string;
+	required: boolean;
+}): boolean {

-function ensureLocalModuleCopy(moduleName: string, required: boolean) {
+function ensureLocalModuleCopy({
+	moduleName,
+	required,
+}: {
+	moduleName: string;
+	required: boolean;
+}) {

-ensureLocalModuleCopy(moduleName, false);
+ensureLocalModuleCopy({ moduleName, required: false });
As per coding guidelines: Functions with 2+ parameters should accept a single params object with named properties instead of positional arguments; Avoid boolean blindness: use options objects with named properties instead of `doThing(true, false, true)`; Use prefixed console logging with pattern `[domain/operation] message` for all logging.

Also applies to: 106-154

Comment thread apps/desktop/electron-builder.ts Outdated
Comment thread apps/desktop/src/lib/electron-app/factories/windows/create.ts
Comment thread apps/desktop/src/lib/trpc/routers/ringtone/index.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/ringtone/index.ts Outdated
Comment on lines +182 to +190
if (process.platform === "win32") {
sendRingtoneEvent("ringtone-play", input.filename);
return { success: true as const };
}),
}

const soundPath = getSoundPath(input.filename);
playSoundFile(soundPath);
return { success: true as const };
}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Check sendRingtoneEvent result before returning success on Windows.
If no window exists, the helper returns false and these paths still return success while skipping playback. Consider falling back to playSoundFile (or logging/returning an error) when the send fails.

Also applies to: 195-202, 236-239

🤖 Prompt for AI Agents
In `@apps/desktop/src/lib/trpc/routers/ringtone/index.ts` around lines 182 - 190,
The Windows branch currently calls sendRingtoneEvent("ringtone-play",
input.filename) and returns success without checking its boolean result; update
the handler in the ringtone router (the Windows-specific branch around
sendRingtoneEvent) to check the returned value and, if it is false, either call
playSoundFile(getSoundPath(input.filename)) as a fallback or return/log an error
and set success to false; apply the same check-and-fallback logic to the other
Windows branches mentioned (the ones around lines 195-202 and 236-239) so
success is only returned when playback was actually initiated or a fallback was
executed.

Comment thread apps/desktop/src/renderer/components/RingtonePlayer/RingtonePlayer.tsx Outdated
Comment thread apps/desktop/src/resources/build/installer.nsh
Comment thread apps/desktop/package.json
"nanoid": "^5.1.6",
"node-addon-api": "^7.1.0",
"node-pty": "1.1.0-beta30",
"node-pty": "npm:@lydell/node-pty@^1.0.1",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AXGZ21 what's the reason for using this package? I think i had to do this for onlook as well but can't recall exactly

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! The @lydell/node-pty package is a fork of the original node-pty library. Based on the change, there are a few likely reasons why this fork was used:

Possible reasons:

  • Bug fixes - The lydell fork may contain fixes for specific issues that haven't been merged into the main package yet
  • Platform-specific compatibility - Since node-pty deals with pseudo-terminals, this fork might have better cross-platform support (Windows/macOS/Linux)
  • Electron compatibility - The fork could have better compatibility with our specific Electron version
  • Maintenance - The main package might have had slower maintenance when this change was made

To confirm the exact reason, it would be helpful to:

  • Check the original PR description or commit message for context
  • Review the lydell/node-pty repository to see what differences exist
  • Look for any related issues that prompted this change

Did you encounter this same issue with Onlook, or are you just reviewing the change for context?

AI Generated by PierrunoYT

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kitenite We use npm:@lydell/node-pty@^1.0.1 because it provides reliable prebuilt binaries (especially for Windows) for Electron, so terminal PTY spawning works and installer builds don’t fail on native compilation.

Also, keep only one node-pty entry in package.json (remove the duplicate).

…nt handling

- Added EventEmitter for ringtone events to manage play and stop actions.
- Refactored sendRingtoneEvent function to use an object parameter for better clarity.
- Updated RingtonePlayer component to subscribe to ringtone events via tRPC, replacing previous IPC event handling.
- Updated the playSoundFile function to include error handling for Windows playback failures.
- Removed redundant error listener and consolidated error logging within the playback callback.
- Added fallback mechanisms for both playing and stopping ringtones when no renderer window is available.
- Updated sendRingtoneEvent calls to check for successful event sending before falling back to direct sound playback or stopping current sound.
- Introduced a condition to prevent the creation of a desktop shortcut if the user opts out.
- Ensured that the existing logic for creating shortcuts in the Start Menu remains intact.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/desktop/electron-builder.ts`:
- Around line 107-109: The packaging config sets npmRebuild: false but
electron-rebuild is never invoked and the copy:native-modules script only copies
symlinks, so native modules will fail at runtime; either set npmRebuild: true in
the electron-builder config (change npmRebuild to true) or add an explicit
pre-pack step to run electron-rebuild (or electron-builder install-app-deps)
from your package.json build/package/release scripts so native modules (e.g.,
better-sqlite3, node-pty) are rebuilt for the Electron platform before
packaging.

In `@apps/desktop/src/lib/trpc/routers/ringtone/index.ts`:
- Around line 32-42: The sendRingtoneEvent function currently always returns
true, preventing callers from detecting whether any listeners handled the event;
change it to return the boolean result of ringtoneEvents.emit(...) and ensure
the play path returns false if params.filename is missing. Concretely, in
sendRingtoneEvent (the function handling channel "ringtone-play" |
"ringtone-stop"), call ringtoneEvents.emit("ringtone-event", ...) and return its
value for both play and stop branches, and return false for invalid play
requests (no filename) so callers can run their fallback playback.
🧹 Nitpick comments (4)
apps/desktop/src/renderer/components/RingtonePlayer/RingtonePlayer.tsx (1)

46-50: Stabilize stopPlayback with useCallback to satisfy exhaustive deps.

The static analysis correctly identifies that stopPlayback is used inside the cleanup effect but not listed in the dependency array. Since stopPlayback is recreated on every render, this could lead to stale closure issues. Wrap it with useCallback to make it stable.

♻️ Proposed fix
-import { useEffect, useRef } from "react";
+import { useCallback, useEffect, useRef } from "react";
 import { electronTrpc } from "renderer/lib/electron-trpc";
 import { getRingtoneUrl } from "renderer/lib/ringtone-urls";
 
 export function RingtonePlayer() {
 	const audioRef = useRef<HTMLAudioElement | null>(null);
 
-	const stopPlayback = () => {
+	const stopPlayback = useCallback(() => {
 		if (!audioRef.current) return;
 		audioRef.current.pause();
 		audioRef.current.currentTime = 0;
-	};
+	}, []);

Then update the effect:

 	useEffect(() => {
 		return () => {
 			stopPlayback();
 		};
-	}, []);
+	}, [stopPlayback]);
apps/desktop/src/lib/trpc/routers/ringtone/index.ts (2)

44-84: PowerShell path escaping may be insufficient for edge cases.

The escaping only handles single quotes ('''), which is correct for PowerShell single-quoted strings. However, file paths with unusual characters (backticks, dollar signs if path somehow contains them) could cause issues. Consider also validating that the path contains only expected characters, or using -LiteralPath where applicable.


183-220: Inconsistent indentation in procedure definitions.

The preview and stop procedures have inconsistent indentation compared to subscribe and list. This appears to be a formatting issue where these procedures are at a different indent level than expected within the router({...}) block.

apps/desktop/electron-builder.ts (1)

13-13: Extract the "1" flag to a named constant.

This avoids a magic number and clarifies intent.

♻️ Suggested change
-const disableWinSigning = process.env.SUPERSET_DISABLE_WIN_SIGNING === "1";
+const DISABLE_WIN_SIGNING_FLAG = "1";
+const disableWinSigning =
+  process.env.SUPERSET_DISABLE_WIN_SIGNING === DISABLE_WIN_SIGNING_FLAG;

Comment thread apps/desktop/electron-builder.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/ringtone/index.ts
- Updated type assertions for legacy panes and file viewers during state migration.
- Ensured proper handling of `needsAttention` and `isLocked` properties to maintain compatibility with the new schema.
… organization ID access

- Added a check to ensure the user is present in the session during token verification.
- Updated access to `activeOrganizationId` in multiple routers to use optional chaining for safer access.
@PwccaCode
Copy link
Copy Markdown

will this be merged?

- Improved the sendRingtoneEvent function to validate the presence of a filename for play requests.
- Updated logic to return false for invalid requests, ensuring better error handling and clarity in event emission.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/desktop/src/lib/trpc/routers/ringtone/index.ts`:
- Around line 215-226: The Windows stop handler may skip killing the fallback
child process when sendRingtoneEvent returns true; modify the stop procedure
(stop: publicProcedure.mutation) to always call stopCurrentSound() (to kill any
fallback playback) and then, if on win32, also call sendRingtoneEvent({ channel:
"ringtone-stop" }) to notify the renderer; ensure both functions run
(stopCurrentSound first) and keep returning { success: true }.
🧹 Nitpick comments (1)
apps/desktop/electron-builder.ts (1)

60-65: Consider moving the icons extraResources entry into the win section.

The comment on line 60 says these icons are for Windows shortcuts, but the entry sits at the top level, so it will be bundled into macOS and Linux builds as well. Moving it under win.extraResources would keep non-Windows artifacts leaner.

Comment thread apps/desktop/src/lib/trpc/routers/ringtone/index.ts
- Refactored the stop procedure to ensure fallback playback is always stopped first.
- Simplified the logic for notifying the renderer to stop playback on Windows, removing unnecessary checks for renderer availability.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/lib/trpc/routers/ringtone/index.ts (1)

169-173: ⚠️ Potential issue | 🟡 Minor

aplay fallback silently swallows errors.

If aplay also fails, the error is discarded and the user gets no feedback. Per coding guidelines: "Never swallow errors silently; at minimum log errors with context before rethrowing or handling them explicitly."

Proposed fix
-				currentSession.process = execFile("aplay", [soundPath], () => {
+				currentSession.process = execFile("aplay", [soundPath], (aplayError) => {
+					if (aplayError) {
+						console.warn("[ringtone/play] Linux aplay fallback failed:", aplayError.message);
+					}
 					if (currentSession?.id === sessionId) {
 						currentSession = null;
 					}
 				});
🧹 Nitpick comments (2)
apps/desktop/src/lib/trpc/routers/ringtone/index.ts (2)

50-90: Extract magic numbers in the PowerShell player script to named constants.

The loop bound 300, sleep interval 200, and WMP playState values (3 = playing, 1 = stopped, 8 = ended) are opaque inline. Consider extracting them at the module top:

+const WMP_POLL_MAX_ITERATIONS = 300;
+const WMP_POLL_INTERVAL_MS = 200;
+// Windows Media Player playState enum values
+const WMP_STATE_PLAYING = 3;
+const WMP_STATE_STOPPED = 1;
+const WMP_STATE_ENDED = 8;

Then reference them in the script template. This makes the effective 60-second timeout (300 × 200 ms) discoverable and adjustable. As per coding guidelines, "Extract hardcoded magic numbers, strings, and enums to named constants at module top instead of leaving them inline in logic."


189-225: Inconsistent indentation: preview and stop are indented one level less than subscribe and list.

preview (Line 189) and stop (Line 215) are at one-tab indent inside the router({}) call, while subscribe (Line 231) and list (Line 248) are at two-tab indent. This appears to be a formatting accident. Aligning all procedures to the same level improves readability.

@PwccaCode
Copy link
Copy Markdown

still no updates on this?

@Kitenite
Copy link
Copy Markdown
Collaborator

Closing: this Windows installer PR from Feb 1 has been superseded by newer Windows support efforts (#2100, #2196, #2322).

@Kitenite Kitenite closed this Mar 13, 2026
@Kitenite
Copy link
Copy Markdown
Collaborator

Hey — just a heads up, this was closed as part of an automated stale PR cleanup. If you think this was done in error, feel free to reopen it!

@Kitenite
Copy link
Copy Markdown
Collaborator

Hey — this was closed by an automated cleanup of PRs with major merge conflicts that are 3+ weeks old. If you think this was done incorrectly, please feel free to reopen it. Sorry for any inconvenience!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants