* fix: make published port links open reliably
Container published-port links now render as real anchors that open on
desktop and mobile, replacing ad hoc window.open calls. A shared service
URL builder centralizes host resolution (configured host, remote node
API host, or the browser host, with no browser fallback for unreachable
remote nodes), protocol selection (HTTPS for port 443), and known app
sub-paths (Plex opens its web path). The container port mapping itself is
the link, with a Copy URL action beside it. The stack Open App menu and
the anatomy panel footer use the same builder, and the menu only offers
Open App when a reachable URL can be built.
* fix: skip UDP ports and scope known-app paths to the container port
Two follow-ups to the published-port links:
- The known-app path (Plex web sub-path) was borrowed from the published
host port even when the container port was known and unregistered, so a
non-Plex service published on host port 32400 wrongly inherited it. The
container-port lookup now wins when known; the published-port lookup stays
a fallback for the menu and anatomy footer, which only have the host port.
- UDP ports could surface as HTTP links. The backend now carries the port
protocol through both container-mapping paths and skips UDP when choosing
the main web port (extracted as selectMainWebPort), and the container card
filters UDP before selecting a port to link.
* feat(stacks): copy stack anatomy as Markdown
Add a "copy md" action to the Stack Anatomy panel that exports the parsed
compose summary as a deterministic Markdown document: services, ports and
volumes tables, restart policy, env file with its variable count, missing
variables, network, and source. Useful for pasting a stack's wiring into a
README, a Git repository, Obsidian, BookStack, or a support thread.
The export carries only env variable names and counts, never the values
stored in .env files.
* fix(stacks): escape backslashes in anatomy Markdown table cells
escapeCell escaped pipes but not the backslash itself, so a backslash in a
cell value (for example a Windows path) could defeat the pipe escaping and
break the rendered table row. Escape the backslash first, then pipes, then
collapse newlines. Adds a regression test.
* fix(stacks): correct git source attribution and CR handling in anatomy export
Gate the Anatomy panel's git source on its owning stack so a slow git-source
response for a previously selected stack can no longer render or be exported
under a different stack. Also collapse lone carriage returns (not just CRLF and
LF) in Markdown table cells so a stray CR cannot break a table row.