roforge-cli 0.3.3 → 0.3.4
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 +31 -2
- package/dist/RoForge.rbxm +0 -0
- package/dist/RoForgeBridge.rbxm +0 -0
- package/package.json +2 -1
- package/src/install.js +72 -0
- package/src/session.js +12 -1
- package/src/tui/tui.js +8 -5
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
|
|
420
|
-
|
|
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
|
+
"version": "0.3.4",
|
|
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)
|
|
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
|
-
|
|
307
|
-
b.
|
|
308
|
-
|
|
309
|
-
|
|
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
|
}
|