mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-09 05:19:33 -10:00
Update the Go module path, imports, install scripts, docs, workflows, packaging and action defaults from Gitlawb/zero to Twigpine/zero. The npm scope (already @twigpine/zero on main, with its @gitlawb/zero migration notes), LICENSE, action author, the OpenGateway provider and historical CHANGELOG links are unchanged. The X-AIMLAPI-Integration-Repo header keeps Gitlawb/zero: it is what AIMLAPI sees for attribution, so changing it needs a maintainer's yes. docs/INSTALL.md keeps `go install github.com/Gitlawb/zero/...`, because every tagged release so far declares that module path. The Homebrew formula comment names the Twigpine/homebrew-tap tap. Co-authored-by: Claude Opus 5.5 <[email protected]>
65 lines
1.8 KiB
Go
65 lines
1.8 KiB
Go
package tui
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
tea "charm.land/bubbletea/v2"
|
|
"github.com/Twigpine/zero/internal/tools"
|
|
)
|
|
|
|
// bashEscapeTimeout bounds a "!cmd" shell escape so a hung command can't freeze
|
|
// the agent indefinitely.
|
|
const bashEscapeTimeout = 30 * time.Second
|
|
|
|
// bashResultMsg carries the combined output of a "!cmd" shell escape back to the
|
|
// model for display in the transcript.
|
|
type bashResultMsg struct {
|
|
command string
|
|
output string
|
|
}
|
|
|
|
// runBashEscape runs a user-typed "!cmd" in the workspace and returns its
|
|
// combined output as a message. The user typed it explicitly, so it runs
|
|
// directly (a deliberate shell escape, outside the agent sandbox), bounded by a
|
|
// timeout and executed asynchronously so the UI stays responsive.
|
|
func runBashEscape(cwd, command string) tea.Cmd {
|
|
return func() tea.Msg {
|
|
ctx, cancel := context.WithTimeout(context.Background(), bashEscapeTimeout)
|
|
defer cancel()
|
|
|
|
cmd := tools.NewHostShellCommandContext(ctx, command)
|
|
if strings.TrimSpace(cwd) != "" {
|
|
cmd.Dir = cwd
|
|
}
|
|
out, err := cmd.CombinedOutput()
|
|
text := strings.TrimRight(string(out), "\n")
|
|
|
|
switch {
|
|
case ctx.Err() == context.DeadlineExceeded:
|
|
text = appendNote(text, "[timed out after "+bashEscapeTimeout.String()+"]")
|
|
case err != nil:
|
|
text = appendNote(text, "[exit error: "+err.Error()+"]")
|
|
}
|
|
if strings.TrimSpace(text) == "" {
|
|
text = "(no output)"
|
|
}
|
|
return bashResultMsg{command: command, output: text}
|
|
}
|
|
}
|
|
|
|
// escapeShell returns the platform shell and arguments for tests and display.
|
|
// Execution itself uses tools.NewHostShellCommandContext so the cmd.exe
|
|
// fallback receives its required raw Windows command line.
|
|
func escapeShell(command string) (string, []string) {
|
|
return tools.HostShellCommand(command)
|
|
}
|
|
|
|
func appendNote(text, note string) string {
|
|
if text == "" {
|
|
return note
|
|
}
|
|
return text + "\n" + note
|
|
}
|