8000 Feedback from a Windows user: notification sounds, installer/Store distribution, CLI new-instance bug, and per-pane quick-launch profiles · Issue #32 · amirlehmam/wmux · GitHub
[go: up one dir, main page]

Skip to content

Feedback from a Windows user: notification sounds, installer/Store distribution, CLI new-instance bug, and per-pane quick-launch profiles #32

Closed

Description

@kevmtt

First off — I really love that this tool exists and lets Windows users catch up to macOS developers. I've been testing wmux for my work and wanted to share constructive feedback on a few things I struggled with, plus one feature suggestion. Code references included in case they help.


1. Notification sounds never play

The Sound setting (Settings → Notifications, Default/None) looks functional but is a no-op:

  • notificationPrefs.sound is defined (settings-slice.ts:246-260) and shown in the UI (NotificationSettings.tsx:51-65) but never read anywhere.
  • There's no audio playback code at all (no new Audio/.play()), and resources/sounds/ is empty (only .gitkeep) despite being bundled into every release.
  • Only the Electron toast + taskbar flash + pane ring fire (notification-manager.ts:4-14).

Suggestion: ship a default sound asset and play it in the NOTIFICATION_FIRE path when sound !== 'none', or remove the setting until implemented so it's not misleading.


2. Proper installer / Microsoft Store distribution + PATH

The portable zip works but limits discoverability and makes PATH setup manual. electron-builder.json already has NSIS config (currently unused) and electron-builder supports MSIX/appx. Rough effort, lowest-friction first:

Option Est. effort Cost / prereqs Notes & risks
Winget (microsoft/winget-pkgs) ~0.5–1 day Free. No code-signing required to publish. Lowest-friction win — a YAML manifest pointing at the existing release zip/exe + SHA256, fully automatable per release via the winget-releaser GitHub Action. Caveat: unsigned binaries still trip SmartScreen on first run, so this improves install UX, not trust.
NSIS installer (already configured) ~1–2 days Code-signing cert is the real cost (below). Config mostly exists; work is building off the OneDrive/spaces path (the documented winCodeSign blocker), wiring signing into the release pipeline, and testing shortcut/PATH registration. Unsigned, NSIS trips SmartScreen more than the zip — only pays off once signing is in place.
Microsoft Store (MSIX/AppX) ~3–5 days + review latency Partner Center account ($19 one-time individual). Store signs the package — no cert purchase needed. Biggest visibility upside and solves signing "for free," but highest technical risk: MSIX runs in a sandboxed container that can break wmux core behaviors — named pipe (\\.\pipe\wmux), spawning external shells/node-pty, writing to ~/.claude. Needs a validation spike before committing; budget extra time if those need workarounds (runFullTrust, packaged-path handling).

Code-signing is the dominant variable for the installer path:

  • Cheapest modern route: Azure Trusted Signing (~$10/mo), integrates with electron-builder.
  • Traditional OV cert ($200–400/yr) builds SmartScreen reputation slowly; EV ($300–700/yr) clears it immediately.
  • The Store path sidesteps cert purchase entirely (Microsoft signs Store MSIX).

Suggested sequencing: Winget first (cheap, fast), then Azure Trusted Signing + the existing NSIS installer mid-term, and treat Store/MSIX as a separate spike gated on confirming the sandbox doesn't break the pipe/PTY architecture. A proper installer would also register a real wmux CLI on PATH automatically — which fixes issue #3.


3. wmux browser open launches a NEW instance instead of using the running one

When Claude Code runs wmux browser open <url> it spawns a fresh wmux window rather than driving the existing one. Two confirmed root causes:

  • Stale compiled CLI: resources/cli/wmux.js:8 hardcodes const PIPE_PATH = '\\\\.\\pipe\\wmux', dropping the process.env.WMUX_PIPE support that exists in source (src/cli/wmux.ts:7). The shipped artifact predates the feature and needs a rebuild.
  • No single-instance lock: src/main/index.ts has no app.requestSingleInstanceLock() / second-instance handler, so a second launch just opens another window instead of focusing the existing one.
  • Underlying trigger: outside a wmux-spawned shell, wmux isn't the CLI (no WMUX_CLI env var / wmux shell function), so the name resolves to the GUI exe on PATH → new instance, args ignored. The CLI script itself never launches the GUI (on pipe failure it just prints "wmux is not running" and exits), confirming the new window comes from the exe being invoked directly.

