ropilot 0.1.42 → 0.1.44

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.
Files changed (2) hide show
  1. package/lib/proxy.js +119 -36
  2. package/package.json +1 -1
package/lib/proxy.js CHANGED
@@ -122,13 +122,49 @@ async function handleToolsList(apiKey, request) {
122
122
  }
123
123
 
124
124
  /**
125
- * Write large script content to a temp file and return the path
125
+ * Track script path -> local file mappings for sourcecontrol
126
+ */
127
+ const scriptLocalFiles = new Map();
128
+
129
+ /**
130
+ * Convert Studio path to local file path in src/ folder
131
+ * e.g., "game.ServerScriptService.MyScript" -> "src/ServerScriptService/MyScript.lua"
132
+ */
133
+ function studioPathToLocalPath(studioPath) {
134
+ const parts = studioPath.split('.');
135
+ // Remove "game" prefix
136
+ if (parts[0] === 'game') {
137
+ parts.shift();
138
+ }
139
+ // Join with / and add .lua extension
140
+ return join('src', ...parts) + '.lua';
141
+ }
142
+
143
+ /**
144
+ * Write script content to local file and track the mapping
145
+ */
146
+ function writeScriptToLocalFile(scriptPath, content) {
147
+ const localPath = studioPathToLocalPath(scriptPath);
148
+ const dir = join(process.cwd(), localPath.split('/').slice(0, -1).join('/'));
149
+
150
+ mkdirSync(dir, { recursive: true });
151
+
152
+ const fullPath = join(process.cwd(), localPath);
153
+ writeFileSync(fullPath, content);
154
+
155
+ // Track mapping for commitscript
156
+ scriptLocalFiles.set(scriptPath, fullPath);
157
+
158
+ return fullPath;
159
+ }
160
+
161
+ /**
162
+ * Write large script content to a temp file (for onboard_action readScript)
126
163
  */
127
164
  function writeScriptToTempFile(scriptPath, content) {
128
165
  const tempDir = join(tmpdir(), 'ropilot-scripts');
129
166
  mkdirSync(tempDir, { recursive: true });
130
167
 
131
- // Create a filename from the script path
132
168
  const safeName = scriptPath.replace(/[^a-zA-Z0-9]/g, '_');
133
169
  const tempFile = join(tempDir, `${safeName}_${randomUUID().slice(0, 8)}.lua`);
134
170
 
@@ -136,6 +172,13 @@ function writeScriptToTempFile(scriptPath, content) {
136
172
  return tempFile;
137
173
  }
138
174
 
175
+ /**
176
+ * Get local file path for a script path
177
+ */
178
+ function getLocalFileForScript(scriptPath) {
179
+ return scriptLocalFiles.get(scriptPath);
180
+ }
181
+
139
182
  /**
140
183
  * Handle MCP tools/call request
141
184
  */
@@ -151,6 +194,38 @@ async function handleToolsCall(apiKey, request) {
151
194
  };
152
195
  }
153
196
 
197
+ // Handle sourcecontrol_commitscript - inject file content before forwarding
198
+ if (request.params?.name === 'ropilot_sourcecontrol_commitscript') {
199
+ const scriptPath = request.params?.arguments?.path;
200
+ const localFile = getLocalFileForScript(scriptPath);
201
+
202
+ if (!localFile) {
203
+ return {
204
+ jsonrpc: '2.0',
205
+ id: request.id,
206
+ result: {
207
+ content: [{ type: 'text', text: `Error: No local file found for "${scriptPath}". Did you call ropilot_sourcecontrol_requestscript first?` }],
208
+ isError: true
209
+ }
210
+ };
211
+ }
212
+
213
+ if (!existsSync(localFile)) {
214
+ return {
215
+ jsonrpc: '2.0',
216
+ id: request.id,
217
+ result: {
218
+ content: [{ type: 'text', text: `Error: Local file not found: ${localFile}` }],
219
+ isError: true
220
+ }
221
+ };
222
+ }
223
+
224
+ // Read the file and inject content into the request
225
+ const content = readFileSync(localFile, 'utf-8');
226
+ request.params.arguments.content = content;
227
+ }
228
+
154
229
  // Forward to edge
