Skip to content
14 changes: 14 additions & 0 deletions cmd/cli/commands/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package commands

import "github.com/spf13/cobra"

func newConfigCmd() *cobra.Command {
c := &cobra.Command{
Use: "config",
Short: "Manage persistent model runner configuration",
}

c.AddCommand(newSandboxConfigCmd())

return c
}
7 changes: 3 additions & 4 deletions cmd/cli/commands/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ func newConfigureCmd() *cobra.Command {
var flags ConfigureFlags

c := &cobra.Command{
Use: "configure [--context-size=<n>] [--speculative-draft-model=<model>] [--hf_overrides=<json>] [--gpu-memory-utilization=<float>] [--mode=<mode>] [--think] [--keep-alive=<duration>] MODEL [-- <runtime-flags...>]",
Aliases: []string{"config"},
Short: "Manage model runtime configurations",
Hidden: true,
Use: "configure [--context-size=<n>] [--speculative-draft-model=<model>] [--hf_overrides=<json>] [--gpu-memory-utilization=<float>] [--mode=<mode>] [--think] [--keep-alive=<duration>] MODEL [-- <runtime-flags...>]",
Short: "Manage model runtime configurations",
Comment thread
CoderHariswar marked this conversation as resolved.
Hidden: true,
Args: func(cmd *cobra.Command, args []string) error {
argsBeforeDash := cmd.ArgsLenAtDash()
if argsBeforeDash == -1 {
Expand Down
26 changes: 21 additions & 5 deletions cmd/cli/commands/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@
appArgs = args[dashIdx:]
}

// If a sandbox tool is configured, launch host apps through it before
// resolving runner endpoints. This keeps sandbox launch independent of
// whether the host app binary itself is installed.
if _, ok := hostApps[app]; ok {
sandboxTool, err := configuredSandboxTool()
if err != nil {
return err
}

if sandboxTool != "" && !configOnly {

Check failure on line 155 in cmd/cli/commands/launch.go

View workflow job for this annotation

GitHub Actions / lint (linux)

File is not properly formatted (gci)

Check failure on line 155 in cmd/cli/commands/launch.go

View workflow job for this annotation

GitHub Actions / lint (windows)

File is not properly formatted (gci)

Check failure on line 155 in cmd/cli/commands/launch.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

File is not properly formatted (gci)
return launchSandboxedHostApp(cmd, sandboxTool, app, appArgs, dryRun)
Comment on lines +155 to +156
}
}

runner, err := getStandaloneRunner(cmd.Context())
if err != nil {
return fmt.Errorf("unable to determine standalone runner endpoint: %w", err)
Expand All @@ -152,18 +166,17 @@
if err != nil {
return err
}

// --config: print configuration without launching
if configOnly {
return printAppConfig(cmd, app, ep, image, port)
}

if ca, ok := containerApps[app]; ok {
return launchContainerApp(cmd, ca, ep.container, image, port, detach, appArgs, dryRun)
}
if cli, ok := hostApps[app]; ok {
return launchHostApp(cmd, app, ep.host, cli, model, runner, appArgs, dryRun)
}

Comment thread
CoderHariswar marked this conversation as resolved.
return fmt.Errorf("unsupported app %q (supported: %s)", app, strings.Join(supportedApps, ", "))
},
}
Expand All @@ -176,6 +189,12 @@
return c
}

func launchSandboxedHostApp(cmd *cobra.Command, sandboxTool, app string, appArgs []string, dryRun bool) error {
args := append([]string{app}, appArgs...)

return runSandboxTool(cmd, sandboxTool, args, dryRun)
}

// listSupportedApps prints all supported apps with their descriptions and install status.
func listSupportedApps(cmd *cobra.Command) error {
cmd.Println("Supported apps:")
Expand Down Expand Up @@ -328,7 +347,6 @@
if bin == "opencode" {
return launchOpenCode(cmd, baseURL, model, runner, appArgs, dryRun)
}

if !dryRun {
if _, err := exec.LookPath(bin); err != nil {
cmd.PrintErrf("%q executable not found in PATH.\n", bin)
Expand All @@ -341,11 +359,9 @@
return fmt.Errorf("%s not found; please install it and re-run", bin)
}
}

if cli.envFn == nil {
return launchUnconfigurableHostApp(cmd, bin, baseURL, cli, appArgs, dryRun)
}

env := cli.envFn(baseURL)
if dryRun {
cmd.Printf("Would run: %s %s\n", bin, strings.Join(appArgs, " "))
Expand Down
1 change: 1 addition & 0 deletions cmd/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func NewRootCmd(cli *command.DockerCli) *cobra.Command {
newShowCmd(),
newComposeCmd(),
newLaunchCmd(),
newConfigCmd(),
newTagCmd(),
newConfigureCmd(),
newPSCmd(),
Expand Down
156 changes: 156 additions & 0 deletions cmd/cli/commands/sandbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package commands

import (
"bufio"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/spf13/cobra"
)

var allowedSandboxTools = map[string]struct{}{
"sbx": {},
}

func newSandboxConfigCmd() *cobra.Command {
return &cobra.Command{
Use: "sandbox.tool <tool>",
Short: "Set the sandbox tool",
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
tool, err := validateSandboxTool(args[0])
if err != nil {
return err
}

return writeSandboxToolConfig(tool)
},
}
}

func validateSandboxTool(tool string) (string, error) {
if _, ok := allowedSandboxTools[tool]; !ok {
return "", fmt.Errorf("unsupported sandbox tool %q", tool)
}

return tool, nil
}

func dmrConfigPath() (string, error) {
configDir, err := os.UserConfigDir()
if err != nil {
return "", fmt.Errorf("unable to determine config directory: %w", err)
}

return filepath.Join(configDir, "dmr", "config.toml"), nil
}

func writeSandboxToolConfig(tool string) error {
path, err := dmrConfigPath()
if err != nil {
return err
}

if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("unable to create config directory: %w", err)
}

content := fmt.Sprintf("[sandbox]\ntool = %q\n", tool)

if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
Comment on lines +61 to +63
return fmt.Errorf("unable to write config: %w", err)
}

return nil
}

func readSandboxToolConfig() (string, error) {
path, err := dmrConfigPath()
if err != nil {
return "", err
}

file, err := os.Open(path)
if os.IsNotExist(err) {
return "", nil
}
if err != nil {
return "", fmt.Errorf("unable to read config: %w", err)
}
defer file.Close()

inSandboxSection := false
scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())

if line == "" || strings.HasPrefix(line, "#") {
continue
}

if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
inSandboxSection = line == "[sandbox]"
continue
}

if !inSandboxSection {
continue
}

key, value, ok := strings.Cut(line, "=")
if !ok {
continue
}

if strings.TrimSpace(key) != "tool" {
continue
}

return strings.Trim(strings.TrimSpace(value), `"`), nil
}

if err := scanner.Err(); err != nil {
return "", fmt.Errorf("unable to parse config: %w", err)
}

return "", nil
}
func runSandboxTool(cmd *cobra.Command, sandboxTool string, args []string, dryRun bool) error {
validatedSandboxTool, err := validateSandboxTool(sandboxTool)
if err != nil {
return err
}

if dryRun {
cmd.Printf("%s %s\n", validatedSandboxTool, strings.Join(args, " "))
return nil
}

switch validatedSandboxTool {
case "sbx":
launchCmd := exec.Command("sbx", args...)
launchCmd.Stdin = os.Stdin
launchCmd.Stdout = os.Stdout
launchCmd.Stderr = os.Stderr

return launchCmd.Run()
default:
return fmt.Errorf("unsupported sandbox tool %q", validatedSandboxTool)
}
}
func configuredSandboxTool() (string, error) {
sandboxTool, err := readSandboxToolConfig()
if err != nil {
return "", err
}

if sandboxTool == "" {
return "", nil
}

return validateSandboxTool(sandboxTool)
}
Loading
Loading