roforge-cli 0.3.3 → 0.3.5

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/bin/roforge.js CHANGED
@@ -262,6 +262,33 @@ async function main() {
262
262
  return;
263
263
  }
264
264
 
265
+ case "install-plugin": {
266
+ const { PLUGINS, findPluginSource, installPlugin, pluginsDir } = await import("../src/install.js");
267
+ const which = (flags._pos && flags._pos[0]) || "bridge";
268
+ if (flags.list || flags.l) {
269
+ console.log(bold("Roblox Studio plugins folder:") + ` ${pluginsDir()}`);
270
+ return;
271
+ }
272
+ if (!PLUGINS[which]) {
273
+ console.error(red(`unknown plugin: ${which} (expected: ${Object.keys(PLUGINS).join(" | ")})`));
274
+ process.exit(1);
275
+ }
276
+ const src = findPluginSource(which);
277
+ if (!src) {
278
+ console.error(red("no built plugin found in this install."));
279
+ console.error(dim(" from a git clone: rojo build -o studio-bridge/dist/RoForgeBridge.rbxm studio-bridge/default.project.json"));
280
+ process.exit(1);
281
+ }
282
+ const { dest } = installPlugin(which);
283
+ console.log(bold("RoForge plugin installed") + dim(" — " + PLUGINS[which].desc + "\n"));
284
+ console.log(` ${green("✓")} ${src}\n → ${dest}\n`);
285
+ console.log(bold("Next:"));
286
+ console.log(" 1. start (or restart) Roblox Studio");
287
+ console.log(" 2. File → Plugins → Manage Plugins — " + which + " is now listed");
288
+ console.log(" 3. run `roforge studio` (or the TUI) and paste the printed token into the plugin dock");
289
+ return;
290
+ }
291
+
265
292
  case "pro": {
266
293
  const { queryProStatus, renderProStatus, probeBridge, startOwnBridge } = await import("../src/pro.js");
267
294
  const port = flags.port ? Number(flags.port) : cfg.bridge.port;
@@ -408,6 +435,7 @@ ${bold("Usage")}
408
435
  roforge tools list all tools
409
436
  roforge login --provider <p> store a key (gemini|groq|openrouter|anthropic|openai)
410
437
  roforge providers list providers, keys, and auto-routing order
438
+ roforge install-plugin install the RoForge Bridge plugin into Studio
411
439
  roforge pro show RoForge Pro license status (needs Studio bridge)
412
440
  roforge analyze <file...> run the official Luau analyzer on files
413
441
  roforge config [set k v] show / set configuration
@@ -416,8 +444,9 @@ ${bold("Usage")}
416
444
  ${bold("How it connects to Studio")}
417
445
  1. Built-in MCP (recommended): Studio → File → Studio Settings → Beta Features →
418
446
  ${bold("MCP Server")} — roforge talks to it at http://localhost:3004/mcp automatically.
419
- 2. RoForge Bridge plugin: install studio-bridge/dist/RoForgeBridge.rbxm into Studio,
420
- paste the bridge token (shown by ${bold("roforge studio")}) into the plugin.
447
+ 2. RoForge Bridge plugin (not in the Roblox Toolbox — install from here):
448
+ ${bold("roforge install-plugin")} → Studio: File Plugins (it's now listed)
449
+ then paste the bridge token (shown by ${bold("roforge studio")}) into the plugin dock.
421
450
 
422
451
  ${bold("Model providers (BYOK, zero backend)")}
423
452
  auto (default): first configured key wins, free tiers first:
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roforge-cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "RoForge \u2014 Claude-Code-style local AI agent for Roblox Studio. BYOK, zero backend, zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,6 +30,7 @@
30
30
  "files": [
31
31
  "bin",
32
32
  "src",
33
+ "dist",
33
34
  "demo",
34
35
  "README.md"
35
36
  ],
package/src/install.js ADDED
@@ -0,0 +1,72 @@
1
+ // Plugin installation: copy a built .rbxm into the OS Roblox Studio plugins
2
+ // folder so it appears under Studio's plugin page.
3
+ //
4
+ // Sources are resolved in this order:
5
+ // 1. the npm package's bundled copy (cli/dist/<name>.rbxm) — works when
6
+ // installed via `npm i -g roforge-cli`
7
+ // 2. the repo layout (<repoRoot>/studio-bridge/dist or <repoRoot>/client/dist)
8
+ // — works when running from a git clone
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ import os from "node:os";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const here = path.dirname(fileURLToPath(import.meta.url)); // cli/src
15
+
16
+ export const PLUGINS = {
17
+ bridge: {
18
+ dest: "RoForgeBridge.rbxm",
19
+ desc: "RoForge Bridge (loopback bridge driven by the roforge CLI — tools, vision, Pro status)",
20
+ repoRel: path.join("..", "..", "studio-bridge", "dist"),
21
+ },
22
+ client: {
23
+ dest: "RoForge.rbxm",
24
+ desc: "RoForge (in-Studio chat dock; standalone mode)",
25
+ repoRel: path.join("..", "..", "client", "dist"),
26
+ },
27
+ };
28
+
29
+ // Studio scans these folders for plugins.
30
+ export function pluginsDir(env = process.env, platform = process.platform, home = os.homedir()) {
31
+ switch (platform) {
32
+ case "win32":
33
+ return path.join(env.LOCALAPPDATA || path.join(home, "AppData", "Local"), "Roblox", "Plugins");
34
+ case "darwin":
35
+ return path.join(home, "Documents", "Roblox", "Plugins");
36
+ default:
37
+ return path.join(env.XDG_DATA_HOME || path.join(home, ".local", "share"), "Roblox", "Plugins");
38
+ }
39
+ }
40
+
41
+ // Find the built .rbxm for `name`. Returns an absolute path or null.
42
+ export function findPluginSource(name, { packageDir = path.join(here, "..") } = {}) {
43
+ const meta = PLUGINS[name];
44
+ if (!meta) return null;
45
+ const candidates = [
46
+ path.join(packageDir, "dist", meta.dest), // npm bundle
47
+ path.join(here, meta.repoRel, meta.dest), // git clone
48
+ ];
49
+ for (const c of candidates) {
50
+ if (fs.existsSync(c)) return c;
51
+ }
52
+ return null;
53
+ }
54
+
55
+ // Copy the plugin into the plugins folder. `destDir` overrides the target
56
+ // (tests). Returns { src, dest }.
57
+ export function installPlugin(name, { destDir } = {}) {
58
+ const meta = PLUGINS[name];
59
+ if (!meta) throw new Error(`unknown plugin: ${name} (expected: ${Object.keys(PLUGINS).join(" | ")})`);
60
+ const src = findPluginSource(name);
61
+ if (!src) {
62
+ throw new Error(
63
+ `no built plugin found (${meta.dest}). From a git clone run: ` +
64
+ `rojo build -o studio-bridge/dist/RoForgeBridge.rbxm studio-bridge/default.project.json`
65
+ );
66
+ }
67
+ const dir = destDir || pluginsDir();
68
+ fs.mkdirSync(dir, { recursive: true });
69
+ const dest = path.join(dir, meta.dest);
70
+ fs.copyFileSync(src, dest);
71
+ return { src, dest };
72
+ }
package/src/session.js CHANGED
@@ -60,7 +60,18 @@ export class Session {
60
60
  if (this.studioInfo.bridge) studio.push("The RoForge Bridge plugin is available (forge_* tools) — it connects when Studio is open and the bridge plugin is active.");
61
61
  const caps = (this.studioInfo.mcpCapture || []).map((n) => `studio_${n}`).join(", ");
62
62
  if (caps) studio.push(`Studio's MCP exposes vision tools (${caps}) — they return an image you can SEE; prefer them for visual checks.`);
63
- if (!studio.length) studio.push("No Studio connection yet — forge_* tools will error until Studio is open with the RoForge Bridge plugin (or enable Studio's built-in MCP beta).");
63
+ if (!studio.length) {
64
+ studio.push(
65
+ "No Studio connection yet — forge_* tools will error until Studio is connected. " +
66
+ "If the user asks how to connect, give EXACTLY these steps (do not invent others — the RoForge " +
67
+ "Bridge plugin is NOT in the Roblox Toolbox): (1) run `roforge install-plugin` to install the " +
68
+ "bundled plugin into Studio's plugins folder, or in Studio use File → Plugins → Manage Plugins → " +
69
+ "Install File… with studio-bridge/dist/RoForgeBridge.rbxm from https://github.com/hacvilke/roforge; " +
70
+ "(2) open the RoForge Bridge dock and paste the bridge token shown by `roforge studio` (or in this " +
71
+ "TUI's /studio output); (3) the status turns green when connected. Alternative: enable Studio's " +
72
+ "built-in MCP (File → Studio Settings → Beta Features → MCP Server) — no plugin needed."
73
+ );
74
+ }
64
75
 
65
76
  return `You are RoForge, a local AI agent for Roblox development, running on the user's machine (Claude-Code-style). You work on two surfaces:
66
77
 
package/src/tui/tui.js CHANGED
@@ -303,11 +303,14 @@ export class TUI {
303
303
  else lines.push(`${red("○")} studio MCP (built-in): not reachable @ ${this.session.cfg.mcpUrl}` + dim(" (File → Studio Settings → Beta Features → MCP Server)"));
304
304
  if (this.session.bridgeServer) {
305
305
  const b = this.session.bridgeServer;
306
- lines.push(
307
- b.connected
308
- ? `${green("●")} bridge plugin: connected (http://${b.host}:${b.port})`
309
- : `${yellow("○")} bridge plugin: waiting for Studio (http://${b.host}:${b.port})`
310
- );
306
+ if (b.connected) {
307
+ lines.push(`${green("●")} bridge plugin: connected (http://${b.host}:${b.port})`);
308
+ } else {
309
+ lines.push(
310
+ `${yellow("○")} bridge plugin: waiting for Studio (http://${b.host}:${b.port})` +
311
+ dim(` — run \`roforge install-plugin\` if not installed; token to paste in the plugin dock: ${b.token}`)
312
+ );
313
+ }
311
314
  }
312
315
  return lines.join("\n");
313
316
  }