diff --git a/README.md b/README.md index 36d8180..1b7f750 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,10 @@ Tool execution uses the configured native Landlock sandbox. Operations requiring Persistent memory is provided by [OptMem](https://github.com/VictorTaelin/OptMem) through `memory_recall` and `memory_remember`; Ollie does not maintain a second memory-file format. History management renders context, tracks usage and cost, caps oversized tool output, and compacts older material when necessary. +### Future work: portable toolsrv hosts + +`toolsrv` should be extensible to other host operating systems so Ollie tools remain useful on as many systems as possible. This includes the host-specific execution, filesystem, process, networking, and sandbox integrations required on BSD systems, macOS, and other Unix-like platforms. `olliesrv` may remain Linux-specific; its role is the agent runtime and orchestration service, while `toolsrv` is the platform-dependent execution boundary. WSL2 should work through its Linux kernel and use the existing Linux implementation. + ## Frontends Shell scripts, Acme, KDE components, and other clients create sessions, write prompts, and read files such as `chat`, `statewait`, `context`, and `feed`. They do not embed provider, tool, or agent-loop logic. diff --git a/cmd/toolsrv/internal/exec/exec.go b/cmd/toolsrv/internal/exec/exec.go index 43fdb67..ec31fd2 100644 --- a/cmd/toolsrv/internal/exec/exec.go +++ b/cmd/toolsrv/internal/exec/exec.go @@ -125,7 +125,7 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE } }() - var sandboxCfg *sandbox.Config + var sandboxCfg sandbox.Sandbox if !yolo { cfgPath := filepath.Join(util.CfgDir(), "sandbox.yaml") f, err := os.Open(cfgPath) @@ -133,11 +133,11 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE return "", fmt.Errorf("sandbox config not found: %w", err) } defer f.Close() - var loadErr error - sandboxCfg, loadErr = sandbox.LoadSandbox(f) + cfg, loadErr := sandbox.LoadSandbox(f) if loadErr != nil { return "", loadErr } + sandboxCfg = cfg } if timeout > 0 { @@ -176,7 +176,7 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE if yolo { cmd = osExec.CommandContext(ctx, interpreter[0], interpreter[1:]...) } else { - wrapped, wrapErr := sandbox.NativeCommand(sandboxCfg, interpreter, cwd, envMap) + wrapped, wrapErr := sandboxCfg.Command(interpreter, cwd, envMap) if wrapErr != nil { return "", wrapErr } diff --git a/cmd/toolsrv/internal/sandbox/config.go b/cmd/toolsrv/internal/sandbox/config.go index a9c1503..fc23f9c 100644 --- a/cmd/toolsrv/internal/sandbox/config.go +++ b/cmd/toolsrv/internal/sandbox/config.go @@ -13,6 +13,11 @@ import ( "gopkg.in/yaml.v3" ) +// Sandbox prepares a command for restricted execution. +type Sandbox interface { + Command(originalCmd []string, cwd string, env map[string]string) ([]string, error) +} + // Config represents the sandbox configuration type Config struct { General GeneralConfig `yaml:"general"` diff --git a/cmd/toolsrv/internal/sandbox/wrapper.go b/cmd/toolsrv/internal/sandbox/wrapper.go index 416d956..a01eb93 100644 --- a/cmd/toolsrv/internal/sandbox/wrapper.go +++ b/cmd/toolsrv/internal/sandbox/wrapper.go @@ -6,8 +6,8 @@ import ( "os" ) -// NativeCommand encodes a native sandbox helper invocation. -func NativeCommand(cfg *Config, originalCmd []string, cwd string, env map[string]string) ([]string, error) { +// Command encodes a native sandbox helper invocation. +func (cfg *Config) Command(originalCmd []string, cwd string, env map[string]string) ([]string, error) { envCopy := make(map[string]string, len(env)) for k, v := range env { envCopy[k] = v