9p: add s/idx — live session index for agent cooperation

Synthetic read-only file at ollie/s/idx. Each line is tab-separated:
  {id}	{state}	{cwd}	{backend}	{model}

Generated on demand from live session state so it's always current.
Enables agents to discover peers by cwd or name without polling
individual session files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-14 14:27:47 +02:00
parent d832965710
commit e176e7ef7f
1 changed files with 22 additions and 1 deletions

View File

@ -11,6 +11,7 @@
// pl/ (dir) plans
// s/ (dir) session directory
// new (r/w) read: KV template; write: create session
// idx (read) live index: name state cwd backend model (tab-separated)
// {session-id}/ rm -r to kill session; mv to rename
// ctl (write) session control: stop, kill, rn, compact, clear
// prompt (write) submit a prompt to the agent
@ -267,6 +268,8 @@ func (s *Server) pathType(path string) string {
return "dir"
case len(parts) == 2 && parts[0] == "s" && parts[1] == "new":
return "file"
case len(parts) == 2 && parts[0] == "s" && parts[1] == "idx":
return "file"
case len(parts) == 1 && parts[0] == "a":
return "dir"
case len(parts) == 1 && parts[0] == "p":
@ -526,6 +529,23 @@ func (s *Server) read(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
return s.readSlice(fc, content)
}
// s/idx is a live index of all sessions: name state cwd backend model.
if path == "/s/idx" {
var sb strings.Builder
s.mu.RLock()
for id, sess := range s.sessions {
sess.mu.RLock()
state := sess.core.State()
cwd := sess.core.CWD()
be := sess.core.BackendName()
model := sess.core.ModelName()
sess.mu.RUnlock()
fmt.Fprintf(&sb, "%s\t%s\t%s\t%s\t%s\n", id, state, cwd, be, model)
}
s.mu.RUnlock()
return s.readSlice(fc, []byte(sb.String()))
}
// backends is a static list of ollie-provided backends.
if path == "/backends" {
content := []byte(strings.Join(backend.Backends(), "\n") + "\n")
@ -1420,6 +1440,7 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte {
}
} else if path == "/s" {
dirs = append(dirs, makeDir("new", "/s/new", false, 0666))
dirs = append(dirs, makeDir("idx", "/s/idx", false, 0444))
s.mu.RLock()
for id := range s.sessions {
dirs = append(dirs, makeDir(id, "/s/"+id, true, plan9.DMDIR|0555))
@ -1517,7 +1538,7 @@ func (s *Server) makeStat(path string) plan9.Dir {
case "backend", "agent", "model", "cwd":
mode = 0666
default:
if path == "/backends" || path == "/help" {
if path == "/backends" || path == "/help" || path == "/s/idx" {
mode = 0444
} else if path == "/s/new" {
mode = 0666