ropilot 0.1.2

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 ADDED
@@ -0,0 +1,76 @@
1
+ # Ropilot CLI
2
+
3
+ AI-powered Roblox development assistant - MCP CLI wrapper.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Run directly with npx (recommended)
9
+ npx ropilot init
10
+
11
+ # Or install globally
12
+ npm install -g ropilot
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ 1. **Initialize Ropilot in your project:**
18
+ ```bash
19
+ npx ropilot init
20
+ ```
21
+ This will:
22
+ - Prompt for your API key (get one at https://ropilot.ai)
23
+ - Download the latest agent prompts and configs
24
+ - Set up `.claude/` directory with subagent definitions
25
+
26
+ 2. **Add to your AI IDE:**
27
+
28
+ **Claude Desktop** - Add to `claude_desktop_config.json`:
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "ropilot": {
33
+ "command": "npx",
34
+ "args": ["ropilot"]
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ **Or use HTTP directly:**
41
+ ```
42
+ https://ropilot.ai/ropilot/mcp/YOUR_API_KEY/message
43
+ ```
44
+
45
+ 3. **Make sure Roblox Studio is running** with the Ropilot plugin installed.
46
+
47
+ ## Commands
48
+
49
+ ```bash
50
+ npx ropilot init [key] # Set up Ropilot in current project
51
+ npx ropilot # Run as stdio MCP server
52
+ npx ropilot config # Show current configuration
53
+ npx ropilot update # Update prompts to latest version
54
+ ```
55
+
56
+ ## How It Works
57
+
58
+ The CLI acts as a thin wrapper around the Ropilot edge server:
59
+
60
+ 1. **On `init`**: Downloads agent prompts and configs from the edge server, sets up your project
61
+ 2. **On `serve`** (default): Runs as a stdio MCP server, proxying all requests to the edge server
62
+
63
+ ## Configuration
64
+
65
+ Global config is stored in `~/.ropilot/config.json`.
66
+
67
+ Project-specific config can be added in `.ropilot.json`:
68
+ ```json
69
+ {
70
+ "apiKey": "ropilot_..."
71
+ }
72
+ ```
73
+
74
+ ## Links
75
+
76
+ - Website: https://ropilot.ai
package/bin/ropilot.js ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Ropilot CLI
5
+ *
6
+ * Commands:
7
+ * ropilot init [key] - Set up Ropilot in current project (downloads prompts, creates configs)
8
+ * ropilot - Run as stdio MCP server (proxies to edge)
9
+ * ropilot config - Show current configuration
10
+ * ropilot update - Update prompts and configs to latest version
11
+ */
12
+
13
+ import { fileURLToPath } from 'url';
14
+ import { dirname, join } from 'path';
15
+ import { existsSync, readFileSync } from 'fs';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = dirname(__filename);
19
+ const libDir = join(__dirname, '..', 'lib');
20
+
21
+ // Parse command line args
22
+ const args = process.argv.slice(2);
23
+ const command = args[0] || 'serve';
24
+
25
+ async function main() {
26
+ switch (command) {
27
+ case 'init': {
28
+ const { init } = await import(join(libDir, 'setup.js'));
29
+ const apiKey = args[1] || null;
30
+ await init(apiKey);
31
+ break;
32
+ }
33
+
34
+ case 'update': {
35
+ const { update } = await import(join(libDir, 'setup.js'));
36
+ await update();
37
+ break;
38
+ }
39
+
40
+ case 'config': {
41
+ const { showConfig } = await import(join(libDir, 'config.js'));
42
+ await showConfig();
43
+ break;
44
+ }
45
+
46
+ case 'serve':
47
+ default: {
48
+ // If first arg looks like a command but isn't recognized, show help
49
+ if (command && !command.startsWith('-') && !['serve', 'init', 'update', 'config'].includes(command)) {
50
+ console.error(`Unknown command: ${command}`);
51
+ console.error('');
52
+ console.error('Usage:');
53
+ console.error(' ropilot init [key] - Set up Ropilot in current project');
54
+ console.error(' ropilot - Run as stdio MCP server');
55
+ console.error(' ropilot config - Show current configuration');
56
+ console.error(' ropilot update - Update prompts to latest version');
57
+ process.exit(1);
58
+ }
59
+
60
+ const { serve } = await import(join(libDir, 'proxy.js'));
61
+ await serve();
62
+ break;
63
+ }
64
+ }
65
+ }
66
+
67
+ main().catch(err => {
68
+ console.error('Error:', err.message);
69
+ process.exit(1);
70
+ });
package/lib/config.js ADDED
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Configuration management for Ropilot CLI
3
+ */
4
+
5
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { homedir } from 'os';
8
+
9
+ // Global config directory (~/.ropilot/)
10
+ const GLOBAL_CONFIG_DIR = join(homedir(), '.ropilot');
11
+ const GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, 'config.json');
12
+
13
+ // Project-level config file
14
+ const PROJECT_CONFIG_FILE = '.ropilot.json';
15
+
16
+ // Edge server base URL
17
+ export const EDGE_URL = 'https://ropilot.ai/ropilot';
18
+
19
+ // Default config
20
+ const DEFAULT_CONFIG = {
21
+ apiKey: null,
22
+ promptsVersion: null,
23
+ lastUpdated: null
24
+ };
25
+
26
+ /**
27
+ * Ensure global config directory exists
28
+ */
29
+ export function ensureConfigDir() {
30
+ if (!existsSync(GLOBAL_CONFIG_DIR)) {
31
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Load global config
37
+ */
38
+ export function loadGlobalConfig() {
39
+ ensureConfigDir();
40
+
41
+ if (existsSync(GLOBAL_CONFIG_FILE)) {
42
+ try {
43
+ return JSON.parse(readFileSync(GLOBAL_CONFIG_FILE, 'utf-8'));
44
+ } catch (e) {
45
+ return { ...DEFAULT_CONFIG };
46
+ }
47
+ }
48
+
49
+ return { ...DEFAULT_CONFIG };
50
+ }
51
+
52
+ /**
53
+ * Save global config
54
+ */
55
+ export function saveGlobalConfig(config) {
56
+ ensureConfigDir();
57
+ writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2));
58
+ }
59
+
60
+ /**
61
+ * Load project config (if exists)
62
+ */
63
+ export function loadProjectConfig() {
64
+ if (existsSync(PROJECT_CONFIG_FILE)) {
65
+ try {
66
+ return JSON.parse(readFileSync(PROJECT_CONFIG_FILE, 'utf-8'));
67
+ } catch (e) {
68
+ return null;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ /**
75
+ * Get the API key (project config overrides global)
76
+ */
77
+ export function getApiKey() {
78
+ const projectConfig = loadProjectConfig();
79
+ if (projectConfig?.apiKey) {
80
+ return projectConfig.apiKey;
81
+ }
82
+
83
+ const globalConfig = loadGlobalConfig();
84
+ return globalConfig.apiKey;
85
+ }
86
+
87
+ /**
88
+ * Set the API key in global config
89
+ */
90
+ export function setApiKey(apiKey) {
91
+ const config = loadGlobalConfig();
92
+ config.apiKey = apiKey;
93
+ saveGlobalConfig(config);
94
+ }
95
+
96
+ /**
97
+ * Show current configuration
98
+ */
99
+ export async function showConfig() {
100
+ const globalConfig = loadGlobalConfig();
101
+ const projectConfig = loadProjectConfig();
102
+
103
+ console.log('Ropilot Configuration');
104
+ console.log('=====================');
105
+ console.log('');
106
+ console.log('Global config (~/.ropilot/config.json):');
107
+ console.log(` API Key: ${globalConfig.apiKey ? globalConfig.apiKey.slice(0, 20) + '...' : '(not set)'}`);
108
+ console.log(` Prompts Version: ${globalConfig.promptsVersion || '(not downloaded)'}`);
109
+ console.log(` Last Updated: ${globalConfig.lastUpdated || 'never'}`);
110
+ console.log('');
111
+
112
+ if (projectConfig) {
113
+ console.log('Project config (.ropilot.json):');
114
+ console.log(` API Key: ${projectConfig.apiKey ? projectConfig.apiKey.slice(0, 20) + '...' : '(not set)'}`);
115
+ console.log('');
116
+ }
117
+
118
+ console.log(`Edge Server: ${EDGE_URL}`);
119
+ }
package/lib/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Ropilot CLI - Main exports
3
+ */
4
+
5
+ export { init, update } from './setup.js';
6
+ export { serve } from './proxy.js';
7
+ export { loadGlobalConfig, saveGlobalConfig, getApiKey, setApiKey, EDGE_URL } from './config.js';
package/lib/proxy.js ADDED
@@ -0,0 +1,209 @@
1
+ /**
2
+ * stdio to HTTP proxy for Ropilot MCP
3
+ *
4
+ * This module implements a stdio MCP server that proxies
5
+ * all requests to the Ropilot edge server.
6
+ */
7
+
8
+ import { createInterface } from 'readline';
9
+ import { getApiKey, EDGE_URL } from './config.js';
10
+
11
+ /**
12
+ * Send JSON-RPC response to stdout
13
+ */
14
+ function sendResponse(response) {
15
+ const json = JSON.stringify(response);
16
+ process.stdout.write(`Content-Length: ${Buffer.byteLength(json)}\r\n\r\n${json}`);
17
+ }
18
+
19
+ /**
20
+ * Send JSON-RPC error response
21
+ */
22
+ function sendError(id, code, message) {
23
+ sendResponse({
24
+ jsonrpc: '2.0',
25
+ id,
26
+ error: { code, message }
27
+ });
28
+ }
29
+
30
+ /**
31
+ * Forward request to edge server
32
+ */
33
+ async function forwardToEdge(apiKey, request) {
34
+ const url = `${EDGE_URL}/mcp/${apiKey}/message`;
35
+
36
+ try {
37
+ const response = await fetch(url, {
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json'
41
+ },
42
+ body: JSON.stringify(request)
43
+ });
44
+
45
+ if (!response.ok) {
46
+ const text = await response.text();
47
+ throw new Error(`Edge server error: ${response.status} ${text}`);
48
+ }
49
+
50
+ return await response.json();
51
+ } catch (err) {
52
+ throw new Error(`Failed to connect to edge server: ${err.message}`);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Handle MCP initialize request
58
+ */
59
+ function handleInitialize(request) {
60
+ return {
61
+ jsonrpc: '2.0',
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
+ };
74
+ }
75
+
76
+ /**
77
+ * Handle MCP tools/list request
78
+ */
79
+ async function handleToolsList(apiKey, request) {
80
+ // Forward to edge to get actual tool list
81
+ return await forwardToEdge(apiKey, request);
82
+ }
83
+
84
+ /**
85
+ * Handle MCP tools/call request
86
+ */
87
+ async function handleToolsCall(apiKey, request) {
88
+ // Forward to edge
89
+ return await forwardToEdge(apiKey, request);
90
+ }
91
+
92
+ /**
93
+ * Process a single MCP request
94
+ */
95
+ async function processRequest(apiKey, request) {
96
+ const method = request.method;
97
+
98
+ switch (method) {
99
+ case 'initialize':
100
+ return handleInitialize(request);
101
+
102
+ case 'initialized':
103
+ // Notification, no response needed
104
+ return null;
105
+
106
+ case 'tools/list':
107
+ return await handleToolsList(apiKey, request);
108
+
109
+ case 'tools/call':
110
+ return await handleToolsCall(apiKey, request);
111
+
112
+ default:
113
+ // Forward unknown methods to edge
114
+ return await forwardToEdge(apiKey, request);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Run the stdio MCP server
120
+ */
121
+ export async function serve() {
122
+ const apiKey = getApiKey();
123
+
124
+ if (!apiKey) {
125
+ console.error('No API key configured.');
126
+ console.error('Run "npx ropilot init" to set up Ropilot.');
127
+ process.exit(1);
128
+ }
129
+
130
+ // Read JSON-RPC messages from stdin
131
+ let buffer = '';
132
+ let contentLength = -1;
133
+
134
+ const rl = createInterface({
135
+ input: process.stdin,
136
+ terminal: false
137
+ });
138
+
139
+ // Handle line-based input (for simpler clients)
140
+ process.stdin.on('data', (chunk) => {
141
+ buffer += chunk.toString();
142
+
143
+ // Try to parse Content-Length header
144
+ while (true) {
145
+ if (contentLength === -1) {
146
+ const headerEnd = buffer.indexOf('\r\n\r\n');
147
+ if (headerEnd === -1) break;
148
+
149
+ const header = buffer.slice(0, headerEnd);
150
+ const match = header.match(/Content-Length: (\d+)/i);
151
+ if (match) {
152
+ contentLength = parseInt(match[1], 10);
153
+ buffer = buffer.slice(headerEnd + 4);
154
+ } else {
155
+ // No Content-Length, try to parse as raw JSON
156
+ try {
157
+ const lineEnd = buffer.indexOf('\n');
158
+ if (lineEnd === -1) break;
159
+
160
+ const line = buffer.slice(0, lineEnd).trim();
161
+ buffer = buffer.slice(lineEnd + 1);
162
+
163
+ if (line) {
164
+ const request = JSON.parse(line);
165
+ handleRequest(apiKey, request);
166
+ }
167
+ } catch (e) {
168
+ buffer = buffer.slice(buffer.indexOf('\n') + 1);
169
+ }
170
+ continue;
171
+ }
172
+ }
173
+
174
+ // We have Content-Length, wait for body
175
+ if (buffer.length >= contentLength) {
176
+ const body = buffer.slice(0, contentLength);
177
+ buffer = buffer.slice(contentLength);
178
+ contentLength = -1;
179
+
180
+ try {
181
+ const request = JSON.parse(body);
182
+ handleRequest(apiKey, request);
183
+ } catch (e) {
184
+ sendError(null, -32700, 'Parse error');
185
+ }
186
+ } else {
187
+ break;
188
+ }
189
+ }
190
+ });
191
+
192
+ // Handle graceful shutdown
193
+ process.on('SIGINT', () => process.exit(0));
194
+ process.on('SIGTERM', () => process.exit(0));
195
+ }
196
+
197
+ /**
198
+ * Handle a parsed request
199
+ */
200
+ async function handleRequest(apiKey, request) {
201
+ try {
202
+ const response = await processRequest(apiKey, request);
203
+ if (response) {
204
+ sendResponse(response);
205
+ }
206
+ } catch (err) {
207
+ sendError(request.id, -32000, err.message);
208
+ }
209
+ }
package/lib/setup.js ADDED
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Setup and initialization for Ropilot CLI
3
+ *
4
+ * Handles:
5
+ * - First-time setup
6
+ * - Downloading system prompts
7
+ * - Creating project configs
8
+ */
9
+
10
+ import { existsSync, writeFileSync, mkdirSync, readFileSync } from 'fs';
11
+ import { join, dirname } from 'path';
12
+ import { homedir } from 'os';
13
+ import { createInterface } from 'readline';
14
+ import {
15
+ loadGlobalConfig,
16
+ saveGlobalConfig,
17
+ setApiKey,
18
+ getApiKey,
19
+ EDGE_URL
20
+ } from './config.js';
21
+
22
+ // Prompts storage directory
23
+ const PROMPTS_DIR = join(homedir(), '.ropilot', 'prompts');
24
+
25
+ /**
26
+ * Prompt for user input
27
+ */
28
+ function prompt(question) {
29
+ const rl = createInterface({
30
+ input: process.stdin,
31
+ output: process.stdout
32
+ });
33
+
34
+ return new Promise(resolve => {
35
+ rl.question(question, answer => {
36
+ rl.close();
37
+ resolve(answer.trim());
38
+ });
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Download prompts from edge server
44
+ */
45
+ async function downloadPrompts(apiKey) {
46
+ console.log('Downloading latest agent package...');
47
+
48
+ try {
49
+ // Fetch from edge server
50
+ const response = await fetch(`${EDGE_URL}/package`);
51
+ if (!response.ok) {
52
+ throw new Error(`Server returned ${response.status}`);
53
+ }
54
+
55
+ const pkg = await response.json();
56
+ console.log(`Package version: ${pkg.version}`);
57
+
58
+ // Ensure prompts directory exists
59
+ mkdirSync(PROMPTS_DIR, { recursive: true });
60
+
61
+ // Write package info
62
+ writeFileSync(join(PROMPTS_DIR, 'package.json'), JSON.stringify(pkg, null, 2));
63
+
64
+ // Update config with version info
65
+ const config = loadGlobalConfig();
66
+ config.promptsVersion = pkg.version;
67
+ config.lastUpdated = new Date().toISOString();
68
+ saveGlobalConfig(config);
69
+
70
+ console.log('Agent package downloaded successfully!');
71
+ return pkg;
72
+ } catch (err) {
73
+ console.error('Failed to download from server:', err.message);
74
+ console.log('Using bundled defaults...');
75
+
76
+ // Fallback to bundled defaults
77
+ const prompts = getDefaultPrompts();
78
+ mkdirSync(PROMPTS_DIR, { recursive: true });
79
+ for (const [name, content] of Object.entries(prompts)) {
80
+ writeFileSync(join(PROMPTS_DIR, name), content);
81
+ }
82
+
83
+ const config = loadGlobalConfig();
84
+ config.promptsVersion = '1.0.0-bundled';
85
+ config.lastUpdated = new Date().toISOString();
86
+ saveGlobalConfig(config);
87
+
88
+ return { version: '1.0.0-bundled', files: prompts };
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Get default prompts (bundled)
94
+ */
95
+ function getDefaultPrompts() {
96
+ return {
97
+ 'CLAUDE.md': `# Ropilot - AI-Powered Roblox Development
98
+
99
+ You are connected to Ropilot, an AI assistant for Roblox Studio development.
100
+
101
+ ## Available Tools
102
+
103
+ Ropilot provides MCP tools for interacting with Roblox Studio:
104
+
105
+ ### Reading & Inspection
106
+ - \`ropilot_listchildren\` - List children of an instance
107
+ - \`ropilot_getproperties\` - Get properties of an instance
108
+ - \`ropilot_search\` - Search for instances by name
109
+ - \`ropilot_searchbyclass\` - Search for instances by class name
110
+
111
+ ### Playtesting
112
+ - \`ropilot_test_start_playtest\` - Start a playtest session
113
+ - \`ropilot_test_stop_playtest\` - Stop the current playtest
114
+ - \`ropilot_test_run_client_lua\` - Run Lua code on the client
115
+ - \`ropilot_test_run_server_lua\` - Run Lua code on the server
116
+
117
+ ### Data Management
118
+ - \`ropilot_reset_data\` - Reset player data in DataStore
119
+
120
+ ## Context Targeting
121
+
122
+ Commands can target different contexts:
123
+ - \`edit\` - Edit mode (default)
124
+ - \`server\` - Server context during playtest
125
+ - \`client\` - Client context during playtest
126
+
127
+ Use the \`target_context\` parameter to specify which context should execute the command.
128
+
129
+ ## Best Practices
130
+
131
+ 1. **Read before modify** - Always inspect the current state before making changes
132
+ 2. **Use specific paths** - Reference instances by their full path (e.g., "Workspace.Map.Building")
133
+ 3. **Delegate playtesting** - Use the roblox-tester subagent for playtest operations
134
+ 4. **Test incrementally** - Start playtests to verify changes work correctly
135
+ `,
136
+
137
+ 'subagents.json': JSON.stringify({
138
+ "roblox-tester": {
139
+ "description": "Fast subagent for executing Roblox playtest steps",
140
+ "tools": ["ropilot_test_*", "ropilot_get_*", "ropilot_execute_lua"],
141
+ "prompt": "You are a Roblox playtest executor. Run the specified test steps and report results concisely."
142
+ }
143
+ }, null, 2)
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Set up agent files in current project
149
+ */
150
+ function setupProjectPrompts(pkg) {
151
+ const files = pkg.files || {};
152
+
153
+ for (const [filePath, content] of Object.entries(files)) {
154
+ const fullPath = filePath;
155
+ const dir = dirname(fullPath);
156
+
157
+ // Create directory if needed
158
+ if (dir && dir !== '.') {
159
+ mkdirSync(dir, { recursive: true });
160
+ }
161
+
162
+ // Check if file exists
163
+ if (existsSync(fullPath)) {
164
+ console.log(` Exists: ${fullPath}`);
165
+
166
+ // For CLAUDE.local.md, append if Ropilot section not present
167
+ if (fullPath.includes('CLAUDE') && fullPath.endsWith('.md')) {
168
+ const existing = readFileSync(fullPath, 'utf-8');
169
+ if (!existing.includes('Ropilot') && !existing.includes('roblox-tester')) {
170
+ writeFileSync(fullPath, existing + '\n\n' + content);
171
+ console.log(` Updated: ${fullPath} (added Ropilot section)`);
172
+ }
173
+ }
174
+ } else {
175
+ writeFileSync(fullPath, content);
176
+ console.log(` Created: ${fullPath}`);
177
+ }
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Initialize Ropilot in current project
183
+ */
184
+ export async function init(providedApiKey = null) {
185
+ console.log('');
186
+ console.log('Welcome to Ropilot!');
187
+ console.log('===================');
188
+ console.log('');
189
+
190
+ // Get API key
191
+ let apiKey = providedApiKey || getApiKey();
192
+
193
+ if (!apiKey) {
194
+ console.log('To use Ropilot, you need an API key.');
195
+ console.log('Get one at: https://ropilot.ai');
196
+ console.log('');
197
+ apiKey = await prompt('Enter your API key (ropilot_...): ');
198
+
199
+ if (!apiKey || !apiKey.startsWith('ropilot_')) {
200
+ console.error('Invalid API key. Must start with "ropilot_"');
201
+ process.exit(1);
202
+ }
203
+
204
+ setApiKey(apiKey);
205
+ console.log('API key saved!');
206
+ console.log('');
207
+ } else {
208
+ console.log(`Using API key: ${apiKey.slice(0, 20)}...`);
209
+ console.log('');
210
+ }
211
+
212
+ // Download prompts
213
+ const pkg = await downloadPrompts(apiKey);
214
+ console.log('');
215
+
216
+ // Set up project prompts
217
+ console.log('Setting up project files...');
218
+ setupProjectPrompts(pkg);
219
+ console.log('');
220
+
221
+ // Done!
222
+ console.log('Setup complete!');
223
+ console.log('');
224
+ console.log('Next steps:');
225
+ console.log('1. Make sure Roblox Studio is running with the Ropilot plugin');
226
+ console.log('2. Add Ropilot to your AI IDE:');
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`);
240
+ console.log('');
241
+ }
242
+
243
+ /**
244
+ * Update prompts to latest version
245
+ */
246
+ export async function update() {
247
+ console.log('Checking for updates...');
248
+
249
+ const apiKey = getApiKey();
250
+ if (!apiKey) {
251
+ console.error('No API key configured. Run "ropilot init" first.');
252
+ process.exit(1);
253
+ }
254
+
255
+ await downloadPrompts(apiKey);
256
+ console.log('');
257
+ console.log('Update complete!');
258
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "ropilot",
3
+ "version": "0.1.2",
4
+ "description": "AI-powered Roblox development assistant - MCP CLI",
5
+ "author": "whut",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "ropilot": "./bin/ropilot.js"
9
+ },
10
+ "main": "./lib/index.js",
11
+ "type": "module",
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "keywords": [
16
+ "roblox",
17
+ "ai",
18
+ "mcp",
19
+ "claude",
20
+ "model-context-protocol"
21
+ ],
22
+ "homepage": "https://ropilot.ai",
23
+ "files": [
24
+ "bin/",
25
+ "lib/",
26
+ "prompts/"
27
+ ],
28
+ "dependencies": {}
29
+ }