summaryrefslogtreecommitdiff
path: root/internal/cli
diff options
context:
space:
mode:
Diffstat (limited to 'internal/cli')
-rw-r--r--internal/cli/root.go19
-rw-r--r--internal/cli/run.go16
-rw-r--r--internal/cli/serve.go31
3 files changed, 42 insertions, 24 deletions
diff --git a/internal/cli/root.go b/internal/cli/root.go
index e57a9d9..2cc8f71 100644
--- a/internal/cli/root.go
+++ b/internal/cli/root.go
@@ -38,18 +38,27 @@ func NewRootCmd() *cobra.Command {
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
// Re-derive DBPath and LogDir after flags are parsed, so --data-dir takes effect.
- // If --config is provided, load that file first; explicit CLI flags override it.
+ // Load config file: explicit --config flag, then default location, then defaults-only.
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
- if cfgFile != "" {
+ filePath := cfgFile
+ if filePath == "" {
+ home, _ := os.UserHomeDir()
+ filePath = filepath.Join(home, ".claudomator", "config.toml")
+ }
+
+ if filePath != "" {
// Save values set by explicit CLI flags before overwriting cfg from file.
flagDataDir := cfg.DataDir
flagClaudeBin := cfg.ClaudeBinaryPath
- loaded, err := config.LoadFile(cfgFile)
- if err != nil {
+ loaded, err := config.LoadFile(filePath)
+ if err != nil && cfgFile != "" {
+ // Only hard-fail if the file was explicitly specified.
return err
}
- *cfg = *loaded
+ if err == nil {
+ *cfg = *loaded
+ }
if cmd.Flags().Changed("data-dir") {
cfg.DataDir = flagDataDir
diff --git a/internal/cli/run.go b/internal/cli/run.go
index 48f34b7..771c7b7 100644
--- a/internal/cli/run.go
+++ b/internal/cli/run.go
@@ -77,8 +77,10 @@ func runTasks(file string, parallel int, dryRun bool) error {
apiURL = "http://" + cfg.ServerAddr
}
- runners := map[string]executor.Runner{
- "claude": &executor.ContainerRunner{
+ runners := map[string]executor.Runner{}
+
+ if cfg.Runners.ClaudeEnabled() {
+ runners["claude"] = &executor.ContainerRunner{
Image: cfg.ClaudeImage,
Logger: logger,
LogDir: cfg.LogDir,
@@ -87,8 +89,10 @@ func runTasks(file string, parallel int, dryRun bool) error {
SSHAuthSock: cfg.SSHAuthSock,
ClaudeBinary: cfg.ClaudeBinaryPath,
GeminiBinary: cfg.GeminiBinaryPath,
- },
- "gemini": &executor.ContainerRunner{
+ }
+ }
+ if cfg.Runners.GeminiEnabled() {
+ runners["gemini"] = &executor.ContainerRunner{
Image: cfg.GeminiImage,
Logger: logger,
LogDir: cfg.LogDir,
@@ -97,11 +101,11 @@ func runTasks(file string, parallel int, dryRun bool) error {
SSHAuthSock: cfg.SSHAuthSock,
ClaudeBinary: cfg.ClaudeBinaryPath,
GeminiBinary: cfg.GeminiBinaryPath,
- },
+ }
}
localClient := buildLocalLLMClient(cfg.LocalModel, logger)
- if localClient != nil {
+ if localClient != nil && cfg.Runners.LocalEnabled() {
runners["local"] = &executor.LocalRunner{
Client: localClient,
Logger: logger,
diff --git a/internal/cli/serve.go b/internal/cli/serve.go
index fe0ba8e..f687e14 100644
--- a/internal/cli/serve.go
+++ b/internal/cli/serve.go
@@ -86,13 +86,16 @@ func serve(addr, basePath string) error {
claudeConfigDir := cfg.ClaudeConfigDir
repoDir, _ := os.Getwd()
+
// Shared per-task agent MCP token registry: runners mint tokens; the API
// server mounts /mcp and resolves them.
agentRegistry := executor.NewRegistry()
- runners := map[string]executor.Runner{
- // ContainerRunner: binaries are resolved via PATH inside the container image,
- // so ClaudeBinary/GeminiBinary are left empty (host paths would not exist inside).
- "claude": &executor.ContainerRunner{
+ runners := map[string]executor.Runner{}
+
+ // ContainerRunner: binaries are resolved via PATH inside the container image,
+ // so ClaudeBinary/GeminiBinary are left empty (host paths would not exist inside).
+ if cfg.Runners.ClaudeEnabled() {
+ runners["claude"] = &executor.ContainerRunner{
Image: cfg.ClaudeImage,
Logger: logger,
LogDir: cfg.LogDir,
@@ -103,8 +106,10 @@ func serve(addr, basePath string) error {
CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
Store: store,
Registry: agentRegistry,
- },
- "gemini": &executor.ContainerRunner{
+ }
+ }
+ if cfg.Runners.GeminiEnabled() {
+ runners["gemini"] = &executor.ContainerRunner{
Image: cfg.GeminiImage,
Logger: logger,
LogDir: cfg.LogDir,
@@ -115,8 +120,10 @@ func serve(addr, basePath string) error {
CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
Store: store,
Registry: agentRegistry,
- },
- "container": &executor.ContainerRunner{
+ }
+ }
+ if cfg.Runners.ContainerEnabled() {
+ runners["container"] = &executor.ContainerRunner{
Image: "claudomator-agent:latest",
Logger: logger,
LogDir: cfg.LogDir,
@@ -127,11 +134,11 @@ func serve(addr, basePath string) error {
CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
Store: store,
Registry: agentRegistry,
- },
+ }
}
localClient := buildLocalLLMClient(cfg.LocalModel, logger)
- if localClient != nil {
+ if localClient != nil && cfg.Runners.LocalEnabled() {
runners["local"] = &executor.LocalRunner{
Client: localClient,
Logger: logger,
@@ -141,7 +148,6 @@ func serve(addr, basePath string) error {
logger.Info("local runner registered", "endpoint", cfg.LocalModel.Endpoint, "model", cfg.LocalModel.Model)
}
-
pool := executor.NewPool(cfg.MaxConcurrent, runners, store, logger)
pool.Classifier = &executor.Classifier{
LLM: localClient,
@@ -152,7 +158,7 @@ func serve(addr, basePath string) error {
}
// Budget accountant: gate paid providers against rolling per-provider caps.
- // With no limits configured this is created but allows everything.
+ // With no limits configured this is a no-op.
var accountant *budget.Accountant
if len(cfg.Budget.Provider5hUSD) > 0 {
window := budget.DefaultWindow
@@ -268,4 +274,3 @@ func serve(addr, basePath string) error {
}
return nil
}
-