Deep Dive — Docker Build & Compose
This document explains the complete Docker path: detection, unified compose generation, build, start/health, logs, and teardown.
Detection
- Repos marked as Docker mode (globally or per-repo) are scanned for a
Dockerfile
. - If found, a Docker service entry is prepared with ports from
ports-map.json
(preferred) or fromEXPOSE
lines.
63:86:src/modes/execution/services/DockerComposeManager.ts
if (fs.existsSync(dockerfilePath)) {
this.logger.info(`🐳 Found Dockerfile in ${repo}`);
const serviceName = this.slug(repo);
if (this.portsMap[serviceName]) { ports = [`${host}:${internal}`]; }
else { ports = await this.extractPortsFromDockerfile(dockerfilePath); }
}
For .NET projects, if a compose file exists in the repo, startup/install default to docker-compose commands:
490:521:src/modes/execution/services/FrameworkDetector.ts
const hasDockerCompose = fs.existsSync(docker-compose.yml|yaml|compose.yml|yaml)
if (hasDockerCompose) return "docker-compose up";
Unified compose generation
- Required infra services (Redis/RabbitMQ/Postgres/TimescaleDB) are added based on env resolution.
- App services (detected Dockerfiles) are added with
build.context
,ports
,depends_on
,networks
,volumes
. - Result is serialized to
docker-compose.unified.yml
in the current working directory.
176:205:src/modes/execution/services/DockerComposeManager.ts
if (requiredInfraServices && requiredInfraServices.size > 0) {
// add infra services with healthchecks, volumes, ports
}
311:329:src/modes/execution/services/DockerComposeManager.ts
unifiedCompose.services[service.name] = { build, ports, depends_on, ... };
const composeContent = yaml.dump(unifiedCompose, { indent: 2, lineWidth: 120 });
375:385:src/modes/execution/services/DockerComposeManager.ts
fs.writeFileSync(path.join(process.cwd(), "docker-compose.unified.yml"), composeContent, "utf-8");
Build
- Services are built with:
docker-compose -f docker-compose.unified.yml build --progress=plain
- The logger tracks steps, percent progress, pulls, and errors; suggests remedies on failures.
537:545:src/modes/execution/services/DockerComposeManager.ts
const dockerCompose = spawn("docker-compose", ["-f", composePath, "build", "--progress=plain"]);
Start & health
- Services are started with:
docker-compose -f docker-compose.unified.yml up -d
- Health is waited for per service (healthy status or running if no healthcheck) with timeout and heartbeats.
764:771:src/modes/execution/services/DockerComposeManager.ts
const dockerCompose = spawn("docker-compose", ["-f", composePath, "up", "-d"]);
919:986:src/modes/execution/services/DockerComposeManager.ts
await this.waitForServicesHealthy(composePath, services, { timeoutMs: 5*60*1000, intervalMs: 2000 });
Stop
- Unified services are stopped with:
docker compose -f docker-compose.unified.yml down
999:1037:src/modes/execution/services/DockerComposeManager.ts
spawn("docker", ["compose", "-f", composePath, "down"], { stdio: "inherit" });
Logs integration
- Each service logs are streamed via
docker-compose logs -f <service>
and piped into the log viewer.
1067:1079:src/modes/execution/services/DockerComposeManager.ts
spawn("docker-compose", ["-f", ..., "logs", "-f", serviceName])
Files produced
docker-compose.unified.yml
(always when Docker/hybrid)- Infra-only compose may also be generated by infra manager:
docker-compose.infra.yml
158:166:src/modes/execution/services/InfraServiceManager.ts
fs.writeFileSync(composePath, composeContent);
Notes & recommendations
- Ports prefer stable host mappings from
ports-map.json
; falls back toEXPOSE
if none. - Infra dependencies are wired with
depends_on: { condition: service_healthy }
. - Health waiting tolerates services without
healthcheck
by treatingrunning
as OK.