plasma-mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +16 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +26 -0
- data/LICENSE +21 -0
- data/README.md +207 -0
- data/Rakefile +16 -0
- data/docs/ROADMAP.md +46 -0
- data/exe/plasma +8 -0
- data/lib/plasma/application.rb +193 -0
- data/lib/plasma/auth.rb +82 -0
- data/lib/plasma/auth_server.rb +45 -0
- data/lib/plasma/cli.rb +93 -0
- data/lib/plasma/component_generator.rb +111 -0
- data/lib/plasma/generator.rb +132 -0
- data/lib/plasma/loader.rb +32 -0
- data/lib/plasma/prompt.rb +10 -0
- data/lib/plasma/resource.rb +39 -0
- data/lib/plasma/server.rb +47 -0
- data/lib/plasma/storage/application_record.rb +10 -0
- data/lib/plasma/storage/record.rb +16 -0
- data/lib/plasma/storage/variable.rb +53 -0
- data/lib/plasma/storage.rb +101 -0
- data/lib/plasma/templates/.dockerignore.erb +40 -0
- data/lib/plasma/templates/.env.erb +2 -0
- data/lib/plasma/templates/.github/workflows/docker-build.yml.erb +52 -0
- data/lib/plasma/templates/.gitignore.erb +40 -0
- data/lib/plasma/templates/.ruby-version.erb +1 -0
- data/lib/plasma/templates/Dockerfile.erb +18 -0
- data/lib/plasma/templates/Gemfile.erb +6 -0
- data/lib/plasma/templates/README.md.erb +228 -0
- data/lib/plasma/templates/app/prompts/example_prompt.rb.erb +30 -0
- data/lib/plasma/templates/app/resources/example_resource.rb.erb +36 -0
- data/lib/plasma/templates/app/tools/example_tool.rb.erb +35 -0
- data/lib/plasma/templates/app/variables/example_variable.erb +20 -0
- data/lib/plasma/templates/config/application.rb.erb +24 -0
- data/lib/plasma/templates/config/boot.rb.erb +12 -0
- data/lib/plasma/templates/config/initializers/example.rb.erb +7 -0
- data/lib/plasma/templates/lib/version.rb.erb +5 -0
- data/lib/plasma/tool.rb +131 -0
- data/lib/plasma/version.rb +5 -0
- data/lib/plasma.rb +19 -0
- data/sig/plasma.rbs +4 -0
- metadata +257 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
name: Build and Publish Multi-Arch Docker Image
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
paths:
|
8
|
+
- 'lib/**/version.rb'
|
9
|
+
tags:
|
10
|
+
- 'v*' # Trigger on all semver-like tags: v1.2.3, v1.2.3-rc.1
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
build-and-push:
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
permissions:
|
16
|
+
contents: read
|
17
|
+
packages: write
|
18
|
+
|
19
|
+
steps:
|
20
|
+
- name: Checkout code
|
21
|
+
uses: actions/checkout@v4
|
22
|
+
|
23
|
+
- name: Extract version from version.rb
|
24
|
+
id: version
|
25
|
+
run: |
|
26
|
+
VERSION=$(ruby -e "require_relative 'lib/<%= name %>/version'; puts <%= name.camelize %>::VERSION")
|
27
|
+
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
28
|
+
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
29
|
+
echo "IS_STABLE=true" >> $GITHUB_ENV
|
30
|
+
else
|
31
|
+
echo "IS_STABLE=false" >> $GITHUB_ENV
|
32
|
+
fi
|
33
|
+
|
34
|
+
- name: Set up Docker Buildx
|
35
|
+
uses: docker/setup-buildx-action@v3
|
36
|
+
|
37
|
+
- name: Login to GitHub Container Registry
|
38
|
+
uses: docker/login-action@v3
|
39
|
+
with:
|
40
|
+
registry: ghcr.io
|
41
|
+
username: ${{ github.actor }}
|
42
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
43
|
+
|
44
|
+
- name: Build and push multi-arch Docker image
|
45
|
+
uses: docker/build-push-action@v5
|
46
|
+
with:
|
47
|
+
context: .
|
48
|
+
platforms: linux/amd64,linux/arm64
|
49
|
+
push: true
|
50
|
+
tags: |
|
51
|
+
ghcr.io/${{ github.repository }}:v${{ env.VERSION }}
|
52
|
+
${{ env.IS_STABLE == 'true' && format('ghcr.io/{0}:latest', github.repository) || '' }}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Ruby
|
2
|
+
*.gem
|
3
|
+
*.rbc
|
4
|
+
/.config
|
5
|
+
/coverage/
|
6
|
+
/InstalledFiles
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/spec/examples.txt
|
10
|
+
/test/tmp/
|
11
|
+
/test/version_tmp/
|
12
|
+
/tmp/
|
13
|
+
|
14
|
+
# Environment
|
15
|
+
.env
|
16
|
+
.env.*
|
17
|
+
!.env.example
|
18
|
+
|
19
|
+
# Logs
|
20
|
+
*.log
|
21
|
+
|
22
|
+
# Editor directories and files
|
23
|
+
.idea
|
24
|
+
.vscode
|
25
|
+
*.swp
|
26
|
+
*.swo
|
27
|
+
*~
|
28
|
+
|
29
|
+
# OS generated files
|
30
|
+
.DS_Store
|
31
|
+
.DS_Store?
|
32
|
+
._*
|
33
|
+
.Spotlight-V100
|
34
|
+
.Trashes
|
35
|
+
ehthumbs.db
|
36
|
+
Thumbs.db
|
37
|
+
|
38
|
+
# Docker
|
39
|
+
.docker/
|
40
|
+
docker-compose.override.yml
|
@@ -0,0 +1 @@
|
|
1
|
+
3.4.3
|
@@ -0,0 +1,18 @@
|
|
1
|
+
FROM ruby:3.4.3-slim
|
2
|
+
|
3
|
+
WORKDIR /<%= name %>
|
4
|
+
|
5
|
+
# Install build dependencies
|
6
|
+
RUN apt-get update && apt-get install -y \
|
7
|
+
build-essential \
|
8
|
+
&& rm -rf /var/lib/apt/lists/*
|
9
|
+
|
10
|
+
# Install dependencies
|
11
|
+
COPY Gemfile Gemfile.lock ./
|
12
|
+
RUN bundle install
|
13
|
+
|
14
|
+
# Copy application code
|
15
|
+
COPY . .
|
16
|
+
|
17
|
+
# Command to run the application
|
18
|
+
CMD ["bundle", "exec", "plasma", "server"]
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# <%= name.camelize %> MCP Server
|
2
|
+
|
3
|
+
This is a Model Context Protocol (MCP) server built with `plasma-mcp` framework.
|
4
|
+
|
5
|
+
## Using with Claude
|
6
|
+
|
7
|
+
To use this MCP server with Claude, add the following configuration to your Claude settings:
|
8
|
+
|
9
|
+
```json
|
10
|
+
{
|
11
|
+
"mcpServers": {
|
12
|
+
"<%= name.underscore %>": {
|
13
|
+
"command": "docker",
|
14
|
+
"args": [
|
15
|
+
"run",
|
16
|
+
"-i",
|
17
|
+
"--rm",
|
18
|
+
"ghcr.io/your-org/<%= name.underscore %>:latest"
|
19
|
+
]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
```
|
24
|
+
|
25
|
+
For local development without Docker:
|
26
|
+
|
27
|
+
```json
|
28
|
+
{
|
29
|
+
"mcpServers": {
|
30
|
+
"<%= name.underscore %>": {
|
31
|
+
"command": "plasma",
|
32
|
+
"args": [
|
33
|
+
"server",
|
34
|
+
"/path/to/<%= name.underscore %>"
|
35
|
+
]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
## Using with VS Code
|
42
|
+
|
43
|
+
Add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`.
|
44
|
+
|
45
|
+
```json
|
46
|
+
{
|
47
|
+
"mcp": {
|
48
|
+
"servers": {
|
49
|
+
"<%= name.underscore %>": {
|
50
|
+
"command": "docker",
|
51
|
+
"args": [
|
52
|
+
"run",
|
53
|
+
"-i",
|
54
|
+
"--rm",
|
55
|
+
"ghcr.io/your-org/<%= name.underscore %>:latest"
|
56
|
+
]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
```
|
62
|
+
|
63
|
+
Optionally, you can add a similar example (i.e. without the `mcp` key) to a file called `.vscode/mcp.json` in your workspace. This will allow you to share the configuration with others.
|
64
|
+
|
65
|
+
```json
|
66
|
+
{
|
67
|
+
"servers": {
|
68
|
+
"<%= name.underscore %>": {
|
69
|
+
"command": "docker",
|
70
|
+
"args": [
|
71
|
+
"run",
|
72
|
+
"-i",
|
73
|
+
"--rm",
|
74
|
+
"ghcr.io/your-org/<%= name.underscore %>:latest"
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
81
|
+
For local development without Docker:
|
82
|
+
|
83
|
+
```json
|
84
|
+
{
|
85
|
+
"mcp": {
|
86
|
+
"servers": {
|
87
|
+
"<%= name.underscore %>": {
|
88
|
+
"command": "plasma",
|
89
|
+
"args": [
|
90
|
+
"server",
|
91
|
+
"/path/to/<%= name.underscore %>"
|
92
|
+
]
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
```
|
98
|
+
|
99
|
+
More about using MCP server tools in VS Code's [agent mode documentation](https://code.visualstudio.com/docs/editor/agent-mode).
|
100
|
+
|
101
|
+
## Setup
|
102
|
+
|
103
|
+
1. Install dependencies:
|
104
|
+
|
105
|
+
```bash
|
106
|
+
bundle install
|
107
|
+
```
|
108
|
+
|
109
|
+
2. Configure environment variables in `.env` file
|
110
|
+
|
111
|
+
## Running the Server
|
112
|
+
|
113
|
+
To start the MCP server:
|
114
|
+
|
115
|
+
```bash
|
116
|
+
plasma server
|
117
|
+
```
|
118
|
+
|
119
|
+
## Authentication
|
120
|
+
|
121
|
+
To run the local authentication system:
|
122
|
+
|
123
|
+
```bash
|
124
|
+
plasma auth
|
125
|
+
```
|
126
|
+
|
127
|
+
## Project Structure
|
128
|
+
|
129
|
+
```
|
130
|
+
<%= name %>/
|
131
|
+
├── app/
|
132
|
+
│ ├── prompts/ # MCP prompts
|
133
|
+
│ ├── resources/ # MCP resources
|
134
|
+
│ ├── tools/ # MCP tools
|
135
|
+
│ ├── variables/ # Per-session variables
|
136
|
+
│ └── records/ # Stored objects
|
137
|
+
├── config/
|
138
|
+
│ ├── initializers/ # Preload configuration
|
139
|
+
│ ├── application.rb # MCP server configuration
|
140
|
+
│ └── boot.rb # Launch ignition sequence
|
141
|
+
└── .env # Environment variables
|
142
|
+
```
|
143
|
+
|
144
|
+
## Adding New Components
|
145
|
+
|
146
|
+
### Adding a new Tool
|
147
|
+
|
148
|
+
Generate a new tool using the CLI:
|
149
|
+
|
150
|
+
```bash
|
151
|
+
plasma g tool my_tool name:string description:string
|
152
|
+
```
|
153
|
+
|
154
|
+
This will generate a tool file in `app/tools/my_tool.rb` that follows this structure:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
# app/tools/my_tool.rb
|
158
|
+
module <%= name.camelize %>
|
159
|
+
module Tools
|
160
|
+
class MyTool < Plasma::Tool
|
161
|
+
param :name,
|
162
|
+
type: :string,
|
163
|
+
description: "Name parameter description"
|
164
|
+
|
165
|
+
param :description,
|
166
|
+
type: :string,
|
167
|
+
description: "Description parameter description"
|
168
|
+
|
169
|
+
def call
|
170
|
+
respond_with(:text,
|
171
|
+
text: "Your tool response here"
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
### Adding a new Prompt
|
180
|
+
|
181
|
+
Generate a new prompt using the CLI:
|
182
|
+
|
183
|
+
```bash
|
184
|
+
plasma g prompt my_prompt
|
185
|
+
```
|
186
|
+
|
187
|
+
This will generate a prompt file in `app/prompts/my_prompt.rb`:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
# app/prompts/my_prompt.rb
|
191
|
+
module <%= name.camelize %>
|
192
|
+
module Prompts
|
193
|
+
class MyPrompt
|
194
|
+
def self.system_prompt
|
195
|
+
<<~PROMPT
|
196
|
+
Your system prompt content here.
|
197
|
+
PROMPT
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
### Adding a new Resource
|
205
|
+
|
206
|
+
Generate a new resource using the CLI:
|
207
|
+
|
208
|
+
```bash
|
209
|
+
plasma g resource my_resource
|
210
|
+
```
|
211
|
+
|
212
|
+
### Adding a new Variable
|
213
|
+
|
214
|
+
Generate a new variable using the CLI:
|
215
|
+
|
216
|
+
```bash
|
217
|
+
plasma g variable my_variable
|
218
|
+
```
|
219
|
+
|
220
|
+
## Interactive Console
|
221
|
+
|
222
|
+
To start an interactive console with your plasma-mcp application loaded:
|
223
|
+
|
224
|
+
```bash
|
225
|
+
plasma console
|
226
|
+
```
|
227
|
+
|
228
|
+
This will give you access to your project's environment where you can interact with your components, storage variables, and other features.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
module Prompts
|
5
|
+
class <%= name.camelize %> < Plasma::Prompt
|
6
|
+
# Define the system prompt content
|
7
|
+
with_metadata do
|
8
|
+
{
|
9
|
+
name: "<%= name.underscore %>",
|
10
|
+
description: "A <%= name.underscore %> prompt",
|
11
|
+
arguments: <%= parameters.map { |name, type| { name: name, description: "The #{name} parameter", required: true } }.to_json %>
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
messages = [
|
17
|
+
{
|
18
|
+
role: "user",
|
19
|
+
content: {
|
20
|
+
type: "text",
|
21
|
+
text: "Process these parameters: <%= parameters.keys.map { |p| "#{p}: #{p}" }.join(", ") %>"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
]
|
25
|
+
|
26
|
+
MessageResponse[message: messages]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
module Resources
|
5
|
+
class <%= name.camelize %> < Plasma::Resource
|
6
|
+
# Required by MCP - defines the resource schema
|
7
|
+
with_metadata do
|
8
|
+
{
|
9
|
+
name: "<%= name.underscore %>",
|
10
|
+
description: "A <%= name.underscore %> resource",
|
11
|
+
content_schema: <%= parameter_schema.to_json %>
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Required by MCP - defines the resource content
|
16
|
+
def content
|
17
|
+
{
|
18
|
+
id: id,
|
19
|
+
<%= parameters.map { |name, type| "#{name}: #{name}" }.join(",\n ") %>
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :id<%= parameters.map { |name, type| ", :#{name}" }.join %>
|
24
|
+
|
25
|
+
def initialize(id:, <%= parameters.map { |name, type| "#{name}:" }.join(", ") %>)
|
26
|
+
@id = id
|
27
|
+
<%= parameters.map { |name, type| "@#{name} = #{name}" }.join("\n ") %>
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def call
|
32
|
+
TextResponse[text: "Here's the data"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
module Tools
|
5
|
+
# A <%= kebab_name %> tool
|
6
|
+
class <%= name.camelize %>Tool < Plasma::Tool
|
7
|
+
<% params.each do |name, type| %>
|
8
|
+
param :<%= name %>, type: <%= type.capitalize %>, description: "<%= name.capitalize %> parameter", required: true
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
# Required, implements the tool functionality
|
12
|
+
def call
|
13
|
+
# Example of different response types:
|
14
|
+
|
15
|
+
# Text response with parameters
|
16
|
+
respond_with(:text, text: "Hello from <%= name.camelize %>Tool with params: <% params.each do |name, type| %>#{params[:<%= name %>]} <% end %>")
|
17
|
+
|
18
|
+
# Image response with mime type
|
19
|
+
# respond_with(:image, data: image_data, mime_type: "image/png")
|
20
|
+
|
21
|
+
# Image response without mime type
|
22
|
+
# respond_with(:image, data: image_data)
|
23
|
+
|
24
|
+
# Resource response with mime type
|
25
|
+
# respond_with(:resource, mime_type: "text/html", text: "Resource content", uri: "https://example.com")
|
26
|
+
|
27
|
+
# Resource response without mime type
|
28
|
+
# respond_with(:resource, text: "Resource content", uri: "https://example.com")
|
29
|
+
|
30
|
+
# Error response
|
31
|
+
# respond_with(:error, text: "An error occurred")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
module Variables
|
5
|
+
# A <%= name.underscore %> variable
|
6
|
+
class <%= name.camelize %> < Plasma::Storage::Variable
|
7
|
+
default <%= default_value %>
|
8
|
+
|
9
|
+
<% operations.each do |op| %>
|
10
|
+
def self.<%= op[:name] %>(<%= op[:params].join(", ") %>)
|
11
|
+
self.set(self.get <%= op[:operator] %> <%= op[:params].first %>)
|
12
|
+
end
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
def self.clear
|
16
|
+
self.set(<%= default_value %>)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "plasma"
|
4
|
+
require_relative "../lib/<%= name %>/version"
|
5
|
+
|
6
|
+
module <%= name.camelize %>
|
7
|
+
class Application < Plasma::Application
|
8
|
+
# Configure your application here
|
9
|
+
self.initialize! do |config|
|
10
|
+
# Name will be automatically set as "<%= name.camelize %> MCP Server" if not set
|
11
|
+
# config.name = "Custom Application Name"
|
12
|
+
config.module_name = "<%= name.camelize %>"
|
13
|
+
|
14
|
+
config.version = <%= name.camelize %>::VERSION
|
15
|
+
config.enable_log = true
|
16
|
+
|
17
|
+
# Example of requiring an environment variable (uncomment to use)
|
18
|
+
# config.require_environment_variable("API_KEY")
|
19
|
+
|
20
|
+
# Example of setting an environment variable (uncomment to use)
|
21
|
+
# config.set_environment_variable("DEBUG_MODE", "true")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Initial ignition sequence
|
4
|
+
require "bundler/setup"
|
5
|
+
Bundler.require(:default, ENV["PLASMA_ENV"] || "development")
|
6
|
+
|
7
|
+
# Load environment variables from .env file
|
8
|
+
require "dotenv"
|
9
|
+
Dotenv.load
|
10
|
+
|
11
|
+
# Load initializers
|
12
|
+
Dir[File.join(__dir__, "initializers/**/*.rb")].sort.each { |f| require f }
|
data/lib/plasma/tool.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "model_context_protocol"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Plasma
|
7
|
+
# Base tool class for PLASMA applications
|
8
|
+
class Tool < ModelContextProtocol::Server::Tool
|
9
|
+
class << self
|
10
|
+
def param(name, type:, description: nil, required: false)
|
11
|
+
@params ||= {}
|
12
|
+
@params[name.to_sym] = {
|
13
|
+
type: type.to_s.downcase,
|
14
|
+
description:,
|
15
|
+
required:
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def defined_params
|
20
|
+
@params || {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def inherited(subclass)
|
24
|
+
super
|
25
|
+
const_name = subclass.to_s.split("::").last
|
26
|
+
Plasma.const_set(const_name, subclass) unless Plasma.const_defined?(const_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def metadata
|
30
|
+
{
|
31
|
+
name: to_s.split("::").last.gsub("Tool", "").underscore,
|
32
|
+
description: extract_description,
|
33
|
+
inputSchema: {
|
34
|
+
type: "object",
|
35
|
+
properties: defined_params.transform_values { |v| v.slice(:type, :description).compact },
|
36
|
+
required: defined_params.select { |_, v| v[:required] }.keys.map(&:to_s)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract_description
|
42
|
+
return @description if @description
|
43
|
+
|
44
|
+
@description = read_comments_from_file(file_path).presence || "No description available"
|
45
|
+
end
|
46
|
+
|
47
|
+
def file_path
|
48
|
+
loader = Zeitwerk::Registry.loaders.first
|
49
|
+
module_name = to_s.split("::")[0..-2].join("::").constantize
|
50
|
+
class_name = to_s.split("::").last.to_sym
|
51
|
+
path = loader.instance_variable_get(:@inceptions).instance_variable_get(:@map)[module_name][class_name]
|
52
|
+
return nil unless path
|
53
|
+
|
54
|
+
File.expand_path(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def read_comments_from_file(file_path)
|
58
|
+
return "No description available" unless file_path
|
59
|
+
|
60
|
+
File.readlines(file_path)
|
61
|
+
.drop_while { |line| line.include?("frozen_string_literal") || line.strip.empty? }
|
62
|
+
.drop_while { |line| line.strip.start_with?("module") }
|
63
|
+
.take_while { |line| line.strip.start_with?("#") }
|
64
|
+
.join
|
65
|
+
.strip
|
66
|
+
.gsub(/^#\s*/, "")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# rubocop:disable Lint/MissingSuper
|
71
|
+
# DO NOT call super as we are deliberately decoupling the tool from the underlying library
|
72
|
+
def initialize(params)
|
73
|
+
@raw_params = params
|
74
|
+
@params = coerce_and_validate!(params)
|
75
|
+
end
|
76
|
+
# rubocop:enable Lint/MissingSuper
|
77
|
+
|
78
|
+
attr_reader :params
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def coerce_and_validate!(input)
|
83
|
+
coerced = {}
|
84
|
+
self.class.defined_params.each do |key, config|
|
85
|
+
value = input[key.to_s]
|
86
|
+
raise ArgumentError, "Missing required parameter: #{key}" if config[:required] && value.nil?
|
87
|
+
|
88
|
+
coerced[key] = coerce_value(value, config[:type])
|
89
|
+
end
|
90
|
+
coerced
|
91
|
+
end
|
92
|
+
|
93
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
94
|
+
# This method is deliberately complex as it handles type coercion and validation
|
95
|
+
def coerce_value(value, type)
|
96
|
+
return if value.nil?
|
97
|
+
|
98
|
+
case type.to_s.downcase.to_sym
|
99
|
+
when :integer then begin
|
100
|
+
Integer(value)
|
101
|
+
rescue StandardError
|
102
|
+
raise ArgumentError, "Invalid integer: #{value}"
|
103
|
+
end
|
104
|
+
when :float then begin
|
105
|
+
Float(value)
|
106
|
+
rescue StandardError
|
107
|
+
raise ArgumentError, "Invalid float: #{value}"
|
108
|
+
end
|
109
|
+
when :boolean then !!(value == true || value.to_s.downcase == "true")
|
110
|
+
when :string then value.to_s
|
111
|
+
when :array
|
112
|
+
if value.is_a?(Array)
|
113
|
+
value
|
114
|
+
elsif value.is_a?(String)
|
115
|
+
begin
|
116
|
+
parsed = JSON.parse(value)
|
117
|
+
raise ArgumentError, "Invalid array: #{value}" unless parsed.is_a?(Array)
|
118
|
+
|
119
|
+
parsed
|
120
|
+
rescue JSON::ParserError
|
121
|
+
raise ArgumentError, "Invalid array: #{value}"
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise ArgumentError, "Invalid array: #{value}"
|
125
|
+
end
|
126
|
+
else value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
130
|
+
end
|
131
|
+
end
|
data/lib/plasma.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "plasma/version"
|
4
|
+
require_relative "plasma/application"
|
5
|
+
require_relative "plasma/generator"
|
6
|
+
require_relative "plasma/component_generator"
|
7
|
+
require_relative "plasma/server"
|
8
|
+
require_relative "plasma/auth"
|
9
|
+
require_relative "plasma/loader"
|
10
|
+
require_relative "plasma/cli"
|
11
|
+
require_relative "plasma/prompt"
|
12
|
+
require_relative "plasma/resource"
|
13
|
+
require_relative "plasma/tool"
|
14
|
+
require_relative "plasma/storage"
|
15
|
+
|
16
|
+
module Plasma
|
17
|
+
class Error < StandardError; end
|
18
|
+
# Your code goes here...
|
19
|
+
end
|
data/sig/plasma.rbs
ADDED