Suggested fixes: add requestSingleInstanceLock with a second-instance focus handler; rebuild/verify resources/cli/wmux.js; ship a dedicated wmux CLI shim on PATH distinct from wmux.exe (ties into issue #2).


4. Feature request: configurable quick-launch profiles next to the + button

I'd love to configure quick-launch shortcuts next to each pane's + button — to open tools, auto-cd into directories, run a startup command, etc. This already exists in cmux as project "custom commands" (cmux.json), and Windows Terminal has the profile-dropdown precedent — wmux is well-positioned because the UI hook is already there.

Current state:

  • The + already has a caret dropdown (SurfaceTabBar.tsx:272-297) but it only offers Terminal / Browser / Markdown — pure type selection.
  • There are no profiles, no startup commands, and no per-tab cwd (pty-manager.ts accepts cwd but no startup command; WT import at config-loader.ts:157-178 keeps only the color scheme and discards profiles / commandline / startingDirectory).

Proposed shape:

  • Profile model: { name, icon, type, shell?, cwd?, startupCommands[] } — e.g. "Backend → cd ./server, npm run dev", "lazygit", "btop".
  • Two config scopes: global in settings.json (alongside the existing 45 shortcuts), and a project-level .wmux.json committed to a repo (mirrors cmux's cmux.json).
  • Surfacing: populate the existing + caret dropdown with these profiles; each entry creates a surface of type in cwd running startupCommands.
  • Free wins: bind any profile to the existing keyboard-shortcut / command-palette infra, and finish the WT import to pull real profiles (commandline + startingDirectory), giving WT users an instant launcher library.

Comparatively small lift (dropdown + PTY cwd/startup-command plumbing + config schema) for a high-visibility quality-of-life feature.


Thanks again for building this — happy to help test fixes or open separate issues if you'd prefer these tracked individually.

Activity

  1. added a commit that references this issue on Jun 15, 2026
  2. amirlehmam commented on Jun 15, 2026

    @amirlehmam
    Owner

    Hey @kevmtt — this is genuinely one of the most useful issues the project has gotten. Thank you for the code references; they made every one of these fast to land. Shipped in v0.8.6:

    1. Notification sounds ✅ fixed

    You were exactly right — notificationPrefs.sound was read nowhere and resources/sounds/ was empty. wmux now ships a default chime and plays it on every notification fire, gated on the Default/None setting. The main process can't play audio, so it emits a notification:play-sound signal on the single NOTIFICATION_FIRE chokepoint (covers OSC 9/99/777 + the activity watcher), and one renderer listener plays the bundled WAV iff sound !== 'none'.

    3. wmux browser open spawning a new instance ✅ fixed

    Both root causes you found are addressed:

    • Single-instance lock: added app.requestSingleInstanceLock() + a second-instance focus handler. A stray wmux … launch now focuses the running window instead of spawning a second one. Named WMUX_INSTANCE instances point Electron's userData at their own dir, so the lock is per-instance and dev/prod still coexist.
    • Stale CLI: rebuilt resources/cli/wmux.js — it honors process.env.WMUX_PIPE again (the shipped artifact had drifted behind source, exactly as you spotted).

    The one piece I deliberately deferred is your item 3c (a dedicated wmux CLI shim on PATH distinct from wmux.exe). It's the cleanest long-term fix but it's coupled to the installer work below, so I'm tracking it there rather than half-shipping it.

    4. Quick-launch profiles ✅ implemented

    Built close to your proposed shape:

    • Model: { name, icon, type, shell?, cwd?, startupCommands[], url? }.
    • Global profiles in Settings → Profiles, including a one-click "Import from Windows Terminal" that finishes the WT import you flagged (commandline → shell, startingDirectory → cwd).
    • Project profiles via a committed .wmux.json at a workspace root (mirrors cmux's cmux.json). Example:
      { \"profiles\": [
        { \"name\": \"Backend\", \"type\": \"terminal\", \"cwd\": \"./server\", \"startupCommands\": [\"npm run dev\"] },
        { \"name\": \"lazygit\", \"icon\": \"🌿\", \"type\": \"terminal\", \"startupCommands\": [\"lazygit\"] },
        { \"name\": \"Grafana\", \"type\": \"browser\", \"url\": \"http://localhost:3000\" }
      ] }
    • Both scopes populate the existing + caret dropdown (project entries get a project badge). Terminal profiles auto-cd and run their startup commands once on fresh PTY creation (re-mounting a keep-alive tab won't re-run them); relative cwd resolves against the workspace cwd.

    2. Installer / Store distribution — partially shipped 🟡

    I took your sequencing recommendation and started with the cheap, no-signing win:

    • Winget: added the manifest set (winget/) + an auto-publish GitHub Action (vedantmgoyal9/winget-releaser). wmux is modeled as a portable-zip install with a nested wmux command alias on PATH. The first submission to microsoft/winget-pkgs + the WINGET_TOKEN secret are a one-time owner step — documented in winget/README.md.

    The rest of #2 comes down to spending decisions that are mine to make, not code, so I'm leaving them as deliberate follow-ups rather than pretending they're done:

    • Code-signing (Azure Trusted Signing ≈ $10/mo, or EV cert) — required before an NSIS installer is worth it, since unsigned NSIS trips SmartScreen harder than the zip.
    • MSIX/Store — needs the sandbox validation spike you called out (named pipe \.\pipe\wmux, node-pty shell spawning, ~/.claude writes) before committing.

    Winget improves install UX, not trust — fully agreed, and called out as such in the release notes.


    Everything except the signing/Store spend is in v0.8.6 now. If you grab the build, please right-click → Unblock the zip (or Get-ChildItem -Recurse | Unblock-File) before running. Would genuinely love a second pass from you on the profiles UX and the new-instance behavior — and yes, please do open separate issues for the CLI-shim and Store-spike if you'd like them tracked individually. 🙏

  3. kevmtt commented on Jun 16, 2026

    @kevmtt
    ContributorAuthor
    Image

    @amirlehmam For me the dropdown isn't working, eventhough I've created profiles.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0