debug mode, don't print to main window, rename go module and main window
This commit is contained in:
parent
8b80aa0fa9
commit
6cb61a7a32
|
|
@ -2,7 +2,8 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"anvillm/internal/debug"
|
||||
"anvillm/internal/backend"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
|
@ -133,7 +134,7 @@ func (b *Backend) CreateSession(ctx context.Context, cwd string) (backend.Sessio
|
|||
|
||||
sess.state = "idle"
|
||||
sess.output.Reset()
|
||||
log.Printf("[session %s] ready (pid=%d)", sess.ID(), sess.pid)
|
||||
debug.Log("[session %s] ready (pid=%d)", sess.ID(), sess.pid)
|
||||
|
||||
return sess, nil
|
||||
}
|
||||
|
|
@ -223,7 +224,7 @@ func (s *Session) reader() {
|
|||
n, err := s.ptmx.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Printf("[session %s] reader error: %v", s.id, err)
|
||||
debug.Log("[session %s] reader error: %v", s.id, err)
|
||||
}
|
||||
close(s.dataCh)
|
||||
// Reap the process
|
||||
|
|
@ -313,7 +314,7 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
s.state = "running"
|
||||
s.output.Reset()
|
||||
|
||||
log.Printf("[session %s] sending: %q", s.id, prompt)
|
||||
debug.Log("[session %s] sending: %q", s.id, prompt)
|
||||
if _, err := s.ptmx.Write([]byte(prompt + "\r")); err != nil {
|
||||
s.state = "idle"
|
||||
return "", fmt.Errorf("write failed: %w", err)
|
||||
|
|
@ -329,7 +330,7 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
|
||||
// Clean output
|
||||
result := s.cleaner.Clean(prompt, s.output.String())
|
||||
log.Printf("[session %s] response: %d bytes", s.id, len(result))
|
||||
debug.Log("[session %s] response: %d bytes", s.id, len(result))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -346,7 +347,6 @@ func (s *Session) waitForComplete(ctx context.Context, prompt string) error {
|
|||
return fmt.Errorf("session closed")
|
||||
}
|
||||
s.output.Write(data)
|
||||
log.Printf("[session %s] +%d bytes, total %d", s.id, len(data), s.output.Len())
|
||||
|
||||
if s.detector.IsComplete(prompt, s.output.String()) {
|
||||
// Drain any remaining data
|
||||
|
|
@ -357,7 +357,7 @@ func (s *Session) waitForComplete(ctx context.Context, prompt string) error {
|
|||
s.output.Write(extra)
|
||||
}
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
log.Printf("[session %s] response complete, %d bytes", s.id, s.output.Len())
|
||||
debug.Log("[session %s] response complete, %d bytes", s.id, s.output.Len())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package tmux
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/debug"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -110,7 +110,7 @@ func (s *Session) reader() {
|
|||
if err != nil {
|
||||
// Only log unexpected errors (not EOF or closed file during shutdown)
|
||||
if err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
|
||||
log.Printf("[session %s] reader error: %v", s.id, err)
|
||||
debug.Log("[session %s] reader error: %v", s.id, err)
|
||||
}
|
||||
close(s.dataCh)
|
||||
s.mu.Lock()
|
||||
|
|
@ -141,19 +141,17 @@ func (s *Session) waitForReady(ctx context.Context, timeout time.Duration) error
|
|||
}
|
||||
s.output.Write(data)
|
||||
|
||||
log.Printf("[session %s] startup: %d bytes accumulated", s.id, s.output.Len())
|
||||
|
||||
// If we have a startup handler and it hasn't completed, call it
|
||||
if !startupDone && s.startupHandler != nil {
|
||||
keys, done := s.startupHandler.HandleStartup(s.output.String())
|
||||
if keys != "" {
|
||||
log.Printf("[session %s] startup handler sending keys: %q", s.id, keys)
|
||||
debug.Log("[session %s] startup handler sending keys: %q", s.id, keys)
|
||||
if err := sendKeys(s.target(), keys); err != nil {
|
||||
return fmt.Errorf("failed to send startup response: %w", err)
|
||||
}
|
||||
}
|
||||
if done {
|
||||
log.Printf("[session %s] startup handler complete", s.id)
|
||||
debug.Log("[session %s] startup handler complete", s.id)
|
||||
startupDone = true
|
||||
s.output.Reset() // Reset output after startup handling
|
||||
}
|
||||
|
|
@ -161,12 +159,12 @@ func (s *Session) waitForReady(ctx context.Context, timeout time.Duration) error
|
|||
|
||||
// Check if ready (only after startup is done)
|
||||
if startupDone && s.detector.IsReady(s.output.String()) {
|
||||
log.Printf("[session %s] ready detected", s.id)
|
||||
debug.Log("[session %s] ready detected", s.id)
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Until(deadline)):
|
||||
if time.Now().After(deadline) {
|
||||
log.Printf("[session %s] timeout, current output: %s", s.id, s.output.String())
|
||||
debug.Log("[session %s] timeout, current output: %s", s.id, s.output.String())
|
||||
return fmt.Errorf("timeout waiting for ready")
|
||||
}
|
||||
}
|
||||
|
|
@ -214,7 +212,7 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
// Release lock during long-running operations so state can be read
|
||||
s.mu.Unlock()
|
||||
|
||||
log.Printf("[session %s] sending: %q", s.id, prompt)
|
||||
debug.Log("[session %s] sending: %q", s.id, prompt)
|
||||
|
||||
// Send prompt using literal mode to avoid special character interpretation
|
||||
if err := sendLiteral(s.target(), prompt); err != nil {
|
||||
|
|
@ -250,9 +248,9 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
rawLen := s.output.Len()
|
||||
rawOutput := s.output.String()
|
||||
result := s.cleaner.Clean(prompt, rawOutput)
|
||||
log.Printf("[session %s] raw: %d bytes, cleaned: %d bytes", s.id, rawLen, len(result))
|
||||
debug.Log("[session %s] raw: %d bytes, cleaned: %d bytes", s.id, rawLen, len(result))
|
||||
if len(result) == 0 && rawLen > 0 {
|
||||
log.Printf("[session %s] WARNING: cleaner returned 0 bytes", s.id)
|
||||
debug.Log("[session %s] WARNING: cleaner returned 0 bytes", s.id)
|
||||
// Debug: show first and last 500 chars of raw output
|
||||
debugFirst := rawOutput
|
||||
if len(debugFirst) > 500 {
|
||||
|
|
@ -262,13 +260,13 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
if len(debugLast) > 500 {
|
||||
debugLast = debugLast[len(debugLast)-500:]
|
||||
}
|
||||
log.Printf("[session %s] DEBUG raw output (first 500 chars): %q", s.id, debugFirst)
|
||||
log.Printf("[session %s] DEBUG raw output (last 500 chars): %q", s.id, debugLast)
|
||||
debug.Log("[session %s] DEBUG raw output (first 500 chars): %q", s.id, debugFirst)
|
||||
debug.Log("[session %s] DEBUG raw output (last 500 chars): %q", s.id, debugLast)
|
||||
|
||||
// Check for key markers (simple check, no ANSI stripping)
|
||||
hasBullet := strings.Contains(rawOutput, "●")
|
||||
hasThinking := strings.Contains(rawOutput, "(esc to interrupt)") || strings.Contains(rawOutput, "∴")
|
||||
log.Printf("[session %s] DEBUG markers: hasBullet=%v, hasThinking=%v", s.id, hasBullet, hasThinking)
|
||||
debug.Log("[session %s] DEBUG markers: hasBullet=%v, hasThinking=%v", s.id, hasBullet, hasThinking)
|
||||
|
||||
// Find where the bullet is
|
||||
if hasBullet {
|
||||
|
|
@ -281,7 +279,7 @@ func (s *Session) Send(ctx context.Context, prompt string) (string, error) {
|
|||
if end > len(rawOutput) {
|
||||
end = len(rawOutput)
|
||||
}
|
||||
log.Printf("[session %s] DEBUG bullet context: %q", s.id, rawOutput[start:end])
|
||||
debug.Log("[session %s] DEBUG bullet context: %q", s.id, rawOutput[start:end])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +298,6 @@ func (s *Session) waitForComplete(ctx context.Context, prompt string) error {
|
|||
return fmt.Errorf("session closed")
|
||||
}
|
||||
s.output.Write(data)
|
||||
log.Printf("[session %s] +%d bytes, total %d", s.id, len(data), s.output.Len())
|
||||
|
||||
if s.detector.IsComplete(prompt, s.output.String()) {
|
||||
// Drain any remaining data
|
||||
|
|
@ -311,7 +308,7 @@ func (s *Session) waitForComplete(ctx context.Context, prompt string) error {
|
|||
s.output.Write(extra)
|
||||
}
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
log.Printf("[session %s] response complete, %d bytes", s.id, s.output.Len())
|
||||
debug.Log("[session %s] response complete, %d bytes", s.id, s.output.Len())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -352,14 +349,14 @@ func (s *Session) Close() error {
|
|||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
log.Printf("[session %s] Close() called, killing window %s:%s", s.id, s.tmuxSession, s.windowName)
|
||||
debug.Log("[session %s] Close() called, killing window %s:%s", s.id, s.tmuxSession, s.windowName)
|
||||
|
||||
// 1. Kill tmux window first (closes pipe-pane writer)
|
||||
if s.tmuxSession != "" && s.windowName != "" {
|
||||
if err := killWindow(s.tmuxSession, s.windowName); err != nil {
|
||||
log.Printf("[session %s] killWindow failed: %v", s.id, err)
|
||||
debug.Log("[session %s] killWindow failed: %v", s.id, err)
|
||||
} else {
|
||||
log.Printf("[session %s] Window %s:%s killed", s.id, s.tmuxSession, s.windowName)
|
||||
debug.Log("[session %s] Window %s:%s killed", s.id, s.tmuxSession, s.windowName)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
package tmux
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/debug"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
|
@ -84,7 +84,7 @@ func (b *Backend) ensureTmuxSession() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[backend %s] creating persistent tmux session: %s", b.cfg.Name, b.tmuxSession)
|
||||
debug.Log("[backend %s] creating persistent tmux session: %s", b.cfg.Name, b.tmuxSession)
|
||||
// Keep window 0 alive to hold the session open
|
||||
// It will be killed when the program exits
|
||||
return createSession(b.tmuxSession, b.cfg.TmuxSize.Rows, b.cfg.TmuxSize.Cols)
|
||||
|
|
@ -93,7 +93,7 @@ func (b *Backend) ensureTmuxSession() error {
|
|||
// Cleanup kills the persistent tmux session (call on program exit)
|
||||
func (b *Backend) Cleanup() error {
|
||||
if sessionExists(b.tmuxSession) {
|
||||
log.Printf("[backend %s] cleaning up tmux session: %s", b.cfg.Name, b.tmuxSession)
|
||||
debug.Log("[backend %s] cleaning up tmux session: %s", b.cfg.Name, b.tmuxSession)
|
||||
return killSession(b.tmuxSession)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -107,7 +107,7 @@ func (b *Backend) CreateSession(ctx context.Context, cwd string) (backend.Sessio
|
|||
id := fmt.Sprintf("%d", atomic.AddUint64(&b.counter, 1))
|
||||
windowName := id // Use session ID as window name
|
||||
|
||||
log.Printf("[session %s] creating window in tmux session %s", id, b.tmuxSession)
|
||||
debug.Log("[session %s] creating window in tmux session %s", id, b.tmuxSession)
|
||||
|
||||
// 1. Ensure persistent tmux session exists
|
||||
if err := b.ensureTmuxSession(); err != nil {
|
||||
|
|
@ -204,7 +204,7 @@ func (b *Backend) CreateSession(ctx context.Context, cwd string) (backend.Sessio
|
|||
// 9. Get PID
|
||||
pid, err := getPanePID(target)
|
||||
if err != nil {
|
||||
log.Printf("[session %s] warning: failed to get PID: %v", id, err)
|
||||
debug.Log("[session %s] warning: failed to get PID: %v", id, err)
|
||||
pid = 0
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ func (b *Backend) CreateSession(ctx context.Context, cwd string) (backend.Sessio
|
|||
|
||||
sess.state = "idle"
|
||||
sess.output.Reset()
|
||||
log.Printf("[session %s] ready (tmux=%s:%s, pid=%d)", sess.ID(), b.tmuxSession, windowName, sess.pid)
|
||||
debug.Log("[session %s] ready (tmux=%s:%s, pid=%d)", sess.ID(), b.tmuxSession, windowName, sess.pid)
|
||||
|
||||
return sess, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
package backends
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"acme-q/internal/backend/tmux"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
package backends
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"acme-q/internal/backend/tmux"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"anvillm/internal/debug"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
|
@ -413,7 +413,7 @@ func SaveWithSmartFilename(sess backend.Session, id string, bodyText string) (st
|
|||
|
||||
smartPath, err := GenerateSmartFilename(tempPath, bodyText)
|
||||
if err != nil {
|
||||
log.Printf("[session %s] Smart filename failed: %v, keeping %s", id, err, tempPath)
|
||||
debug.Log("[session %s] Smart filename failed: %v, keeping %s", id, err, tempPath)
|
||||
return tempPath, nil
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +421,7 @@ func SaveWithSmartFilename(sess backend.Session, id string, bodyText string) (st
|
|||
if err := os.Rename(tempPath, smartPath); err == nil {
|
||||
return smartPath, nil
|
||||
} else {
|
||||
log.Printf("[session %s] Rename failed: %v", id, err)
|
||||
debug.Log("[session %s] Rename failed: %v", id, err)
|
||||
return tempPath, nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package debug
|
||||
|
||||
import "log"
|
||||
|
||||
// Enabled controls whether debug logs are printed
|
||||
var Enabled = false
|
||||
|
||||
// Log prints a log message only when debug mode is enabled
|
||||
func Log(format string, args ...interface{}) {
|
||||
if Enabled {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
package p9
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"acme-q/internal/backend/tmux"
|
||||
"acme-q/internal/backends"
|
||||
"acme-q/internal/session"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"anvillm/internal/backends"
|
||||
"anvillm/internal/session"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"anvillm/internal/backend"
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
|
|
|||
86
main.go
86
main.go
|
|
@ -2,11 +2,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"acme-q/internal/backend"
|
||||
"acme-q/internal/backend/tmux"
|
||||
"acme-q/internal/backends"
|
||||
"acme-q/internal/p9"
|
||||
"acme-q/internal/session"
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"anvillm/internal/backends"
|
||||
"anvillm/internal/debug"
|
||||
"anvillm/internal/p9"
|
||||
"anvillm/internal/session"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
|
@ -23,7 +24,7 @@ import (
|
|||
"9fans.net/go/acme"
|
||||
)
|
||||
|
||||
const windowName = "/Q/"
|
||||
const windowName = "/AnviLLM/"
|
||||
|
||||
// Terminal to use for tmux attach (configurable)
|
||||
// Common options: "foot", "kitty", "xterm", "st", "alacritty"
|
||||
|
|
@ -46,10 +47,10 @@ func main() {
|
|||
switch backendName {
|
||||
case "claude":
|
||||
backend = backends.NewClaude()
|
||||
log.Printf("Using claude backend")
|
||||
debug.Log("Using claude backend")
|
||||
case "kiro-cli":
|
||||
backend = backends.NewKiroCLI()
|
||||
log.Printf("Using kiro-cli backend")
|
||||
debug.Log("Using kiro-cli backend")
|
||||
default:
|
||||
log.Fatalf("Unknown backend: %s (available: kiro-cli, claude)", backendName)
|
||||
}
|
||||
|
|
@ -127,47 +128,47 @@ func main() {
|
|||
|
||||
switch cmd {
|
||||
case "New":
|
||||
// Use current directory if no path specified
|
||||
cwd := arg
|
||||
if cwd == "" {
|
||||
cwd, _ = os.Getwd()
|
||||
// Require path argument
|
||||
if arg == "" {
|
||||
fmt.Fprintf(os.Stderr, "Error: New requires a path argument\n")
|
||||
continue
|
||||
}
|
||||
sess, err := mgr.New(cwd)
|
||||
sess, err := mgr.New(arg)
|
||||
if err != nil {
|
||||
w.Fprintf("body", "Error: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
_, err = openChatWindow(sess)
|
||||
if err != nil {
|
||||
w.Fprintf("body", "Error opening chat: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Error opening chat: %v\n", err)
|
||||
continue
|
||||
}
|
||||
// WinID is set inside openChatWindow
|
||||
refreshList(w, mgr)
|
||||
case "Open":
|
||||
if arg == "" {
|
||||
w.Fprintf("body", "Usage: Open <session-id>\n")
|
||||
fmt.Fprintf(os.Stderr, "Usage: Open <session-id>\n")
|
||||
continue
|
||||
}
|
||||
sess := mgr.Get(arg)
|
||||
if sess == nil {
|
||||
w.Fprintf("body", "Session not found: %s\n", arg)
|
||||
fmt.Fprintf(os.Stderr, "Session not found: %s\n", arg)
|
||||
continue
|
||||
}
|
||||
_, err := openChatWindow(sess)
|
||||
if err != nil {
|
||||
w.Fprintf("body", "Error opening chat: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Error opening chat: %v\n", err)
|
||||
continue
|
||||
}
|
||||
// WinID is set inside openChatWindow
|
||||
case "Kill":
|
||||
if arg == "" {
|
||||
w.Fprintf("body", "Usage: Kill <pid>\n")
|
||||
fmt.Fprintf(os.Stderr, "Usage: Kill <pid>\n")
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(arg)
|
||||
if err != nil {
|
||||
w.Fprintf("body", "Invalid pid: %s\n", arg)
|
||||
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", arg)
|
||||
continue
|
||||
}
|
||||
// Find session by pid and kill it
|
||||
|
|
@ -178,9 +179,9 @@ func main() {
|
|||
if meta.Pid == pid {
|
||||
// First kill the process
|
||||
if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
|
||||
log.Printf("[session %s] Failed to kill PID %d: %v", id, pid, err)
|
||||
debug.Log("[session %s] Failed to kill PID %d: %v", id, pid, err)
|
||||
} else {
|
||||
log.Printf("[session %s] Killed PID %d", id, pid)
|
||||
debug.Log("[session %s] Killed PID %d", id, pid)
|
||||
}
|
||||
// Then close the tmux window
|
||||
sess.Close()
|
||||
|
|
@ -192,22 +193,23 @@ func main() {
|
|||
refreshList(w, mgr)
|
||||
case "Get":
|
||||
refreshList(w, mgr)
|
||||
case "Debug":
|
||||
debug.Enabled = !debug.Enabled
|
||||
state := "disabled"
|
||||
if debug.Enabled {
|
||||
state = "enabled"
|
||||
}
|
||||
fmt.Printf("Debug mode %s\n", state)
|
||||
case "Login":
|
||||
cmd := exec.Command("firefox")
|
||||
cmd.Start()
|
||||
cmd = exec.Command("foot", "-e", "q", "login")
|
||||
log.Printf("starting terminal, pid will follow")
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("terminal start error: %v", err)
|
||||
} else {
|
||||
log.Printf("terminal started, pid=%d", cmd.Process.Pid)
|
||||
}
|
||||
cmd.Start()
|
||||
default:
|
||||
w.WriteEvent(e)
|
||||
}
|
||||
case 'l', 'L':
|
||||
text := strings.TrimSpace(string(e.Text))
|
||||
log.Printf("[/Q/] Look: text=%q", text)
|
||||
if sess := mgr.Get(text); sess != nil {
|
||||
// Try to focus existing window, or open new one
|
||||
meta := sess.Metadata()
|
||||
|
|
@ -315,9 +317,9 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
case "Stop":
|
||||
ctx := context.Background()
|
||||
if err := sess.Stop(ctx); err != nil {
|
||||
log.Printf("[session %s] Stop error: %v", sess.ID(), err)
|
||||
debug.Log("[session %s] Stop error: %v", sess.ID(), err)
|
||||
} else {
|
||||
log.Printf("[session %s] Sent CTRL+C", sess.ID())
|
||||
debug.Log("[session %s] Sent CTRL+C", sess.ID())
|
||||
}
|
||||
case "Attach":
|
||||
// Attach to tmux window (only works for tmux-based backends)
|
||||
|
|
@ -330,23 +332,23 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
target := fmt.Sprintf("%s:%s", tmuxSession, tmuxWindow)
|
||||
cmd := exec.Command(terminalCommand, "-e", "tmux", "attach", "-t", target)
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("[session %s] Failed to launch terminal: %v", sess.ID(), err)
|
||||
debug.Log("[session %s] Failed to launch terminal: %v", sess.ID(), err)
|
||||
} else {
|
||||
log.Printf("[session %s] Launched terminal attached to window: %s", sess.ID(), target)
|
||||
debug.Log("[session %s] Launched terminal attached to window: %s", sess.ID(), target)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
log.Printf("[session %s] Attach not supported: not a tmux-based backend", sess.ID())
|
||||
debug.Log("[session %s] Attach not supported: not a tmux-based backend", sess.ID())
|
||||
}
|
||||
case "Alias":
|
||||
if arg == "" {
|
||||
log.Printf("[session %s] Usage: Alias <name>", sess.ID())
|
||||
debug.Log("[session %s] Usage: Alias <name>", sess.ID())
|
||||
continue
|
||||
}
|
||||
// Validate alias
|
||||
matched, _ := regexp.MatchString(`^[A-Za-z0-9_-]+$`, arg)
|
||||
if !matched {
|
||||
log.Printf("[session %s] Invalid alias: must match [A-Za-z0-9_-]+", sess.ID())
|
||||
debug.Log("[session %s] Invalid alias: must match [A-Za-z0-9_-]+", sess.ID())
|
||||
continue
|
||||
}
|
||||
sess.SetAlias(arg)
|
||||
|
|
@ -354,7 +356,7 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
meta := sess.Metadata()
|
||||
newName := filepath.Join(meta.Cwd, fmt.Sprintf("+Chat.%s", arg))
|
||||
w.Name(newName)
|
||||
log.Printf("[session %s] alias set to %s", sess.ID(), arg)
|
||||
debug.Log("[session %s] alias set to %s", sess.ID(), arg)
|
||||
case "Save":
|
||||
// Grab first part of window content for filename hints
|
||||
var bodyText string
|
||||
|
|
@ -376,10 +378,10 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
savePath, err = backends.SaveWithSmartFilename(sess, sess.ID(), bodyText)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("[session %s] Error saving: %v", sess.ID(), err)
|
||||
debug.Log("[session %s] Error saving: %v", sess.ID(), err)
|
||||
return
|
||||
}
|
||||
log.Printf("[session %s] Saved to %s", sess.ID(), savePath)
|
||||
debug.Log("[session %s] Saved to %s", sess.ID(), savePath)
|
||||
}()
|
||||
case "Sessions":
|
||||
openSessionsWindow(w, sess)
|
||||
|
|
@ -395,14 +397,14 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
func sendPrompt(w *acme.Win, sess backend.Session) {
|
||||
body, err := w.ReadAll("body")
|
||||
if err != nil {
|
||||
log.Printf("[session %s] Error reading body: %v", sess.ID(), err)
|
||||
debug.Log("[session %s] Error reading body: %v", sess.ID(), err)
|
||||
return
|
||||
}
|
||||
|
||||
content := string(body)
|
||||
idx := strings.LastIndex(content, "USER:")
|
||||
if idx < 0 {
|
||||
log.Printf("[session %s] No USER: section found", sess.ID())
|
||||
debug.Log("[session %s] No USER: section found", sess.ID())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +418,7 @@ func sendPrompt(w *acme.Win, sess backend.Session) {
|
|||
ctx := context.Background()
|
||||
response, err := sess.Send(ctx, prompt)
|
||||
if err != nil {
|
||||
log.Printf("[session %s] Error: %v", sess.ID(), err)
|
||||
debug.Log("[session %s] Error: %v", sess.ID(), err)
|
||||
} else {
|
||||
w.Fprintf("body", "%s\n", response)
|
||||
}
|
||||
|
|
|
|||
Reference in New Issue