rethink save/load
This commit is contained in:
parent
3f570e993e
commit
f104c6aa5e
|
|
@ -4,7 +4,6 @@ package backends
|
|||
import (
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"anvillm/internal/debug"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
|
@ -301,7 +300,7 @@ func stripANSI(s string) string {
|
|||
// SessionsDir returns the path to the sessions storage directory
|
||||
func SessionsDir() string {
|
||||
home, _ := os.UserHomeDir()
|
||||
dir := filepath.Join(home, ".config", "acme-q", "sessions")
|
||||
dir := filepath.Join(home, ".config", "anvillm", "sessions")
|
||||
os.MkdirAll(dir, 0755)
|
||||
return dir
|
||||
}
|
||||
|
|
@ -395,48 +394,8 @@ func contains(slice []string, item string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// SavePath returns the save file path for a session ID
|
||||
func SavePath(id string) string {
|
||||
return filepath.Join(SessionsDir(), id+".json")
|
||||
}
|
||||
|
||||
// SendCtl is a helper to send a control command to kiro-cli
|
||||
func SendCtl(sess backend.Session, cmd string) error {
|
||||
_, err := sess.Send(context.Background(), cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
// Save saves a session using kiro-cli's /chat save command
|
||||
func Save(sess backend.Session, id string) error {
|
||||
return SendCtl(sess, "/chat save "+SavePath(id))
|
||||
}
|
||||
|
||||
// Load loads a session using kiro-cli's /chat load command
|
||||
func Load(sess backend.Session, path string) error {
|
||||
return SendCtl(sess, "/chat load "+path)
|
||||
}
|
||||
|
||||
// SaveWithSmartFilename saves with a generated filename
|
||||
func SaveWithSmartFilename(sess backend.Session, id string, bodyText string) (string, error) {
|
||||
tempPath := SavePath(id)
|
||||
if err := SendCtl(sess, "/chat save "+tempPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
smartPath, err := GenerateSmartFilename(tempPath, bodyText)
|
||||
if err != nil {
|
||||
debug.Log("[session %s] Smart filename failed: %v, keeping %s", id, err, tempPath)
|
||||
return tempPath, nil
|
||||
}
|
||||
|
||||
if smartPath != tempPath {
|
||||
if err := os.Rename(tempPath, smartPath); err == nil {
|
||||
return smartPath, nil
|
||||
} else {
|
||||
debug.Log("[session %s] Rename failed: %v", id, err)
|
||||
return tempPath, nil
|
||||
}
|
||||
}
|
||||
|
||||
return smartPath, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ package p9
|
|||
import (
|
||||
"anvillm/internal/backend"
|
||||
"anvillm/internal/backend/tmux"
|
||||
"anvillm/internal/backends"
|
||||
"anvillm/internal/session"
|
||||
"context"
|
||||
"errors"
|
||||
|
|
@ -29,7 +28,7 @@ agent/
|
|||
ctl (write) "new <backend> <cwd>" creates session, returns id
|
||||
list (read) list sessions: "id state pid cwd"
|
||||
{session-id}/
|
||||
ctl (write) "save [path]", "load path", "kill"
|
||||
ctl (write) "stop", "kill"
|
||||
in (write) send prompt, blocks until response
|
||||
out (read) response from last prompt
|
||||
err (read) stderr/debug output
|
||||
|
|
@ -322,7 +321,7 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
}
|
||||
args := strings.Fields(input)
|
||||
if len(args) == 0 {
|
||||
return errFcall(fc, "usage: stop | save [path] | load path | kill")
|
||||
return errFcall(fc, "usage: stop | kill")
|
||||
}
|
||||
switch args[0] {
|
||||
case "stop":
|
||||
|
|
@ -330,21 +329,6 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
if err := sess.Stop(ctx); err != nil {
|
||||
return errFcall(fc, err.Error())
|
||||
}
|
||||
case "save":
|
||||
path := backends.SavePath(sess.ID())
|
||||
if len(args) > 1 {
|
||||
path = args[1]
|
||||
}
|
||||
if err := backends.SendCtl(sess, "/chat save "+path); err != nil {
|
||||
return errFcall(fc, err.Error())
|
||||
}
|
||||
case "load":
|
||||
if len(args) < 2 {
|
||||
return errFcall(fc, "load requires path")
|
||||
}
|
||||
if err := backends.Load(sess, args[1]); err != nil {
|
||||
return errFcall(fc, err.Error())
|
||||
}
|
||||
case "kill":
|
||||
sess.Close()
|
||||
s.mgr.Remove(sess.ID())
|
||||
|
|
|
|||
|
|
@ -3,9 +3,16 @@ package sandbox
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// pathEntry holds a path with its permission type
|
||||
type pathEntry struct {
|
||||
path string
|
||||
flag string // --ro, --rox, --rw, --rwx
|
||||
}
|
||||
|
||||
// WrapCommand wraps a command with landrun based on the configuration.
|
||||
// Returns the wrapped command args, or the original command if landrun is unavailable.
|
||||
func WrapCommand(cfg *Config, originalCmd []string, cwd string) []string {
|
||||
|
|
@ -44,38 +51,46 @@ func WrapCommand(cfg *Config, originalCmd []string, cwd string) []string {
|
|||
args = append(args, "--add-exec")
|
||||
}
|
||||
|
||||
// Filesystem permissions - RO (read-only, no execute)
|
||||
// Collect all filesystem paths
|
||||
var entries []pathEntry
|
||||
for _, path := range cfg.Filesystem.RO {
|
||||
expanded := expandPath(path, cwd, home, tmpdir)
|
||||
if pathExists(expanded) {
|
||||
args = append(args, "--ro", expanded)
|
||||
entries = append(entries, pathEntry{expanded, "--ro"})
|
||||
}
|
||||
}
|
||||
|
||||
// Filesystem permissions - ROX (read-only with execute)
|
||||
for _, path := range cfg.Filesystem.ROX {
|
||||
expanded := expandPath(path, cwd, home, tmpdir)
|
||||
if pathExists(expanded) {
|
||||
args = append(args, "--rox", expanded)
|
||||
entries = append(entries, pathEntry{expanded, "--rox"})
|
||||
}
|
||||
}
|
||||
|
||||
// Filesystem permissions - RW (read-write, no execute)
|
||||
for _, path := range cfg.Filesystem.RW {
|
||||
expanded := expandPath(path, cwd, home, tmpdir)
|
||||
if pathExists(expanded) {
|
||||
args = append(args, "--rw", expanded)
|
||||
entries = append(entries, pathEntry{expanded, "--rw"})
|
||||
}
|
||||
}
|
||||
|
||||
// Filesystem permissions - RWX (read-write with execute)
|
||||
for _, path := range cfg.Filesystem.RWX {
|
||||
expanded := expandPath(path, cwd, home, tmpdir)
|
||||
if pathExists(expanded) {
|
||||
args = append(args, "--rwx", expanded)
|
||||
entries = append(entries, pathEntry{expanded, "--rwx"})
|
||||
}
|
||||
}
|
||||
|
||||
// Sort paths so parents come before children (shorter paths first, then alphabetically)
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
if len(entries[i].path) != len(entries[j].path) {
|
||||
return len(entries[i].path) < len(entries[j].path)
|
||||
}
|
||||
return entries[i].path < entries[j].path
|
||||
})
|
||||
|
||||
// Add sorted paths to args
|
||||
for _, e := range entries {
|
||||
args = append(args, e.flag, e.path)
|
||||
}
|
||||
|
||||
// Network permissions
|
||||
if cfg.Network.Unrestricted {
|
||||
args = append(args, "--unrestricted-network")
|
||||
|
|
|
|||
28
main.go
28
main.go
|
|
@ -297,7 +297,7 @@ func openChatWindow(sess backend.Session) (*acme.Win, error) {
|
|||
return nil, err
|
||||
}
|
||||
w.Name(name)
|
||||
w.Write("tag", []byte("Send Stop Attach Alias Save Sessions "))
|
||||
w.Write("tag", []byte("Send Stop Attach Alias Sessions "))
|
||||
w.Fprintf("body", "# Session %s\n# cwd: %s\n\nUSER:\n", sess.ID(), meta.Cwd)
|
||||
w.Ctl("clean")
|
||||
|
||||
|
|
@ -372,32 +372,6 @@ func handleChatWindow(w *acme.Win, sess backend.Session) {
|
|||
newName := filepath.Join(meta.Cwd, fmt.Sprintf("+Chat.%s", arg))
|
||||
w.Name(newName)
|
||||
fmt.Printf("Alias set to %s\n", arg)
|
||||
case "Save":
|
||||
// Grab first part of window content for filename hints
|
||||
var bodyText string
|
||||
if body, err := w.ReadAll("body"); err == nil && len(body) > 0 {
|
||||
if len(body) > 500 {
|
||||
body = body[:500]
|
||||
}
|
||||
bodyText = string(body)
|
||||
}
|
||||
go func() {
|
||||
var savePath string
|
||||
var err error
|
||||
if arg != "" {
|
||||
// Save to explicit path
|
||||
savePath = arg
|
||||
err = backends.SendCtl(sess, "/chat save "+savePath)
|
||||
} else {
|
||||
// Save with smart filename
|
||||
savePath, err = backends.SaveWithSmartFilename(sess, sess.ID(), bodyText)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error saving: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Saved to %s\n", savePath)
|
||||
}()
|
||||
case "Sessions":
|
||||
openSessionsWindow(w, sess)
|
||||
default:
|
||||
|
|
|
|||
Reference in New Issue