# OpenRPC Manager Implementation Plan

## 1. Understanding the Requirements

The task requires us to:
- Create an OpenRPC Manager (ORPCManager)
- Read JSON files from services in pkg/openrpc
- Create a model for OpenRPC spec in a separate file
- Read the OpenRPC specs into the model
- Keep these models in memory in the ORPCManager
- Create supporting methods like list_methods
- Create a command in @cmd/ to test this behavior

## 2. Project Structure

Here's the proposed file structure for our implementation:

```
pkg/
  openrpc/
    models/
      spec.go       # OpenRPC specification model
    manager.go      # ORPCManager implementation
cmd/
  orpctest/
    main.go         # Test command for the ORPCManager
```

## 3. Implementation Details

### 3.1 OpenRPC Specification Model (pkg/openrpc/models/spec.go)

We'll create a Go struct model that represents the OpenRPC specification based on the structure observed in zinit.json:

```mermaid
classDiagram
    class OpenRPCSpec {
        +string OpenRPC
        +InfoObject Info
        +Server[] Servers
        +Method[] Methods
    }
    
    class InfoObject {
        +string Version
        +string Title
        +string Description
        +LicenseObject License
    }
    
    class LicenseObject {
        +string Name
    }
    
    class Server {
        +string Name
        +string URL
    }
    
    class Method {
        +string Name
        +string Description
        +Parameter[] Params
        +ResultObject Result
        +Example[] Examples
        +ErrorObject[] Errors
    }
    
    class Parameter {
        +string Name
        +string Description
        +bool Required
        +SchemaObject Schema
    }
    
    class ResultObject {
        +string Name
        +string Description
        +SchemaObject Schema
    }
    
    class SchemaObject {
        +string Type
        +map[string]interface{} Properties
        +SchemaObject Items
        +map[string]SchemaObject AdditionalProperties
    }
    
    class Example {
        +string Name
        +map[string]interface{}[] Params
        +ExampleResultObject Result
    }
    
    class ExampleResultObject {
        +string Name
        +interface{} Value
    }
    
    class ErrorObject {
        +int Code
        +string Message
        +string Data
    }
    
    OpenRPCSpec --> InfoObject
    OpenRPCSpec --> Server
    OpenRPCSpec --> Method
    Method --> Parameter
    Method --> ResultObject
    Method --> Example
    Method --> ErrorObject
    Parameter --> SchemaObject
    ResultObject --> SchemaObject
    Example --> ExampleResultObject
```

### 3.2 OpenRPC Manager (pkg/openrpc/manager.go)

The ORPCManager will be responsible for:
- Loading OpenRPC specifications from JSON files
- Storing and managing these specifications in memory
- Providing methods to access and manipulate the specifications

```mermaid
classDiagram
    class ORPCManager {
        -map[string]*OpenRPCSpec specs
        +NewORPCManager() *ORPCManager
        +LoadSpecs(dir string) error
        +LoadSpec(path string) error
        +GetSpec(name string) *OpenRPCSpec
        +ListSpecs() []string
        +ListMethods(specName string) []string
        +GetMethod(specName string, methodName string) *Method
    }
    
    ORPCManager --> OpenRPCSpec
```

### 3.3 Test Command (cmd/orpctest/main.go)

We'll create a command-line tool to test the ORPCManager functionality:
- Initialize the ORPCManager
- Load specifications from the pkg/openrpc/services directory
- List available specifications
- List methods for each specification
- Display details for specific methods

## 4. Implementation Steps

1. **Create the OpenRPC Specification Model**:
   - Define the Go structs for the OpenRPC specification
   - Implement JSON marshaling/unmarshaling
   - Add validation functions

2. **Implement the ORPCManager**:
   - Create the manager struct with a map to store specifications
   - Implement methods to load specifications from files
   - Implement methods to access and manipulate specifications

3. **Create the Test Command**:
   - Implement a command-line interface to test the ORPCManager
   - Add options to list specifications, methods, and display details

4. **Write Tests**:
   - Write unit tests for the OpenRPC model
   - Write unit tests for the ORPCManager
   - Write integration tests for the entire system

## 5. Detailed Method Specifications

### 5.1 ORPCManager Methods

#### NewORPCManager()
- Creates a new instance of the ORPCManager
- Initializes the specs map

#### LoadSpecs(dir string) error
- Reads all JSON files in the specified directory
- For each file, calls LoadSpec()
- Returns an error if any file fails to load

#### LoadSpec(path string) error
- Reads the JSON file at the specified path
- Parses the JSON into an OpenRPCSpec struct
- Validates the specification
- Stores the specification in the specs map using the filename (without extension) as the key
- Returns an error if any step fails

#### GetSpec(name string) *OpenRPCSpec
- Returns the OpenRPCSpec with the specified name
- Returns nil if the specification doesn't exist

#### ListSpecs() []string
- Returns a list of all loaded specification names

#### ListMethods(specName string) []string
- Returns a list of all method names in the specified specification
- Returns an empty list if the specification doesn't exist

#### GetMethod(specName string, methodName string) *Method
- Returns the Method with the specified name from the specified specification
- Returns nil if the specification or method doesn't exist

## 6. Example Usage

```go
// Initialize the ORPCManager
manager := openrpc.NewORPCManager()

// Load all specifications from the services directory
err := manager.LoadSpecs("pkg/openrpc/services")
if err != nil {
    log.Fatalf("Failed to load specifications: %v", err)
}

// List all loaded specifications
specs := manager.ListSpecs()
fmt.Println("Loaded specifications:")
for _, spec := range specs {
    fmt.Printf("- %s\n", spec)
}

// List all methods in the zinit specification
methods := manager.ListMethods("zinit")
fmt.Println("\nMethods in zinit specification:")
for _, method := range methods {
    fmt.Printf("- %s\n", method)
}

// Get details for a specific method
method := manager.GetMethod("zinit", "service_list")
if method != nil {
    fmt.Printf("\nDetails for method 'service_list':\n")
    fmt.Printf("Description: %s\n", method.Description)
    fmt.Printf("Parameters: %d\n", len(method.Params))
    fmt.Printf("Examples: %d\n", len(method.Examples))
}