I assume for it to be useful to show the local categories first, your users are browsing for a sufficing category, rather than the optimal category. Otherwise, given “the list of remote products can change at any time,” users will never know when to stop browsing. The task is basically impossible.
Search Instead? If users are looking for a specific category rather than browsing for a sufficing one, then maybe you need to provide a Search feature, rather than a tree, which first searches locally and, if nothing close is found, then searches remotely.
Manual Refresh. I’m skeptical that the refresh idea would work because it seems users won’t know how often they need to click refresh. It seems like a lot of extra learning and effort. Manual refresh only prevents the user from being interrupted while they looking at a category or when they’re about to select a category (by it scrolling away spontaneously). Maybe you can mostly prevent that problem by keeping the currently selected category fixed in the pane and adding new categories above and below it as they arrive. Manual refresh doesn’t help the “what changed?” problem or the “where did that other old item go?” problem.
Two Trees. Two trees sounds fine if Local and Remote is meaningful to the users, especially if users have a sense when their target is likely to be Local or Remote (so they can ignore the Local tree and wait for the Remote tree). Perhaps you can make the distinction meaningful to your users by doing something like labeling the Local tree “Quick Search” and the Remote tree “Exhaustive Search.” However, given remote products can change at any time, this doesn’t solve the problem of jumpiness within the remote list.
Append to Tree. If there is no particularly meaningful sort order to the categories (i.e., users are going to have to scan from the top down, like done with Search results), then show the local categories at the top and append the remote categories as they arrive to the bottom of the list. This keeps the list stable preventing old categories from getting lost among new categories, and users will learn that whatever changed will be at the bottom of the tree. If they can’t find anything sufficing at first, they scroll down and wait for more to appear.
Animation on Insert. If it’s necessary to maintain the sort order, one solution may be to address the jumpiness rather than the update part of the problem. Have a single tree and, when a new category arrives slide (over a period of about 500ms) the old categories apart to make room for it. Again, keep the currently selected category still and slide the others around it so what users are looking at is least likely to move. Assuming users have already scrolled to the point in the sort order where the sufficing category will likely be, they see any new category worth considering, and, thanks to the smooth animation, not lose any old category they’re still considering. This could mean making your own tree or list box control.
Placeholders. Perhaps there is some way to make a reasonable guess of the remote categories before they arrive, maybe based on previous sessions. If the app is used frequently or if multiple users use the same local storage, I’d think this would be quite accurate. Load the tree with the local categories and inert placeholders for the remote categories (perhaps labeled “searching…”). If a remote category is determined to be empty, change the placeholder to indicate zero items, but don’t remove it. This limits the jumpiness to only new categories that were not in the original guess. A statistical analysis of the category changes will tell you if this happens at an acceptably low frequency.