155
230
  const response = await forwardToEdge(apiKey, request);
156
231
 
@@ -173,6 +248,48 @@ async function handleToolsCall(apiKey, request) {
173
248
  }
174
249
  }
175
250
 
251
+ // Handle sourcecontrol_requestscript - write to src/ folder
252
+ if (request.params?.name === 'ropilot_sourcecontrol_requestscript') {
253
+ const content = response?.result?.content;
254
+ if (content && Array.isArray(content) && content[0]?.text) {
255
+ const scriptContent = content[0].text;
256
+ const scriptPath = request.params.arguments.path || 'unknown';
257
+
258
+ // Check for error responses
259
+ if (scriptContent.startsWith('Error:')) {
260
+ return response;
261
+ }
262
+
263
+ // Write to src/ folder
264
+ const localFile = writeScriptToLocalFile(scriptPath, scriptContent);
265
+ response.result.content = [{
266
+ type: 'text',
267
+ text: `Script saved to:\n${localFile}\n\nEdit this file, then call ropilot_sourcecontrol_commitscript with path: "${scriptPath}"`
268
+ }];
269
+ }
270
+ }
271
+
272
+ // Handle sourcecontrol_createscript - auto-write to src/ folder
273
+ if (request.params?.name === 'ropilot_sourcecontrol_createscript') {
274
+ const content = response?.result?.content;
275
+ if (content && Array.isArray(content) && content[0]?.text) {
276
+ const responseText = content[0].text;
277
+
278
+ // Check for CREATED: prefix
279
+ if (responseText.startsWith('CREATED:')) {
280
+ const scriptPath = responseText.replace('CREATED:', '').trim();
281
+ const source = request.params.arguments.source || '';
282
+
283
+ // Write to src/ folder
284
+ const localFile = writeScriptToLocalFile(scriptPath, source);
285
+ response.result.content = [{
286
+ type: 'text',
287
+ text: `Created script: ${scriptPath}\nLocal file: ${localFile}\n\nEdit this file, then call ropilot_sourcecontrol_commitscript with path: "${scriptPath}"`
288
+ }];
289
+ }
290
+ }
291
+ }
292
+
176
293
  return response;
177
294
  }
178
295
 
@@ -269,37 +386,6 @@ async function checkPluginUpdate() {
269
386
  }
270
387
  }
271
388
 
272
- /**
273
- * Try to start rojo serve in background (non-blocking, silent on failure)
274
- */
275
- function tryStartRojoServe() {
276
- try {
277
- // Check if default.project.json exists (indicates a Rojo project)
278
- if (!existsSync(join(process.cwd(), 'default.project.json'))) {
279
- return; // Not a Rojo project
280
- }
281
-
282
- // Check if rojo serve is already running
283
- const check = spawn('pgrep', ['-f', 'rojo serve'], { stdio: 'pipe' });
284
- check.on('close', (code) => {
285
- // code 0 = found running process, code 1 = not found
286
- if (code === 0) {
287
- return; // Rojo already running
288
- }
289
-
290
- // Start rojo serve in background
291
- const child = spawn('rojo', ['serve'], {
292
- cwd: process.cwd(),
293
- detached: true,
294
- stdio: 'ignore',
295
- shell: true
296
- });
297
- child.unref();
298
- });
299
- } catch {
300
- // Silently ignore
301
- }
302
- }
303
389
 
304
390
  /**
305
391
  * Run the stdio MCP server
@@ -319,9 +405,6 @@ export async function serve() {
319
405
  // Check for plugin updates in background (non-blocking)
320
406
  checkPluginUpdate();
321
407
 
322
- // Start rojo serve in background if available (non-blocking, silent on failure)
323
- tryStartRojoServe();
324
-
325
408
  // Read JSON-RPC messages from stdin
326
409
  // Supports both Content-Length framing (LSP-style) and newline-delimited JSON
327
410
  let buffer = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ropilot",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "AI-powered Roblox development assistant - MCP CLI",
5
5
  "author": "whut",
6
6
  "license": "MIT",