11package commands
22
33import (
4+ "context"
45 "fmt"
56 "os/exec"
67 "path/filepath"
78 "strings"
9+ "sync"
810)
911
12+ // lastRunOutput stores the combined output of the most recent /run invocation.
13+ // Protected by lastRunMu so concurrent commands don't corrupt it.
14+ var (
15+ lastRunOutput string
16+ lastRunMu sync.Mutex
17+ )
18+
19+ // LastRunOutput returns the captured output of the most recent /run call.
20+ func LastRunOutput () string {
21+ lastRunMu .Lock ()
22+ defer lastRunMu .Unlock ()
23+ return lastRunOutput
24+ }
25+
1026// RegisterDevCommands adds development commands.
1127func RegisterDevCommands (r * Registry ) {
1228 registerDevBuildCommands (r )
@@ -110,11 +126,23 @@ func cmdFormat(ctx Context) Result {
110126
111127func cmdRun (ctx Context ) Result {
112128 if ! ctx .HasArg (1 ) {
113- fmt .Println ("Usage: /run <command>" )
129+ fmt .Println ("Usage: /run [--ask] <command>" )
114130 return Result {Handled : true }
115131 }
116132
117- cmdStr := ctx .Args ()
133+ // Parse optional --ask flag: /run --ask <cmd>
134+ askMode := false
135+ argStart := 1
136+ if ctx .Arg (1 ) == "--ask" {
137+ askMode = true
138+ argStart = 2
139+ if ! ctx .HasArg (argStart ) {
140+ fmt .Println ("Usage: /run --ask <command>" )
141+ return Result {Handled : true }
142+ }
143+ }
144+
145+ cmdStr := strings .Join (ctx .Parts [argStart :], " " )
118146
119147 // Safe-mode gate: require confirmation for arbitrary shell execution.
120148 if ctx .SafeMode != nil && * ctx .SafeMode {
@@ -136,10 +164,26 @@ func cmdRun(ctx Context) Result {
136164 cmd := exec .Command ("sh" , "-c" , cmdStr )
137165 cmd .Dir = ctx .RepoPath
138166 output , err := cmd .CombinedOutput ()
139- fmt .Println (string (output ))
167+ outStr := string (output )
168+ fmt .Print (outStr )
169+
170+ // Store output for /explain-error and future /run --ask invocations.
171+ lastRunMu .Lock ()
172+ lastRunOutput = outStr
173+ lastRunMu .Unlock ()
174+
140175 if err != nil {
141176 PrintError ("Command failed: %s" , err )
142177 }
178+
179+ // --ask: send output to agent automatically.
180+ if askMode && ctx .REPL .StreamAndPrint != nil && (outStr != "" || err != nil ) {
181+ prompt := fmt .Sprintf (
182+ "I ran: `%s`\n \n Output:\n ```\n %s\n ```\n \n What does this mean and what should I do?" ,
183+ cmdStr , outStr )
184+ ctx .REPL .StreamAndPrint (context .Background (), ctx .Agent , prompt , ctx .RepoPath )
185+ }
186+
143187 return Result {Handled : true }
144188}
145189
@@ -295,12 +339,18 @@ func cmdFix(ctx Context) Result {
295339func cmdExplainError (ctx Context ) Result {
296340 errText := strings .TrimSpace (strings .TrimPrefix (ctx .Line , ctx .Parts [0 ]))
297341 if errText == "" {
298- fmt .Println ("Usage: /explain-error <error message>" )
299- return Result {Handled : true }
342+ // Fall back to the last /run output if available.
343+ errText = LastRunOutput ()
344+ if errText == "" {
345+ fmt .Println ("Usage: /explain-error <error message>" )
346+ fmt .Println (" (or run /run <cmd> first to auto-capture output)" )
347+ return Result {Handled : true }
348+ }
349+ fmt .Printf ("%s(using last /run output)%s\n " , ColorDim , ColorReset )
300350 }
301351 prompt := fmt .Sprintf ("Explain this error message clearly: what does it mean, what caused it, and how to fix it?\n \n Error:\n %s" , errText )
302352 if ctx .REPL .StreamAndPrint != nil {
303- ctx .REPL .StreamAndPrint (nil , ctx .Agent , prompt , ctx .RepoPath )
353+ ctx .REPL .StreamAndPrint (context . Background () , ctx .Agent , prompt , ctx .RepoPath )
304354 }
305355 return Result {Handled : true }
306356}
0 commit comments