MCPcopy Create free account
hub / github.com/diillson/chatcli / executeInteractive

Method executeInteractive

cli/agent/command_executor.go:170–251  ·  view source on GitHub ↗

executeInteractive executa comando interativo

(ctx context.Context, shell, shellFlag, command string)

Source from the content-addressed store, hash-verified

168
169// executeInteractive executa comando interativo
170func (e *CommandExecutor) executeInteractive(ctx context.Context, shell, shellFlag, command string) (*ExecutionResult, error) {
171 start := time.Now()
172 result := &ExecutionResult{Command: command}
173
174 fmt.Println(i18n.T("agent.executor.interactive_mode_header"))
175 fmt.Println(i18n.T("agent.executor.interactive_mode_info"))
176 fmt.Println(i18n.T("agent.executor.interactive_mode_exit_tip"))
177 fmt.Println("----------------------------------------------")
178
179 if runtime.GOOS != "windows" {
180 saneCmd := exec.Command("stty", "sane")
181 saneCmd.Stdin = os.Stdin
182 if err := saneCmd.Run(); err != nil {
183 e.logger.Warn(i18n.T("agent.executor.fail_restore_terminal"), zap.Error(err))
184 }
185 }
186
187 // Configuração de perfil do shell (bashrc/zshrc)
188 shellConfigPath := e.getShellConfigPath(shell)
189 var shellCommand string
190
191 // Security (M13): Default to --noprofile --norc. Opt-in via CHATCLI_AGENT_SOURCE_SHELL_CONFIG=true.
192 sourceShellConfig := strings.EqualFold(os.Getenv("CHATCLI_AGENT_SOURCE_SHELL_CONFIG"), "true")
193
194 // No Windows, a lógica de 'source' não funciona igual. Simplificamos para executar direto.
195 if runtime.GOOS == "windows" {
196 shellCommand = command
197 } else {
198 if sourceShellConfig && shellConfigPath != "" {
199 if err := e.validateShellConfig(shellConfigPath); err != nil {
200 e.logger.Warn("Skipping shell config sourcing", zap.Error(err))
201 shellConfigPath = ""
202 }
203 // Additional validation: file ownership must match current user
204 if shellConfigPath != "" {
205 if info, err := os.Stat(shellConfigPath); err == nil {
206 // Check file size (reject > 1MB — shell configs shouldn't be that large)
207 if info.Size() > 1024*1024 {
208 e.logger.Warn("Shell config too large, skipping", zap.Int64("size", info.Size()))
209 shellConfigPath = ""
210 }
211 }
212 }
213 } else {
214 shellConfigPath = "" // Don't source shell config by default
215 }
216
217 if shellConfigPath != "" {
218 shellCommand = fmt.Sprintf("source %s 2>/dev/null || true; %s", utils.ShellQuote(shellConfigPath), command)
219 } else {
220 shellCommand = command
221 }
222 }
223
224 cmd := exec.CommandContext(ctx, shell, shellFlag, shellCommand) //#nosec G204 G702 -- agent interactive shell command, validated upstream
225
226 cmd.Stdin = os.Stdin
227 cmd.Stdout = os.Stdout

Callers 1

ExecuteMethod · 0.95

Implementers 2

MockCommandExecutorutils/git_utils_test.go
OSCommandExecutorutils/exec_utils.go

Calls 9

getShellConfigPathMethod · 0.95
validateShellConfigMethod · 0.95
TFunction · 0.92
ShellQuoteFunction · 0.92
WarnMethod · 0.80
RunMethod · 0.65
ErrorMethod · 0.65
SizeMethod · 0.45
StringMethod · 0.45

Tested by

no test coverage detected