feat(cli): generate nexus.yaml in-process, eliminate nexus init shell-out#247
Merged
windoliver merged 3 commits intomainfrom Apr 12, 2026
Merged
feat(cli): generate nexus.yaml in-process, eliminate nexus init shell-out#247windoliver merged 3 commits intomainfrom
windoliver merged 3 commits intomainfrom
Conversation
…-out Resolves #196. Grove now generates nexus.yaml directly without shelling out to the nexus CLI, giving each worktree a stable isolated Nexus instance derived from its path. Key changes: - derivePort(cwd): FNV-1a hash → deterministic port [10000, 59999] - generateNexusYaml(): replaces `nexus init` for YAML generation - ensureNexusComposeFile(): provisions nexus-stack.yml + pgvector SQL before `nexus up` (fills the gap left by removing `nexus init`) - readNexusState(): unified state.json reader, removes 3 duplicates - buildNexusUpArgs(): extracted to prevent flag divergence on fallback - discoverRunningNexus(): drops brittle :edge ancestor filter, detects by port 2026 binding — works across :latest/:stable/:edge image tags - Remove DEFAULT_NEXUS_URL from candidateUrls — fixes OrbStack cross-worktree session leakage (port 2026 was forwarded by OrbStack) - persistNexusUrlToConfig(): extracted from startServices(), callers call it explicitly — makes the side effect visible and testable - waitForServiceHealth(): replaces 5s blind sleep with backoff polling - Fix silent error swallowing in headless mode (report vs onProgress) - 36 unit tests for derivePort, inferNexusPreset, readNexusState, generateNexusYaml, readNexusUrl, readNexusApiKey E2E validated: two parallel worktrees (ports 45592, 19411) boot independently, auth keys are rejected cross-instance, contributions cannot cross over.
main re-added DEFAULT_NEXUS_URL to candidateUrls; keeping it out to prevent OrbStack cross-worktree session leakage (another project's Nexus container forwarded to localhost:2026). Adopt main's ordering (GROVE_NEXUS_URL first as highest-priority override).
Format nexus-lifecycle.ts and init.ts per biome rules. Remove unused GenerateNexusYamlOptions import and prefix unused result variable with _ in nexus-lifecycle.test.ts.
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.
Closes #196.
Summary
generateNexusYaml()— generatesnexus.yamldirectly in TypeScript using FNV-1a port derivation; nonexus initshell-out needed for initializationderivePort(cwd)— stable per-worktree port[10000, 59999]from path hash; each worktree gets an isolated Nexus instance that survives restartsensureNexusComposeFile()— provisionsnexus-stack.yml+001-enable-pgvector.sqlbeforenexus upruns (fills the gap left by removingnexus init)DEFAULT_NEXUS_URL(localhost:2026) from candidate URL list; OrbStack was forwarding another project's Nexus container to that port, causing grove to adopt a foreign Nexus instancediscoverRunningNexus— dropped brittle--filter ancestor=:edgethat missed:latest/:stableimages; now detects by port 2026 binding with worktree ownership checkpersistNexusUrlToConfig()— extracted fromstartServices()as explicit call-site responsibility; makes the grove.json side effect visible and testablewaitForServiceHealth()— replaces 5s blind sleep with exponential-backoff health pollingreport()instead ofoptions.onProgress?.()so errors are visible without a TUITests
36 new unit tests in
src/cli/nexus-lifecycle.test.tscovering:derivePort: stability, range, snapshots, collision resistance, edge casesinferNexusPreset: all mode/preset combinationsreadNexusState: missing/malformed/valid JSONgenerateNexusYaml: schema correctness, port derivation, idempotency, api_key generationreadNexusUrl: YAML parsing, missing ports, malformed inputreadNexusApiKey: priority order (env > state.json > nexus.yaml)E2E
Two parallel worktrees validated simultaneously:
discoverRunningNexusreturns each worktree's own port only"Invalid or missing API key")