Skip to content

[TEST] fix/boot-options — dynamic port handling on boot + docker controls on shutdown#61

Merged
nitesh32 merged 8 commits into
pre-releasefrom
fix/boot-options
May 24, 2026
Merged

[TEST] fix/boot-options — dynamic port handling on boot + docker controls on shutdown#61
nitesh32 merged 8 commits into
pre-releasefrom
fix/boot-options

Conversation

@Dead-Bytes
Copy link
Copy Markdown
Collaborator

What changed

  • bytebell boot now recovers from Docker port conflicts interactively instead of failing outright:
    • Detects bind: address already in use on mongo/neo4j/redis and identifies the offending port.
    • Diagnoses the conflict (is it another bytebell container? a different docker container? a non-docker process?) via new dockerPortDiagnostics.ts.
    • Prompts the user with an Ink picker (PortConflictSelector.tsx) to reuse the existing service, kill the conflicting container, change bytebell's port, or cancel — with up to 4 retry rounds.
    • Persists per-service port overrides under ~/.bytebell/ via new infraPorts.ts, and threads them into compose as MONGO_HOST_PORT / NEO4J_HTTP_HOST_PORT / NEO4J_BOLT_HOST_PORT / REDIS_HOST_PORT env vars (compose file defaults preserved).
    • When the user picks "reuse", boot skips that service in docker compose up and continues.
  • bytebell shutdown now manages Docker infra instead of always leaving it running:
    • New --with-docker and --keep-docker flags (mutually exclusive) for non-interactive use.
    • When neither flag is passed and stdin is a TTY, prompts via StopInfraPrompt.tsx whether to also tear down Docker.
    • Non-TTY default is unchanged (keep Docker running) for script compatibility.
  • Refactored BootCommand.ts into smaller functions (bringInfraUp, handlePortConflict, startServer) so the conflict-recovery loop is readable.
  • Added DockerPortConflictError + down() to dockerInfra.ts; up() now accepts ports and servicesToStart.
  • Added SPDX headers to the modified CLI command files.
  • Updated packages/cli/README.md to document the new behaviour.

Why

Two recurring boot-time pain points on developer machines:

  1. Port conflicts — users running their own Mongo/Redis/Neo4j (or a stale bytebell stack from a previous install) hit Bind for 127.0.0.1:6379 failed: port is already allocated and had no remediation path other than reading the docker error and manually editing compose. Boot now diagnoses and offers concrete actions.
  2. Stuck Docker infrabytebell shutdown only stopped the server, leaving mongo/neo4j/redis running. Users had to remember docker compose -f … to fully tear down. Now shutdown can do both, with explicit flags for CI/scripts.

Per project rules: all state stays under ~/.bytebell/ (no .env), all outbound calls unchanged, single-tenant orgId=local invariants untouched.

How to test

Port conflict recovery on boot

  1. Occupy one of the infra ports manually:
       docker run -d --rm -p 127.0.0.1:6379:6379 --name rogue-redis redis:7

Run bytebell boot.

Expect: spinner fails, then the PortConflictSelector appears showing that port 6379 is held by container rogue-redis. Options: Reuse, Kill container, Change port, Cancel.

Pick Kill container → boot retries, container is removed, bytebell's redis comes up on 6379.

Re-run with rogue-redis back up and pick Change port → enter e.g. 6390 → boot continues, and ~/.bytebell/infra-ports.json (or wherever infraPorts.ts persists) now records the override. Subsequent boots reuse 6390.

Re-run and pick Reuse → boot succeeds and logs reusing existing service on port 6379 for redis (not managed by bytebell).

Cleanup: docker rm -f rogue-redis.

Non-docker port holder
python3 -m http.server 27017 (or any process binding the mongo port).
bytebell boot → conflict prompt should detect there is no container holding the port and Kill option should be disabled / explain you must stop the process yourself.

Shutdown flags
bytebell boot (let infra start).
bytebell shutdown --with-docker → server stops, then docker compose down runs; docker ps shows no bytebell containers.
bytebell boot again.
bytebell shutdown --keep-docker → server stops, infra still running (docker ps shows mongo/neo4j/redis).
bytebell shutdown interactively (TTY) → prompts "Stop Docker infra too?"; both Yes and No paths exit cleanly.
bytebell shutdown --with-docker --keep-docker → exits 1 with the mutually-exclusive error.
Regression sanity
Boot with no conflicts behaves exactly as before (no extra prompts, same success output).
bytebell shutdown over a pipe / in a script (non-TTY) leaves Docker running by default — no breaking change for existing automation.

nitesh32 and others added 6 commits May 18, 2026 17:29
Replace the generic markdown bug template with YAML Issue Forms tailored
to Bytebell, plus a feature request form and a chooser config.yml.

