feat(agent-runtime): candidate-list connection with build-machine IP injection - #148
Open
kitakkun wants to merge 1 commit into
Open
feat(agent-runtime): candidate-list connection with build-machine IP injection#148kitakkun wants to merge 1 commit into
kitakkun wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a “zero-config” connection mechanism for JetWhale agents by (1) trying an ordered list of host candidates at runtime and (2) introducing a Gradle plugin that generates code to inject the build machine’s LAN addresses/hostname into the app at build time.
Changes:
- Agent runtime now resolves an ordered, deduplicated host-candidate list (explicit host → build-injected addresses/hostname → localhost) and walks it on every (re)connect with a short per-candidate timeout.
- New Gradle plugin
com.kitakkun.jetwhale.agentgeneratesapplyJetWhaleBuildEnvironment()and wires generated sources into the consuming module’s Kotlin source set(s). - Demo + getting-started guide updated to use the generated no-op-safe initializer call and remove hardcoded host configuration.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| jetwhale-gradle-plugin/src/main/kotlin/com/kitakkun/jetwhale/gradle/JetWhaleAgentPlugin.kt | New plugin: registers extension, generates build-environment source, wires into Kotlin source sets. |
| jetwhale-gradle-plugin/src/main/kotlin/com/kitakkun/jetwhale/gradle/GenerateBuildEnvironmentTask.kt | Task that renders the generated applyJetWhaleBuildEnvironment() Kotlin source. |
| jetwhale-gradle-plugin/build.gradle.kts | Adds Kotlin Gradle plugin compileOnly dependency and registers com.kitakkun.jetwhale.agent. |
| jetwhale-agent-runtime/src/commonMain/kotlin/com/kitakkun/jetwhale/agent/runtime/JetWhaleServiceDsl.kt | Switches startup to pass resolved host candidates; tracks whether host was explicitly set. |
| jetwhale-agent-runtime/src/commonMain/kotlin/com/kitakkun/jetwhale/agent/runtime/JetWhaleMessagingService.kt | Updates messaging-service API to accept ordered host candidates. |
| jetwhale-agent-runtime/src/commonMain/kotlin/com/kitakkun/jetwhale/agent/runtime/DefaultJetWhaleMessagingService.kt | Implements candidate walking with per-candidate timeout and logging. |
| jetwhale-agent-runtime/src/commonMain/kotlin/com/kitakkun/jetwhale/agent/runtime/JetWhaleBuildEnvironment.kt | New public registry for build-injected host candidates. |
| jetwhale-agent-runtime/src/commonMain/kotlin/com/kitakkun/jetwhale/agent/runtime/HostCandidateResolver.kt | New resolver to order/dedup candidates (explicit vs injected vs localhost). |
| jetwhale-agent-runtime/src/jvmTest/kotlin/com/kitakkun/jetwhale/agent/runtime/HostCandidateResolverTest.kt | Tests ordering, deduplication, and idempotent registration. |
| jetwhale-agent-runtime/api/jvm/jetwhale-agent-runtime.api | ABI update for new public JetWhaleBuildEnvironment. |
| jetwhale-agent-runtime/api/jetwhale-agent-runtime.klib.api | KLIB ABI update for new public JetWhaleBuildEnvironment. |
| docs/guide/getting-started.md | Documents zero-config candidate resolution + CI disable switch. |
| demo/shared/src/commonMain/kotlin/com/kitakkun/jetwhale/demo/shared/InitializeJetWhale.kt | Calls applyJetWhaleBuildEnvironment() and removes hardcoded host in demo. |
| demo/shared/build.gradle.kts | Applies com.kitakkun.jetwhale.agent plugin for demo module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| injectEnabled.set(extension.injectBuildHostCandidates) | ||
| // Captured at configuration time on the build machine; staleness is acceptable (see class | ||
| // KDoc) and the values are task inputs so a machine/address change re-runs generation. | ||
| hostName.set(resolveHostName()) |
Comment on lines
+56
to
+57
| // Captured at configuration time on the build machine; staleness is acceptable (see class | ||
| // KDoc) and the values are task inputs so a machine/address change re-runs generation. |
Comment on lines
36
to
37
| artifactId = "jetwhale-gradle-plugin" | ||
| name = "JetWhale Gradle Plugin" |
…injection
Connection targets become an ordered candidate list tried per attempt with
a short per-candidate timeout (2s), walked the same way on reconnect:
explicit `host` (when set, wins) -> build-injected LAN addresses ->
localhost fallback. The winning candidate is logged at INFO.
A new `com.kitakkun.jetwhale.agent` Gradle plugin captures the build
machine's non-loopback IPv4 addresses and hostname at build time and
generates `applyJetWhaleBuildEnvironment()` into the applied module's
Kotlin source set, which registers them via the new public
`JetWhaleBuildEnvironment` registry. Call it once before `startJetWhale {}`
and a physical device reaches the build machine with no host/IP written;
emulators/simulators fall through to localhost. Injection is toggled with
`jetwhale { injectBuildHostCandidates = false }` (e.g. for CI); when off the
generated function is a no-op.
The demo drops its hardcoded host to prove the zero-config path.
mDNS discovery (separate PR) plugs in as the optional last-resort candidate
source.
kitakkun
force-pushed
the
feat/build-host-candidates
branch
from
July 19, 2026 05:28
80c890d to
e140fb6
Compare
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.
Motivation
The primary zero-config goal: a physical device on the LAN should reach the debugger host with no
host/IP written anywhere. Hardcoding the build machine's LAN IP in
connection { host = "192.168.x.x" }is machine-specific and brittle. This PR makes the agent try anordered list of candidate addresses and adds a Gradle plugin that injects the build machine's own
addresses at build time.
Candidate-list connection core (
jetwhale-agent-runtime)Connection targets are now an ordered candidate list, tried per connection attempt with a short
per-candidate timeout (2s) and walked the same way on every reconnect. The first that answers wins
and is logged at INFO. Order:
hostset inconnection { }— when set, it wins and is tried first.localhost— fallback for emulators, simulators, and ADB-forwarded devices.So one build runs on a physical device (reaches the build machine) and on an emulator (falls through
to localhost) with no code change.
Build-machine IP injection (
com.kitakkun.jetwhale.agentGradle plugin)A new plugin apps apply:
plugins { id("com.kitakkun.jetwhale.agent") }At build time it collects the machine's non-loopback IPv4 addresses + hostname and generates a source
file into the module's
commonMain(ormain) Kotlin source set:Linkage
Cross-module auto-run is not portable across all KMP targets (no top-level init on native/JS), so the
generated function is wired through the existing initialize path: call
applyJetWhaleBuildEnvironment()once before
startJetWhale {}(the demo does this). When injection is disabled or the plugin wasnever applied, the function is generated as a no-op, so the call site always compiles.
Configuration
jetwhale { injectBuildHostCandidates = false } // e.g. for CI/release buildsDefault is on. Explicit DSL
hostconfig always overrides injected candidates.Staleness
Addresses are captured at build time — correct as long as the build machine keeps the same addresses
(the norm when one machine builds and debugs). When stale, the agent simply falls through to the next
candidate. Documented in KDoc and
docs/guide/getting-started.md.Demo
InitializeJetWhale.ktdrops its hardcoded host entirely, proving the zero-config path on a physicaldevice and an emulator alike.
Tests
HostCandidateResolverTestcovers ordering (injected-first vs explicit-wins), dedup, localhost-only,and idempotent registration. The Gradle plugin's generation + source-set wiring is exercised
end-to-end by the demo build (
:demo:shared:compileKotlinJvmcompiles the generated source).Verification
:jetwhale-gradle-plugin:build,:jetwhale-agent-runtime:jvmTest,compileKotlinIosArm64,compileKotlinJs,compileKotlinLinuxX64,compileKotlinMingwX64,compileAndroidMain,:demo:shared:compileKotlinJvm,checkLegacyAbi,spotlessApplyall pass. ABI dumps updated(new public
JetWhaleBuildEnvironment).Relationship to mDNS PR
Companion PR #146 adds mDNS/Bonjour discovery. It plugs in here as the optional last-resort candidate
source; this PR is the headline zero-config mechanism.