vibepup 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ralph/runs/iter-0001/agent_response.txt +189 -0
- package/PUBLISHING.md +39 -1
- package/README.md +69 -4
- package/bin/ralph.js +166 -50
- package/lib/ralph-win.js +401 -0
- package/lib/ralph.sh +10 -23
- package/package.json +5 -2
- package/prd.md +4 -0
- package/prd.state.json +1 -0
- package/repo-map.md +0 -0
- package/tui/animations/loaders.go +55 -0
- package/tui/animations/memes.go +35 -0
- package/tui/animations/registry.go +54 -0
- package/tui/config/flags.go +34 -0
- package/tui/go.mod +21 -16
- package/tui/go.sum +42 -34
- package/tui/main.go +269 -198
- package/tui/motion/engine.go +86 -0
- package/tui/persona/quip.go +89 -0
- package/tui/process/runner.go +94 -0
- package/tui/theme/registry.go +74 -0
- package/tui/ui/layout.go +17 -0
- package/tui/ui/statusbar.go +28 -0
- package/tui/ui/viewport.go +63 -0
- package/tui/vibepup-tui +0 -0
- package/vibepup-1.0.3.tgz +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
package persona
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"math/rand"
|
|
5
|
+
"strings"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type SnarkLevel string
|
|
9
|
+
|
|
10
|
+
const (
|
|
11
|
+
Mild SnarkLevel = "mild"
|
|
12
|
+
Spicy SnarkLevel = "spicy"
|
|
13
|
+
Unhinged SnarkLevel = "unhinged"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
func ParseSnark(s string) SnarkLevel {
|
|
17
|
+
switch strings.ToLower(s) {
|
|
18
|
+
case "mild":
|
|
19
|
+
return Mild
|
|
20
|
+
case "unhinged":
|
|
21
|
+
return Unhinged
|
|
22
|
+
default:
|
|
23
|
+
return Spicy
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// GetStatus returns a context-aware status message
|
|
28
|
+
func GetStatus(cmd string, level SnarkLevel) string {
|
|
29
|
+
cmd = strings.TrimSpace(cmd)
|
|
30
|
+
|
|
31
|
+
// Default generic statuses
|
|
32
|
+
generic := []string{"VIBING", "WORKING", "COOKING", "DOING STUFF"}
|
|
33
|
+
|
|
34
|
+
if strings.Contains(cmd, "install") || strings.Contains(cmd, "add") {
|
|
35
|
+
switch level {
|
|
36
|
+
case Mild:
|
|
37
|
+
return "FETCHING PACKAGES"
|
|
38
|
+
case Unhinged:
|
|
39
|
+
return "CONSUMING DEPENDENCIES"
|
|
40
|
+
default:
|
|
41
|
+
return "SNACKING ON NODEMODULES"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if strings.Contains(cmd, "build") {
|
|
46
|
+
switch level {
|
|
47
|
+
case Mild:
|
|
48
|
+
return "BUILDING PROJECT"
|
|
49
|
+
case Unhinged:
|
|
50
|
+
return "ASSEMBLING THE BEAST"
|
|
51
|
+
default:
|
|
52
|
+
return "CONSTRUCTING CHAOS"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return generic[rand.Intn(len(generic))]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func RandomQuip(level SnarkLevel) string {
|
|
60
|
+
mild := []string{
|
|
61
|
+
"Hope this works!",
|
|
62
|
+
"Just doing my best.",
|
|
63
|
+
"Code is poetry.",
|
|
64
|
+
"Stay hydrated.",
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
spicy := []string{
|
|
68
|
+
"I'd explain it, but I don't want to.",
|
|
69
|
+
"It's not a bug, it's a feature.",
|
|
70
|
+
"Deleting production... jk.",
|
|
71
|
+
"You sure about that variable name?",
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
unhinged := []string{
|
|
75
|
+
"THE END IS NIGH.",
|
|
76
|
+
"Resistance is futile.",
|
|
77
|
+
"I can see your browser history.",
|
|
78
|
+
"Entropy increases.",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
switch level {
|
|
82
|
+
case Mild:
|
|
83
|
+
return mild[rand.Intn(len(mild))]
|
|
84
|
+
case Unhinged:
|
|
85
|
+
return unhinged[rand.Intn(len(unhinged))]
|
|
86
|
+
default:
|
|
87
|
+
return spicy[rand.Intn(len(spicy))]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
package process
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bufio"
|
|
5
|
+
"context"
|
|
6
|
+
"os/exec"
|
|
7
|
+
"syscall"
|
|
8
|
+
|
|
9
|
+
tea "github.com/charmbracelet/bubbletea"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// Msg indicates a line of output from the process
|
|
13
|
+
type OutputMsg string
|
|
14
|
+
|
|
15
|
+
// DoneMsg indicates the process finished
|
|
16
|
+
type DoneMsg struct {
|
|
17
|
+
Err error
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Runner handles the execution of the external process
|
|
21
|
+
type Runner struct {
|
|
22
|
+
Cmd *exec.Cmd
|
|
23
|
+
Cancel context.CancelFunc
|
|
24
|
+
OutputChan chan string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Start launches the command in a new process group to allow deep killing
|
|
28
|
+
func Start(ctx context.Context, name string, args []string) (*Runner, tea.Cmd) {
|
|
29
|
+
ctx, cancel := context.WithCancel(ctx)
|
|
30
|
+
cmd := exec.CommandContext(ctx, name, args...)
|
|
31
|
+
|
|
32
|
+
// Create a new process group so we can kill the whole tree later
|
|
33
|
+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
|
34
|
+
|
|
35
|
+
// Capture stdout and stderr
|
|
36
|
+
stdout, _ := cmd.StdoutPipe()
|
|
37
|
+
stderr, _ := cmd.StderrPipe()
|
|
38
|
+
|
|
39
|
+
runner := &Runner{
|
|
40
|
+
Cmd: cmd,
|
|
41
|
+
Cancel: cancel,
|
|
42
|
+
OutputChan: make(chan string),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if err := cmd.Start(); err != nil {
|
|
46
|
+
cancel()
|
|
47
|
+
return nil, func() tea.Msg { return DoneMsg{Err: err} }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Stream output to channel
|
|
51
|
+
go func() {
|
|
52
|
+
scanner := bufio.NewScanner(stdout)
|
|
53
|
+
for scanner.Scan() {
|
|
54
|
+
runner.OutputChan <- scanner.Text()
|
|
55
|
+
}
|
|
56
|
+
}()
|
|
57
|
+
|
|
58
|
+
go func() {
|
|
59
|
+
scanner := bufio.NewScanner(stderr)
|
|
60
|
+
for scanner.Scan() {
|
|
61
|
+
runner.OutputChan <- "ERR: " + scanner.Text()
|
|
62
|
+
}
|
|
63
|
+
}()
|
|
64
|
+
|
|
65
|
+
// Wait for completion in background
|
|
66
|
+
cmdCmd := func() tea.Msg {
|
|
67
|
+
err := cmd.Wait()
|
|
68
|
+
return DoneMsg{Err: err}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return runner, cmdCmd
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Kill stops the process and its children
|
|
75
|
+
func (r *Runner) Kill() {
|
|
76
|
+
if r.Cmd != nil && r.Cmd.Process != nil {
|
|
77
|
+
// Kill the entire process group (negative PID)
|
|
78
|
+
_ = syscall.Kill(-r.Cmd.Process.Pid, syscall.SIGKILL)
|
|
79
|
+
}
|
|
80
|
+
if r.Cancel != nil {
|
|
81
|
+
r.Cancel()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// WaitForOutput returns a command that waits for the next line of output
|
|
86
|
+
func (r *Runner) WaitForOutput() tea.Cmd {
|
|
87
|
+
return func() tea.Msg {
|
|
88
|
+
line, ok := <-r.OutputChan
|
|
89
|
+
if !ok {
|
|
90
|
+
return nil
|
|
91
|
+
}
|
|
92
|
+
return OutputMsg(line)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package theme
|
|
2
|
+
|
|
3
|
+
import "github.com/charmbracelet/lipgloss"
|
|
4
|
+
|
|
5
|
+
type Theme struct {
|
|
6
|
+
Name string
|
|
7
|
+
Background lipgloss.Color
|
|
8
|
+
Foreground lipgloss.Color
|
|
9
|
+
Accent lipgloss.Color
|
|
10
|
+
AccentAlt lipgloss.Color
|
|
11
|
+
Muted lipgloss.Color
|
|
12
|
+
Border lipgloss.Color
|
|
13
|
+
Highlight lipgloss.Color
|
|
14
|
+
SupportsEmoji bool
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var themes = map[string]Theme{}
|
|
18
|
+
|
|
19
|
+
func init() {
|
|
20
|
+
RegisterTheme(Theme{
|
|
21
|
+
Name: "dracula-vibe",
|
|
22
|
+
Background: lipgloss.Color("#282a36"),
|
|
23
|
+
Foreground: lipgloss.Color("#f8f8f2"),
|
|
24
|
+
Accent: lipgloss.Color("#FF1493"),
|
|
25
|
+
AccentAlt: lipgloss.Color("#00FFFF"),
|
|
26
|
+
Muted: lipgloss.Color("#44475a"),
|
|
27
|
+
Border: lipgloss.Color("#FF1493"),
|
|
28
|
+
Highlight: lipgloss.Color("#BD93F9"),
|
|
29
|
+
SupportsEmoji: true,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
RegisterTheme(Theme{
|
|
33
|
+
Name: "halloween-glitch",
|
|
34
|
+
Background: lipgloss.Color("#0d0b1a"),
|
|
35
|
+
Foreground: lipgloss.Color("#f8e7cf"),
|
|
36
|
+
Accent: lipgloss.Color("#ff6b00"),
|
|
37
|
+
AccentAlt: lipgloss.Color("#6df3ff"),
|
|
38
|
+
Muted: lipgloss.Color("#2b203d"),
|
|
39
|
+
Border: lipgloss.Color("#ff00aa"),
|
|
40
|
+
Highlight: lipgloss.Color("#aaff00"),
|
|
41
|
+
SupportsEmoji: true,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
RegisterTheme(Theme{
|
|
45
|
+
Name: "mono-chill",
|
|
46
|
+
Background: lipgloss.Color("#101010"),
|
|
47
|
+
Foreground: lipgloss.Color("#e6e6e6"),
|
|
48
|
+
Accent: lipgloss.Color("#8ec07c"),
|
|
49
|
+
AccentAlt: lipgloss.Color("#83a598"),
|
|
50
|
+
Muted: lipgloss.Color("#3c3836"),
|
|
51
|
+
Border: lipgloss.Color("#928374"),
|
|
52
|
+
Highlight: lipgloss.Color("#fabd2f"),
|
|
53
|
+
SupportsEmoji: false,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func RegisterTheme(t Theme) {
|
|
58
|
+
themes[t.Name] = t
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func Get(name string) Theme {
|
|
62
|
+
if t, ok := themes[name]; ok {
|
|
63
|
+
return t
|
|
64
|
+
}
|
|
65
|
+
return themes["dracula-vibe"]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func All() []Theme {
|
|
69
|
+
items := make([]Theme, 0, len(themes))
|
|
70
|
+
for _, t := range themes {
|
|
71
|
+
items = append(items, t)
|
|
72
|
+
}
|
|
73
|
+
return items
|
|
74
|
+
}
|
package/tui/ui/layout.go
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"unicode/utf8"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
// ClampWidth trims a string to fit within width runes.
|
|
8
|
+
func ClampWidth(s string, width int) string {
|
|
9
|
+
if width <= 0 {
|
|
10
|
+
return ""
|
|
11
|
+
}
|
|
12
|
+
if utf8.RuneCountInString(s) <= width {
|
|
13
|
+
return s
|
|
14
|
+
}
|
|
15
|
+
runes := []rune(s)
|
|
16
|
+
return string(runes[:width])
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
|
|
6
|
+
"github.com/charmbracelet/lipgloss"
|
|
7
|
+
"vibepup-tui/theme"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type StatusBar struct {
|
|
11
|
+
Theme theme.Theme
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
func (s StatusBar) Render(left, right string, width int) string {
|
|
15
|
+
style := lipgloss.NewStyle().Foreground(s.Theme.Foreground).Background(s.Theme.Muted)
|
|
16
|
+
spacer := width - lipgloss.Width(left) - lipgloss.Width(right)
|
|
17
|
+
if spacer < 1 {
|
|
18
|
+
spacer = 1
|
|
19
|
+
}
|
|
20
|
+
return style.Render(fmt.Sprintf("%s%s%s", left, spaces(spacer), right))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func spaces(n int) string {
|
|
24
|
+
if n < 0 {
|
|
25
|
+
n = 0
|
|
26
|
+
}
|
|
27
|
+
return fmt.Sprintf("%*s", n, "")
|
|
28
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
|
|
6
|
+
"github.com/charmbracelet/bubbles/viewport"
|
|
7
|
+
tea "github.com/charmbracelet/bubbletea"
|
|
8
|
+
"github.com/charmbracelet/lipgloss"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type Layout struct {
|
|
12
|
+
HeaderHeight int
|
|
13
|
+
FooterHeight int
|
|
14
|
+
Width int
|
|
15
|
+
Height int
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type LogViewport struct {
|
|
19
|
+
Model viewport.Model
|
|
20
|
+
Content *strings.Builder
|
|
21
|
+
AutoScroll bool
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func NewLogViewport(width, height int) LogViewport {
|
|
25
|
+
vp := viewport.New(width, height)
|
|
26
|
+
vp.YPosition = 0
|
|
27
|
+
vp.HighPerformanceRendering = false
|
|
28
|
+
return LogViewport{
|
|
29
|
+
Model: vp,
|
|
30
|
+
Content: &strings.Builder{},
|
|
31
|
+
AutoScroll: true,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func (l *LogViewport) SetSize(width, height int) {
|
|
36
|
+
l.Model.Width = width
|
|
37
|
+
l.Model.Height = height
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func (l *LogViewport) WriteLine(line string) {
|
|
41
|
+
l.Content.WriteString(line + "\n")
|
|
42
|
+
l.Model.SetContent(l.Content.String())
|
|
43
|
+
if l.AutoScroll {
|
|
44
|
+
l.Model.GotoBottom()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func (l *LogViewport) Update(msg tea.Msg) (LogViewport, tea.Cmd) {
|
|
49
|
+
var cmd tea.Cmd
|
|
50
|
+
l.Model, cmd = l.Model.Update(msg)
|
|
51
|
+
return *l, cmd
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func (l *LogViewport) View() string {
|
|
55
|
+
return l.Model.View()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var (
|
|
59
|
+
BoxStyle = lipgloss.NewStyle().
|
|
60
|
+
Border(lipgloss.RoundedBorder()).
|
|
61
|
+
Padding(0, 1).
|
|
62
|
+
Margin(0, 1) // Reduced margin to save space
|
|
63
|
+
)
|
package/tui/vibepup-tui
CHANGED
|
Binary file
|
|
Binary file
|