- bug_report.yml: structured form with required fields (summary, repro,
  expected, version) and optional fields for component, LLM provider,
  OS, Bun version, logs, and context. Dropdown for affected component
  includes "Not sure" so contributors aren't gated on architectural
  knowledge.
- feature_request.yml: slimmed to problem / proposal / alternatives /
  context so OSS contributors can file ideas without first reading
  CLAUDE.md or understanding the tier model.
- config.yml: disables blank issues, routes security reports to
  SECURITY.md (team@bytebell.ai) instead of GHSA, links Discussions for
  questions, and surfaces contributing.md for newcomers.
Copilot AI review requested due to automatic review settings May 21, 2026 11:54
@Dead-Bytes Dead-Bytes added bug Something isn't working enhancement New feature or request Ready for Review Ready for review from reviewers labels May 21, 2026
@Dead-Bytes Dead-Bytes requested a review from nitesh32 May 21, 2026 11:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the CLI’s local dev ergonomics by making bytebell boot resilient to Docker port conflicts (interactive diagnosis + resolution with retries) and extending bytebell shutdown to optionally tear down Docker infra (prompted in TTYs, deterministic flags for scripts).

Changes:

  • Added interactive Docker port-conflict diagnosis + resolution flow during bytebell boot (reuse/kill/change/cancel) and threaded configurable host ports into compose via .env.
  • Added bytebell shutdown infra management via --with-docker / --keep-docker and a TTY Ink prompt.
  • Refactored Docker infra management utilities to support per-service startup and improved error typing (port-conflict error).

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/cli/src/BootCommand.ts Adds retry loop + interactive port-conflict handling and service skipping for boot.
packages/cli/src/dockerInfra.ts Adds down(), supports passing port values + selective service startup, introduces DockerPortConflictError.
packages/cli/src/dockerPortDiagnostics.ts Adds compose-stderr port parsing + diagnostics for container/process occupying a port.
packages/cli/src/infraPorts.ts Derives/writes infra host ports from configured URIs and generates compose .env body.
packages/cli/src/portConflictPrompt.ts Wires diagnostics into the interactive port-conflict selector prompt.
packages/cli/src/PortConflictSelector.tsx Ink UI for resolving port conflicts (reuse/kill/change/cancel + port input).
packages/cli/src/ShutdownCommand.ts Adds flags + prompting to optionally stop Docker infra during shutdown.
packages/cli/src/shutdownPrompts.ts Ink render helper for the shutdown “stop Docker?” prompt.
packages/cli/src/StopInfraPrompt.tsx Ink UI for shutdown infra stop confirmation.
packages/cli/README.md Documents new boot conflict-recovery behavior and shutdown Docker controls.
infra/docker/docker-compose.yml Switches hardcoded host ports to env-substituted ${…:-default} ports.
Comments suppressed due to low confidence (1)

packages/cli/src/ShutdownCommand.ts:41

  • When the PID file is missing/stale (pid === null), shutdown returns early and never evaluates --with-docker / --keep-docker (or the interactive prompt). This means bytebell shutdown --with-docker won’t stop Docker infra if the server is already down, which seems to contradict the new flag semantics. Consider still running decideStopDocker()/stopDocker() in this branch (or at least honoring --with-docker).
  const pidFile = path.join(getBytebellHome(), "pid");
  const pid = await readPid(pidFile);
  if (pid === null) {
    success("server is not running.");
    process.stdout.write(dockerHint());
    return;
  }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

stderr += chunk.toString("utf8");
});
child.on("error", (cause: Error) => reject(cause));
child.on("exit", () => resolve({ stdout, stderr }));
if (skip.size === 0) {
return ["mongo", "neo4j", "redis"];
}
return (["mongo", "neo4j", "redis"] as const).filter((s) => !skip.has(s));
Comment on lines +54 to +57
case "neo4j-bolt":
case "neo4j-http":
setConfigValue(Config.Neo4jUri, replacePort(readString(Config.Neo4jUri), boltPortForService(service, newPort)));
return;
Comment on lines +150 to +155
if (props.canKill) {
return {
action: "kill",
label: `Stop the conflicting container and reuse port ${props.port}`,
hint: `docker rm -f ${props.occupantLabel}`,
};
Comment on lines 219 to +223
resolve({ stdout, stderr });
return;
}
const port = parsePortFromComposeError(stderr);
if (port !== null) {
@nitesh32 nitesh32 changed the base branch from main to pre-release May 24, 2026 15:56
@nitesh32 nitesh32 merged commit ce7f46f into pre-release May 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request Ready for Review Ready for review from reviewers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants