summaryrefslogtreecommitdiffstats
path: root/main.go
diff options
context:
space:
mode:
authorBx <bx@boxstep.io>2026-08-25 13:35:04 -0700
committerBx <bx@boxstep.io>2026-08-25 13:35:04 -0700
commit1171a091c883c3e59bc81d8aacad9f38763b237b (patch)
tree4c0d9d9bc6f385005bc4a929a6cf96b98651f902 /main.go
parent50ca864530f5672528cd90032cdc3089f347a9bb (diff)
downloadpico-1171a091c883c3e59bc81d8aacad9f38763b237b.tar.gz
pico-1171a091c883c3e59bc81d8aacad9f38763b237b.zip
bare (non‑interactive) mode: output just the raw resultmain
Diffstat (limited to 'main.go')
-rw-r--r--main.go45
1 files changed, 39 insertions, 6 deletions
diff --git a/main.go b/main.go
index df82ac9..c17cf5e 100644
--- a/main.go
+++ b/main.go
@@ -301,9 +301,7 @@ func toolBash(in map[string]any) (string, error) {
301 case out = <-done: 301 case out = <-done:
302 case <-time.After(30 * time.Second): 302 case <-time.After(30 * time.Second):
303 // Kill the GROUP, not just sh: `sh -c "sleep 60"` forks, and the 303 // Kill the GROUP, not just sh: `sh -c "sleep 60"` forks, and the
304 // grandchild inherits the pipe's write end. Killing sh alone leaves 304 // grandchild inherits the pipe's write end.
305 // the pipe open and the drain below blocks until the grandchild
306 // exits on its own -- a 30s timeout that takes 60s.
307 if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil { 305 if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
308 cmd.Process.Kill() 306 cmd.Process.Kill()
309 } 307 }
@@ -500,10 +498,20 @@ func agentLoop(messages *[]message) error {
500 } 498 }
501 switch b.Type { 499 switch b.Type {
502 case "text": 500 case "text":
503 fmt.Printf("\n%s⏺%s %s\n", cyan, reset, renderMarkdown(b.Text)) 501 if bareMode {
502 // In bare mode, output raw text without leading newline or markers.
503 fmt.Print(b.Text)
504 if !strings.HasSuffix(b.Text, "\n") {
505 fmt.Print("\n")
506 }
507 } else {
508 fmt.Printf("\n%s⏺%s %s\n", cyan, reset, renderMarkdown(b.Text))
509 }
504 case "tool_use": 510 case "tool_use":
505 fmt.Printf("\n%s⏺ %s%s(%s%s%s)\n", 511 if !bareMode {
506 green, capitalize(b.Name), reset, dim, argPreview(b.Name, b.Input), reset) 512 fmt.Printf("\n%s⏺ %s%s(%s%s%s)\n",
513 green, capitalize(b.Name), reset, dim, argPreview(b.Name, b.Input), reset)
514 }
507 out := runTool(b.Name, b.Input) 515 out := runTool(b.Name, b.Input)
508 printResult(out) 516 printResult(out)
509 results = append(results, toolResult{"tool_result", b.ID, out}) 517 results = append(results, toolResult{"tool_result", b.ID, out})
@@ -560,7 +568,18 @@ func argPreview(name string, input json.RawMessage) string {
560 return "" 568 return ""
561} 569}
562 570
571// Global flag indicating bare (non‑interactive) mode.
572var bareMode bool
573
563func printResult(out string) { 574func printResult(out string) {
575 if bareMode {
576 // In bare mode output the raw result.
577 fmt.Print(out)
578 if !strings.HasSuffix(out, "\n") {
579 fmt.Print("\n")
580 }
581 return
582 }
564 lines := strings.Split(out, "\n") 583 lines := strings.Split(out, "\n")
565 preview := truncate(lines[0], 60) 584 preview := truncate(lines[0], 60)
566 if len(lines) > 1 { 585 if len(lines) > 1 {
@@ -574,6 +593,20 @@ func printResult(out string) {
574// ---------------------------------------------------------------------- REPL 593// ---------------------------------------------------------------------- REPL
575 594
576func main() { 595func main() {
596 fi, _ := os.Stdin.Stat()
597 bareMode = (fi.Mode() & os.ModeCharDevice) == 0
598
599 if bareMode {
600 data, _ := io.ReadAll(os.Stdin)
601 line := strings.TrimSpace(string(data))
602 if line == "" {
603 return
604 }
605 messages := []message{{"user", line}}
606 _ = agentLoop(&messages) // errors are printed inside agentLoop via fmt.Printf in interactive mode; here we ignore.
607 return
608 }
609
577 cwd, _ := os.Getwd() 610 cwd, _ := os.Getwd()
578 fmt.Printf("%spico%s | %s%s | %s%s\n\n", bold, reset, dim, model, cwd, reset) 611 fmt.Printf("%spico%s | %s%s | %s%s\n\n", bold, reset, dim, model, cwd, reset)
579 612