Skip to content

bug(windows): tray icon exits after 3s and fails to launch detached host (ocx tray install) #2804

Description

@benedictusrey

Client or integration

Codex CLI

Area

CLI

Summary

When running ocx tray install on Windows:

  1. The command reports Windows tray: installed and running.
  2. Within ~3 seconds, the tray process silently terminates, and subsequent ocx tray status calls report Windows tray: installed, not currently running.
  3. In the Windows taskbar, the icon remains as a "ghost" that instantly disappears upon right-click or hover.

Expected Behavior

ocx tray install should launch a persistent background tray process that remains running and displays the context menu on right-click.


Root Causes

  1. Environment Dropped in Detached Host (src/tray/windows.ts):
    DETACHED_TRAY_HOST_LAUNCHER uses $startInfo.UseShellExecute = $true. In .NET, UseShellExecute = $true invokes ShellExecuteEx, discarding process environment variables (OCX_TRAY_ENTRY_B64). When bun src/cli/index.ts __tray-host launches without it, parseTrayHostEntry() throws Missing tray host entry and exits immediately.

  2. Leftover Stop Signal Consumed on First Timer Tick (src/tray/windows-tray.ps1):
    signalTrayStop() sets the named event Local\OpenCodexTrayStop-<hash>. When the new tray starts in -Mode Run, it never resets this event. On the first 3000ms timer tick, if ($stopEvent.WaitOne(0)) detects the leftover signal and calls [System.Windows.Forms.Application]::Exit().

  3. WinForms Context Menu Styling & Non-Guarded I/O (src/tray/windows-tray.ps1):
    [System.Windows.Forms.Application]::EnableVisualStyles() is missing, causing ContextMenuStrip rendering issues. Additionally, $ErrorActionPreference = "Stop" causes minor I/O locks on tray-heartbeat.json to abort the UI thread.


Proposed Fix

1. Direct Launch via Native VBS Host in src/tray/windows.ts

Launch opencodex-tray.vbs via wscript.exe directly in spawnTray, matching the exact detached execution model used by Windows boot:

function spawnTray(state: WindowsTrayEntry): void {
  const launcher = installedTrayLauncherPath();
  if (existsSync(launcher)) {
    const wscript = join(process.env.SystemRoot ?? "C:\\Windows", "System32", "wscript.exe");
    execFileSync(wscript, ["//B", "//NoLogo", launcher], {
      stdio: "ignore",
      windowsHide: true,
      timeout: 15_000,
    });
    return;
  }
  launchWindowsTrayHost(state);
}

If retaining DETACHED_TRAY_HOST_LAUNCHER as a fallback, ensure environment inheritance is preserved:

const DETACHED_TRAY_HOST_LAUNCHER = [
  "$startInfo = New-Object System.Diagnostics.ProcessStartInfo",
  "$startInfo.FileName = $env:OCX_TRAY_HOST_BUN",
  "$startInfo.Arguments = $env:OCX_TRAY_HOST_ARGS",
  "$startInfo.UseShellExecute = $false",
  "$startInfo.CreateNoWindow = $true",
  "$startInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden",
  "$startInfo.EnvironmentVariables['OCX_TRAY_ENTRY_B64'] = $env:OCX_TRAY_ENTRY_B64",
  "$child = [System.Diagnostics.Process]::Start($startInfo)",
  "if ($null -eq $child) { throw 'Windows tray host did not start.' }",
  "$child.Dispose()",
].join("; ");

2. Reset Stop Signal & Guard Timer in src/tray/windows-tray.ps1

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
try { [System.Windows.Forms.Application]::EnableVisualStyles() } catch { }

# Reset stop event on startup in Run mode
$stopEvent = New-Object System.Threading.EventWaitHandle($false, [System.Threading.EventResetMode]::AutoReset, "Local\OpenCodexTrayStop-$stableHash", [ref]$stopEventCreated)
if ($Mode -eq "Stop") {
  [void]$stopEvent.Set()
  $stopEvent.Dispose()
  exit 0
} else {
  [void]$stopEvent.Reset()
}

# Guard the timer tick
$timer.add_Tick({
  try {
    if ($stopEvent.WaitOne(0)) {
      [System.Windows.Forms.Application]::Exit()
      return
    }
    Update-TrayState
  } catch {
    Write-ActionLog "timer tick failed: $($_.Exception.Message)"
  }
})

Reproduction

  1. On a Windows machine, run: ocx tray install
  2. Observe immediate output: Windows tray: installed and running
  3. Wait 5-10 seconds and run: ocx tray status
  4. Notice status reports: Windows tray: installed, not currently running
  5. Observe taskbar tray icon: moving the cursor over or right-clicking the icon causes it to disappear instantly.

Version

2.34.0

Operating system

Windows 11 (x64)

Provider and model

N/A (OS-level CLI/tray packaging issue)

Logs or error output

PS C:\Users\Alpha> ocx tray install
Windows tray: installed and running

PS C:\Users\Alpha> ocx tray status
Windows tray: installed and running

PS C:\Users\Alpha> ocx tray status
Windows tray: installed, not currently running

Screenshots and supporting files

No response

Redacted configuration

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

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

    bugSomething isn't workingcliCLI, config inject, packaging flagsguiDashboard, tray, settings UIplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions