diff --git a/cmd/antares/main.go b/cmd/antares/main.go index ba362240..0f6fe5e9 100644 --- a/cmd/antares/main.go +++ b/cmd/antares/main.go @@ -171,6 +171,11 @@ func cmdTUI() error { } rt.cfg = cfg rt.agent.SetConfig(cfg) + // Setup (web or terminal) creates the chosen workspace; ensure it + // exists before the TUI starts in case the path was only written. + if err := os.MkdirAll(cfg.Agent.Workspace, 0o755); err != nil { + return fmt.Errorf("preparing workspace: %w", err) + } } return tui.New(rt.agent, rt.cfg, rt.db).Run(ctx) @@ -201,8 +206,13 @@ func bootstrap(ctx context.Context) (*runtimeServices, error) { if err := logx.Setup(cfg.Logging.Level, cfg.Logging.File, cfg.Logging.JSON); err != nil { return nil, fmt.Errorf("setting up logging: %w", err) } - if err := os.MkdirAll(cfg.Agent.Workspace, 0o755); err != nil { - return nil, fmt.Errorf("preparing workspace: %w", err) + // Defer workspace creation until setup finishes. Creating the default + // path here leaves a leftover ~/antares-workspace when the user picks a + // custom directory in the wizard. + if !needsSetup(cfg) { + if err := os.MkdirAll(cfg.Agent.Workspace, 0o755); err != nil { + return nil, fmt.Errorf("preparing workspace: %w", err) + } } db, err := store.Open(ctx, cfg.Database.Driver, cfg.Database.DSN, diff --git a/cmd/antares/setup.go b/cmd/antares/setup.go index e71741a1..045b5f79 100644 --- a/cmd/antares/setup.go +++ b/cmd/antares/setup.go @@ -317,13 +317,11 @@ func runTerminalSetup(ctx context.Context, rt *runtimeServices) error { } cfg.Model.Default = model - // 5. Workspace + // 5. Workspace — only record the path here; create the directory after the + // full wizard finishes so a cancelled run does not leave an empty folder. fmt.Println() ws := promptLine(fmt.Sprintf(" Workspace directory (default %s): ", cfg.Agent.Workspace), cfg.Agent.Workspace) cfg.Agent.Workspace = config.Expand(ws) - if err := os.MkdirAll(cfg.Agent.Workspace, 0o755); err != nil { - return fmt.Errorf("creating workspace: %w", err) - } // 5b. Storage. SQLite is the default and needs nothing; Postgres asks for a // DSN and is verified now so a bad string surfaces here, not on next start. @@ -392,6 +390,9 @@ func runTerminalSetup(ctx context.Context, rt *runtimeServices) error { if err := config.Save(cfg); err != nil { return fmt.Errorf("saving configuration: %w", err) } + if err := os.MkdirAll(cfg.Agent.Workspace, 0o755); err != nil { + return fmt.Errorf("creating workspace: %w", err) + } rt.cfg = cfg rt.agent.SetConfig(cfg)