dockerimg: use --progress=quiet to always show docker build failure

In non-verbose mode, --progress=quiet is very quiet when everything
works, but prints an actual error when something fails (e.g. the
dockerfile is bad or you ran out of space).

While here, remove the partial stdout/stderr plumbing that did not
quite work (because the code sometimes used os.Stdout/os.Stderr
directly).

For #37
For #41
diff --git a/cmd/sketch/main.go b/cmd/sketch/main.go
index f6d382c..43cb5d2 100644
--- a/cmd/sketch/main.go
+++ b/cmd/sketch/main.go
@@ -1,11 +1,9 @@
 package main
 
 import (
-	"bytes"
 	"context"
 	"flag"
 	"fmt"
-	"io"
 	"log/slog"
 	"math/rand/v2"
 	"net"
@@ -228,16 +226,6 @@
 		return fmt.Errorf("sketch: cannot determine current working directory: %v", err)
 	}
 
-	// Configure stdout/stderr for container launch
-	var stdout, stderr io.Writer
-	var outbuf, errbuf *bytes.Buffer
-	if flags.verbose {
-		stdout, stderr = os.Stdout, os.Stderr
-	} else {
-		outbuf, errbuf = &bytes.Buffer{}, &bytes.Buffer{}
-		stdout, stderr = outbuf, errbuf
-	}
-
 	// Configure and launch the container
 	config := dockerimg.ContainerConfig{
 		SessionID:         flags.sessionID,
@@ -261,11 +249,12 @@
 		OneShot:           flags.oneShot,
 		Prompt:            flags.prompt,
 		InitialCommit:     flags.initialCommit,
+		Verbose:           flags.verbose,
 	}
 
-	if err := dockerimg.LaunchContainer(ctx, stdout, stderr, config); err != nil {
+	if err := dockerimg.LaunchContainer(ctx, config); err != nil {
 		if flags.verbose {
-			fmt.Fprintf(os.Stderr, "dockerimg.LaunchContainer failed: %v\ndockerimg.LaunchContainer stderr:\n%s\ndockerimg.LaunchContainer stdout:\n%s\n", err, errbuf.String(), outbuf.String())
+			fmt.Fprintf(os.Stderr, "dockerimg launch container failed: %v\n", err)
 		}
 		return err
 	}
diff --git a/dockerimg/dockerimg.go b/dockerimg/dockerimg.go
index 1fabafc..66f1654 100644
--- a/dockerimg/dockerimg.go
+++ b/dockerimg/dockerimg.go
@@ -87,11 +87,14 @@
 
 	// Initial commit to use as starting point
 	InitialCommit string
+
+	// Verbose enables verbose output
+	Verbose bool
 }
 
 // LaunchContainer creates a docker container for a project, installs sketch and opens a connection to it.
 // It writes status to stdout.
-func LaunchContainer(ctx context.Context, stdout, stderr io.Writer, config ContainerConfig) error {
+func LaunchContainer(ctx context.Context, config ContainerConfig) error {
 	if _, err := exec.LookPath("docker"); err != nil {
 		if runtime.GOOS == "darwin" {
 			return fmt.Errorf("cannot find `docker` binary; run: brew install docker colima && colima start")
@@ -117,14 +120,14 @@
 		return err
 	}
 
-	imgName, err := findOrBuildDockerImage(ctx, stdout, stderr, config.Path, gitRoot, config.AntURL, config.AntAPIKey, config.ForceRebuild)
+	imgName, err := findOrBuildDockerImage(ctx, config.Path, gitRoot, config.AntURL, config.AntAPIKey, config.ForceRebuild, config.Verbose)
 	if err != nil {
 		return err
 	}
 
 	linuxSketchBin := config.SketchBinaryLinux
 	if linuxSketchBin == "" {
-		linuxSketchBin, err = buildLinuxSketchBin(ctx, config.Path)
+		linuxSketchBin, err = buildLinuxSketchBin(ctx)
 		if err != nil {
 			return err
 		}
@@ -265,7 +268,7 @@
 	}
 	sshHost, sshPort, err := net.SplitHostPort(localSSHAddr)
 	if err != nil {
-		return appendInternalErr(fmt.Errorf("Error splitting ssh host and port: %w", err))
+		return appendInternalErr(fmt.Errorf("failed to split ssh host and port: %w", err))
 	}
 
 	var sshServerIdentity, sshUserIdentity []byte
@@ -468,7 +471,7 @@
 	return nil
 }
 
-func buildLinuxSketchBin(ctx context.Context, path string) (string, error) {
+func buildLinuxSketchBin(ctx context.Context) (string, error) {
 	homeDir, err := os.UserHomeDir()
 	if err != nil {
 		return "", err
@@ -589,7 +592,7 @@
 	return nil
 }
 
-func findOrBuildDockerImage(ctx context.Context, stdout, stderr io.Writer, cwd, gitRoot, antURL, antAPIKey string, forceRebuild bool) (imgName string, err error) {
+func findOrBuildDockerImage(ctx context.Context, cwd, gitRoot, antURL, antAPIKey string, forceRebuild, verbose bool) (imgName string, err error) {
 	h := sha256.Sum256([]byte(gitRoot))
 	imgName = "sketch-" + hex.EncodeToString(h[:6])
 
@@ -658,7 +661,9 @@
 		}
 		defer os.Remove(dockerfilePath)
 
-		fmt.Fprintf(stderr, "generated Dockerfile in %s:\n\t%s\n\n", time.Since(start).Round(time.Millisecond), strings.Replace(dockerfile, "\n", "\n\t", -1))
+		if verbose {
+			fmt.Fprintf(os.Stderr, "generated Dockerfile in %s:\n\t%s\n\n", time.Since(start).Round(time.Millisecond), strings.Replace(dockerfile, "\n", "\n\t", -1))
+		}
 	}
 
 	var gitUserEmail, gitUserName string
@@ -680,18 +685,15 @@
 		"-f", dockerfilePath,
 		"--build-arg", "GIT_USER_EMAIL="+gitUserEmail,
 		"--build-arg", "GIT_USER_NAME="+gitUserName,
-		".",
 	)
-	cmd.Dir = gitRoot
-	cmd.Stdout = stdout
-	cmd.Stderr = stderr
-	fmt.Printf("🏗️  building docker image %s... (use -verbose to see build output)\n", imgName)
-	dockerfileContent, err := os.ReadFile(dockerfilePath)
-	if err != nil {
-		return "", fmt.Errorf("failed to read Dockerfile: %w", err)
+	if !verbose {
+		cmd.Args = append(cmd.Args, "--progress=quiet")
 	}
-	// TODO: this is sometimes a repeat of earlier. Remove the earlier call?
-	fmt.Fprintf(stdout, "Dockerfile:\n%s\n", string(dockerfileContent))
+	cmd.Args = append(cmd.Args, ".")
+	cmd.Dir = gitRoot
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	fmt.Printf("🏗️  building docker image %s... (use -verbose to see build output)\n", imgName)
 
 	err = run(ctx, "docker build", cmd)
 	if err != nil {