feat(m4): single instance IPC
- LaunchCommand: ShowMain / OpenWorkspace(path), doubles as IPC message
- LaunchArguments: first non-blank arg wins, blank-only args -> ShowMain
- IpcProtocol: strict newline-line codec (show / open+path), tolerant
of trailing-newline framing only
- SingleInstanceService: per-session named mutex decides primary;
primary serves a named-pipe loop (decode -> dispatch -> ack) with
handler failures contained; secondary retries send, exits on ack
- Program/App wiring: secondary forwards command and exits; primary
activates the main window for forwarded commands (workspace switch
deferred to the workspace UI milestone)
- 15 new tests (protocol codec, argument parsing); smoke-verified:
instance 1 stays alive, instance 2 self-exits with code 0