Skip to content

Commit b5bc614

Browse files
Merge pull request #171 from ibuildthecloud/confirm
feat: Add --confirm to prompt for destructive behavior
2 parents c8fefa6 + eb1440e commit b5bc614

File tree

5 files changed

+107
-2
lines changed

5 files changed

+107
-2
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/gptscript-ai/gptscript
33
go 1.22.0
44

55
require (
6+
github.com/AlecAivazis/survey/v2 v2.3.7
67
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
78
github.com/acorn-io/broadcaster v0.0.0-20240105011354-bfadd4a7b45d
89
github.com/acorn-io/cmd v0.0.0-20240203032901-e9e631185ddb
@@ -44,11 +45,13 @@ require (
4445
github.com/hexops/gotextdiff v1.0.3 // indirect
4546
github.com/hexops/valast v1.4.3 // indirect
4647
github.com/inconshreveable/mousetrap v1.1.0 // indirect
48+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
4749
github.com/klauspost/compress v1.16.5 // indirect
4850
github.com/klauspost/pgzip v1.2.5 // indirect
4951
github.com/mattn/go-colorable v0.1.13 // indirect
5052
github.com/mattn/go-isatty v0.0.20 // indirect
5153
github.com/mattn/go-runewidth v0.0.10 // indirect
54+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
5255
github.com/nightlyone/lockfile v1.0.0 // indirect
5356
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
5457
github.com/olekukonko/tablewriter v0.0.6-0.20230925090304-df64c4bbad77 // indirect

go.sum

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+
1515
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
1616
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
1717
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
18+
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
19+
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
1820
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 h1:+tu3HOoMXB7RXEINRVIpxJCT+KdYiI7LAEAUrOw3dIU=
1921
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZdiDllfyYH5l5OkAaZtk7VkWe89bPJFmnDBNHxg=
2022
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2123
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
24+
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
25+
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
2226
github.com/acorn-io/baaah v0.0.0-20240119160309-2a58ee757bbd h1:Zbau2J6sEPl1H4gqnEx4/TI55eZncQR5cjfPOcG2lxE=
2327
github.com/acorn-io/baaah v0.0.0-20240119160309-2a58ee757bbd/go.mod h1:13nTO3svO8zTD3j9E5c86tCtK5YrKsK5sxca4Lwkbc0=
2428
github.com/acorn-io/broadcaster v0.0.0-20240105011354-bfadd4a7b45d h1:hfpNQkJ4I2b8+DbMr8m97gG67ku0uPsMzUfskVu3cHU=
@@ -46,6 +50,8 @@ github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEyc
4650
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
4751
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
4852
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
53+
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
54+
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
4955
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5056
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5157
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -125,13 +131,17 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
125131
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
126132
github.com/hexops/valast v1.4.3 h1:oBoGERMJh6UZdRc6cduE1CTPK+VAdXA59Y1HFgu3sm0=
127133
github.com/hexops/valast v1.4.3/go.mod h1:Iqx2kLj3Jn47wuXpj3wX40xn6F93QNFBHuiKBerkTGA=
134+
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
135+
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
128136
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
129137
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
130138
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
131139
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
132140
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
133141
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
134142
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
143+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
144+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
135145
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
136146
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
137147
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
@@ -147,16 +157,20 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
147157
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
148158
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
149159
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
160+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
150161
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
151162
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
152163
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
164+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
153165
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
154166
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
155167
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
156168
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
157169
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
158170
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
159171
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
172+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
173+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
160174
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
161175
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
162176
github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA=
@@ -204,6 +218,7 @@ github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cma
204218
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
205219
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
206220
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
221+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
207222
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
208223
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
209224
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
@@ -293,6 +308,7 @@ golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
293308
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
294309
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
295310
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
311+
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
296312
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
297313
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
298314
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -329,6 +345,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
329345
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
330346
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
331347
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
348+
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
332349
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
333350
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
334351
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

pkg/builtin/builtin.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import (
1212
"os"
1313
"os/exec"
1414
"path/filepath"
15+
"runtime"
1516
"sort"
1617
"strings"
1718
"time"
1819

1920
"github.com/BurntSushi/locker"
21+
"github.com/google/shlex"
22+
"github.com/gptscript-ai/gptscript/pkg/confirm"
2023
"github.com/gptscript-ai/gptscript/pkg/types"
2124
"github.com/jaytaylor/html2text"
2225
)
@@ -240,7 +243,22 @@ func SysExec(ctx context.Context, env []string, input string) (string, error) {
240243

241244
log.Debugf("Running %s in %s", params.Command, params.Directory)
242245

243-
cmd := exec.Command("/bin/sh", "-c", params.Command)
246+
if err := confirm.Promptf(ctx, "Run command: %s", params.Command); err != nil {
247+
return "", err
248+
}
249+
250+
var cmd *exec.Cmd
251+
252+
if runtime.GOOS == "windows" {
253+
args, err := shlex.Split(params.Command)
254+
if err != nil {
255+
return "", fmt.Errorf("parsing command: %w", err)
256+
}
257+
cmd = exec.Command(args[0], args[1:]...)
258+
} else {
259+
cmd = exec.Command("/bin/sh", "-c", params.Command)
260+
}
261+
244262
cmd.Env = env
245263
cmd.Dir = params.Directory
246264
out, err := cmd.CombinedOutput()
@@ -292,6 +310,12 @@ func SysWrite(ctx context.Context, env []string, input string) (string, error) {
292310
}
293311
}
294312

313+
if _, err := os.Stat(params.Filename); err == nil {
314+
if err := confirm.Promptf(ctx, "Overwrite: %s", params.Filename); err != nil {
315+
return "", err
316+
}
317+
}
318+
295319
data := []byte(params.Content)
296320
log.Debugf("Wrote %d bytes to file %s", len(data), params.Filename)
297321

@@ -311,6 +335,12 @@ func SysAppend(ctx context.Context, env []string, input string) (string, error)
311335
locker.Lock(params.Filename)
312336
defer locker.Unlock(params.Filename)
313337

338+
if _, err := os.Stat(params.Filename); err == nil {
339+
if err := confirm.Promptf(ctx, "Write to existing file: %s.", params.Filename); err != nil {
340+
return "", err
341+
}
342+
}
343+
314344
f, err := os.OpenFile(params.Filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
315345
if err != nil {
316346
return "", err
@@ -448,6 +478,10 @@ func SysRemove(ctx context.Context, env []string, input string) (string, error)
448478
return "", err
449479
}
450480

481+
if err := confirm.Promptf(ctx, "Remove: %s", params.Location); err != nil {
482+
return "", err
483+
}
484+
451485
// Lock the file to prevent concurrent writes from other tool calls.
452486
locker.Lock(params.Location)
453487
defer locker.Unlock(params.Location)

pkg/cli/gptscript.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/gptscript-ai/gptscript/pkg/assemble"
1212
"github.com/gptscript-ai/gptscript/pkg/builtin"
1313
"github.com/gptscript-ai/gptscript/pkg/cache"
14+
"github.com/gptscript-ai/gptscript/pkg/confirm"
1415
"github.com/gptscript-ai/gptscript/pkg/engine"
1516
"github.com/gptscript-ai/gptscript/pkg/input"
1617
"github.com/gptscript-ai/gptscript/pkg/llm"
@@ -37,6 +38,7 @@ type GPTScript struct {
3738
CacheOptions
3839
OpenAIOptions
3940
DisplayOptions
41+
Confirm bool `usage:"Prompt before running potentially dangerous commands"`
4042
Debug bool `usage:"Enable debug logging"`
4143
Quiet *bool `usage:"No output logging (set --quiet=false to force on even when there is no TTY)" short:"q"`
4244
Output string `usage:"Save output to a file, or - for stdout" short:"o"`
@@ -245,7 +247,11 @@ func (r *GPTScript) Run(cmd *cobra.Command, args []string) error {
245247
return err
246248
}
247249

248-
s, err := runner.Run(cmd.Context(), prg, os.Environ(), toolInput)
250+
ctx := cmd.Context()
251+
if r.Confirm {
252+
ctx = confirm.WithConfirm(ctx, confirm.TextPrompt{})
253+
}
254+
s, err := runner.Run(ctx, prg, os.Environ(), toolInput)
249255
if err != nil {
250256
return err
251257
}

pkg/confirm/confirm.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package confirm
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
8+
"github.com/AlecAivazis/survey/v2"
9+
)
10+
11+
type Confirm interface {
12+
Confirm(prompt string) error
13+
}
14+
15+
type confirmer struct{}
16+
17+
func WithConfirm(ctx context.Context, c Confirm) context.Context {
18+
return context.WithValue(ctx, confirmer{}, c)
19+
}
20+
21+
func Promptf(ctx context.Context, fmtString string, args ...any) error {
22+
c, ok := ctx.Value(confirmer{}).(Confirm)
23+
if !ok {
24+
return nil
25+
}
26+
return c.Confirm(fmt.Sprintf(fmtString, args...))
27+
}
28+
29+
type TextPrompt struct {
30+
}
31+
32+
func (t TextPrompt) Confirm(prompt string) error {
33+
var result bool
34+
err := survey.AskOne(&survey.Confirm{
35+
Message: prompt,
36+
Default: false,
37+
}, &result)
38+
if err != nil {
39+
return err
40+
}
41+
if !result {
42+
return errors.New("abort")
43+
}
44+
return nil
45+
}

0 commit comments

Comments
 (0)