feat: resolve discovered server IPs to hostnames, dedup and shorten labels - #29
Merged
matt-gribben merged 7 commits intoAug 17, 2026
Merged
Conversation
- Implements reverse DNS resolution for discovered servers - IPs are resolved to hostnames (e.g., 192.168.1.42 → workstation.local) - Deduplicates servers by hostname+port to collapse multiple network interfaces - Same machine on multiple IPs now appears once with resolved hostname - Graceful fallback: unresolved IPs stay as-is - Caching to avoid redundant DNS lookups within a scan Fixes Hypabolic#19 (multiple IPs of same machine appearing as separate entries)
Root cause: resolveUrlHostname() and dedupByHostname() reconstructed the URL using new URL().pathname, which defaults to '/' even when the original URL had no path. This turned 'http://192.168.1.42:8080' into 'http://hostname:8080/', and downstream code that does `${baseUrl}/v1` produced a double slash (//v1), causing 404s from llama.cpp and other backends. Fix: replace only the hostname substring in the original URL string, preserving whatever path/trailing-slash state existed before. Also fixes TS strict-mode noUncheckedIndexedAccess errors introduced in the dedup helper.
- Add shortHostname() helper in dns.ts — strips everything after the first dot (macpro16.fritz.box → macpro16), skips IPs and localhost - Add shortLabel() helper in engine.ts — builds 'Kind (shortHost:port)' - All labels now use short hostnames, saving horizontal space in UI - baseUrl keeps the full hostname for correct DNS resolution Tests: - dns.test.ts: 18 tests (added shortHostname) - hostname-dedup.test.ts: 8 tests (added short label test)
- workstation.local, devbox.local instead of macpro16.fritz.box, dagobert.fritz.box - local-host.local instead of myMac.fritz.box - Tests fully isolated — no dependency on actual machine hostname or domain
…olved hostname - getLocalDomain() cascades: os.hostname() → env vars → /etc/resolv.conf - shortHostname() strips domain suffix for same-LAN hostnames - hostPortOf() now uses shortHostname() for compact /crossbar labels - dedupByHostname() collapses IPs resolving to the same hostname - 27 unit tests for the fallback chain, shortening, and crash resistance
Call clearCache at the start of discoverLocalhost/discoverLan, strip the full shared domain suffix (not only the first label), and drop the unimplemented co-location claims from the dedup docs. Also correct changelog dates to 2026. Co-authored-by: Cursor <cursoragent@cursor.com>
matt-gribben
force-pushed
the
feat/hostname-resolution-v2
branch
from
August 17, 2026 02:45
e59f0bb to
929b48a
Compare
matt-gribben
approved these changes
Aug 17, 2026
matt-gribben
left a comment
Contributor
There was a problem hiding this comment.
Approved after rebase onto main (#28 + #30) and a small maintainer polish pass:
clearCache()now runs at the start of each discover call (was imported but unused)shortHostnamestrips the full shared suffix- Docs match implementation (loopback vs LAN hostname stay separate keys)
- Changelog dates corrected to 2026
CI pending; will merge when green.
matt-gribben
added a commit
that referenced
this pull request
Aug 17, 2026
Bump for work landed since v0.7.0: - hostname resolution, LAN dedup, and shortened labels (#29, #21) - animated /crossbar scan progress with ESC abort (#30, #23) - fix removing no-auth servers without error (#28, #27) Publish by triggering the Release workflow with tag v0.8.0 (or pushing the tag); release.yml verifies the tag matches package.json. Co-authored-by: Cursor <cursoragent@cursor.com>
matt-gribben
added a commit
that referenced
this pull request
Aug 17, 2026
feat: resolve discovered server IPs to hostnames, dedup and shorten labels
matt-gribben
added a commit
that referenced
this pull request
Aug 17, 2026
Bump for work landed since v0.7.0: - hostname resolution, LAN dedup, and shortened labels (#29, #21) - animated /crossbar scan progress with ESC abort (#30, #23) - fix removing no-auth servers without error (#28, #27) Publish by triggering the Release workflow with tag v0.8.0 (or pushing the tag); release.yml verifies the tag matches package.json.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #21
Resolves discovered server IPs to hostnames and dedups servers that resolve to the same host (e.g. multiple NICs on one machine appearing as separate entries).
Changes
src/discovery/dns.ts—resolveHostname()/resolveUrlHostname()(reverse DNS with caching),shortHostname()(strips shared domain suffix for compact labels),getLocalDomain()(cascadesos.hostname()→ env vars →/etc/resolv.conf)src/discovery/engine.ts—discoverLocalhost()/discoverLan()resolve hostnames and dedup by hostname+port after the existing origin-based dedup;clearCache()at the start of each scansrc/ui/onboarding.ts—hostPortOf()usesshortHostname()so same-domain LAN servers show asdevbox:8080instead ofdevbox.fritz.box:8080Follow-up on rebase
Rebased onto
mainafter #28 and #30. Maintainer polish:clearCache()into each discover entry pointdocs/hostname-dedup.mdwith actual behavior (no unimplemented co-location preference)Testing
All 624 tests pass,
tsc --noEmitclean.