@@ -18,6 +18,7 @@ import { Rule } from './rules/types'
1818import { buildSystemPrompt } from './system'
1919import { seedAllowedCommands } from './tools/shell/shell_execute'
2020import { removeDisabledTools } from './tools/tools'
21+ import { startContainer } from './util/docker/container'
2122import { createInterruptHandler , InterruptHandlerOptions } from './util/interrupts/interrupts'
2223import { createPrompter } from './util/prompter/prompter'
2324import { createLimiter } from './util/ratelimits/limiter'
@@ -61,13 +62,17 @@ async function main() {
6162 const disableToolsFlags = '--disable-tools <string>'
6263 const disableToolsDescription = 'Comma-separated list of tool names to disable.'
6364
65+ const sandboxedFlags = '--sandboxed'
66+ const sandboxedDescription = 'Run shell commands in a Docker container (alpine image).'
67+
6468 program
6569 . option ( historyFlags , historyDescription )
6670 . option ( portFlags , portDescription )
6771 . option ( cwdFlags , cwdDescription )
6872 . option ( yoloFlags , yoloDescription )
6973 . option ( oneShotFlags , oneShotDescription )
7074 . option ( disableToolsFlags , disableToolsDescription )
75+ . option ( sandboxedFlags , sandboxedDescription )
7176 . action ( options => {
7277 if ( options . cwd ) {
7378 process . chdir ( options . cwd )
@@ -84,6 +89,7 @@ async function main() {
8489 options . oneShot ,
8590 options . yolo ,
8691 options . disableTools ,
92+ options . sandboxed ,
8793 )
8894 } )
8995
@@ -101,6 +107,7 @@ async function chat(
101107 oneShot ?: string ,
102108 yolo : boolean = false ,
103109 disabledTools ?: string ,
110+ sandboxed : boolean = false ,
104111) {
105112 if ( ! process . stdin . setRawMode ) {
106113 throw new Error ( 'chat command is not supported in this environment.' )
@@ -136,14 +143,20 @@ async function chat(
136143 await registerTools ( client )
137144 await seedAllowedCommands ( )
138145
146+ const interruptHandler = createInterruptHandler ( rl )
147+ const interruptInputOptions = rootInterruptHandlerOptions ( rl )
148+
149+ const container = sandboxed
150+ ? await startContainer ( { interruptHandler, preferences, contextStateManager } )
151+ : undefined
152+
139153 try {
140- const interruptHandler = createInterruptHandler ( rl )
141- const interruptInputOptions = rootInterruptHandlerOptions ( rl )
142154 const prompter = createPrompter (
143155 rl ,
144156 interruptHandler ,
145157 attentionGetter ( preferences . attentionCommand ?? defaultAttentionCommand ) ,
146158 )
159+
147160 const provider = await providers . createProvider ( {
148161 contextState : contextStateManager ,
149162 modelName : preferences . defaultModel ,
@@ -164,6 +177,7 @@ async function chat(
164177 contextStateManager,
165178 yolo,
166179 tools : allowedToolNames ,
180+ container,
167181 }
168182
169183 await registerContextListeners ( context , client )
@@ -180,6 +194,7 @@ async function chat(
180194 interruptInputOptions ,
181195 )
182196 } finally {
197+ await container ?. stop ( )
183198 process . stdin . unpipe ( filter )
184199 filter . destroy ( )
185200 rl . close ( )
0 commit comments