diff --git a/internal/adapters/forge/forge.go b/internal/adapters/forge/forge.go index bf4c6ec..2f9069b 100644 --- a/internal/adapters/forge/forge.go +++ b/internal/adapters/forge/forge.go @@ -296,6 +296,9 @@ func (f *ForgeAdapter) buildArgs(config usecase.RunScriptConfig) []string { } args = append(args, "-vvvv") + // Passthrough args from CLI (after --) + args = append(args, config.PassthroughArgs...) + return args } diff --git a/internal/cli/run.go b/internal/cli/run.go index 7dd5368..d1fc3c9 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -60,12 +60,36 @@ Examples: treb run script/deploy/DeployCounter.s.sol --debug # Run with specific network and profile - treb run script/deploy/DeployCounter.s.sol --network sepolia --profile production`, - Args: cobra.ExactArgs(1), + treb run script/deploy/DeployCounter.s.sol --network sepolia --profile production + + # Pass extra flags to forge script (after --) + treb run script/deploy/DeployCounter.s.sol -- --skip-simulation + treb run script/deploy/DeployCounter.s.sol -- --gas-estimate-multiplier 200`, + Args: func(cmd *cobra.Command, args []string) error { + // Require at least 1 arg (script ref). Additional args after -- are passthrough. + dashIdx := cmd.ArgsLenAtDash() + if dashIdx == 0 { + return fmt.Errorf("requires a script reference argument before --") + } + positional := args + if dashIdx > 0 { + positional = args[:dashIdx] + } + if len(positional) != 1 { + return fmt.Errorf("accepts 1 arg(s), received %d", len(positional)) + } + return nil + }, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - // Get app from context (v2 usecase wiring) + // Split positional args from passthrough args (after --) deploymentScriptRef := args[0] + var passthroughArgs []string + if dashIdx := cmd.ArgsLenAtDash(); dashIdx >= 0 { + passthroughArgs = args[dashIdx:] + } + + // Get app from context (v2 usecase wiring) app, err := getApp(cmd) if err != nil { return err @@ -86,12 +110,13 @@ Examples: } params := usecase.RunScriptParams{ - ScriptRef: deploymentScriptRef, - Parameters: parsedEnvVars, - DryRun: dryRun, - Debug: debug, - DebugJSON: debugJSON, - DumpCommand: dumpCmd, + ScriptRef: deploymentScriptRef, + Parameters: parsedEnvVars, + DryRun: dryRun, + Debug: debug, + DebugJSON: debugJSON, + DumpCommand: dumpCmd, + PassthroughArgs: passthroughArgs, } result, err := app.RunScript.Run(cmd.Context(), params) if err != nil { diff --git a/internal/usecase/ports.go b/internal/usecase/ports.go index dd3851f..3e22feb 100644 --- a/internal/usecase/ports.go +++ b/internal/usecase/ports.go @@ -263,6 +263,7 @@ type RunScriptConfig struct { SenderScriptConfig config.SenderScriptConfig Progress ProgressSink ForkEnvOverrides map[string]string // env var overrides for fork mode (e.g. NETWORK_RPC_URL=http://localhost:PORT) + PassthroughArgs []string // Additional args passed through to forge script (after --) } // RunResultHydrator hydrated RunResults with domain models. diff --git a/internal/usecase/run_script.go b/internal/usecase/run_script.go index c0e99be..6c616e2 100644 --- a/internal/usecase/run_script.go +++ b/internal/usecase/run_script.go @@ -13,14 +13,15 @@ import ( // RunScriptParams contains parameters for running a script type RunScriptParams struct { - ScriptRef string - Parameters map[string]string - DryRun bool - Debug bool - DebugJSON bool - Verbose bool - NonInteractive bool - DumpCommand bool + ScriptRef string + Parameters map[string]string + DryRun bool + Debug bool + DebugJSON bool + Verbose bool + NonInteractive bool + DumpCommand bool + PassthroughArgs []string // Additional args passed through to forge script (after --) } // RunScriptResult contains the result of running a script @@ -185,6 +186,7 @@ func (uc *RunScript) Run(ctx context.Context, params RunScriptParams) (*RunScrip SenderScriptConfig: *senderScriptConfig, Slow: uc.config.Slow, ForkEnvOverrides: forkEnvOverrides, + PassthroughArgs: params.PassthroughArgs, } // Fork mode pre-run checks: health check + snapshot