The engine builds images as part of `Up` — there's no standalone "build the image, run the feature pipeline, but don't create a container" entry point. Upstream `@devcontainers/cli` ships a `build` subcommand for CI / pre-bake scenarios; we can't ship our equivalent in `cmd/devcontainer` without this.
Proposed API (rough):
```go
type BuildOptions struct {
LocalWorkspaceFolder string
ConfigPath string
LocalEnv map[string]string
NoCache bool
PullPolicy PullPolicy
ImageName []string // tags to apply to the final image
Platform string
Push bool
CacheFrom []string
CacheTo []string
Events chan<- events.Event
}
type BuildResult struct {
ImageID string
Tags []string
}
func (e *Engine) Build(ctx context.Context, opts BuildOptions) (*BuildResult, error)
```
Implementation should share the resolve → feature-pipeline → image-build path that `Up` already runs, just stopping before container creation. Compose sources are out of scope (matches upstream `build`).
Once this lands, the CLI `build` command is a thin wrapper.
The engine builds images as part of `Up` — there's no standalone "build the image, run the feature pipeline, but don't create a container" entry point. Upstream `@devcontainers/cli` ships a `build` subcommand for CI / pre-bake scenarios; we can't ship our equivalent in `cmd/devcontainer` without this.
Proposed API (rough):
```go
type BuildOptions struct {
LocalWorkspaceFolder string
ConfigPath string
LocalEnv map[string]string
}
type BuildResult struct {
ImageID string
Tags []string
}
func (e *Engine) Build(ctx context.Context, opts BuildOptions) (*BuildResult, error)
```
Implementation should share the resolve → feature-pipeline → image-build path that `Up` already runs, just stopping before container creation. Compose sources are out of scope (matches upstream `build`).
Once this lands, the CLI `build` command is a thin wrapper.