12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 | package tools
import (
"context"
"time"
"blinker/internal/policy"
"blinker/internal/sandbox"
)
// previewOpts are the answers to a preview's changes.
var previewOpts = []Option{
{Label: "Apply the changes", Allow: true},
{Label: "Discard them"},
{Label: "Discard them, and tell the model why", Explain: true},
}
// preview runs an Unsafe_Bash script the user chose to preview: with its
// writes kept aside and no network, shown to the user with its output,
// and made only if they approve. The model sees the output only then.
func (t *Toolbox) preview(ctx context.Context, r Result, tool, script string, timeout time.Duration) (Result, error) {
ran, p, err := t.runCmd(ctx, r, sandbox.Cmd{
Mode: policy.UnsafeMode, Argv: []string{t.SB.Shell(), "-c", script},
Timeout: timeout, Preview: true,
})
if err != nil {
return previewFailed(ctx, r, err)
}
// Failing leaves the files in the session's dir, which goes when the
// session ends: nothing of them reaches the project.
defer p.Discard()
changes, about, err := p.Describe(t.SB.Project())
if err != nil {
return previewFailed(ctx, r, err)
}
title := "Unsafe_Bash's script, run as a preview, would make these changes"
if changes == "" && about == "" {
title = "Unsafe_Bash's script, run as a preview, changed no files"
}
_, ok, err := t.ask(ctx, Question{
Tool: tool, Title: title, Body: ran.Detail, Diff: changes, About: about,
Opts: previewOpts, Pager: true,
}, &r, "The user discarded what this script changed. It ran as a preview, so nothing it wrote was kept.")
if !ok {
return r, err
}
if err := t.SB.Apply(ctx, p); err != nil {
r.Output, r.Failed, r.Detail = "The user approved the script's changes, but applying them failed: "+err.Error(), true, "failed"
return r, nil
}
ran.Output += "\n[sandbox] It ran as a preview, and the user applied the files it changed."
return ran, nil
}
// previewFailed reports a preview that failed to the user only: the error
// may name what the script made, and the model sees nothing of a preview
// the user has not approved.
func previewFailed(ctx context.Context, r Result, err error) (Result, error) {
if ctx.Err() != nil {
return r, ctx.Err()
}
r.Output, r.Failed, r.Detail = "The script ran as a preview, which failed, so nothing it wrote was kept. The user saw why.", true, "the preview failed: "+err.Error()
return r, nil
}
|