rename EDSL constructors for clarity
- Leaf → FileNode (file node) - Dir → DirNode (directory node) - Blueprint → Dynamic (state-dependent directory) The names now clearly indicate what they create: - FileNode: a file - DirNode: a directory - Dynamic: a directory whose children depend on runtime state
This commit is contained in:
parent
99e88ef407
commit
7c6dff4a01
|
|
@ -5,11 +5,11 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
// TestBlueprintBasic tests the basic Blueprint pattern:
|
||||
// TestDynamicBasic tests the basic Blueprint pattern:
|
||||
// - Declares structure statically
|
||||
// - Instances function provides identity (name, aliases, UID/GID)
|
||||
// - Handlers receive context with bound data
|
||||
func TestBlueprintBasic(t *testing.T) {
|
||||
func TestDynamicBasic(t *testing.T) {
|
||||
// Test data that instances will bind to ctx
|
||||
type testData struct {
|
||||
ID string
|
||||
|
|
@ -22,8 +22,8 @@ func TestBlueprintBasic(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a Blueprint with static structure and dynamic instances
|
||||
spec := Dir("/",
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
var out []Instance
|
||||
for _, d := range instances {
|
||||
data := d // capture
|
||||
|
|
@ -36,10 +36,10 @@ func TestBlueprintBasic(t *testing.T) {
|
|||
}
|
||||
return out, nil
|
||||
},
|
||||
Leaf("id", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("id", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("test-id\n"), nil
|
||||
})),
|
||||
Leaf("name", 0666,
|
||||
FileNode("name", 0666,
|
||||
Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("test-name\n"), nil
|
||||
}),
|
||||
|
|
@ -138,8 +138,8 @@ func TestBlueprintBasic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintNestedStructure tests nested Blueprint nodes
|
||||
func TestBlueprintNestedStructure(t *testing.T) {
|
||||
// TestDynamicNestedStructure tests nested Blueprint nodes
|
||||
func TestDynamicNestedStructure(t *testing.T) {
|
||||
// Outer instances (like sessions)
|
||||
outerInstances := []struct {
|
||||
ID string
|
||||
|
|
@ -157,8 +157,8 @@ func TestBlueprintNestedStructure(t *testing.T) {
|
|||
{ID: "agent-b", Name: "agentB"},
|
||||
}
|
||||
|
||||
spec := Dir("/",
|
||||
Blueprint("{outer}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{outer}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
var out []Instance
|
||||
for _, d := range outerInstances {
|
||||
data := d
|
||||
|
|
@ -169,11 +169,11 @@ func TestBlueprintNestedStructure(t *testing.T) {
|
|||
}
|
||||
return out, nil
|
||||
},
|
||||
Leaf("outer-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("outer-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("outer\n"), nil
|
||||
})),
|
||||
Dir("inner-dir",
|
||||
Blueprint("{inner}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
DirNode("inner-dir",
|
||||
Dynamic("{inner}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
var out []Instance
|
||||
for _, d := range innerInstances {
|
||||
data := d
|
||||
|
|
@ -184,7 +184,7 @@ func TestBlueprintNestedStructure(t *testing.T) {
|
|||
}
|
||||
return out, nil
|
||||
},
|
||||
Leaf("inner-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("inner-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("inner\n"), nil
|
||||
})),
|
||||
),
|
||||
|
|
@ -230,13 +230,13 @@ func TestBlueprintNestedStructure(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintContextPropagation tests that context is properly propagated
|
||||
func TestBlueprintContextPropagation(t *testing.T) {
|
||||
// TestDynamicContextPropagation tests that context is properly propagated
|
||||
func TestDynamicContextPropagation(t *testing.T) {
|
||||
// Use a channel to capture the context value seen by the handler
|
||||
seen := make(chan string, 1)
|
||||
|
||||
spec := Dir("/",
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return []Instance{
|
||||
{
|
||||
Name: "test-instance",
|
||||
|
|
@ -245,7 +245,7 @@ func TestBlueprintContextPropagation(t *testing.T) {
|
|||
},
|
||||
}, nil
|
||||
},
|
||||
Leaf("check", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("check", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
seen <- "handler-called"
|
||||
return []byte("ok\n"), nil
|
||||
})),
|
||||
|
|
@ -273,16 +273,16 @@ func TestBlueprintContextPropagation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintUIDGIDInheritance tests UID/GID resolution
|
||||
func TestBlueprintUIDGIDInheritance(t *testing.T) {
|
||||
spec := Dir("/", UID("root-uid"), GID("root-gid"),
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
// TestDynamicUIDGIDInheritance tests UID/GID resolution
|
||||
func TestDynamicUIDGIDInheritance(t *testing.T) {
|
||||
spec := DirNode("/", UID("root-uid"), GID("root-gid"),
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return []Instance{
|
||||
{Name: "with-uid", UID: "custom-uid", GID: "custom-gid"},
|
||||
{Name: "without-uid"}, // should inherit
|
||||
}, nil
|
||||
},
|
||||
Leaf("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("data\n"), nil
|
||||
})),
|
||||
),
|
||||
|
|
@ -324,12 +324,12 @@ func TestBlueprintUIDGIDInheritance(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintRename tests the rename callback on instances
|
||||
func TestBlueprintRename(t *testing.T) {
|
||||
// TestDynamicRename tests the rename callback on instances
|
||||
func TestDynamicRename(t *testing.T) {
|
||||
renamed := ""
|
||||
|
||||
spec := Dir("/",
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return []Instance{
|
||||
{
|
||||
Name: "original",
|
||||
|
|
@ -340,7 +340,7 @@ func TestBlueprintRename(t *testing.T) {
|
|||
},
|
||||
}, nil
|
||||
},
|
||||
Leaf("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("data\n"), nil
|
||||
})),
|
||||
),
|
||||
|
|
@ -359,13 +359,13 @@ func TestBlueprintRename(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintEmptyInstances tests behavior when no instances exist
|
||||
func TestBlueprintEmptyInstances(t *testing.T) {
|
||||
spec := Dir("/",
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
// TestDynamicEmptyInstances tests behavior when no instances exist
|
||||
func TestDynamicEmptyInstances(t *testing.T) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return nil, nil // empty
|
||||
},
|
||||
Leaf("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("data\n"), nil
|
||||
})),
|
||||
),
|
||||
|
|
@ -389,24 +389,24 @@ func TestBlueprintEmptyInstances(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintMixedStaticAndDynamic tests Blueprint alongside static children
|
||||
func TestBlueprintMixedStaticAndDynamic(t *testing.T) {
|
||||
spec := Dir("/",
|
||||
Leaf("static-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
// TestDynamicMixedStaticAndDynamic tests Blueprint alongside static children
|
||||
func TestDynamicMixedStaticAndDynamic(t *testing.T) {
|
||||
spec := DirNode("/",
|
||||
FileNode("static-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("static\n"), nil
|
||||
})),
|
||||
Dir("static-dir",
|
||||
Leaf("nested", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
DirNode("static-dir",
|
||||
FileNode("nested", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("nested-static\n"), nil
|
||||
})),
|
||||
),
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return []Instance{
|
||||
{Name: "dynamic1"},
|
||||
{Name: "dynamic2"},
|
||||
}, nil
|
||||
},
|
||||
Leaf("dynamic-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("dynamic-file", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("dynamic\n"), nil
|
||||
})),
|
||||
),
|
||||
|
|
@ -453,16 +453,16 @@ func TestBlueprintMixedStaticAndDynamic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlueprintStatMode tests that blueprint instances get correct file mode
|
||||
func TestBlueprintStatMode(t *testing.T) {
|
||||
spec := Dir("/",
|
||||
Blueprint("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
// TestDynamicStatMode tests that blueprint instances get correct file mode
|
||||
func TestDynamicStatMode(t *testing.T) {
|
||||
spec := DirNode("/",
|
||||
Dynamic("{id}", func(ctx HandlerCtx) ([]Instance, error) {
|
||||
return []Instance{{Name: "instance"}}, nil
|
||||
},
|
||||
Leaf("readable", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("readable", 0444, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("r\n"), nil
|
||||
})),
|
||||
Leaf("writable", 0666,
|
||||
FileNode("writable", 0666,
|
||||
Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("rw\n"), nil
|
||||
}),
|
||||
|
|
@ -470,7 +470,7 @@ func TestBlueprintStatMode(t *testing.T) {
|
|||
return nil
|
||||
}),
|
||||
),
|
||||
Leaf("executable", 0555, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
FileNode("executable", 0555, Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte("#!/bin/sh\n"), nil
|
||||
})),
|
||||
),
|
||||
20
fs/fsnode.go
20
fs/fsnode.go
|
|
@ -166,8 +166,8 @@ type NodeOption func(*FsNodeDecl)
|
|||
|
||||
// ── EDSL constructors ────────────────────────────────────────────
|
||||
|
||||
// Dir declares a static directory node, optionally with NodeOptions (GID, UID).
|
||||
func Dir(name string, args ...any) FsNodeDecl {
|
||||
// DirNode declares a static directory node, optionally with NodeOptions (GID, UID).
|
||||
func DirNode(name string, args ...any) FsNodeDecl {
|
||||
d := FsNodeDecl{Name: name}
|
||||
for _, a := range args {
|
||||
switch v := a.(type) {
|
||||
|
|
@ -182,22 +182,22 @@ func Dir(name string, args ...any) FsNodeDecl {
|
|||
|
||||
// TemplateDir declares a dynamic directory node whose children are
|
||||
// resolved at runtime by list. The list function is a factory that
|
||||
// returns fully-built subtrees — no blueprint children needed here.
|
||||
// returns fully-built subtrees — no Dynamic children needed here.
|
||||
func TemplateDir(name string, list ListFn) FsNodeDecl {
|
||||
return FsNodeDecl{Name: name, List: list}
|
||||
}
|
||||
|
||||
// Blueprint declares a directory template with static structure.
|
||||
// Dynamic declares a state-dependent directory with static structure.
|
||||
// The instances function returns identity info for each instance;
|
||||
// handlers access instance data via ctx.Session/ctx.Agent/ctx.AgentLog.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Blueprint("{id}", sessionInstances,
|
||||
// Leaf("name", 0666, Read(readSessionName), Write(writeSessionName)),
|
||||
// Leaf("state", 0444, Read(readSessionState)),
|
||||
// Dynamic("{id}", sessionInstances,
|
||||
// FileNode("name", 0666, Read(readSessionName), Write(writeSessionName)),
|
||||
// FileNode("state", 0444, Read(readSessionState)),
|
||||
// )
|
||||
func Blueprint(name string, instances InstanceFn, args ...any) FsNodeDecl {
|
||||
func Dynamic(name string, instances InstanceFn, args ...any) FsNodeDecl {
|
||||
d := FsNodeDecl{Name: name, Instances: instances}
|
||||
for _, a := range args {
|
||||
switch v := a.(type) {
|
||||
|
|
@ -210,8 +210,8 @@ func Blueprint(name string, instances InstanceFn, args ...any) FsNodeDecl {
|
|||
return d
|
||||
}
|
||||
|
||||
// Leaf declares a file node (non-directory).
|
||||
func Leaf(name string, mode os.FileMode, opts ...NodeOption) FsNodeDecl {
|
||||
// FileNode declares a file node (non-directory).
|
||||
func FileNode(name string, mode os.FileMode, opts ...NodeOption) FsNodeDecl {
|
||||
d := FsNodeDecl{Name: name, Mode: mode}
|
||||
for _, o := range opts {
|
||||
o(&d)
|
||||
|
|
|
|||
108
fs/spec.go
108
fs/spec.go
|
|
@ -27,30 +27,30 @@ import (
|
|||
|
||||
var treeSpecUID, treeSpecGID string
|
||||
|
||||
var treeSpec = Dir("/",
|
||||
var treeSpec = DirNode("/",
|
||||
// Root ownership: UID/GID set at NewRoot() time.
|
||||
// Every child inherits from root unless overridden.
|
||||
|
||||
// ── Root-level files (owned by system user, group "agent") ──
|
||||
Leaf("backends", 0444, Read(readBackends), GID("agent")),
|
||||
Leaf("help", 0444, Read(readHelp), GID("agent")),
|
||||
Leaf("models", 0444, Read(readModels), GID("agent")),
|
||||
Leaf("agents", 0444, Read(readAgents), GID("agent")),
|
||||
Leaf("tools", 0444, Read(readTools), GID("agent")),
|
||||
Leaf("ctl", 0666, Write(writeRootCtl), GID("agent")),
|
||||
Leaf("eventwait", 0444,
|
||||
FileNode("backends", 0444, Read(readBackends), GID("agent")),
|
||||
FileNode("help", 0444, Read(readHelp), GID("agent")),
|
||||
FileNode("models", 0444, Read(readModels), GID("agent")),
|
||||
FileNode("agents", 0444, Read(readAgents), GID("agent")),
|
||||
FileNode("tools", 0444, Read(readTools), GID("agent")),
|
||||
FileNode("ctl", 0666, Write(writeRootCtl), GID("agent")),
|
||||
FileNode("eventwait", 0444,
|
||||
Read(readEventwait),
|
||||
Stream(blockEventwait),
|
||||
GID("agent"),
|
||||
),
|
||||
Leaf("complete", 0666, Request(requestComplete), GID("agent")),
|
||||
Leaf("generate", 0666, Request(requestGenerate), GID("agent")),
|
||||
Leaf("route", 0666, Request(requestRoute), GID("agent")),
|
||||
Leaf("aliases", 0444, Read(readAliases), GID("agent")),
|
||||
FileNode("complete", 0666, Request(requestComplete), GID("agent")),
|
||||
FileNode("generate", 0666, Request(requestGenerate), GID("agent")),
|
||||
FileNode("route", 0666, Request(requestRoute), GID("agent")),
|
||||
FileNode("aliases", 0444, Read(readAliases), GID("agent")),
|
||||
|
||||
// ── elevate/ (owned by system user, group "agent") ──────────
|
||||
Dir("elevate", GID("agent"),
|
||||
Leaf("policy", 0666,
|
||||
DirNode("elevate", GID("agent"),
|
||||
FileNode("policy", 0666,
|
||||
Read(readElevatePolicy),
|
||||
Write(writeElevatePolicy),
|
||||
),
|
||||
|
|
@ -59,66 +59,66 @@ var treeSpec = Dir("/",
|
|||
),
|
||||
|
||||
// ── session/ ────────────────────────────────────────────────
|
||||
Dir("session", GID("agent"),
|
||||
DirNode("session", GID("agent"),
|
||||
// session/new and session/idx are owned by system user
|
||||
Leaf("new", 0666, Request(requestSessionNew)),
|
||||
Leaf("idx", 0444, Read(readSessionIdx)),
|
||||
FileNode("new", 0666, Request(requestSessionNew)),
|
||||
FileNode("idx", 0444, Read(readSessionIdx)),
|
||||
|
||||
// {id} — dynamic per-session directory.
|
||||
// Handlers access session via ctx.Session.
|
||||
Blueprint("{id}", sessionInstances,
|
||||
Dynamic("{id}", sessionInstances,
|
||||
// env — session environment
|
||||
Leaf("env", 0444, Read(readSessionEnv)),
|
||||
FileNode("env", 0444, Read(readSessionEnv)),
|
||||
|
||||
// paused — session pause status
|
||||
Leaf("paused", 0444, Read(readSessionPaused)),
|
||||
FileNode("paused", 0444, Read(readSessionPaused)),
|
||||
|
||||
// connected — RPC connection status
|
||||
Leaf("connected", 0444, Read(readSessionConnected)),
|
||||
FileNode("connected", 0444, Read(readSessionConnected)),
|
||||
|
||||
// ctl — session control
|
||||
Leaf("ctl", 0666, Read(nopRead), Write(writeSessionCtl)),
|
||||
FileNode("ctl", 0666, Read(nopRead), Write(writeSessionCtl)),
|
||||
|
||||
// name — mutable session name
|
||||
Leaf("name", 0666, Read(readSessionName), Write(writeSessionName)),
|
||||
FileNode("name", 0666, Read(readSessionName), Write(writeSessionName)),
|
||||
|
||||
// id — immutable session ID
|
||||
Leaf("id", 0444, Read(readSessionID)),
|
||||
FileNode("id", 0444, Read(readSessionID)),
|
||||
|
||||
// elevate — session elevation policy
|
||||
Leaf("elevate", 0666, Read(readSessionElevate), Write(writeSessionElevate)),
|
||||
FileNode("elevate", 0666, Read(readSessionElevate), Write(writeSessionElevate)),
|
||||
|
||||
// agent/ — contains per-agent subdirectories
|
||||
Dir("agent",
|
||||
Leaf("new", 0666, Request(requestAgentNew)),
|
||||
DirNode("agent",
|
||||
FileNode("new", 0666, Request(requestAgentNew)),
|
||||
|
||||
// {aid} — dynamic per-agent directory.
|
||||
// Handlers access agent via ctx.Agent and ctx.AgentLog.
|
||||
Blueprint("{aid}", agentInstances,
|
||||
Leaf("prompt", 0666, Write(writeAgentPrompt)),
|
||||
Leaf("prompt.prev", 0444, Read(readAgentPromptPrev)),
|
||||
Leaf("fifo.in", 0222, Write(writeAgentFifoIn)),
|
||||
Leaf("fifo.out", 0444, Read(readAgentFifoOut)),
|
||||
Leaf("chat", 0444, Stat(statAgentChat), Read(readAgentChat), Stream(streamAgentChat)),
|
||||
Leaf("connection", 0444, Read(readAgentConnection)),
|
||||
Leaf("state", 0444, Read(readAgentState)),
|
||||
Leaf("statewait", 0444, Read(readAgentState), BlockOnce(blockAgentStateWait)),
|
||||
Leaf("log", 0444, Read(readAgentLog)),
|
||||
Leaf("offset", 0444, Read(readAgentOffset)),
|
||||
Leaf("plan", 0666, Read(readAgentPlan), Write(writeAgentPlan)),
|
||||
Leaf("cfg", 0666, Read(readAgentCfg), Write(writeAgentCfg)),
|
||||
Leaf("ctl", 0666, Write(writeAgentCtl)),
|
||||
Leaf("cwd", 0666, Read(readAgentCwd), Write(writeAgentCwd)),
|
||||
Leaf("usage", 0444, Read(readAgentUsage)),
|
||||
Leaf("cost", 0444, Read(readAgentCost)),
|
||||
Leaf("ctxsz", 0444, Read(readAgentCtxsz)),
|
||||
Leaf("models", 0444, Read(readAgentModels)),
|
||||
Leaf("systemprompt", 0444, Read(readAgentSystemprompt)),
|
||||
Leaf("context", 0444, Read(readAgentContext)),
|
||||
Leaf("tail", 0555, Read(readAgentTail)),
|
||||
Leaf("tools", 0666, Read(readAgentTools), Write(writeAgentTools)),
|
||||
Leaf("name", 0666, Read(readAgentName), Write(writeAgentName)),
|
||||
Leaf("id", 0444, Read(readAgentID)),
|
||||
Dynamic("{aid}", agentInstances,
|
||||
FileNode("prompt", 0666, Write(writeAgentPrompt)),
|
||||
FileNode("prompt.prev", 0444, Read(readAgentPromptPrev)),
|
||||
FileNode("fifo.in", 0222, Write(writeAgentFifoIn)),
|
||||
FileNode("fifo.out", 0444, Read(readAgentFifoOut)),
|
||||
FileNode("chat", 0444, Stat(statAgentChat), Read(readAgentChat), Stream(streamAgentChat)),
|
||||
FileNode("connection", 0444, Read(readAgentConnection)),
|
||||
FileNode("state", 0444, Read(readAgentState)),
|
||||
FileNode("statewait", 0444, Read(readAgentState), BlockOnce(blockAgentStateWait)),
|
||||
FileNode("log", 0444, Read(readAgentLog)),
|
||||
FileNode("offset", 0444, Read(readAgentOffset)),
|
||||
FileNode("plan", 0666, Read(readAgentPlan), Write(writeAgentPlan)),
|
||||
FileNode("cfg", 0666, Read(readAgentCfg), Write(writeAgentCfg)),
|
||||
FileNode("ctl", 0666, Write(writeAgentCtl)),
|
||||
FileNode("cwd", 0666, Read(readAgentCwd), Write(writeAgentCwd)),
|
||||
FileNode("usage", 0444, Read(readAgentUsage)),
|
||||
FileNode("cost", 0444, Read(readAgentCost)),
|
||||
FileNode("ctxsz", 0444, Read(readAgentCtxsz)),
|
||||
FileNode("models", 0444, Read(readAgentModels)),
|
||||
FileNode("systemprompt", 0444, Read(readAgentSystemprompt)),
|
||||
FileNode("context", 0444, Read(readAgentContext)),
|
||||
FileNode("tail", 0555, Read(readAgentTail)),
|
||||
FileNode("tools", 0666, Read(readAgentTools), Write(writeAgentTools)),
|
||||
FileNode("name", 0666, Read(readAgentName), Write(writeAgentName)),
|
||||
FileNode("id", 0444, Read(readAgentID)),
|
||||
|
||||
// proc/ — detached processes (still uses TemplateDir for simplicity)
|
||||
TemplateDir("proc", listProcesses),
|
||||
|
|
@ -310,7 +310,7 @@ func listElevatePending(ctx HandlerCtx) ([]FsNodeDecl, error) {
|
|||
out := make([]FsNodeDecl, len(pending))
|
||||
for i, r := range pending {
|
||||
id, req := r.ID, r
|
||||
out[i] = Leaf(id, 0666,
|
||||
out[i] = FileNode(id, 0666,
|
||||
Read(func(_ HandlerCtx) ([]byte, error) {
|
||||
return []byte(req.Summary() + "\n"), nil
|
||||
}),
|
||||
|
|
@ -867,7 +867,7 @@ func listProcesses(ctx HandlerCtx) ([]FsNodeDecl, error) {
|
|||
for i, p := range procs {
|
||||
pid := p.PID
|
||||
pidStr := strconv.Itoa(pid)
|
||||
out[i] = Leaf(pidStr, 0444,
|
||||
out[i] = FileNode(pidStr, 0444,
|
||||
Read(func(ctx HandlerCtx) ([]byte, error) {
|
||||
output, err := ctx.Agent.GetDetachedOutput(pid)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue