dominus-cli 0.2.0 → 0.2.1
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/dist/index.js +174 -78
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import fs5, { existsSync, readFileSync, unlinkSync } from 'fs';
|
|
3
|
+
import path4, { join } from 'path';
|
|
4
|
+
import os3, { tmpdir } from 'os';
|
|
5
5
|
import { nanoid } from 'nanoid';
|
|
6
6
|
import { WebSocket, WebSocketServer } from 'ws';
|
|
7
7
|
import { EventEmitter } from 'events';
|
|
@@ -18,6 +18,7 @@ import { execSync } from 'child_process';
|
|
|
18
18
|
import { randomBytes } from 'crypto';
|
|
19
19
|
import Spinner from 'ink-spinner';
|
|
20
20
|
import OpenAI from 'openai';
|
|
21
|
+
import https from 'https';
|
|
21
22
|
|
|
22
23
|
var __defProp = Object.defineProperty;
|
|
23
24
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -55,14 +56,14 @@ function resolveProviderSettings(config) {
|
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
function ensureDir() {
|
|
58
|
-
if (!
|
|
59
|
-
|
|
59
|
+
if (!fs5.existsSync(DOMINUS_DIR)) {
|
|
60
|
+
fs5.mkdirSync(DOMINUS_DIR, { recursive: true });
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
function readJson(filePath, defaults) {
|
|
63
64
|
try {
|
|
64
|
-
if (
|
|
65
|
-
const raw =
|
|
65
|
+
if (fs5.existsSync(filePath)) {
|
|
66
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
66
67
|
return { ...defaults, ...JSON.parse(raw) };
|
|
67
68
|
}
|
|
68
69
|
} catch {
|
|
@@ -71,7 +72,7 @@ function readJson(filePath, defaults) {
|
|
|
71
72
|
}
|
|
72
73
|
function writeJson(filePath, data) {
|
|
73
74
|
ensureDir();
|
|
74
|
-
|
|
75
|
+
fs5.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
75
76
|
}
|
|
76
77
|
function loadConfig() {
|
|
77
78
|
ensureDir();
|
|
@@ -123,10 +124,10 @@ function createConfigAccess() {
|
|
|
123
124
|
var DOMINUS_DIR, CONFIG_PATH, DB_PATH, RULES_PATH, PROVIDERS, DEFAULTS, DEFAULT_RULES;
|
|
124
125
|
var init_config = __esm({
|
|
125
126
|
"src/config/config.ts"() {
|
|
126
|
-
DOMINUS_DIR =
|
|
127
|
-
CONFIG_PATH =
|
|
128
|
-
DB_PATH =
|
|
129
|
-
RULES_PATH =
|
|
127
|
+
DOMINUS_DIR = path4.join(os3.homedir(), ".dominus");
|
|
128
|
+
CONFIG_PATH = path4.join(DOMINUS_DIR, "config.json");
|
|
129
|
+
DB_PATH = path4.join(DOMINUS_DIR, "dominus.db");
|
|
130
|
+
RULES_PATH = path4.join(DOMINUS_DIR, "rules.json");
|
|
130
131
|
PROVIDERS = {
|
|
131
132
|
openai: {
|
|
132
133
|
name: "OpenAI",
|
|
@@ -641,14 +642,14 @@ __export(store_exports, {
|
|
|
641
642
|
function persist() {
|
|
642
643
|
if (!db) return;
|
|
643
644
|
const data = db.export();
|
|
644
|
-
|
|
645
|
+
fs5.writeFileSync(dbPath, Buffer.from(data));
|
|
645
646
|
}
|
|
646
647
|
async function initMemoryStore() {
|
|
647
648
|
if (db) return;
|
|
648
649
|
dbPath = getDbPath();
|
|
649
650
|
const SQL = await initSqlJs();
|
|
650
|
-
if (
|
|
651
|
-
const buffer =
|
|
651
|
+
if (fs5.existsSync(dbPath)) {
|
|
652
|
+
const buffer = fs5.readFileSync(dbPath);
|
|
652
653
|
db = new SQL.Database(buffer);
|
|
653
654
|
} else {
|
|
654
655
|
db = new SQL.Database();
|
|
@@ -939,10 +940,10 @@ var init_read_script = __esm({
|
|
|
939
940
|
if (!ctx.isStudioConnected()) {
|
|
940
941
|
return { success: false, error: "Studio is not connected" };
|
|
941
942
|
}
|
|
942
|
-
const
|
|
943
|
-
const response = await ctx.sendToStudio(CliMsg.GET_SCRIPT, { path:
|
|
943
|
+
const path5 = params.path;
|
|
944
|
+
const response = await ctx.sendToStudio(CliMsg.GET_SCRIPT, { path: path5 });
|
|
944
945
|
if (!response.payload) {
|
|
945
|
-
return { success: false, error: `Script not found: ${
|
|
946
|
+
return { success: false, error: `Script not found: ${path5}` };
|
|
946
947
|
}
|
|
947
948
|
return {
|
|
948
949
|
success: true,
|
|
@@ -988,14 +989,14 @@ var init_edit_script = __esm({
|
|
|
988
989
|
if (!ctx.isStudioConnected()) {
|
|
989
990
|
return { success: false, error: "Studio is not connected" };
|
|
990
991
|
}
|
|
991
|
-
const
|
|
992
|
+
const path5 = params.path;
|
|
992
993
|
const source = params.source;
|
|
993
|
-
const response = await ctx.sendToStudio(CliMsg.SET_SCRIPT, { path:
|
|
994
|
+
const response = await ctx.sendToStudio(CliMsg.SET_SCRIPT, { path: path5, source });
|
|
994
995
|
const payload = response.payload;
|
|
995
996
|
if (!payload.success) {
|
|
996
997
|
return { success: false, error: payload.error ?? "Failed to edit script" };
|
|
997
998
|
}
|
|
998
|
-
return { success: true, data: { path:
|
|
999
|
+
return { success: true, data: { path: path5, linesWritten: source.split("\n").length } };
|
|
999
1000
|
}
|
|
1000
1001
|
};
|
|
1001
1002
|
}
|
|
@@ -1681,8 +1682,8 @@ __export(clone_instance_exports, {
|
|
|
1681
1682
|
tool: () => tool18
|
|
1682
1683
|
});
|
|
1683
1684
|
function buildCloneCode(params) {
|
|
1684
|
-
const
|
|
1685
|
-
const parts =
|
|
1685
|
+
const path5 = params.path;
|
|
1686
|
+
const parts = path5.split(".");
|
|
1686
1687
|
let resolve = "game";
|
|
1687
1688
|
for (const p of parts) {
|
|
1688
1689
|
resolve += `["${p}"]`;
|
|
@@ -1823,8 +1824,8 @@ __export(build_multiple_exports, {
|
|
|
1823
1824
|
});
|
|
1824
1825
|
function generateBatchCode(parts, groupName, groupParent) {
|
|
1825
1826
|
const lines = [];
|
|
1826
|
-
function resolveParent(
|
|
1827
|
-
const segs =
|
|
1827
|
+
function resolveParent(path5) {
|
|
1828
|
+
const segs = path5.split(".");
|
|
1828
1829
|
let r = "game";
|
|
1829
1830
|
for (const s of segs) r += `["${s}"]`;
|
|
1830
1831
|
return r;
|
|
@@ -2088,11 +2089,11 @@ var init_upload_asset = __esm({
|
|
|
2088
2089
|
const assetType = params.assetType;
|
|
2089
2090
|
const name = params.name;
|
|
2090
2091
|
const description = params.description ?? "";
|
|
2091
|
-
if (!
|
|
2092
|
+
if (!fs5.existsSync(filePath)) {
|
|
2092
2093
|
return { success: false, error: `File not found: ${filePath}` };
|
|
2093
2094
|
}
|
|
2094
|
-
const fileBuffer =
|
|
2095
|
-
const fileName =
|
|
2095
|
+
const fileBuffer = fs5.readFileSync(filePath);
|
|
2096
|
+
const fileName = path4.basename(filePath);
|
|
2096
2097
|
const typeMapping = {
|
|
2097
2098
|
Image: "Decal",
|
|
2098
2099
|
Audio: "Audio",
|
|
@@ -2166,15 +2167,15 @@ async function startMcpServer() {
|
|
|
2166
2167
|
}
|
|
2167
2168
|
const mcp = new McpServer({
|
|
2168
2169
|
name: "dominus",
|
|
2169
|
-
version: "0.2.
|
|
2170
|
+
version: "0.2.1"
|
|
2170
2171
|
});
|
|
2171
2172
|
mcp.tool(
|
|
2172
2173
|
"read_script",
|
|
2173
2174
|
"Read the source code of a script in Roblox Studio",
|
|
2174
2175
|
{ path: z.string().describe('Full instance path, e.g. "ServerScriptService.GameManager"') },
|
|
2175
|
-
async ({ path:
|
|
2176
|
+
async ({ path: path5 }) => {
|
|
2176
2177
|
assertConnected();
|
|
2177
|
-
const res = await bridge.sendRequest(CliMsg.GET_SCRIPT, { path:
|
|
2178
|
+
const res = await bridge.sendRequest(CliMsg.GET_SCRIPT, { path: path5 });
|
|
2178
2179
|
return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
|
|
2179
2180
|
}
|
|
2180
2181
|
);
|
|
@@ -2185,9 +2186,9 @@ async function startMcpServer() {
|
|
|
2185
2186
|
path: z.string().describe("Full instance path"),
|
|
2186
2187
|
source: z.string().describe("New complete source code")
|
|
2187
2188
|
},
|
|
2188
|
-
async ({ path:
|
|
2189
|
+
async ({ path: path5, source }) => {
|
|
2189
2190
|
assertConnected();
|
|
2190
|
-
const res = await bridge.sendRequest(CliMsg.SET_SCRIPT, { path:
|
|
2191
|
+
const res = await bridge.sendRequest(CliMsg.SET_SCRIPT, { path: path5, source });
|
|
2191
2192
|
return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
|
|
2192
2193
|
}
|
|
2193
2194
|
);
|
|
@@ -2221,9 +2222,9 @@ async function startMcpServer() {
|
|
|
2221
2222
|
"get_properties",
|
|
2222
2223
|
"Get all properties of an instance in Roblox Studio",
|
|
2223
2224
|
{ path: z.string().describe("Full instance path") },
|
|
2224
|
-
async ({ path:
|
|
2225
|
+
async ({ path: path5 }) => {
|
|
2225
2226
|
assertConnected();
|
|
2226
|
-
const res = await bridge.sendRequest(CliMsg.GET_PROPERTIES, { path:
|
|
2227
|
+
const res = await bridge.sendRequest(CliMsg.GET_PROPERTIES, { path: path5 });
|
|
2227
2228
|
return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
|
|
2228
2229
|
}
|
|
2229
2230
|
);
|
|
@@ -2234,9 +2235,9 @@ async function startMcpServer() {
|
|
|
2234
2235
|
path: z.string().describe("Full instance path"),
|
|
2235
2236
|
properties: z.record(z.unknown()).describe("Key-value pairs of properties to set")
|
|
2236
2237
|
},
|
|
2237
|
-
async ({ path:
|
|
2238
|
+
async ({ path: path5, properties }) => {
|
|
2238
2239
|
assertConnected();
|
|
2239
|
-
const res = await bridge.sendRequest(CliMsg.SET_PROPERTIES, { path:
|
|
2240
|
+
const res = await bridge.sendRequest(CliMsg.SET_PROPERTIES, { path: path5, properties });
|
|
2240
2241
|
return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
|
|
2241
2242
|
}
|
|
2242
2243
|
);
|
|
@@ -2264,9 +2265,9 @@ async function startMcpServer() {
|
|
|
2264
2265
|
"delete_instance",
|
|
2265
2266
|
"Delete an instance from the Roblox Studio DataModel",
|
|
2266
2267
|
{ path: z.string().describe("Full instance path to delete") },
|
|
2267
|
-
async ({ path:
|
|
2268
|
+
async ({ path: path5 }) => {
|
|
2268
2269
|
assertConnected();
|
|
2269
|
-
const res = await bridge.sendRequest(CliMsg.DELETE_INSTANCE, { path:
|
|
2270
|
+
const res = await bridge.sendRequest(CliMsg.DELETE_INSTANCE, { path: path5 });
|
|
2270
2271
|
return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
|
|
2271
2272
|
}
|
|
2272
2273
|
);
|
|
@@ -2463,8 +2464,8 @@ async function startMcpServer() {
|
|
|
2463
2464
|
const parentParts = parent.split(".");
|
|
2464
2465
|
let parentResolve = "game";
|
|
2465
2466
|
for (const p of parentParts) parentResolve += `["${p}"]`;
|
|
2466
|
-
const resolves = params.paths.map((
|
|
2467
|
-
const parts =
|
|
2467
|
+
const resolves = params.paths.map((path5) => {
|
|
2468
|
+
const parts = path5.split(".");
|
|
2468
2469
|
let r = "game";
|
|
2469
2470
|
for (const part of parts) r += `["${part}"]`;
|
|
2470
2471
|
return r;
|
|
@@ -2504,8 +2505,8 @@ async function startMcpServer() {
|
|
|
2504
2505
|
const parts = params.parts;
|
|
2505
2506
|
const groupName = params.groupName;
|
|
2506
2507
|
const groupParent = params.groupParent ?? "Workspace";
|
|
2507
|
-
function resolveP(
|
|
2508
|
-
const segs =
|
|
2508
|
+
function resolveP(path5) {
|
|
2509
|
+
const segs = path5.split(".");
|
|
2509
2510
|
let r = "game";
|
|
2510
2511
|
for (const s of segs) r += `["${s}"]`;
|
|
2511
2512
|
return r;
|
|
@@ -4306,7 +4307,98 @@ function createDefaultRegistry() {
|
|
|
4306
4307
|
// src/index.tsx
|
|
4307
4308
|
init_store();
|
|
4308
4309
|
init_config();
|
|
4309
|
-
var
|
|
4310
|
+
var CACHE_DIR = path4.join(os3.homedir(), ".dominus");
|
|
4311
|
+
var CACHE_FILE = path4.join(CACHE_DIR, "update-check.json");
|
|
4312
|
+
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
4313
|
+
var NPM_PACKAGE = "dominus-cli";
|
|
4314
|
+
function readCache() {
|
|
4315
|
+
try {
|
|
4316
|
+
if (fs5.existsSync(CACHE_FILE)) {
|
|
4317
|
+
return JSON.parse(fs5.readFileSync(CACHE_FILE, "utf-8"));
|
|
4318
|
+
}
|
|
4319
|
+
} catch {
|
|
4320
|
+
}
|
|
4321
|
+
return { lastCheck: 0, latestVersion: null };
|
|
4322
|
+
}
|
|
4323
|
+
function writeCache(cache) {
|
|
4324
|
+
try {
|
|
4325
|
+
if (!fs5.existsSync(CACHE_DIR)) fs5.mkdirSync(CACHE_DIR, { recursive: true });
|
|
4326
|
+
fs5.writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf-8");
|
|
4327
|
+
} catch {
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
function fetchLatestVersion() {
|
|
4331
|
+
return new Promise((resolve) => {
|
|
4332
|
+
const req = https.get(
|
|
4333
|
+
`https://registry.npmjs.org/${NPM_PACKAGE}/latest`,
|
|
4334
|
+
{ headers: { Accept: "application/json" }, timeout: 5e3 },
|
|
4335
|
+
(res) => {
|
|
4336
|
+
if (res.statusCode !== 200) {
|
|
4337
|
+
resolve(null);
|
|
4338
|
+
res.resume();
|
|
4339
|
+
return;
|
|
4340
|
+
}
|
|
4341
|
+
let body = "";
|
|
4342
|
+
res.on("data", (c) => body += c);
|
|
4343
|
+
res.on("end", () => {
|
|
4344
|
+
try {
|
|
4345
|
+
resolve(JSON.parse(body).version ?? null);
|
|
4346
|
+
} catch {
|
|
4347
|
+
resolve(null);
|
|
4348
|
+
}
|
|
4349
|
+
});
|
|
4350
|
+
}
|
|
4351
|
+
);
|
|
4352
|
+
req.on("error", () => resolve(null));
|
|
4353
|
+
req.on("timeout", () => {
|
|
4354
|
+
req.destroy();
|
|
4355
|
+
resolve(null);
|
|
4356
|
+
});
|
|
4357
|
+
});
|
|
4358
|
+
}
|
|
4359
|
+
function compareVersions(current, latest) {
|
|
4360
|
+
const a = current.split(".").map(Number);
|
|
4361
|
+
const b = latest.split(".").map(Number);
|
|
4362
|
+
for (let i = 0; i < 3; i++) {
|
|
4363
|
+
if ((b[i] ?? 0) > (a[i] ?? 0)) return 1;
|
|
4364
|
+
if ((b[i] ?? 0) < (a[i] ?? 0)) return -1;
|
|
4365
|
+
}
|
|
4366
|
+
return 0;
|
|
4367
|
+
}
|
|
4368
|
+
async function checkForUpdate(currentVersion) {
|
|
4369
|
+
try {
|
|
4370
|
+
const cache = readCache();
|
|
4371
|
+
const now = Date.now();
|
|
4372
|
+
if (now - cache.lastCheck < CHECK_INTERVAL_MS && cache.latestVersion) {
|
|
4373
|
+
if (compareVersions(currentVersion, cache.latestVersion) > 0) {
|
|
4374
|
+
return { updateAvailable: true, currentVersion, latestVersion: cache.latestVersion };
|
|
4375
|
+
}
|
|
4376
|
+
return null;
|
|
4377
|
+
}
|
|
4378
|
+
const latest = await fetchLatestVersion();
|
|
4379
|
+
writeCache({ lastCheck: now, latestVersion: latest });
|
|
4380
|
+
if (latest && compareVersions(currentVersion, latest) > 0) {
|
|
4381
|
+
return { updateAvailable: true, currentVersion, latestVersion: latest };
|
|
4382
|
+
}
|
|
4383
|
+
} catch {
|
|
4384
|
+
}
|
|
4385
|
+
return null;
|
|
4386
|
+
}
|
|
4387
|
+
function formatUpdateMessage(info) {
|
|
4388
|
+
const line1 = `Update available: ${info.currentVersion} \u2192 ${info.latestVersion}`;
|
|
4389
|
+
const line2 = `Run: npm i -g ${NPM_PACKAGE}`;
|
|
4390
|
+
const width = Math.max(line1.length, line2.length) + 4;
|
|
4391
|
+
const pad = (s) => ` \u2502 ${s}${" ".repeat(width - s.length - 4)} \u2502`;
|
|
4392
|
+
return [
|
|
4393
|
+
"",
|
|
4394
|
+
` \u256D${"\u2500".repeat(width)}\u256E`,
|
|
4395
|
+
pad(line1),
|
|
4396
|
+
pad(line2),
|
|
4397
|
+
` \u2570${"\u2500".repeat(width)}\u256F`,
|
|
4398
|
+
""
|
|
4399
|
+
].join("\n");
|
|
4400
|
+
}
|
|
4401
|
+
var VERSION = "0.2.1";
|
|
4310
4402
|
var program = new Command();
|
|
4311
4403
|
program.name("dominus").description("AI-powered autonomous agent for Roblox Studio development").version(VERSION);
|
|
4312
4404
|
program.command("start", { isDefault: true }).description("Launch the Dominus TUI agent").option("-p, --port <port>", "WebSocket server port", "18088").action(async (opts) => {
|
|
@@ -4326,6 +4418,10 @@ program.command("start", { isDefault: true }).description("Launch the Dominus TU
|
|
|
4326
4418
|
setConfigValue("userName", firstName);
|
|
4327
4419
|
}
|
|
4328
4420
|
}
|
|
4421
|
+
checkForUpdate(VERSION).then((info) => {
|
|
4422
|
+
if (info) process.stderr.write(formatUpdateMessage(info));
|
|
4423
|
+
}).catch(() => {
|
|
4424
|
+
});
|
|
4329
4425
|
await launchApp(port);
|
|
4330
4426
|
});
|
|
4331
4427
|
var configCmd = program.command("config").description("Manage Dominus configuration");
|
|
@@ -4416,24 +4512,24 @@ rulesCmd.command("list").description("List all rules").action(() => {
|
|
|
4416
4512
|
});
|
|
4417
4513
|
program.command("install-plugin").description("Build & install the Dominus plugin into Roblox Studio").action(async () => {
|
|
4418
4514
|
const { execSync: execSync2 } = await import('child_process');
|
|
4419
|
-
const packageRoot =
|
|
4420
|
-
const pluginDir =
|
|
4421
|
-
const pluginProject =
|
|
4422
|
-
const studioPlugins =
|
|
4423
|
-
|
|
4515
|
+
const packageRoot = path4.resolve(import.meta.dirname ?? __dirname, "..");
|
|
4516
|
+
const pluginDir = path4.join(packageRoot, "plugin");
|
|
4517
|
+
const pluginProject = path4.join(pluginDir, "default.project.json");
|
|
4518
|
+
const studioPlugins = path4.join(
|
|
4519
|
+
os3.homedir(),
|
|
4424
4520
|
"AppData",
|
|
4425
4521
|
"Local",
|
|
4426
4522
|
"Roblox",
|
|
4427
4523
|
"Plugins"
|
|
4428
4524
|
);
|
|
4429
|
-
const destFile =
|
|
4430
|
-
if (!
|
|
4525
|
+
const destFile = path4.join(studioPlugins, "Dominus.rbxm");
|
|
4526
|
+
if (!fs5.existsSync(pluginProject)) {
|
|
4431
4527
|
console.log(" \u2716 Plugin source not found.");
|
|
4432
4528
|
console.log(` Expected at: ${pluginDir}`);
|
|
4433
4529
|
return;
|
|
4434
4530
|
}
|
|
4435
|
-
if (!
|
|
4436
|
-
|
|
4531
|
+
if (!fs5.existsSync(studioPlugins)) {
|
|
4532
|
+
fs5.mkdirSync(studioPlugins, { recursive: true });
|
|
4437
4533
|
}
|
|
4438
4534
|
let rojoAvailable = false;
|
|
4439
4535
|
try {
|
|
@@ -4460,49 +4556,49 @@ program.command("mcp").description("Start the Dominus MCP server (for Cursor, Cl
|
|
|
4460
4556
|
await startMcpServer2();
|
|
4461
4557
|
});
|
|
4462
4558
|
function getMcpTargets() {
|
|
4463
|
-
const home =
|
|
4464
|
-
const appData = process.env.APPDATA ||
|
|
4465
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
4559
|
+
const home = os3.homedir();
|
|
4560
|
+
const appData = process.env.APPDATA || path4.join(home, "AppData", "Roaming");
|
|
4561
|
+
const localAppData = process.env.LOCALAPPDATA || path4.join(home, "AppData", "Local");
|
|
4466
4562
|
const cwd = process.cwd();
|
|
4467
4563
|
return [
|
|
4468
4564
|
{
|
|
4469
4565
|
name: "Cursor (project)",
|
|
4470
|
-
configPath:
|
|
4566
|
+
configPath: path4.join(cwd, ".cursor", "mcp.json"),
|
|
4471
4567
|
keyPath: ["mcpServers"]
|
|
4472
4568
|
},
|
|
4473
4569
|
{
|
|
4474
4570
|
name: "Cursor (global)",
|
|
4475
|
-
configPath:
|
|
4571
|
+
configPath: path4.join(home, ".cursor", "mcp.json"),
|
|
4476
4572
|
keyPath: ["mcpServers"]
|
|
4477
4573
|
},
|
|
4478
4574
|
{
|
|
4479
4575
|
name: "Claude Desktop",
|
|
4480
|
-
configPath:
|
|
4576
|
+
configPath: path4.join(appData, "Claude", "claude_desktop_config.json"),
|
|
4481
4577
|
keyPath: ["mcpServers"]
|
|
4482
4578
|
},
|
|
4483
4579
|
{
|
|
4484
4580
|
name: "Claude Code",
|
|
4485
|
-
configPath:
|
|
4581
|
+
configPath: path4.join(home, ".claude.json"),
|
|
4486
4582
|
keyPath: ["mcpServers"]
|
|
4487
4583
|
},
|
|
4488
4584
|
{
|
|
4489
4585
|
name: "Windsurf (project)",
|
|
4490
|
-
configPath:
|
|
4586
|
+
configPath: path4.join(cwd, ".windsurf", "mcp.json"),
|
|
4491
4587
|
keyPath: ["mcpServers"]
|
|
4492
4588
|
},
|
|
4493
4589
|
{
|
|
4494
4590
|
name: "Windsurf (global)",
|
|
4495
|
-
configPath:
|
|
4591
|
+
configPath: path4.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
4496
4592
|
keyPath: ["mcpServers"]
|
|
4497
4593
|
},
|
|
4498
4594
|
{
|
|
4499
4595
|
name: "VS Code (project)",
|
|
4500
|
-
configPath:
|
|
4596
|
+
configPath: path4.join(cwd, ".vscode", "mcp.json"),
|
|
4501
4597
|
keyPath: ["servers"]
|
|
4502
4598
|
},
|
|
4503
4599
|
{
|
|
4504
4600
|
name: "VS Code (global)",
|
|
4505
|
-
configPath:
|
|
4601
|
+
configPath: path4.join(localAppData, "Code", "User", "settings.json"),
|
|
4506
4602
|
keyPath: ["mcp", "servers"]
|
|
4507
4603
|
}
|
|
4508
4604
|
];
|
|
@@ -4514,9 +4610,9 @@ var dominusEntry = {
|
|
|
4514
4610
|
};
|
|
4515
4611
|
function injectMcpConfig(target) {
|
|
4516
4612
|
let config = {};
|
|
4517
|
-
if (
|
|
4613
|
+
if (fs5.existsSync(target.configPath)) {
|
|
4518
4614
|
try {
|
|
4519
|
-
config = JSON.parse(
|
|
4615
|
+
config = JSON.parse(fs5.readFileSync(target.configPath, "utf-8"));
|
|
4520
4616
|
} catch {
|
|
4521
4617
|
config = {};
|
|
4522
4618
|
}
|
|
@@ -4532,12 +4628,12 @@ function injectMcpConfig(target) {
|
|
|
4532
4628
|
return { status: "already" };
|
|
4533
4629
|
}
|
|
4534
4630
|
obj["dominus"] = { ...dominusEntry };
|
|
4535
|
-
const dir =
|
|
4536
|
-
if (!
|
|
4537
|
-
|
|
4631
|
+
const dir = path4.dirname(target.configPath);
|
|
4632
|
+
if (!fs5.existsSync(dir)) {
|
|
4633
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
4538
4634
|
}
|
|
4539
|
-
|
|
4540
|
-
return { status:
|
|
4635
|
+
fs5.writeFileSync(target.configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
4636
|
+
return { status: fs5.existsSync(target.configPath) ? "installed" : "created" };
|
|
4541
4637
|
}
|
|
4542
4638
|
program.command("mcp-install").description("Auto-install Dominus MCP into Cursor, VS Code, Claude Desktop, Windsurf, etc.").option("-a, --all", "Install to all detected editors").action(async (opts) => {
|
|
4543
4639
|
const targets = getMcpTargets();
|
|
@@ -4559,7 +4655,7 @@ program.command("mcp-install").description("Auto-install Dominus MCP into Cursor
|
|
|
4559
4655
|
}
|
|
4560
4656
|
const detected = targets.map((t) => ({
|
|
4561
4657
|
target: t,
|
|
4562
|
-
exists:
|
|
4658
|
+
exists: fs5.existsSync(path4.dirname(t.configPath))
|
|
4563
4659
|
}));
|
|
4564
4660
|
const toInstall = detected.filter((d) => d.exists);
|
|
4565
4661
|
if (toInstall.length === 0) {
|
|
@@ -4632,23 +4728,23 @@ program.command("mcp-setup").description("Print MCP configuration for manual set
|
|
|
4632
4728
|
console.log("");
|
|
4633
4729
|
});
|
|
4634
4730
|
function buildPluginXml(pluginDir, destFile) {
|
|
4635
|
-
const srcDir =
|
|
4636
|
-
if (!
|
|
4731
|
+
const srcDir = path4.join(pluginDir, "src");
|
|
4732
|
+
if (!fs5.existsSync(srcDir)) {
|
|
4637
4733
|
console.log(` \u2716 Plugin source directory not found: ${srcDir}`);
|
|
4638
4734
|
return;
|
|
4639
4735
|
}
|
|
4640
|
-
const files =
|
|
4736
|
+
const files = fs5.readdirSync(srcDir).filter((f) => f.endsWith(".lua"));
|
|
4641
4737
|
const mainFile = files.find((f) => f === "init.server.lua");
|
|
4642
4738
|
const moduleFiles = files.filter((f) => f !== "init.server.lua");
|
|
4643
4739
|
if (!mainFile) {
|
|
4644
4740
|
console.log(" \u2716 init.server.lua not found in plugin source");
|
|
4645
4741
|
return;
|
|
4646
4742
|
}
|
|
4647
|
-
const mainSource =
|
|
4743
|
+
const mainSource = fs5.readFileSync(path4.join(srcDir, mainFile), "utf-8");
|
|
4648
4744
|
let moduleItems = "";
|
|
4649
4745
|
for (const mf of moduleFiles) {
|
|
4650
4746
|
const modName = mf.replace(".lua", "");
|
|
4651
|
-
const modSource =
|
|
4747
|
+
const modSource = fs5.readFileSync(path4.join(srcDir, mf), "utf-8");
|
|
4652
4748
|
moduleItems += `
|
|
4653
4749
|
<Item class="ModuleScript" referent="${modName}">
|
|
4654
4750
|
<Properties>
|
|
@@ -4666,7 +4762,7 @@ function buildPluginXml(pluginDir, destFile) {
|
|
|
4666
4762
|
</Properties>${moduleItems}
|
|
4667
4763
|
</Item>
|
|
4668
4764
|
</roblox>`;
|
|
4669
|
-
|
|
4765
|
+
fs5.writeFileSync(destFile, rbxmx, "utf-8");
|
|
4670
4766
|
console.log(` \u2714 Plugin installed to: ${destFile}`);
|
|
4671
4767
|
console.log(" Restart Roblox Studio to load the plugin.");
|
|
4672
4768
|
}
|