Bug Description
The ! shell escape feature is only partially implemented. The autocomplete/suggestion layer recognizes the ! trigger and provides shell history completions, but the REPL does not intercept !-prefixed input for execution. Instead, the input is sent to the LLM as a regular chat message.
Steps to Reproduce
- Run
iac-code
- Type
!ls (or any !<command>)
- Observe that shell history suggestions appear as expected
- Press Enter to submit
Expected Behavior
The command after ! (e.g. ls) should be executed in the user's shell, with stdout/stderr displayed in the conversation. The output should ideally be injected into the conversation context so the LLM can reference it in subsequent turns.
Actual Behavior
The !ls input is sent directly to the LLM as a chat message. No shell command is executed.
Root Cause
The suggestion layer is fully wired up:
ShellHistoryProvider (src/iac_code/ui/suggestions/shell_history_provider.py) handles the ! trigger and returns history-based completions.
TokenExtractor (src/iac_code/ui/suggestions/token_extractor.py:66-74) recognizes ! at line start as a valid trigger.
However, the REPL input loop (src/iac_code/ui/repl.py:358-366) only checks for / (slash commands) before falling through to chat:
user_input = user_input.strip()
if not user_input:
continue
if self.command_registry.is_command(user_input): # only matches "/"
self._record_command_history(user_input)
await self._handle_command(user_input)
continue
# ... falls through to _handle_chat()
There is no branch to intercept !-prefixed input, strip the prefix, execute it as a subprocess, and display the result.
Suggested Fix
Add a ! check in the REPL input loop (between the empty-input guard and the / command check), e.g.:
if user_input.startswith("!"):
shell_cmd = user_input[1:].strip()
if shell_cmd:
await self._handle_shell_escape(shell_cmd)
continue
Where _handle_shell_escape runs the command via subprocess, prints stdout/stderr, and optionally appends the output to the conversation context.
Operating System
macOS
Python Version
3.12.7
iac-code Version
0.2.3
LLM Provider
No response
IaC Type
Not applicable
Additional Context
This feature mirrors the ! <command> shell escape convention used in tools like Claude Code, vim, and Python's REPL, where prefixing input with ! runs it in the host shell.
Bug Description
The
!shell escape feature is only partially implemented. The autocomplete/suggestion layer recognizes the!trigger and provides shell history completions, but the REPL does not intercept!-prefixed input for execution. Instead, the input is sent to the LLM as a regular chat message.Steps to Reproduce
iac-code!ls(or any!<command>)Expected Behavior
The command after
!(e.g.ls) should be executed in the user's shell, with stdout/stderr displayed in the conversation. The output should ideally be injected into the conversation context so the LLM can reference it in subsequent turns.Actual Behavior
The
!lsinput is sent directly to the LLM as a chat message. No shell command is executed.Root Cause
The suggestion layer is fully wired up:
ShellHistoryProvider(src/iac_code/ui/suggestions/shell_history_provider.py) handles the!trigger and returns history-based completions.TokenExtractor(src/iac_code/ui/suggestions/token_extractor.py:66-74) recognizes!at line start as a valid trigger.However, the REPL input loop (
src/iac_code/ui/repl.py:358-366) only checks for/(slash commands) before falling through to chat:There is no branch to intercept
!-prefixed input, strip the prefix, execute it as a subprocess, and display the result.Suggested Fix
Add a
!check in the REPL input loop (between the empty-input guard and the/command check), e.g.:Where
_handle_shell_escaperuns the command viasubprocess, prints stdout/stderr, and optionally appends the output to the conversation context.Operating System
macOS
Python Version
3.12.7
iac-code Version
0.2.3
LLM Provider
No response
IaC Type
Not applicable
Additional Context
This feature mirrors the
! <command>shell escape convention used in tools like Claude Code, vim, and Python's REPL, where prefixing input with!runs it in the host shell.