diff --git a/pkg/skills/registry.go b/pkg/skills/registry.go index 6907d6e..62ba2a0 100644 --- a/pkg/skills/registry.go +++ b/pkg/skills/registry.go @@ -4,6 +4,7 @@ package skills import ( "fmt" + "sort" "os" "path/filepath" "strings" @@ -86,6 +87,7 @@ func (r *Registry) Summaries() []SkillInfo { for _, info := range r.global { out = append(out, info) } + sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name }) return out } @@ -133,6 +135,7 @@ func (r *Registry) Loaded(sessionID string) []SkillInfo { out = append(out, info) } } + sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name }) return out } diff --git a/pkg/tools/execute/registry.go b/pkg/tools/execute/registry.go index bf77ec9..b9a174c 100644 --- a/pkg/tools/execute/registry.go +++ b/pkg/tools/execute/registry.go @@ -2,6 +2,8 @@ package execute import ( "fmt" + "strings" + "sort" "os" "path/filepath" "sync" @@ -45,6 +47,9 @@ func (r *Registry) Discover() error { continue } script := string(data) + if !strings.Contains(script, "ollie:prompt") { + continue + } global[e.Name()] = ParseToolInfo(e.Name(), script) } r.mu.Lock() @@ -63,6 +68,7 @@ func (r *Registry) Summaries() []tools.ToolInfo { Description: info.Description, }) } + sort.Slice(summaries, func(i, j int) bool { return summaries[i].Name < summaries[j].Name }) return summaries } @@ -121,6 +127,7 @@ func (r *Registry) Loaded(sessionID string) []tools.ToolInfo { for _, info := range sessionTools { loaded = append(loaded, info) } + sort.Slice(loaded, func(i, j int) bool { return loaded[i].Name < loaded[j].Name }) return loaded } diff --git a/pkg/tools/execute/schema.go b/pkg/tools/execute/schema.go index 8aaf71f..9f0fe23 100644 --- a/pkg/tools/execute/schema.go +++ b/pkg/tools/execute/schema.go @@ -79,7 +79,7 @@ func ParseToolInfo(name, script string) tools.ToolInfo { desc := ExtractShortDescription(prompt) argsSchema := ExtractArgsSchema(script) if argsSchema == nil { - argsSchema = json.RawMessage(`{"type":"object","properties":{"tool":{"type":"string"},"args":{"type":"array","items":{"type":"string"}}},"required":["tool","args"]}`) + argsSchema = json.RawMessage(`{"type":"object","properties":{}}`) } meta := ExtractMetadata(script) tier := ExtractTier(script) diff --git a/pkg/tools/execute/server.go b/pkg/tools/execute/server.go index 3b33bbc..9352ccf 100644 --- a/pkg/tools/execute/server.go +++ b/pkg/tools/execute/server.go @@ -274,7 +274,7 @@ func (e *Server) SetToolRegistry(r *Registry, sessionID string) { } // callPromotedTool executes a tool promoted via the registry by running the -// script file inside the sandbox, or elevated if the args request it. +// script file inside the sandbox, piping the JSON args to stdin. func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.RawMessage) (json.RawMessage, error) { // Resolve script path. if strings.Contains(tool, "/") || strings.Contains(tool, "..") { @@ -282,32 +282,23 @@ func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.Ra } path := filepath.Join(ToolsPath(), tool) - // Parse args — extract positional args and optional elevated flag. - var positional []string + // Extract elevated flag (dispatch-level concern, not passed to tool). elevated := false var argMap map[string]interface{} if err := json.Unmarshal(args, &argMap); err == nil { - if argsArr, ok := argMap["args"]; ok { - if arr, ok := argsArr.([]interface{}); ok { - for _, v := range arr { - positional = append(positional, fmt.Sprintf("%v", v)) - } - } - } if e, ok := argMap["elevated"]; ok { if b, ok := e.(bool); ok { elevated = b } + // Remove elevated from the args passed to the tool. + delete(argMap, "elevated") + args, _ = json.Marshal(argMap) } } - // Build a shell command that runs the tool script with its args. - quoted := make([]string, 0, len(positional)+1) - quoted = append(quoted, path) - for _, a := range positional { - quoted = append(quoted, fmt.Sprintf("%q", a)) - } - code := strings.Join(quoted, " ") + // The tool script receives JSON args on stdin. + code := path + stdinData := string(args) var result string var err error @@ -317,7 +308,7 @@ func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.Ra e.wdMu.RUnlock() result, err = e.executeElevated(ctx, code, workDir, 30) } else { - result, err = e.executeWithStdin(ctx, code, "bash", 30, "default", false, "") + result, err = e.executeWithStdin(ctx, code, "bash", 30, "default", false, stdinData) } if err != nil { return json.Marshal(map[string]interface{}{ @@ -332,6 +323,7 @@ func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.Ra + // Close is called when the session ends. Calls OnClose hook if registered. func (e *Server) Close() { e.cleanupDetached()