Multi-instance Tentacle with cross-platform service host
Adds Octopus-style multi-instance support and a generic service host abstraction so the binary + systemd/launchd/WinService flow actually works end-to-end across all platforms.
Core architecture:
- PlatformPaths: unified per-OS config dir resolution (Linux /etc, macOS /Library/Application Support, Windows %ProgramData%) with user-scope fallback when running unprivileged.
- InstanceRegistry: cross-platform JSON-backed instance registry at instances.json, replacing the Windows Registry / Linux JSON split that Octopus inherited. Supports case-insensitive lookup, schema versioning, auto-created Default instance.
- TentacleConfigFile: persistent per-instance JSON config that IConfigurationBuilder consumes natively. Merge-based updates skip empty values so partial overrides don't wipe existing keys. Unix permissions locked to 600.
- IServiceHost: OS-agnostic service-manager abstraction with SystemdServiceHost (complete) plus WindowsServiceHost / LaunchdServiceHost placeholders. ServiceHostFactory uses a registry pattern so adding a new platform is a one-line change.
Fixes the critical register -> systemd gap:
- register now persists effective settings to the instance config file after a successful registration. systemd's "run --instance NAME" can then start the agent with no other arguments.
- service install generates units with the correct ExecStart (Environment.ProcessPath, not the broken "dotnet *.dll" fallback) and passes --instance NAME when not Default.
- service install returns non-zero when systemctl fails, no longer falsely reports success on Docker/WSL1 without systemd.
New commands:
- create-instance --instance NAME [--config PATH]
- list-instances
- delete-instance --instance NAME
- --instance NAME flag now honoured by register / run / show-* / new-certificate / service install.
Server-side:
- Squid.Api.Program ConfigureKestrel uses SelfCert.Base64 so port 7078 (API) and 10943 (Halibut) present the same thumbprint. Fixes the TLS pinning mismatch where UI-displayed ServerThumbprint (SelfCert) disagreed with what Kestrel actually served (dev-cert).
install-tentacle.sh:
- Auto-installs libicu + ca-certificates across apt/dnf/yum/apk. .NET 9 globalization can't start without libicu; prior behaviour aborted with SIGABRT.
- Supports both v-prefixed and plain version tags.
- Creates /etc/squid-tentacle with mode 700.
- Makes Squid.Calamari executable (Tentacle spawns it at runtime).
- Verification uses the "help" subcommand instead of --help (which was routed to RunCommand).
Modernisation:
- RuntimeInformation.IsOSPlatform(...) replaced with OperatingSystem.IsLinux()/IsWindows()/IsMacOS() throughout.
- CommandResolver extracted for unit-testable command routing.
Tests: +38 new tests covering config file round-trips, instance registry persistence, platform path conventions, systemd unit generation, and factory dispatch. All 3992 unit tests and integration tests pass; 782/782 Tentacle tests (excluding pre-existing metrics flakiness) pass.