ropilot 0.1.2 → 0.1.3
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.
- package/README.md +1 -1
- package/lib/config.js +1 -1
- package/lib/proxy.js +54 -18
- package/lib/setup.js +114 -17
- package/package.json +1 -1
package/README.md
CHANGED
package/lib/config.js
CHANGED
|
@@ -14,7 +14,7 @@ const GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, 'config.json');
|
|
|
14
14
|
const PROJECT_CONFIG_FILE = '.ropilot.json';
|
|
15
15
|
|
|
16
16
|
// Edge server base URL
|
|
17
|
-
export const EDGE_URL = 'https://ropilot.ai/
|
|
17
|
+
export const EDGE_URL = 'https://ropilot.ai/edge';
|
|
18
18
|
|
|
19
19
|
// Default config
|
|
20
20
|
const DEFAULT_CONFIG = {
|
package/lib/proxy.js
CHANGED
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { createInterface } from 'readline';
|
|
9
|
-
import {
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
import { getApiKey, EDGE_URL, loadGlobalConfig, saveGlobalConfig } from './config.js';
|
|
13
|
+
|
|
14
|
+
// Plugin version check URL (served from ropilot.ai main server)
|
|
15
|
+
const PLUGIN_VERSION_URL = 'https://ropilot.ai/plugin/version';
|
|
16
|
+
const PLUGIN_DOWNLOAD_URL = 'https://ropilot.ai/plugin/StudioPlugin.lua';
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Send JSON-RPC response to stdout
|
|
@@ -54,23 +61,11 @@ async function forwardToEdge(apiKey, request) {
|
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
/**
|
|
57
|
-
* Handle MCP initialize request
|
|
64
|
+
* Handle MCP initialize request - forward to edge to get instructions
|
|
58
65
|
*/
|
|
59
|
-
function handleInitialize(request) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
id: request.id,
|
|
63
|
-
result: {
|
|
64
|
-
protocolVersion: '2024-11-05',
|
|
65
|
-
capabilities: {
|
|
66
|
-
tools: {}
|
|
67
|
-
},
|
|
68
|
-
serverInfo: {
|
|
69
|
-
name: 'ropilot',
|
|
70
|
-
version: '0.1.0'
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
};
|
|
66
|
+
async function handleInitialize(apiKey, request) {
|
|
67
|
+
const edgeResponse = await forwardToEdge(apiKey, request);
|
|
68
|
+
return edgeResponse;
|
|
74
69
|
}
|
|
75
70
|
|
|
76
71
|
/**
|
|
@@ -97,7 +92,7 @@ async function processRequest(apiKey, request) {
|
|
|
97
92
|
|
|
98
93
|
switch (method) {
|
|
99
94
|
case 'initialize':
|
|
100
|
-
return handleInitialize(request);
|
|
95
|
+
return await handleInitialize(apiKey, request);
|
|
101
96
|
|
|
102
97
|
case 'initialized':
|
|
103
98
|
// Notification, no response needed
|
|
@@ -115,6 +110,44 @@ async function processRequest(apiKey, request) {
|
|
|
115
110
|
}
|
|
116
111
|
}
|
|
117
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Check for plugin updates (runs in background, writes to stderr)
|
|
115
|
+
*/
|
|
116
|
+
async function checkPluginUpdate() {
|
|
117
|
+
try {
|
|
118
|
+
const response = await fetch(PLUGIN_VERSION_URL);
|
|
119
|
+
if (!response.ok) return;
|
|
120
|
+
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
const latestVersion = data.version;
|
|
123
|
+
const downloadUrl = data.download_url || PLUGIN_DOWNLOAD_URL;
|
|
124
|
+
|
|
125
|
+
// Check if we've already notified about this version
|
|
126
|
+
const config = loadGlobalConfig();
|
|
127
|
+
const lastNotifiedVersion = config.lastPluginVersionNotified;
|
|
128
|
+
|
|
129
|
+
if (latestVersion && latestVersion !== lastNotifiedVersion) {
|
|
130
|
+
// Check if we have a stored plugin version
|
|
131
|
+
const storedVersion = config.pluginVersion;
|
|
132
|
+
|
|
133
|
+
if (!storedVersion || storedVersion !== latestVersion) {
|
|
134
|
+
// New version available - notify via stderr (doesn't interfere with MCP protocol)
|
|
135
|
+
console.error('');
|
|
136
|
+
console.error(`[Ropilot] Plugin update available: v${latestVersion}`);
|
|
137
|
+
console.error(`[Ropilot] Download: ${downloadUrl}`);
|
|
138
|
+
console.error(`[Ropilot] Install to Roblox Studio plugins folder and restart Studio.`);
|
|
139
|
+
console.error('');
|
|
140
|
+
|
|
141
|
+
// Save that we notified about this version
|
|
142
|
+
config.lastPluginVersionNotified = latestVersion;
|
|
143
|
+
saveGlobalConfig(config);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} catch (err) {
|
|
147
|
+
// Silently ignore update check errors - not critical
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
118
151
|
/**
|
|
119
152
|
* Run the stdio MCP server
|
|
120
153
|
*/
|
|
@@ -127,6 +160,9 @@ export async function serve() {
|
|
|
127
160
|
process.exit(1);
|
|
128
161
|
}
|
|
129
162
|
|
|
163
|
+
// Check for plugin updates in background (non-blocking)
|
|
164
|
+
checkPluginUpdate();
|
|
165
|
+
|
|
130
166
|
// Read JSON-RPC messages from stdin
|
|
131
167
|
let buffer = '';
|
|
132
168
|
let contentLength = -1;
|
package/lib/setup.js
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* - First-time setup
|
|
6
6
|
* - Downloading system prompts
|
|
7
7
|
* - Creating project configs
|
|
8
|
+
* - Installing Studio plugin
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import { existsSync, writeFileSync, mkdirSync, readFileSync } from 'fs';
|
|
11
12
|
import { join, dirname } from 'path';
|
|
12
|
-
import { homedir } from 'os';
|
|
13
|
+
import { homedir, platform } from 'os';
|
|
13
14
|
import { createInterface } from 'readline';
|
|
14
15
|
import {
|
|
15
16
|
loadGlobalConfig,
|
|
@@ -22,6 +23,25 @@ import {
|
|
|
22
23
|
// Prompts storage directory
|
|
23
24
|
const PROMPTS_DIR = join(homedir(), '.ropilot', 'prompts');
|
|
24
25
|
|
|
26
|
+
// Plugin URLs
|
|
27
|
+
const PLUGIN_VERSION_URL = 'https://ropilot.ai/plugin/version';
|
|
28
|
+
const PLUGIN_DOWNLOAD_URL = 'https://ropilot.ai/plugin/StudioPlugin.lua';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get Roblox plugins folder path based on OS
|
|
32
|
+
*/
|
|
33
|
+
function getPluginsFolder() {
|
|
34
|
+
const os = platform();
|
|
35
|
+
if (os === 'win32') {
|
|
36
|
+
return join(process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'), 'Roblox', 'Plugins');
|
|
37
|
+
} else if (os === 'darwin') {
|
|
38
|
+
return join(homedir(), 'Documents', 'Roblox', 'Plugins');
|
|
39
|
+
} else {
|
|
40
|
+
// Linux - Roblox doesn't officially support Linux, but some use Wine
|
|
41
|
+
return join(homedir(), '.local', 'share', 'Roblox', 'Plugins');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
25
45
|
/**
|
|
26
46
|
* Prompt for user input
|
|
27
47
|
*/
|
|
@@ -39,6 +59,89 @@ function prompt(question) {
|
|
|
39
59
|
});
|
|
40
60
|
}
|
|
41
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Install Studio plugin to Roblox plugins folder
|
|
64
|
+
*/
|
|
65
|
+
async function installPlugin() {
|
|
66
|
+
console.log('Installing Studio plugin...');
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// Check plugin version
|
|
70
|
+
const versionResponse = await fetch(PLUGIN_VERSION_URL);
|
|
71
|
+
if (!versionResponse.ok) {
|
|
72
|
+
throw new Error(`Failed to fetch plugin version: ${versionResponse.status}`);
|
|
73
|
+
}
|
|
74
|
+
const versionInfo = await versionResponse.json();
|
|
75
|
+
console.log(` Plugin version: ${versionInfo.version}`);
|
|
76
|
+
|
|
77
|
+
// Download plugin
|
|
78
|
+
const pluginResponse = await fetch(PLUGIN_DOWNLOAD_URL);
|
|
79
|
+
if (!pluginResponse.ok) {
|
|
80
|
+
throw new Error(`Failed to download plugin: ${pluginResponse.status}`);
|
|
81
|
+
}
|
|
82
|
+
const pluginSource = await pluginResponse.text();
|
|
83
|
+
|
|
84
|
+
// Get plugins folder
|
|
85
|
+
const pluginsFolder = getPluginsFolder();
|
|
86
|
+
|
|
87
|
+
// Create plugins folder if it doesn't exist
|
|
88
|
+
mkdirSync(pluginsFolder, { recursive: true });
|
|
89
|
+
|
|
90
|
+
// Write plugin file
|
|
91
|
+
const pluginPath = join(pluginsFolder, 'RopilotPlugin.lua');
|
|
92
|
+
writeFileSync(pluginPath, pluginSource);
|
|
93
|
+
|
|
94
|
+
console.log(` Installed to: ${pluginPath}`);
|
|
95
|
+
|
|
96
|
+
// Save version to config
|
|
97
|
+
const config = loadGlobalConfig();
|
|
98
|
+
config.pluginVersion = versionInfo.version;
|
|
99
|
+
saveGlobalConfig(config);
|
|
100
|
+
|
|
101
|
+
return true;
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error(` Failed to install plugin: ${err.message}`);
|
|
104
|
+
console.log(' You can manually download from: https://ropilot.ai/plugin/StudioPlugin.lua');
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Create .mcp.json for Claude Code compatibility
|
|
111
|
+
*/
|
|
112
|
+
function createMcpConfig() {
|
|
113
|
+
const mcpConfig = {
|
|
114
|
+
mcpServers: {
|
|
115
|
+
ropilot: {
|
|
116
|
+
command: "npx",
|
|
117
|
+
args: ["ropilot"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const mcpPath = '.mcp.json';
|
|
123
|
+
|
|
124
|
+
if (existsSync(mcpPath)) {
|
|
125
|
+
// Merge with existing config
|
|
126
|
+
try {
|
|
127
|
+
const existing = JSON.parse(readFileSync(mcpPath, 'utf-8'));
|
|
128
|
+
if (!existing.mcpServers?.ropilot) {
|
|
129
|
+
existing.mcpServers = existing.mcpServers || {};
|
|
130
|
+
existing.mcpServers.ropilot = mcpConfig.mcpServers.ropilot;
|
|
131
|
+
writeFileSync(mcpPath, JSON.stringify(existing, null, 2));
|
|
132
|
+
console.log(` Updated: ${mcpPath} (added ropilot server)`);
|
|
133
|
+
} else {
|
|
134
|
+
console.log(` Exists: ${mcpPath} (ropilot already configured)`);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error(` Failed to update ${mcpPath}: ${err.message}`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
|
|
141
|
+
console.log(` Created: ${mcpPath}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
42
145
|
/**
|
|
43
146
|
* Download prompts from edge server
|
|
44
147
|
*/
|
|
@@ -209,34 +312,28 @@ export async function init(providedApiKey = null) {
|
|
|
209
312
|
console.log('');
|
|
210
313
|
}
|
|
211
314
|
|
|
315
|
+
// Install Studio plugin
|
|
316
|
+
console.log('');
|
|
317
|
+
await installPlugin();
|
|
318
|
+
console.log('');
|
|
319
|
+
|
|
212
320
|
// Download prompts
|
|
213
321
|
const pkg = await downloadPrompts(apiKey);
|
|
214
322
|
console.log('');
|
|
215
323
|
|
|
216
|
-
// Set up project
|
|
324
|
+
// Set up project files
|
|
217
325
|
console.log('Setting up project files...');
|
|
218
326
|
setupProjectPrompts(pkg);
|
|
327
|
+
createMcpConfig();
|
|
219
328
|
console.log('');
|
|
220
329
|
|
|
221
330
|
// Done!
|
|
222
331
|
console.log('Setup complete!');
|
|
223
332
|
console.log('');
|
|
224
333
|
console.log('Next steps:');
|
|
225
|
-
console.log('1.
|
|
226
|
-
console.log('2.
|
|
227
|
-
console.log('');
|
|
228
|
-
console.log(' For Claude Desktop, add to claude_desktop_config.json:');
|
|
229
|
-
console.log(' {');
|
|
230
|
-
console.log(' "mcpServers": {');
|
|
231
|
-
console.log(' "ropilot": {');
|
|
232
|
-
console.log(' "command": "npx",');
|
|
233
|
-
console.log(' "args": ["ropilot"]');
|
|
234
|
-
console.log(' }');
|
|
235
|
-
console.log(' }');
|
|
236
|
-
console.log(' }');
|
|
237
|
-
console.log('');
|
|
238
|
-
console.log(' Or use HTTP directly:');
|
|
239
|
-
console.log(` ${EDGE_URL}/mcp/${apiKey}/message`);
|
|
334
|
+
console.log('1. Restart Roblox Studio to load the plugin');
|
|
335
|
+
console.log('2. In Studio: Plugins tab → Ropilot → Settings → Enter your API key');
|
|
336
|
+
console.log('3. Run Claude Code in this directory - it will auto-detect .mcp.json');
|
|
240
337
|
console.log('');
|
|
241
338
|
}
|
|
242
339
|
|