diff --git a/cmd/olliesrv/bypass_notify.go b/cmd/olliesrv/bypass_notify.go index c025f8e..22780b5 100644 --- a/cmd/olliesrv/bypass_notify.go +++ b/cmd/olliesrv/bypass_notify.go @@ -5,7 +5,7 @@ import ( "sync" "github.com/godbus/dbus/v5" - "ollie/bypass" + "ollie/cmd/olliesrv/internal/bypass" ) // bypassNotifier handles desktop notifications for bypass requests diff --git a/agent/agent.go b/cmd/olliesrv/internal/agent/agent.go similarity index 99% rename from agent/agent.go rename to cmd/olliesrv/internal/agent/agent.go index e483ce4..5113811 100644 --- a/agent/agent.go +++ b/cmd/olliesrv/internal/agent/agent.go @@ -9,7 +9,7 @@ import ( "sync/atomic" "syscall" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" olog "ollie/log" "ollie/paths" "ollie/toolsrv" diff --git a/agent/agent_config.go b/cmd/olliesrv/internal/agent/agent_config.go similarity index 97% rename from agent/agent_config.go rename to cmd/olliesrv/internal/agent/agent_config.go index a75688a..e362c1c 100644 --- a/agent/agent_config.go +++ b/cmd/olliesrv/internal/agent/agent_config.go @@ -4,7 +4,7 @@ import ( "encoding/json" "io" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" ) // Prompt holds the agent prompt — a list of file paths to read and concatenate. diff --git a/agent/agent_test.go b/cmd/olliesrv/internal/agent/agent_test.go similarity index 100% rename from agent/agent_test.go rename to cmd/olliesrv/internal/agent/agent_test.go diff --git a/agent/commands.go b/cmd/olliesrv/internal/agent/commands.go similarity index 100% rename from agent/commands.go rename to cmd/olliesrv/internal/agent/commands.go diff --git a/agent/config_paths.go b/cmd/olliesrv/internal/agent/config_paths.go similarity index 100% rename from agent/config_paths.go rename to cmd/olliesrv/internal/agent/config_paths.go diff --git a/agent/cost.go b/cmd/olliesrv/internal/agent/cost.go similarity index 98% rename from agent/cost.go rename to cmd/olliesrv/internal/agent/cost.go index d0686ac..0ad48a1 100644 --- a/agent/cost.go +++ b/cmd/olliesrv/internal/agent/cost.go @@ -3,7 +3,7 @@ package agent import ( "strings" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" ) // auditTruncate trims s to 200 runes for log output. diff --git a/agent/fifo.go b/cmd/olliesrv/internal/agent/fifo.go similarity index 100% rename from agent/fifo.go rename to cmd/olliesrv/internal/agent/fifo.go diff --git a/agent/fifo_test.go b/cmd/olliesrv/internal/agent/fifo_test.go similarity index 100% rename from agent/fifo_test.go rename to cmd/olliesrv/internal/agent/fifo_test.go diff --git a/agent/history.go b/cmd/olliesrv/internal/agent/history.go similarity index 99% rename from agent/history.go rename to cmd/olliesrv/internal/agent/history.go index 7d5c32e..0010c87 100644 --- a/agent/history.go +++ b/cmd/olliesrv/internal/agent/history.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" "ollie/paths" "gopkg.in/yaml.v3" diff --git a/agent/loop.go b/cmd/olliesrv/internal/agent/loop.go similarity index 99% rename from agent/loop.go rename to cmd/olliesrv/internal/agent/loop.go index 7ad1282..112a04b 100644 --- a/agent/loop.go +++ b/cmd/olliesrv/internal/agent/loop.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" "ollie/paths" "ollie/toolsrv" ) diff --git a/agent/prompt_resolver.go b/cmd/olliesrv/internal/agent/prompt_resolver.go similarity index 100% rename from agent/prompt_resolver.go rename to cmd/olliesrv/internal/agent/prompt_resolver.go diff --git a/agent/runtime.go b/cmd/olliesrv/internal/agent/runtime.go similarity index 98% rename from agent/runtime.go rename to cmd/olliesrv/internal/agent/runtime.go index ef717ca..b69e6bc 100644 --- a/agent/runtime.go +++ b/cmd/olliesrv/internal/agent/runtime.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "ollie/backend" - "ollie/prompts" + "ollie/cmd/olliesrv/internal/backend" + "ollie/cmd/olliesrv/internal/prompts" "ollie/toolsrv" ) diff --git a/agent/runtime_test.go b/cmd/olliesrv/internal/agent/runtime_test.go similarity index 100% rename from agent/runtime_test.go rename to cmd/olliesrv/internal/agent/runtime_test.go diff --git a/agent/text_parse.go b/cmd/olliesrv/internal/agent/text_parse.go similarity index 99% rename from agent/text_parse.go rename to cmd/olliesrv/internal/agent/text_parse.go index 3c198eb..e80ab47 100644 --- a/agent/text_parse.go +++ b/cmd/olliesrv/internal/agent/text_parse.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" ) // parseTextToolCalls extracts tool calls from assistant text when the model diff --git a/agent/turn.go b/cmd/olliesrv/internal/agent/turn.go similarity index 99% rename from agent/turn.go rename to cmd/olliesrv/internal/agent/turn.go index 83b47ae..cca9a2f 100644 --- a/agent/turn.go +++ b/cmd/olliesrv/internal/agent/turn.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" "ollie/toolsrv" ) diff --git a/backend/anthropic.go b/cmd/olliesrv/internal/backend/anthropic.go similarity index 100% rename from backend/anthropic.go rename to cmd/olliesrv/internal/backend/anthropic.go diff --git a/backend/anthropic_stream_test.go b/cmd/olliesrv/internal/backend/anthropic_stream_test.go similarity index 100% rename from backend/anthropic_stream_test.go rename to cmd/olliesrv/internal/backend/anthropic_stream_test.go diff --git a/backend/backend.go b/cmd/olliesrv/internal/backend/backend.go similarity index 100% rename from backend/backend.go rename to cmd/olliesrv/internal/backend/backend.go diff --git a/backend/backend_test.go b/cmd/olliesrv/internal/backend/backend_test.go similarity index 99% rename from backend/backend_test.go rename to cmd/olliesrv/internal/backend/backend_test.go index 9c5c9fa..d555995 100644 --- a/backend/backend_test.go +++ b/cmd/olliesrv/internal/backend/backend_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" ) func mustNewOpenAI(t *testing.T, name, baseURL, apiKey string) *backend.OpenAIBackend { diff --git a/backend/base.go b/cmd/olliesrv/internal/backend/base.go similarity index 100% rename from backend/base.go rename to cmd/olliesrv/internal/backend/base.go diff --git a/backend/codewhisperer_test.go b/cmd/olliesrv/internal/backend/codewhisperer_test.go similarity index 100% rename from backend/codewhisperer_test.go rename to cmd/olliesrv/internal/backend/codewhisperer_test.go diff --git a/backend/config.go b/cmd/olliesrv/internal/backend/config.go similarity index 100% rename from backend/config.go rename to cmd/olliesrv/internal/backend/config.go diff --git a/backend/copilot.go b/cmd/olliesrv/internal/backend/copilot.go similarity index 100% rename from backend/copilot.go rename to cmd/olliesrv/internal/backend/copilot.go diff --git a/backend/export_test.go b/cmd/olliesrv/internal/backend/export_test.go similarity index 100% rename from backend/export_test.go rename to cmd/olliesrv/internal/backend/export_test.go diff --git a/backend/gemini.go b/cmd/olliesrv/internal/backend/gemini.go similarity index 100% rename from backend/gemini.go rename to cmd/olliesrv/internal/backend/gemini.go diff --git a/backend/kiro.go b/cmd/olliesrv/internal/backend/kiro.go similarity index 100% rename from backend/kiro.go rename to cmd/olliesrv/internal/backend/kiro.go diff --git a/backend/kiro_internal.go b/cmd/olliesrv/internal/backend/kiro_internal.go similarity index 100% rename from backend/kiro_internal.go rename to cmd/olliesrv/internal/backend/kiro_internal.go diff --git a/backend/new.go b/cmd/olliesrv/internal/backend/new.go similarity index 100% rename from backend/new.go rename to cmd/olliesrv/internal/backend/new.go diff --git a/backend/new_test.go b/cmd/olliesrv/internal/backend/new_test.go similarity index 100% rename from backend/new_test.go rename to cmd/olliesrv/internal/backend/new_test.go diff --git a/backend/ollama.go b/cmd/olliesrv/internal/backend/ollama.go similarity index 100% rename from backend/ollama.go rename to cmd/olliesrv/internal/backend/ollama.go diff --git a/backend/ollama_stream_test.go b/cmd/olliesrv/internal/backend/ollama_stream_test.go similarity index 100% rename from backend/ollama_stream_test.go rename to cmd/olliesrv/internal/backend/ollama_stream_test.go diff --git a/backend/oneshot.go b/cmd/olliesrv/internal/backend/oneshot.go similarity index 100% rename from backend/oneshot.go rename to cmd/olliesrv/internal/backend/oneshot.go diff --git a/backend/openai.go b/cmd/olliesrv/internal/backend/openai.go similarity index 100% rename from backend/openai.go rename to cmd/olliesrv/internal/backend/openai.go diff --git a/backend/openai_encode_test.go b/cmd/olliesrv/internal/backend/openai_encode_test.go similarity index 100% rename from backend/openai_encode_test.go rename to cmd/olliesrv/internal/backend/openai_encode_test.go diff --git a/backend/openai_stream_test.go b/cmd/olliesrv/internal/backend/openai_stream_test.go similarity index 100% rename from backend/openai_stream_test.go rename to cmd/olliesrv/internal/backend/openai_stream_test.go diff --git a/backend/openai_test.go b/cmd/olliesrv/internal/backend/openai_test.go similarity index 100% rename from backend/openai_test.go rename to cmd/olliesrv/internal/backend/openai_test.go diff --git a/backend/pool.go b/cmd/olliesrv/internal/backend/pool.go similarity index 100% rename from backend/pool.go rename to cmd/olliesrv/internal/backend/pool.go diff --git a/backend/testhelper_test.go b/cmd/olliesrv/internal/backend/testhelper_test.go similarity index 100% rename from backend/testhelper_test.go rename to cmd/olliesrv/internal/backend/testhelper_test.go diff --git a/bypass/broker.go b/cmd/olliesrv/internal/bypass/broker.go similarity index 100% rename from bypass/broker.go rename to cmd/olliesrv/internal/bypass/broker.go diff --git a/bypass/broker_test.go b/cmd/olliesrv/internal/bypass/broker_test.go similarity index 100% rename from bypass/broker_test.go rename to cmd/olliesrv/internal/bypass/broker_test.go diff --git a/bypass/policy.go b/cmd/olliesrv/internal/bypass/policy.go similarity index 100% rename from bypass/policy.go rename to cmd/olliesrv/internal/bypass/policy.go diff --git a/bypass/policy_test.go b/cmd/olliesrv/internal/bypass/policy_test.go similarity index 100% rename from bypass/policy_test.go rename to cmd/olliesrv/internal/bypass/policy_test.go diff --git a/bypass/request.go b/cmd/olliesrv/internal/bypass/request.go similarity index 100% rename from bypass/request.go rename to cmd/olliesrv/internal/bypass/request.go diff --git a/fs/agent_log.go b/cmd/olliesrv/internal/fs/agent_log.go similarity index 98% rename from fs/agent_log.go rename to cmd/olliesrv/internal/fs/agent_log.go index 5df7be6..c6444be 100644 --- a/fs/agent_log.go +++ b/cmd/olliesrv/internal/fs/agent_log.go @@ -3,8 +3,8 @@ package fs import ( "sync" - "ollie/agent" - "ollie/backend" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/backend" "ollie/format" ) diff --git a/fs/cache.go b/cmd/olliesrv/internal/fs/cache.go similarity index 96% rename from fs/cache.go rename to cmd/olliesrv/internal/fs/cache.go index f63cfea..eca40ea 100644 --- a/fs/cache.go +++ b/cmd/olliesrv/internal/fs/cache.go @@ -5,7 +5,7 @@ import ( "strings" "sync" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" ) // ModelCache caches the model list from all backends. diff --git a/fs/ctl.go b/cmd/olliesrv/internal/fs/ctl.go similarity index 100% rename from fs/ctl.go rename to cmd/olliesrv/internal/fs/ctl.go diff --git a/fs/handlers_agent.go b/cmd/olliesrv/internal/fs/handlers_agent.go similarity index 99% rename from fs/handlers_agent.go rename to cmd/olliesrv/internal/fs/handlers_agent.go index ae27492..f6decb1 100644 --- a/fs/handlers_agent.go +++ b/cmd/olliesrv/internal/fs/handlers_agent.go @@ -8,9 +8,9 @@ import ( "strconv" "strings" - "ollie/agent" + "ollie/cmd/olliesrv/internal/agent" "ollie/paths" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" ) func requestAgentNew(ctx HandlerCtx, data []byte) ([]byte, error) { diff --git a/fs/handlers_root.go b/cmd/olliesrv/internal/fs/handlers_root.go similarity index 97% rename from fs/handlers_root.go rename to cmd/olliesrv/internal/fs/handlers_root.go index 7f1ffb6..15ee4fa 100644 --- a/fs/handlers_root.go +++ b/cmd/olliesrv/internal/fs/handlers_root.go @@ -8,11 +8,11 @@ import ( "strings" "sync" - "ollie/agent" - "ollie/backend" - "ollie/bypass" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/backend" + "ollie/cmd/olliesrv/internal/bypass" "ollie/fsedsl" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" "ollie/toolsrv" ) diff --git a/fs/handlers_session.go b/cmd/olliesrv/internal/fs/handlers_session.go similarity index 98% rename from fs/handlers_session.go rename to cmd/olliesrv/internal/fs/handlers_session.go index 6befa0f..34b7511 100644 --- a/fs/handlers_session.go +++ b/cmd/olliesrv/internal/fs/handlers_session.go @@ -5,8 +5,8 @@ import ( "os" "strings" - "ollie/bypass" - "ollie/session" + "ollie/cmd/olliesrv/internal/bypass" + "ollie/cmd/olliesrv/internal/session" ) func readSessionIdx(_ HandlerCtx) ([]byte, error) { diff --git a/fs/lifecycle.go b/cmd/olliesrv/internal/fs/lifecycle.go similarity index 97% rename from fs/lifecycle.go rename to cmd/olliesrv/internal/fs/lifecycle.go index a6f5cca..23ea705 100644 --- a/fs/lifecycle.go +++ b/cmd/olliesrv/internal/fs/lifecycle.go @@ -3,7 +3,7 @@ package fs import ( "sync" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" ) // RootState holds the root-level state for the 9P filesystem. diff --git a/fs/newroot.go b/cmd/olliesrv/internal/fs/newroot.go similarity index 96% rename from fs/newroot.go rename to cmd/olliesrv/internal/fs/newroot.go index a90b55f..b71172a 100644 --- a/fs/newroot.go +++ b/cmd/olliesrv/internal/fs/newroot.go @@ -4,10 +4,10 @@ import ( "context" "os/user" - "ollie/bypass" + "ollie/cmd/olliesrv/internal/bypass" "ollie/fsedsl" olog "ollie/log" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" ) // Config carries all runtime dependencies for the filesystem tree. diff --git a/fs/replay_test.go b/cmd/olliesrv/internal/fs/replay_test.go similarity index 99% rename from fs/replay_test.go rename to cmd/olliesrv/internal/fs/replay_test.go index 4e68d9d..155b40b 100644 --- a/fs/replay_test.go +++ b/cmd/olliesrv/internal/fs/replay_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "ollie/backend" + "ollie/cmd/olliesrv/internal/backend" "ollie/format" ) diff --git a/fs/session_node.go b/cmd/olliesrv/internal/fs/session_node.go similarity index 97% rename from fs/session_node.go rename to cmd/olliesrv/internal/fs/session_node.go index bd8f72e..4ea4853 100644 --- a/fs/session_node.go +++ b/cmd/olliesrv/internal/fs/session_node.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "ollie/agent" - "ollie/session" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/session" "ollie/toolsrv" ) diff --git a/fs/spec.go b/cmd/olliesrv/internal/fs/spec.go similarity index 99% rename from fs/spec.go rename to cmd/olliesrv/internal/fs/spec.go index 6b10b31..8cf97f8 100644 --- a/fs/spec.go +++ b/cmd/olliesrv/internal/fs/spec.go @@ -7,8 +7,8 @@ package fs import ( "context" - "ollie/agent" - "ollie/bypass" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/bypass" "ollie/fsedsl" olog "ollie/log" ) diff --git a/prompts/prompts.go b/cmd/olliesrv/internal/prompts/prompts.go similarity index 100% rename from prompts/prompts.go rename to cmd/olliesrv/internal/prompts/prompts.go diff --git a/prompts/prompts_test.go b/cmd/olliesrv/internal/prompts/prompts_test.go similarity index 100% rename from prompts/prompts_test.go rename to cmd/olliesrv/internal/prompts/prompts_test.go diff --git a/prompts/system_prompt.md b/cmd/olliesrv/internal/prompts/system_prompt.md similarity index 100% rename from prompts/system_prompt.md rename to cmd/olliesrv/internal/prompts/system_prompt.md diff --git a/session/event.go b/cmd/olliesrv/internal/session/event.go similarity index 100% rename from session/event.go rename to cmd/olliesrv/internal/session/event.go diff --git a/session/persist.go b/cmd/olliesrv/internal/session/persist.go similarity index 98% rename from session/persist.go rename to cmd/olliesrv/internal/session/persist.go index 4b489d6..1c0d192 100644 --- a/session/persist.go +++ b/cmd/olliesrv/internal/session/persist.go @@ -9,8 +9,8 @@ import ( "strings" "sync" - "ollie/agent" - "ollie/backend" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/backend" ) // --- Persistence --- diff --git a/session/registry.go b/cmd/olliesrv/internal/session/registry.go similarity index 99% rename from session/registry.go rename to cmd/olliesrv/internal/session/registry.go index f367238..b463a7d 100644 --- a/session/registry.go +++ b/cmd/olliesrv/internal/session/registry.go @@ -17,8 +17,8 @@ import ( "sync" "time" - "ollie/agent" - "ollie/backend" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/backend" olog "ollie/log" "ollie/paths" ) diff --git a/session/session.go b/cmd/olliesrv/internal/session/session.go similarity index 99% rename from session/session.go rename to cmd/olliesrv/internal/session/session.go index 78ead3b..30bf35b 100644 --- a/session/session.go +++ b/cmd/olliesrv/internal/session/session.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "ollie/agent" + "ollie/cmd/olliesrv/internal/agent" olog "ollie/log" "ollie/paths" "ollie/toolsrv" diff --git a/session/setup.go b/cmd/olliesrv/internal/session/setup.go similarity index 98% rename from session/setup.go rename to cmd/olliesrv/internal/session/setup.go index b027dab..a10b3b9 100644 --- a/session/setup.go +++ b/cmd/olliesrv/internal/session/setup.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - "ollie/agent" + "ollie/cmd/olliesrv/internal/agent" "ollie/paths" - "ollie/prompts" + "ollie/cmd/olliesrv/internal/prompts" "ollie/toolsrv" ) diff --git a/cmd/olliesrv/main.go b/cmd/olliesrv/main.go index 2302ad8..e03373b 100644 --- a/cmd/olliesrv/main.go +++ b/cmd/olliesrv/main.go @@ -14,13 +14,13 @@ import ( "syscall" "9fans.net/go/plan9/client" - "ollie/agent" - "ollie/bypass" + "ollie/cmd/olliesrv/internal/agent" + "ollie/cmd/olliesrv/internal/bypass" "ollie/env" - "ollie/fs" + "ollie/cmd/olliesrv/internal/fs" olog "ollie/log" "ollie/paths" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" "github.com/godbus/dbus/v5" ) diff --git a/cmd/olliesrv/server.go b/cmd/olliesrv/server.go index 32c9291..8ec6ed1 100644 --- a/cmd/olliesrv/server.go +++ b/cmd/olliesrv/server.go @@ -14,9 +14,9 @@ import ( "sync" "time" - "ollie/fs" + "ollie/cmd/olliesrv/internal/fs" olog "ollie/log" - "ollie/session" + "ollie/cmd/olliesrv/internal/session" "9fans.net/go/plan9" ) diff --git a/toolsrv/auth9p.go b/cmd/toolsrv/auth9p.go similarity index 96% rename from toolsrv/auth9p.go rename to cmd/toolsrv/auth9p.go index d4941ec..971a793 100644 --- a/toolsrv/auth9p.go +++ b/cmd/toolsrv/auth9p.go @@ -1,5 +1,5 @@ // auth9p.go - Authentication helpers for 9P toolsrv -package toolsrv +package main import ( "crypto/rand" diff --git a/toolsrv/exec9p.go b/cmd/toolsrv/exec9p.go similarity index 90% rename from toolsrv/exec9p.go rename to cmd/toolsrv/exec9p.go index 4389d28..6e3f2d8 100644 --- a/toolsrv/exec9p.go +++ b/cmd/toolsrv/exec9p.go @@ -1,5 +1,5 @@ // exec9p.go - Decoupled tool execution for 9P toolsrv -package toolsrv +package main import ( "bytes" @@ -16,8 +16,9 @@ import ( "syscall" "time" + "ollie/cmd/toolsrv/internal/sandbox" "ollie/paths" - "ollie/sandbox" + "ollie/toolsrv" ) // ExecConfig contains all context needed for tool execution. @@ -29,20 +30,6 @@ type ExecConfig struct { Timeout int } -// ToolResult is the JSON structure returned by tool execution. -type ToolResult struct { - Content []ToolResultContent `json:"content"` - IsError bool `json:"isError,omitempty"` -} - -// ToolResultContent is a single content item in a tool result. -type ToolResultContent struct { - Type string `json:"type"` - Text string `json:"text,omitempty"` - MediaType string `json:"mediaType,omitempty"` - Data string `json:"data,omitempty"` -} - // StreamFunc returns the streaming output function from context, if any. func StreamFunc(ctx context.Context) func(string) { if fn, ok := ctx.Value(streamKey{}).(func(string)); ok { @@ -60,9 +47,9 @@ func WithStreamFunc(ctx context.Context, fn func(string)) context.Context { // ExecuteTool runs a tool script with the given args and returns the result. // This is the core execution function, decoupled from Server. -func ExecuteTool(ctx context.Context, info ToolInfo, args json.RawMessage, cfg ExecConfig) (json.RawMessage, error) { +func ExecuteTool(ctx context.Context, info toolsrv.ToolInfo, args json.RawMessage, cfg ExecConfig) (json.RawMessage, error) { // Resolve script path - toolPath, err := ResolveTool(info.Name) + toolPath, err := toolsrv.ResolveTool(info.Name) if err != nil { return nil, fmt.Errorf("resolve tool %s: %w", info.Name, err) } @@ -109,7 +96,7 @@ func ExecuteTool(ctx context.Context, info ToolInfo, args json.RawMessage, cfg E // Check if tool requires sudo needsSudo := false - if m, err := LoadMetaFile(info.Name); err == nil && m != nil { + if m, err := toolsrv.LoadMetaFile(info.Name); err == nil && m != nil { resolved := m.Resolve() if resolved != nil && resolved.Sudo { needsSudo = true @@ -135,13 +122,13 @@ func ExecuteTool(ctx context.Context, info ToolInfo, args json.RawMessage, cfg E } if err != nil { - return json.Marshal(ToolResult{ + return json.Marshal(toolsrv.ToolResult{ IsError: true, - Content: []ToolResultContent{{Type: "text", Text: result + ": " + err.Error()}}, + Content: []toolsrv.ToolResultContent{{Type: "text", Text: result + ": " + err.Error()}}, }) } - return json.Marshal(ToolResult{ - Content: []ToolResultContent{{Type: "text", Text: result}}, + return json.Marshal(toolsrv.ToolResult{ + Content: []toolsrv.ToolResultContent{{Type: "text", Text: result}}, }) } diff --git a/toolsrv/fs9p.go b/cmd/toolsrv/fs9p.go similarity index 97% rename from toolsrv/fs9p.go rename to cmd/toolsrv/fs9p.go index 05090e9..7a341ab 100644 --- a/toolsrv/fs9p.go +++ b/cmd/toolsrv/fs9p.go @@ -21,7 +21,7 @@ // tool=shell // cmd=ls -la // timeout=30 -package toolsrv +package main import ( "bytes" @@ -36,6 +36,8 @@ import ( "sync/atomic" "syscall" "time" + + "ollie/toolsrv" ) // FS9P implements a 9P-style tool server. @@ -45,7 +47,7 @@ type FS9P struct { cwd string env map[string]string - registry *Registry + registry *toolsrv.Registry sessID string yolo bool @@ -88,7 +90,7 @@ func NewFS9P(cwd string) *FS9P { } // SetRegistry configures the tool registry and session ID. -func (fs *FS9P) SetRegistry(r *Registry, sessID string) { +func (fs *FS9P) SetRegistry(r *toolsrv.Registry, sessID string) { fs.mu.Lock() fs.registry = r fs.sessID = sessID @@ -136,7 +138,7 @@ func (fs *FS9P) GetEnv(key string) string { // --- Tool Registry --- // ListTools returns loaded tools for the current session. -func (fs *FS9P) ListTools() []ToolInfo { +func (fs *FS9P) ListTools() []toolsrv.ToolInfo { fs.mu.RLock() reg := fs.registry sid := fs.sessID @@ -299,7 +301,7 @@ func (fs *FS9P) NewProc(ctx context.Context, payload string, background bool) (r } // executeTool runs a tool and returns output + exit code. -func (fs *FS9P) executeTool(ctx context.Context, info ToolInfo, args map[string]string, cwd string, envExtra map[string]string, yolo bool) (string, int) { +func (fs *FS9P) executeTool(ctx context.Context, info toolsrv.ToolInfo, args map[string]string, cwd string, envExtra map[string]string, yolo bool) (string, int) { // Convert args map to JSON for the execution path jsonArgs := argsToJSON(args) diff --git a/toolsrv/fs9p_test.go b/cmd/toolsrv/fs9p_test.go similarity index 98% rename from toolsrv/fs9p_test.go rename to cmd/toolsrv/fs9p_test.go index 1672ee3..134ffae 100644 --- a/toolsrv/fs9p_test.go +++ b/cmd/toolsrv/fs9p_test.go @@ -1,10 +1,12 @@ -package toolsrv +package main import ( "context" "strings" "testing" "time" + + "ollie/toolsrv" ) func TestFS9P_Basic(t *testing.T) { @@ -76,7 +78,7 @@ func TestFS9P_ProcLimit(t *testing.T) { fs.procLimit = 2 // Create a fake registry and session ID - reg, err := NewRegistry() + reg, err := toolsrv.NewRegistry() if err != nil { t.Skip("no tools directory available") } diff --git a/toolsrv/integration_test.go b/cmd/toolsrv/integration_test.go similarity index 87% rename from toolsrv/integration_test.go rename to cmd/toolsrv/integration_test.go index 086fe14..bb33df0 100644 --- a/toolsrv/integration_test.go +++ b/cmd/toolsrv/integration_test.go @@ -2,7 +2,7 @@ // // These tests build and spawn a real toolsrv process, then connect via 9P // to verify the authentication flow works correctly. -package toolsrv +package main import ( "context" @@ -14,6 +14,8 @@ import ( "strings" "testing" "time" + + "ollie/toolsrv" ) var testToolsrvBinary string @@ -95,7 +97,7 @@ func TestIntegration_FirstConnectionSetsSecret(t *testing.T) { // First connection with a secret should succeed secret := "test-secret-first-connection" - conn, err := Dial(socketPath, secret) + conn, err := toolsrv.Dial(socketPath, secret) if err != nil { t.Fatalf("first Dial failed: %v", err) } @@ -119,7 +121,7 @@ func TestIntegration_SameSecretReconnects(t *testing.T) { secret := "test-secret-reconnect" // First connection establishes the secret - conn1, err := Dial(socketPath, secret) + conn1, err := toolsrv.Dial(socketPath, secret) if err != nil { t.Fatalf("first Dial failed: %v", err) } @@ -127,7 +129,7 @@ func TestIntegration_SameSecretReconnects(t *testing.T) { conn1.Close() // Second connection with same secret should succeed - conn2, err := Dial(socketPath, secret) + conn2, err := toolsrv.Dial(socketPath, secret) if err != nil { t.Fatalf("second Dial failed: %v", err) } @@ -144,14 +146,14 @@ func TestIntegration_WrongSecretFails(t *testing.T) { defer cleanup() // First connection establishes the secret - conn1, err := Dial(socketPath, "correct-secret") + conn1, err := toolsrv.Dial(socketPath, "correct-secret") if err != nil { t.Fatalf("first Dial failed: %v", err) } conn1.Close() // Second connection with wrong secret should fail - conn2, err := Dial(socketPath, "wrong-secret") + conn2, err := toolsrv.Dial(socketPath, "wrong-secret") if err == nil { conn2.Close() t.Fatal("Dial with wrong secret should fail") @@ -163,7 +165,7 @@ func TestIntegration_EmptySecretGeneratesOne(t *testing.T) { defer cleanup() // Empty secret should generate a random one - conn, err := Dial(socketPath, "") + conn, err := toolsrv.Dial(socketPath, "") if err != nil { t.Fatalf("Dial with empty secret failed: %v", err) } @@ -184,7 +186,7 @@ func TestIntegration_BasicOperations(t *testing.T) { socketPath, cleanup := startTestServer(t) defer cleanup() - conn, err := Dial(socketPath, "test-secret-ops") + conn, err := toolsrv.Dial(socketPath, "test-secret-ops") if err != nil { t.Fatalf("Dial failed: %v", err) } @@ -214,14 +216,14 @@ func TestIntegration_BasicOperations(t *testing.T) { func TestIntegration_ToolExecution(t *testing.T) { // Skip if tools directory doesn't exist (CI environment) - if _, err := os.ReadDir(ToolsPath()); err != nil { + if _, err := os.ReadDir(toolsrv.ToolsPath()); err != nil { t.Skipf("skipping: tools directory not available: %v", err) } socketPath, cleanup := startTestServer(t) defer cleanup() - conn, err := Dial(socketPath, "test-secret-exec") + conn, err := toolsrv.Dial(socketPath, "test-secret-exec") if err != nil { t.Fatalf("Dial failed: %v", err) } @@ -257,14 +259,14 @@ func TestIntegration_ToolExecution(t *testing.T) { } // Parse the result the same way agent/runtime.go does - var toolResult ToolResult + var toolResult toolsrv.ToolResult if err := json.Unmarshal(result, &toolResult); err != nil { - t.Fatalf("failed to parse ToolResult: %v (raw: %s)", err, string(result)) + t.Fatalf("failed to parse toolsrv.ToolResult: %v (raw: %s)", err, string(result)) } // Verify structure if len(toolResult.Content) == 0 { - t.Fatal("ToolResult.Content is empty") + t.Fatal("toolsrv.ToolResult.Content is empty") } if toolResult.Content[0].Type != "text" { t.Errorf("expected type 'text', got %q", toolResult.Content[0].Type) @@ -273,7 +275,7 @@ func TestIntegration_ToolExecution(t *testing.T) { t.Errorf("output doesn't contain expected text: %q", toolResult.Content[0].Text) } if toolResult.IsError { - t.Error("ToolResult.IsError should be false") + t.Error("toolsrv.ToolResult.IsError should be false") } t.Logf("Tool result: %+v", toolResult) @@ -281,14 +283,14 @@ func TestIntegration_ToolExecution(t *testing.T) { func TestIntegration_MultilineContent(t *testing.T) { // Skip if tools directory doesn't exist (CI environment) - if _, err := os.ReadDir(ToolsPath()); err != nil { + if _, err := os.ReadDir(toolsrv.ToolsPath()); err != nil { t.Skipf("skipping: tools directory not available: %v", err) } socketPath, cleanup := startTestServer(t) defer cleanup() - conn, err := Dial(socketPath, "test-secret-multiline") + conn, err := toolsrv.Dial(socketPath, "test-secret-multiline") if err != nil { t.Fatalf("Dial failed: %v", err) } @@ -312,9 +314,9 @@ func TestIntegration_MultilineContent(t *testing.T) { t.Fatalf("CallTool failed: %v", err) } - var toolResult ToolResult + var toolResult toolsrv.ToolResult if err := json.Unmarshal(result, &toolResult); err != nil { - t.Fatalf("failed to parse ToolResult: %v (raw: %s)", err, string(result)) + t.Fatalf("failed to parse toolsrv.ToolResult: %v (raw: %s)", err, string(result)) } if toolResult.IsError { @@ -334,14 +336,14 @@ func TestIntegration_MultilineContent(t *testing.T) { func TestIntegration_ToolExecutionError(t *testing.T) { // Skip if tools directory doesn't exist (CI environment) - if _, err := os.ReadDir(ToolsPath()); err != nil { + if _, err := os.ReadDir(toolsrv.ToolsPath()); err != nil { t.Skipf("skipping: tools directory not available: %v", err) } socketPath, cleanup := startTestServer(t) defer cleanup() - conn, err := Dial(socketPath, "test-secret-exec-err") + conn, err := toolsrv.Dial(socketPath, "test-secret-exec-err") if err != nil { t.Fatalf("Dial failed: %v", err) } @@ -361,14 +363,14 @@ func TestIntegration_ToolExecutionError(t *testing.T) { } // Parse the result - var toolResult ToolResult + var toolResult toolsrv.ToolResult if err := json.Unmarshal(result, &toolResult); err != nil { - t.Fatalf("failed to parse ToolResult: %v (raw: %s)", err, string(result)) + t.Fatalf("failed to parse toolsrv.ToolResult: %v (raw: %s)", err, string(result)) } // Should have exit code in output if len(toolResult.Content) == 0 { - t.Fatal("ToolResult.Content is empty") + t.Fatal("toolsrv.ToolResult.Content is empty") } if !strings.Contains(toolResult.Content[0].Text, "exit: 42") { t.Errorf("output doesn't contain exit code: %q", toolResult.Content[0].Text) @@ -384,13 +386,13 @@ func TestIntegration_ProcessKeeperReconnect(t *testing.T) { secret := "test-secret-keeper" // Create a process manually (simulating what Spawn returns) - proc := &Process{ + proc := &toolsrv.Process{ SocketPath: socketPath, Secret: secret, } // Create keeper without respawn (we're testing reconnect, not respawn) - keeper := NewProcessKeeper(context.Background(), proc, nil) + keeper := toolsrv.NewProcessKeeper(context.Background(), proc, nil) // First dial conn1, err := keeper.Dial() @@ -419,7 +421,7 @@ func TestIntegration_ConcurrentConnections(t *testing.T) { secret := "test-secret-concurrent" // Establish the secret - conn0, err := Dial(socketPath, secret) + conn0, err := toolsrv.Dial(socketPath, secret) if err != nil { t.Fatalf("initial Dial failed: %v", err) } @@ -428,11 +430,11 @@ func TestIntegration_ConcurrentConnections(t *testing.T) { // Open multiple concurrent connections const numConns = 5 - conns := make([]*Conn, numConns) + conns := make([]*toolsrv.Conn, numConns) errors := make([]error, numConns) for i := 0; i < numConns; i++ { - conns[i], errors[i] = Dial(socketPath, secret) + conns[i], errors[i] = toolsrv.Dial(socketPath, secret) } // Check all succeeded with same token @@ -461,7 +463,7 @@ func TestIntegration_ProcessKeeperRespawn(t *testing.T) { socketPath1, cleanup1 := startTestServer(t) secret1 := "secret-for-first-server" - conn1, err := Dial(socketPath1, secret1) + conn1, err := toolsrv.Dial(socketPath1, secret1) if err != nil { cleanup1() t.Fatalf("first Dial failed: %v", err) @@ -478,7 +480,7 @@ func TestIntegration_ProcessKeeperRespawn(t *testing.T) { // New server should accept a new secret (any secret, since it's fresh) secret2 := "secret-for-second-server" - conn2, err := Dial(socketPath2, secret2) + conn2, err := toolsrv.Dial(socketPath2, secret2) if err != nil { t.Fatalf("second Dial failed: %v", err) } @@ -491,18 +493,18 @@ func TestIntegration_ProcessKeeperRespawn(t *testing.T) { } // Old secret should NOT work on new server - conn3, err := Dial(socketPath2, secret1) + conn3, err := toolsrv.Dial(socketPath2, secret1) if err == nil { conn3.Close() t.Error("old secret should not work on new server") } // Verify ProcessKeeper handles this correctly - proc := &Process{ + proc := &toolsrv.Process{ SocketPath: socketPath2, Secret: secret2, } - keeper := NewProcessKeeper(context.Background(), proc, nil) + keeper := toolsrv.NewProcessKeeper(context.Background(), proc, nil) conn4, err := keeper.Dial() if err != nil { diff --git a/sandbox/config.go b/cmd/toolsrv/internal/sandbox/config.go similarity index 100% rename from sandbox/config.go rename to cmd/toolsrv/internal/sandbox/config.go diff --git a/sandbox/default.yaml b/cmd/toolsrv/internal/sandbox/default.yaml similarity index 100% rename from sandbox/default.yaml rename to cmd/toolsrv/internal/sandbox/default.yaml diff --git a/sandbox/detect.go b/cmd/toolsrv/internal/sandbox/detect.go similarity index 100% rename from sandbox/detect.go rename to cmd/toolsrv/internal/sandbox/detect.go diff --git a/sandbox/restricted.yaml b/cmd/toolsrv/internal/sandbox/restricted.yaml similarity index 100% rename from sandbox/restricted.yaml rename to cmd/toolsrv/internal/sandbox/restricted.yaml diff --git a/sandbox/sandbox_test.go b/cmd/toolsrv/internal/sandbox/sandbox_test.go similarity index 100% rename from sandbox/sandbox_test.go rename to cmd/toolsrv/internal/sandbox/sandbox_test.go diff --git a/sandbox/wrapper.go b/cmd/toolsrv/internal/sandbox/wrapper.go similarity index 100% rename from sandbox/wrapper.go rename to cmd/toolsrv/internal/sandbox/wrapper.go diff --git a/cmd/toolsrv/main.go b/cmd/toolsrv/main.go index a3f93b9..918d06d 100644 --- a/cmd/toolsrv/main.go +++ b/cmd/toolsrv/main.go @@ -62,15 +62,15 @@ func main() { } // Create 9P server (secret is established via Tauth, not env var) - srv := toolsrv.NewServer9P() + srv := NewServer9P() srv.SetYolo(*yolo) if toolReg != nil && sid != "" { srv.SetRegistry(toolReg, sid) } // Build the filesystem tree - ctx := toolsrv.ToolsrvCtx{Server: srv} - tree := fsedsl.BuildTree(toolsrv.ToolsrvSpec(), ctx) + ctx := ToolsrvCtx{Server: srv} + tree := fsedsl.BuildTree(ToolsrvSpec(), ctx) if tree == nil { fmt.Fprintln(os.Stderr, "error: failed to build filesystem tree") os.Exit(1) diff --git a/cmd/toolsrv/server.go b/cmd/toolsrv/server.go index 982ad88..8bb97ec 100644 --- a/cmd/toolsrv/server.go +++ b/cmd/toolsrv/server.go @@ -10,7 +10,6 @@ import ( "sync" "ollie/fsedsl" - "ollie/toolsrv" "9fans.net/go/plan9" ) @@ -42,12 +41,12 @@ type connState struct { authFids map[uint32]*authFid ctx context.Context uname string - srv *toolsrv.Server9P + srv *Server9P noAuth bool // skip authentication (for debugging) } // serve9P handles a single 9P connection using the fsedsl tree. -func serve9P(ctx context.Context, conn net.Conn, tree *fsedsl.Tree, srv *toolsrv.Server9P, noAuth bool) { +func serve9P(ctx context.Context, conn net.Conn, tree *fsedsl.Tree, srv *Server9P, noAuth bool) { defer conn.Close() cs := &connState{ diff --git a/toolsrv/server9p.go b/cmd/toolsrv/server9p.go similarity index 93% rename from toolsrv/server9p.go rename to cmd/toolsrv/server9p.go index 00bc114..24c7d1f 100644 --- a/toolsrv/server9p.go +++ b/cmd/toolsrv/server9p.go @@ -1,5 +1,5 @@ // server9p.go - State management for 9P toolsrv -package toolsrv +package main import ( "crypto/rand" @@ -9,6 +9,7 @@ import ( "sync" "ollie/fsedsl" + "ollie/toolsrv" ) // Server9P holds the state for the 9P tool server. @@ -17,7 +18,7 @@ type Server9P struct { secret string // set on first auth, verified on subsequent token string // session token returned after auth - registry *Registry // tool registry + registry *toolsrv.Registry // tool registry sessID string // session ID for registry scoping yolo bool // skip sandbox @@ -33,7 +34,7 @@ func NewServer9P() *Server9P { } // SetRegistry configures the tool registry and session ID. -func (s *Server9P) SetRegistry(r *Registry, sessID string) { +func (s *Server9P) SetRegistry(r *toolsrv.Registry, sessID string) { s.mu.Lock() s.registry = r s.sessID = sessID diff --git a/toolsrv/server9p_test.go b/cmd/toolsrv/server9p_test.go similarity index 99% rename from toolsrv/server9p_test.go rename to cmd/toolsrv/server9p_test.go index 731bc8b..10f541e 100644 --- a/toolsrv/server9p_test.go +++ b/cmd/toolsrv/server9p_test.go @@ -1,4 +1,4 @@ -package toolsrv +package main import ( "testing" diff --git a/toolsrv/spec9p.go b/cmd/toolsrv/spec9p.go similarity index 99% rename from toolsrv/spec9p.go rename to cmd/toolsrv/spec9p.go index e2a4b6c..b308754 100644 --- a/toolsrv/spec9p.go +++ b/cmd/toolsrv/spec9p.go @@ -1,5 +1,5 @@ // spec9p.go - fsedsl-based namespace specification for toolsrv -package toolsrv +package main import ( "context" diff --git a/toolsrv/types.go b/toolsrv/types.go new file mode 100644 index 0000000..fddf7fa --- /dev/null +++ b/toolsrv/types.go @@ -0,0 +1,16 @@ +// types.go - Shared types for toolsrv +package toolsrv + +// ToolResult is the structured result from a tool execution. +type ToolResult struct { + Content []ToolResultContent `json:"content"` + IsError bool `json:"isError,omitempty"` +} + +// ToolResultContent is a single content item in a tool result. +type ToolResultContent struct { + Type string `json:"type"` + Text string `json:"text,omitempty"` + MediaType string `json:"mediaType,omitempty"` + Data string `json:"data,omitempty"` +}