From 56f9daf13c5c7cd34ce207b1cd16efcfe52a5fad Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Mon, 13 Apr 2026 13:08:15 +0200 Subject: [PATCH] 9p: implement Tremove for /p, /sk, /t Allows rm on files under the prompts, skills, and tools directories. Skills remove the entire skill directory (including SKILL.md). Other paths still return 'remove not supported'. --- internal/p9/server.go | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/internal/p9/server.go b/internal/p9/server.go index 2dadb26..02f62e7 100644 --- a/internal/p9/server.go +++ b/internal/p9/server.go @@ -166,7 +166,7 @@ func (s *Server) handle(cs *connState, fc *plan9.Fcall) *plan9.Fcall { case plan9.Tclunk: return s.clunk(cs, fc) case plan9.Tremove: - return errFcall(fc, "remove not supported") + return s.remove(cs, fc) default: return errFcall(fc, "unsupported operation") } @@ -722,6 +722,41 @@ func (s *Server) clunk(cs *connState, fc *plan9.Fcall) *plan9.Fcall { return &plan9.Fcall{Type: plan9.Rclunk, Tag: fc.Tag} } +func (s *Server) remove(cs *connState, fc *plan9.Fcall) *plan9.Fcall { + cs.mu.Lock() + f, ok := cs.fids[fc.Fid] + if ok { + delete(cs.fids, fc.Fid) + } + cs.mu.Unlock() + if !ok { + return errFcall(fc, "bad fid") + } + + path := f.path + var err error + switch { + case strings.HasPrefix(path, "/p/"): + err = os.Remove(s.promptsDir + "/" + pathBase(path)) + case strings.HasPrefix(path, "/sk/"): + name := strings.TrimSuffix(pathBase(path), ".md") + for _, m := range skills.List() { + if m.Name == name { + err = os.RemoveAll(m.Dir) + break + } + } + case strings.HasPrefix(path, "/t/"): + err = os.Remove(execute.ToolsPath() + "/" + pathBase(path)) + default: + return errFcall(fc, "remove not supported") + } + if err != nil { + return errFcall(fc, err.Error()) + } + return &plan9.Fcall{Type: plan9.Rremove, Tag: fc.Tag} +} + // handleWrite processes a fully-assembled write payload for the given path. // Called asynchronously from clunk. func (s *Server) handleWrite(path, input string) {